* [PATCH 1/4] tools: add spectrum-installer
@ 2026-01-04 14:00 Johannes Süllner
2026-01-04 14:00 ` [PATCH 2/4] host/rootfs: integrate spectrum-installer Johannes Süllner
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Johannes Süllner @ 2026-01-04 14:00 UTC (permalink / raw)
To: devel; +Cc: Johannes Süllner
Written in Rust using the Iced GUI library. Uses `lsblk-rs` to offer a
list of disks where the user can choose one to install Spectrum on.
Uses `systemd-repart` for the installation, which is running in an
embedded terminal window using `iced-term`.
Signed-off-by: Johannes Süllner <johannes.suellner@mailbox.org>
---
pkgs/default.nix | 1 +
tools/spectrum-installer/Cargo.lock | 5106 +++++++++++++++++
tools/spectrum-installer/Cargo.lock.license | 2 +
tools/spectrum-installer/Cargo.toml | 14 +
tools/spectrum-installer/default.nix | 41 +
.../res/installer_logo_mesh.svg | 85 +
.../res/repart.d/10-esp.conf | 8 +
.../res/repart.d/20-verity-A.conf | 9 +
.../res/repart.d/21-rootfs-A.conf | 9 +
.../res/repart.d/30-verity-B.conf | 8 +
.../res/repart.d/31-rootfs-B.conf | 8 +
.../res/repart.d/40-home.conf | 7 +
tools/spectrum-installer/shell.nix | 30 +
tools/spectrum-installer/src/main.rs | 52 +
.../src/pages/completion.rs | 112 +
.../src/pages/confirmation.rs | 108 +
.../src/pages/disk_selection.rs | 134 +
.../src/pages/installation.rs | 182 +
tools/spectrum-installer/src/pages/layout.rs | 122 +
tools/spectrum-installer/src/pages/mod.rs | 43 +
tools/spectrum-installer/src/pages/welcome.rs | 62 +
21 files changed, 6143 insertions(+)
create mode 100644 tools/spectrum-installer/Cargo.lock
create mode 100644 tools/spectrum-installer/Cargo.lock.license
create mode 100644 tools/spectrum-installer/Cargo.toml
create mode 100644 tools/spectrum-installer/default.nix
create mode 100644 tools/spectrum-installer/res/installer_logo_mesh.svg
create mode 100644 tools/spectrum-installer/res/repart.d/10-esp.conf
create mode 100644 tools/spectrum-installer/res/repart.d/20-verity-A.conf
create mode 100644 tools/spectrum-installer/res/repart.d/21-rootfs-A.conf
create mode 100644 tools/spectrum-installer/res/repart.d/30-verity-B.conf
create mode 100644 tools/spectrum-installer/res/repart.d/31-rootfs-B.conf
create mode 100644 tools/spectrum-installer/res/repart.d/40-home.conf
create mode 100644 tools/spectrum-installer/shell.nix
create mode 100644 tools/spectrum-installer/src/main.rs
create mode 100644 tools/spectrum-installer/src/pages/completion.rs
create mode 100644 tools/spectrum-installer/src/pages/confirmation.rs
create mode 100644 tools/spectrum-installer/src/pages/disk_selection.rs
create mode 100644 tools/spectrum-installer/src/pages/installation.rs
create mode 100644 tools/spectrum-installer/src/pages/layout.rs
create mode 100644 tools/spectrum-installer/src/pages/mod.rs
create mode 100644 tools/spectrum-installer/src/pages/welcome.rs
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 4dbdfee..a80c5b3 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -74,6 +74,7 @@ let
../release/live/build
../tools/mount-flatpak/target
../tools/router/target
+ ../tools/spectrum-installer/target
../tools/xdg-desktop-portal-spectrum-host/target
../vm/sys/net/build
]));
diff --git a/tools/spectrum-installer/Cargo.lock b/tools/spectrum-installer/Cargo.lock
new file mode 100644
index 0000000..4be50ef
--- /dev/null
+++ b/tools/spectrum-installer/Cargo.lock
@@ -0,0 +1,5106 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "ab_glyph"
+version = "0.2.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2"
+dependencies = [
+ "ab_glyph_rasterizer",
+ "owned_ttf_parser",
+]
+
+[[package]]
+name = "ab_glyph_rasterizer"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "ahash"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
+dependencies = [
+ "getrandom 0.2.16",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
+dependencies = [
+ "cfg-if",
+ "getrandom 0.3.4",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "alacritty_terminal"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46319972e74179d707445f64aaa2893bbf6a111de3a9af29b7eb382f8b39e282"
+dependencies = [
+ "base64",
+ "bitflags 2.10.0",
+ "home",
+ "libc",
+ "log",
+ "miow",
+ "parking_lot 0.12.5",
+ "piper",
+ "polling 3.11.0",
+ "regex-automata",
+ "rustix 1.1.2",
+ "rustix-openpty",
+ "serde",
+ "signal-hook",
+ "unicode-width 0.2.2",
+ "vte",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "aliasable"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "android-activity"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046"
+dependencies = [
+ "android-properties",
+ "bitflags 2.10.0",
+ "cc",
+ "cesu8",
+ "jni",
+ "jni-sys",
+ "libc",
+ "log",
+ "ndk",
+ "ndk-context",
+ "ndk-sys 0.6.0+11769913",
+ "num_enum",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "android-properties"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
+name = "approx"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "as-raw-xcb-connection"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
+
+[[package]]
+name = "ash"
+version = "0.37.3+1.3.251"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a"
+dependencies = [
+ "libloading 0.7.4",
+]
+
+[[package]]
+name = "async-broadcast"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
+dependencies = [
+ "event-listener 5.4.1",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-channel"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
+dependencies = [
+ "concurrent-queue",
+ "event-listener 2.5.3",
+ "futures-core",
+]
+
+[[package]]
+name = "async-channel"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
+dependencies = [
+ "concurrent-queue",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-executor"
+version = "1.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8"
+dependencies = [
+ "async-task",
+ "concurrent-queue",
+ "fastrand 2.3.0",
+ "futures-lite 2.6.1",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "async-fs"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
+dependencies = [
+ "async-lock 2.8.0",
+ "autocfg",
+ "blocking",
+ "futures-lite 1.13.0",
+]
+
+[[package]]
+name = "async-fs"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5"
+dependencies = [
+ "async-lock 3.4.1",
+ "blocking",
+ "futures-lite 2.6.1",
+]
+
+[[package]]
+name = "async-io"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
+dependencies = [
+ "async-lock 2.8.0",
+ "autocfg",
+ "cfg-if",
+ "concurrent-queue",
+ "futures-lite 1.13.0",
+ "log",
+ "parking",
+ "polling 2.8.0",
+ "rustix 0.37.28",
+ "slab",
+ "socket2 0.4.10",
+ "waker-fn",
+]
+
+[[package]]
+name = "async-io"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "concurrent-queue",
+ "futures-io",
+ "futures-lite 2.6.1",
+ "parking",
+ "polling 3.11.0",
+ "rustix 1.1.2",
+ "slab",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "async-lock"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
+dependencies = [
+ "event-listener 2.5.3",
+]
+
+[[package]]
+name = "async-lock"
+version = "3.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
+dependencies = [
+ "event-listener 5.4.1",
+ "event-listener-strategy",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-net"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f"
+dependencies = [
+ "async-io 1.13.0",
+ "blocking",
+ "futures-lite 1.13.0",
+]
+
+[[package]]
+name = "async-process"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88"
+dependencies = [
+ "async-io 1.13.0",
+ "async-lock 2.8.0",
+ "async-signal",
+ "blocking",
+ "cfg-if",
+ "event-listener 3.1.0",
+ "futures-lite 1.13.0",
+ "rustix 0.38.44",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "async-process"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
+dependencies = [
+ "async-channel 2.5.0",
+ "async-io 2.6.0",
+ "async-lock 3.4.1",
+ "async-signal",
+ "async-task",
+ "blocking",
+ "cfg-if",
+ "event-listener 5.4.1",
+ "futures-lite 2.6.1",
+ "rustix 1.1.2",
+]
+
+[[package]]
+name = "async-recursion"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "async-signal"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c"
+dependencies = [
+ "async-io 2.6.0",
+ "async-lock 3.4.1",
+ "atomic-waker",
+ "cfg-if",
+ "futures-core",
+ "futures-io",
+ "rustix 1.1.2",
+ "signal-hook-registry",
+ "slab",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "async-task"
+version = "4.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bit-set"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+
+[[package]]
+name = "bit_field"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "block"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block2"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
+dependencies = [
+ "objc2",
+]
+
+[[package]]
+name = "blocking"
+version = "1.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
+dependencies = [
+ "async-channel 2.5.0",
+ "async-task",
+ "futures-io",
+ "futures-lite 2.6.1",
+ "piper",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+
+[[package]]
+name = "by_address"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
+
+[[package]]
+name = "bytemuck"
+version = "1.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
+
+[[package]]
+name = "calloop"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
+dependencies = [
+ "bitflags 2.10.0",
+ "log",
+ "polling 3.11.0",
+ "rustix 0.38.44",
+ "slab",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "calloop"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb9f6e1368bd4621d2c86baa7e37de77a938adf5221e5dd3d6133340101b309e"
+dependencies = [
+ "bitflags 2.10.0",
+ "polling 3.11.0",
+ "rustix 1.1.2",
+ "slab",
+ "tracing",
+]
+
+[[package]]
+name = "calloop-wayland-source"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
+dependencies = [
+ "calloop 0.13.0",
+ "rustix 0.38.44",
+ "wayland-backend",
+ "wayland-client",
+]
+
+[[package]]
+name = "calloop-wayland-source"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
+dependencies = [
+ "calloop 0.14.3",
+ "rustix 1.1.2",
+ "wayland-backend",
+ "wayland-client",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cesu8"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "chrono"
+version = "0.4.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
+dependencies = [
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "wasm-bindgen",
+ "windows-link",
+]
+
+[[package]]
+name = "clipboard-win"
+version = "5.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
+dependencies = [
+ "error-code",
+]
+
+[[package]]
+name = "clipboard_macos"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f"
+dependencies = [
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "clipboard_wayland"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "003f886bc4e2987729d10c1db3424e7f80809f3fc22dbc16c685738887cb37b8"
+dependencies = [
+ "smithay-clipboard",
+]
+
+[[package]]
+name = "clipboard_x11"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c"
+dependencies = [
+ "thiserror 1.0.69",
+ "x11rb",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
+dependencies = [
+ "termcolor",
+ "unicode-width 0.1.14",
+]
+
+[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
+[[package]]
+name = "com"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6"
+dependencies = [
+ "com_macros",
+]
+
+[[package]]
+name = "com_macros"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5"
+dependencies = [
+ "com_macros_support",
+ "proc-macro2",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "com_macros_support"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "concurrent-queue"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "core-graphics"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation 0.9.4",
+ "core-graphics-types 0.1.3",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
+dependencies = [
+ "bitflags 2.10.0",
+ "core-foundation 0.10.1",
+ "core-graphics-types 0.2.0",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation 0.9.4",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
+dependencies = [
+ "bitflags 2.10.0",
+ "core-foundation 0.10.1",
+ "libc",
+]
+
+[[package]]
+name = "cosmic-text"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59fd57d82eb4bfe7ffa9b1cec0c05e2fd378155b47f255a67983cb4afe0e80c2"
+dependencies = [
+ "bitflags 2.10.0",
+ "fontdb",
+ "log",
+ "rangemap",
+ "rayon",
+ "rustc-hash 1.1.0",
+ "rustybuzz",
+ "self_cell",
+ "swash",
+ "sys-locale",
+ "ttf-parser 0.21.1",
+ "unicode-bidi",
+ "unicode-linebreak",
+ "unicode-script",
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "ctor-lite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b"
+
+[[package]]
+name = "cursor-icon"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
+
+[[package]]
+name = "d3d12"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307"
+dependencies = [
+ "bitflags 2.10.0",
+ "libloading 0.8.9",
+ "winapi",
+]
+
+[[package]]
+name = "dark-light"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a76fa97167fa740dcdbfe18e8895601e1bc36525f09b044e00916e717c03a3c"
+dependencies = [
+ "dconf_rs",
+ "detect-desktop-environment",
+ "dirs",
+ "objc",
+ "rust-ini",
+ "web-sys",
+ "winreg",
+ "zbus",
+]
+
+[[package]]
+name = "dconf_rs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b"
+
+[[package]]
+name = "detect-desktop-environment"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810"
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
+[[package]]
+name = "dirs"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
+name = "dispatch"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
+
+[[package]]
+name = "dlib"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
+dependencies = [
+ "libloading 0.8.9",
+]
+
+[[package]]
+name = "dlv-list"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
+
+[[package]]
+name = "downcast-rs"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
+
+[[package]]
+name = "dpi"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
+
+[[package]]
+name = "drm"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1"
+dependencies = [
+ "bitflags 2.10.0",
+ "bytemuck",
+ "drm-ffi",
+ "drm-fourcc",
+ "rustix 0.38.44",
+]
+
+[[package]]
+name = "drm-ffi"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53"
+dependencies = [
+ "drm-sys",
+ "rustix 0.38.44",
+]
+
+[[package]]
+name = "drm-fourcc"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
+
+[[package]]
+name = "drm-sys"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986"
+dependencies = [
+ "libc",
+ "linux-raw-sys 0.6.5",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "endi"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
+
+[[package]]
+name = "enumflags2"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
+dependencies = [
+ "enumflags2_derive",
+ "serde",
+]
+
+[[package]]
+name = "enumflags2_derive"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "error-code"
+version = "3.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
+
+[[package]]
+name = "etagere"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc89bf99e5dc15954a60f707c1e09d7540e5cd9af85fa75caa0b510bc08c5342"
+dependencies = [
+ "euclid",
+ "svg_fmt",
+]
+
+[[package]]
+name = "euclid"
+version = "0.22.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "event-listener"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+
+[[package]]
+name = "event-listener"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener"
+version = "5.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
+dependencies = [
+ "event-listener 5.4.1",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "exr"
+version = "1.74.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
+dependencies = [
+ "bit_field",
+ "half",
+ "lebe",
+ "miniz_oxide",
+ "rayon-core",
+ "smallvec",
+ "zune-inflate",
+]
+
+[[package]]
+name = "fast-srgb8"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
+
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "fdeflate"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
+
+[[package]]
+name = "flate2"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "float_next_after"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8"
+
+[[package]]
+name = "font-types"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3971f9a5ca983419cdc386941ba3b9e1feba01a0ab888adf78739feb2798492"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "fontconfig-parser"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
+dependencies = [
+ "roxmltree",
+]
+
+[[package]]
+name = "fontdb"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3"
+dependencies = [
+ "fontconfig-parser",
+ "log",
+ "memmap2",
+ "slotmap",
+ "tinyvec",
+ "ttf-parser 0.20.0",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
+dependencies = [
+ "foreign-types-macros",
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-macros"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
+
+[[package]]
+name = "futures"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+ "num_cpus",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-lite"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
+dependencies = [
+ "fastrand 1.9.0",
+ "futures-core",
+ "futures-io",
+ "memchr",
+ "parking",
+ "pin-project-lite",
+ "waker-fn",
+]
+
+[[package]]
+name = "futures-lite"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
+dependencies = [
+ "fastrand 2.3.0",
+ "futures-core",
+ "futures-io",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "gethostname"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
+dependencies = [
+ "rustix 1.1.2",
+ "windows-link",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+]
+
+[[package]]
+name = "gif"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
+dependencies = [
+ "color_quant",
+ "weezl",
+]
+
+[[package]]
+name = "gl_generator"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
+dependencies = [
+ "khronos_api",
+ "log",
+ "xml-rs",
+]
+
+[[package]]
+name = "glam"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
+
+[[package]]
+name = "glow"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
+dependencies = [
+ "js-sys",
+ "slotmap",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "glutin_wgl_sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead"
+dependencies = [
+ "gl_generator",
+]
+
+[[package]]
+name = "gpu-alloc"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
+dependencies = [
+ "bitflags 2.10.0",
+ "gpu-alloc-types",
+]
+
+[[package]]
+name = "gpu-alloc-types"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
+dependencies = [
+ "bitflags 2.10.0",
+]
+
+[[package]]
+name = "gpu-allocator"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
+dependencies = [
+ "log",
+ "presser",
+ "thiserror 1.0.69",
+ "winapi",
+ "windows",
+]
+
+[[package]]
+name = "gpu-descriptor"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c"
+dependencies = [
+ "bitflags 2.10.0",
+ "gpu-descriptor-types",
+ "hashbrown 0.14.5",
+]
+
+[[package]]
+name = "gpu-descriptor-types"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c"
+dependencies = [
+ "bitflags 2.10.0",
+]
+
+[[package]]
+name = "guillotiere"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782"
+dependencies = [
+ "euclid",
+ "svg_fmt",
+]
+
+[[package]]
+name = "half"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+ "zerocopy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+dependencies = [
+ "ahash 0.7.8",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash 0.8.12",
+ "allocator-api2",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+
+[[package]]
+name = "hassle-rs"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890"
+dependencies = [
+ "bitflags 2.10.0",
+ "com",
+ "libc",
+ "libloading 0.8.9",
+ "thiserror 1.0.69",
+ "widestring",
+ "winapi",
+]
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "hermit-abi"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "hexf-parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
+
+[[package]]
+name = "home"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core 0.62.2",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "iced"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88acfabc84ec077eaf9ede3457ffa3a104626d79022a9bf7f296093b1d60c73f"
+dependencies = [
+ "iced_core",
+ "iced_futures",
+ "iced_renderer",
+ "iced_widget",
+ "iced_winit",
+ "image",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "iced_aw"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "582c517a94ce3205da98e9c10b26bb71aa36b7d7d084441d826dc912711d1bac"
+dependencies = [
+ "cfg-if",
+ "chrono",
+ "getrandom 0.3.4",
+ "iced",
+ "iced_fonts 0.1.1",
+ "itertools",
+ "num-format",
+ "num-traits",
+ "web-time",
+]
+
+[[package]]
+name = "iced_core"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0013a238275494641bf8f1732a23a808196540dc67b22ff97099c044ae4c8a1c"
+dependencies = [
+ "bitflags 2.10.0",
+ "bytes",
+ "dark-light",
+ "glam",
+ "log",
+ "num-traits",
+ "once_cell",
+ "palette",
+ "rustc-hash 2.1.1",
+ "smol_str",
+ "thiserror 1.0.69",
+ "web-time",
+]
+
+[[package]]
+name = "iced_fonts"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df7deb0800a850ee25c8a42559f72c0f249e577feb3aad37b9b65dc1e517e52a"
+dependencies = [
+ "iced_core",
+]
+
+[[package]]
+name = "iced_fonts"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7db9d45e87bc3ac22ff82e2d9dea9139f1c055137f1e0f39df3d68110fcee7a9"
+dependencies = [
+ "iced_core",
+ "iced_widget",
+]
+
+[[package]]
+name = "iced_futures"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c04a6745ba2e80f32cf01e034fd00d853aa4f4cd8b91888099cb7aaee0d5d7c"
+dependencies = [
+ "futures",
+ "iced_core",
+ "log",
+ "rustc-hash 2.1.1",
+ "smol",
+ "tokio",
+ "wasm-bindgen-futures",
+ "wasm-timer",
+]
+
+[[package]]
+name = "iced_glyphon"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41c3bb56f1820ca252bc1d0994ece33d233a55657c0c263ea7cb16895adbde82"
+dependencies = [
+ "cosmic-text",
+ "etagere",
+ "lru",
+ "rustc-hash 2.1.1",
+ "wgpu",
+]
+
+[[package]]
+name = "iced_graphics"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba25a18cfa6d5cc160aca7e1b34f73ccdff21680fa8702168c09739767b6c66f"
+dependencies = [
+ "bitflags 2.10.0",
+ "bytemuck",
+ "cosmic-text",
+ "half",
+ "iced_core",
+ "iced_futures",
+ "image",
+ "kamadak-exif",
+ "log",
+ "lyon_path",
+ "once_cell",
+ "raw-window-handle",
+ "rustc-hash 2.1.1",
+ "thiserror 1.0.69",
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "iced_renderer"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73558208059f9e622df2bf434e044ee2f838ce75201a023cf0ca3e1244f46c2a"
+dependencies = [
+ "iced_graphics",
+ "iced_tiny_skia",
+ "iced_wgpu",
+ "log",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "iced_runtime"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "348b5b2c61c934d88ca3b0ed1ed913291e923d086a66fa288ce9669da9ef62b5"
+dependencies = [
+ "bytes",
+ "iced_core",
+ "iced_futures",
+ "raw-window-handle",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "iced_term"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75dd9ece683674e3d83f422516b08978eead151acec63aa3360bc38b75338b7"
+dependencies = [
+ "alacritty_terminal",
+ "anyhow",
+ "iced",
+ "iced_core",
+ "iced_graphics",
+ "open",
+ "tokio",
+]
+
+[[package]]
+name = "iced_tiny_skia"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c625d368284fcc43b0b36b176f76eff1abebe7959dd58bd8ce6897d641962a50"
+dependencies = [
+ "bytemuck",
+ "cosmic-text",
+ "iced_graphics",
+ "kurbo",
+ "log",
+ "rustc-hash 2.1.1",
+ "softbuffer",
+ "tiny-skia",
+]
+
+[[package]]
+name = "iced_wgpu"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15708887133671d2bcc6c1d01d1f176f43a64d6cdc3b2bf893396c3ee498295f"
+dependencies = [
+ "bitflags 2.10.0",
+ "bytemuck",
+ "futures",
+ "glam",
+ "guillotiere",
+ "iced_glyphon",
+ "iced_graphics",
+ "log",
+ "lyon",
+ "once_cell",
+ "rustc-hash 2.1.1",
+ "thiserror 1.0.69",
+ "wgpu",
+]
+
+[[package]]
+name = "iced_widget"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81429e1b950b0e4bca65be4c4278fea6678ea782030a411778f26fa9f8983e1d"
+dependencies = [
+ "iced_renderer",
+ "iced_runtime",
+ "num-traits",
+ "once_cell",
+ "ouroboros",
+ "rustc-hash 2.1.1",
+ "thiserror 1.0.69",
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "iced_winit"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f44cd4e1c594b6334f409282937bf972ba14d31fedf03c23aa595d982a2fda28"
+dependencies = [
+ "iced_futures",
+ "iced_graphics",
+ "iced_runtime",
+ "log",
+ "rustc-hash 2.1.1",
+ "thiserror 1.0.69",
+ "tracing",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winapi",
+ "window_clipboard",
+ "winit",
+]
+
+[[package]]
+name = "image"
+version = "0.24.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
+dependencies = [
+ "bytemuck",
+ "byteorder",
+ "color_quant",
+ "exr",
+ "gif",
+ "jpeg-decoder",
+ "num-traits",
+ "png",
+ "qoi",
+ "tiff",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.16.1",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi 0.3.9",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "is-docker"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "is-wsl"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
+dependencies = [
+ "is-docker",
+ "once_cell",
+]
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "jni"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
+dependencies = [
+ "cesu8",
+ "cfg-if",
+ "combine",
+ "jni-sys",
+ "log",
+ "thiserror 1.0.69",
+ "walkdir",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
+
+[[package]]
+name = "jpeg-decoder"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
+dependencies = [
+ "rayon",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "kamadak-exif"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef4fc70d0ab7e5b6bafa30216a6b48705ea964cdfc29c050f2412295eba58077"
+dependencies = [
+ "mutate_once",
+]
+
+[[package]]
+name = "khronos-egl"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
+dependencies = [
+ "libc",
+ "libloading 0.8.9",
+ "pkg-config",
+]
+
+[[package]]
+name = "khronos_api"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
+
+[[package]]
+name = "kurbo"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1618d4ebd923e97d67e7cd363d80aef35fe961005cbbbb3d2dad8bdd1bc63440"
+dependencies = [
+ "arrayvec",
+ "smallvec",
+]
+
+[[package]]
+name = "lebe"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
+
+[[package]]
+name = "libc"
+version = "0.2.177"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link",
+]
+
+[[package]]
+name = "libm"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
+
+[[package]]
+name = "libredox"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
+dependencies = [
+ "bitflags 2.10.0",
+ "libc",
+ "redox_syscall 0.5.18",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+
+[[package]]
+name = "lru"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
+
+[[package]]
+name = "lsblk"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f50cb1109b79638b78a02ac752040c3e6b649f06e00e4587660fd4408d6a26"
+dependencies = [
+ "paste",
+ "thiserror 2.0.17",
+]
+
+[[package]]
+name = "lyon"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbcb7d54d54c8937364c9d41902d066656817dce1e03a44e5533afebd1ef4352"
+dependencies = [
+ "lyon_algorithms",
+ "lyon_tessellation",
+]
+
+[[package]]
+name = "lyon_algorithms"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c0829e28c4f336396f250d850c3987e16ce6db057ffe047ce0dd54aab6b647"
+dependencies = [
+ "lyon_path",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_geom"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e260b6de923e6e47adfedf6243013a7a874684165a6a277594ee3906021b2343"
+dependencies = [
+ "arrayvec",
+ "euclid",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_path"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aeca86bcfd632a15984ba029b539ffb811e0a70bf55e814ef8b0f54f506fdeb"
+dependencies = [
+ "lyon_geom",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_tessellation"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3f586142e1280335b1bc89539f7c97dd80f08fc43e9ab1b74ef0a42b04aa353"
+dependencies = [
+ "float_next_after",
+ "lyon_path",
+ "num-traits",
+]
+
+[[package]]
+name = "malloc_buf"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+
+[[package]]
+name = "memmap2"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "metal"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25"
+dependencies = [
+ "bitflags 2.10.0",
+ "block",
+ "core-graphics-types 0.1.3",
+ "foreign-types",
+ "log",
+ "objc",
+ "paste",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+ "simd-adler32",
+]
+
+[[package]]
+name = "mio"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "miow"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "mutate_once"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af"
+
+[[package]]
+name = "naga"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843"
+dependencies = [
+ "bit-set",
+ "bitflags 2.10.0",
+ "codespan-reporting",
+ "hexf-parse",
+ "indexmap",
+ "log",
+ "num-traits",
+ "rustc-hash 1.1.0",
+ "spirv",
+ "termcolor",
+ "thiserror 1.0.69",
+ "unicode-xid",
+]
+
+[[package]]
+name = "ndk"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
+dependencies = [
+ "bitflags 2.10.0",
+ "jni-sys",
+ "log",
+ "ndk-sys 0.6.0+11769913",
+ "num_enum",
+ "raw-window-handle",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "ndk-context"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
+
+[[package]]
+name = "ndk-sys"
+version = "0.5.0+25.2.9519653"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "ndk-sys"
+version = "0.6.0+11769913"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "nix"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
+dependencies = [
+ "bitflags 2.10.0",
+ "cfg-if",
+ "cfg_aliases 0.2.1",
+ "libc",
+ "memoffset",
+]
+
+[[package]]
+name = "num-format"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
+dependencies = [
+ "arrayvec",
+ "itoa",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+ "libm",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
+dependencies = [
+ "hermit-abi 0.5.2",
+ "libc",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
+dependencies = [
+ "num_enum_derive",
+ "rustversion",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+ "objc_exception",
+]
+
+[[package]]
+name = "objc-sys"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
+
+[[package]]
+name = "objc2"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
+dependencies = [
+ "objc-sys",
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-app-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
+dependencies = [
+ "bitflags 2.10.0",
+ "block2",
+ "libc",
+ "objc2",
+ "objc2-core-data",
+ "objc2-core-image",
+ "objc2-foundation",
+ "objc2-quartz-core",
+]
+
+[[package]]
+name = "objc2-cloud-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
+dependencies = [
+ "bitflags 2.10.0",
+ "block2",
+ "objc2",
+ "objc2-core-location",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-contacts"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-data"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
+dependencies = [
+ "bitflags 2.10.0",
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-image"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-foundation",
+ "objc2-metal",
+]
+
+[[package]]
+name = "objc2-core-location"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-contacts",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
+
+[[package]]
+name = "objc2-foundation"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
+dependencies = [
+ "bitflags 2.10.0",
+ "block2",
+ "dispatch",
+ "libc",
+ "objc2",
+]
+
+[[package]]
+name = "objc2-link-presentation"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-metal"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
+dependencies = [
+ "bitflags 2.10.0",
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-quartz-core"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
+dependencies = [
+ "bitflags 2.10.0",
+ "block2",
+ "objc2",
+ "objc2-foundation",
+ "objc2-metal",
+]
+
+[[package]]
+name = "objc2-symbols"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-ui-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
+dependencies = [
+ "bitflags 2.10.0",
+ "block2",
+ "objc2",
+ "objc2-cloud-kit",
+ "objc2-core-data",
+ "objc2-core-image",
+ "objc2-core-location",
+ "objc2-foundation",
+ "objc2-link-presentation",
+ "objc2-quartz-core",
+ "objc2-symbols",
+ "objc2-uniform-type-identifiers",
+ "objc2-user-notifications",
+]
+
+[[package]]
+name = "objc2-uniform-type-identifiers"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-user-notifications"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
+dependencies = [
+ "bitflags 2.10.0",
+ "block2",
+ "objc2",
+ "objc2-core-location",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc_exception"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "open"
+version = "5.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc"
+dependencies = [
+ "is-wsl",
+ "libc",
+ "pathdiff",
+]
+
+[[package]]
+name = "orbclient"
+version = "0.3.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "247ad146e19b9437f8604c21f8652423595cf710ad108af40e77d3ae6e96b827"
+dependencies = [
+ "libredox",
+]
+
+[[package]]
+name = "ordered-multimap"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
+dependencies = [
+ "dlv-list",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "ordered-stream"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "ouroboros"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
+dependencies = [
+ "aliasable",
+ "ouroboros_macro",
+ "static_assertions",
+]
+
+[[package]]
+name = "ouroboros_macro"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "proc-macro2-diagnostics",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "owned_ttf_parser"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b"
+dependencies = [
+ "ttf-parser 0.25.1",
+]
+
+[[package]]
+name = "palette"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6"
+dependencies = [
+ "approx",
+ "fast-srgb8",
+ "palette_derive",
+ "phf",
+]
+
+[[package]]
+name = "palette_derive"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30"
+dependencies = [
+ "by_address",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "parking"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
+
+[[package]]
+name = "parking_lot"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core 0.8.6",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core 0.9.12",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
+dependencies = [
+ "cfg-if",
+ "instant",
+ "libc",
+ "redox_syscall 0.2.16",
+ "smallvec",
+ "winapi",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall 0.5.18",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pathdiff"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "phf"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
+dependencies = [
+ "phf_macros",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
+dependencies = [
+ "phf_shared",
+ "rand",
+]
+
+[[package]]
+name = "phf_macros"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "piper"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
+dependencies = [
+ "atomic-waker",
+ "fastrand 2.3.0",
+ "futures-io",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "png"
+version = "0.17.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
+dependencies = [
+ "bitflags 1.3.2",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "polling"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
+dependencies = [
+ "autocfg",
+ "bitflags 1.3.2",
+ "cfg-if",
+ "concurrent-queue",
+ "libc",
+ "log",
+ "pin-project-lite",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "polling"
+version = "3.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
+dependencies = [
+ "cfg-if",
+ "concurrent-queue",
+ "hermit-abi 0.5.2",
+ "pin-project-lite",
+ "rustix 1.1.2",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "presser"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "proc-macro2-diagnostics"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+ "version_check",
+ "yansi",
+]
+
+[[package]]
+name = "profiling"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
+
+[[package]]
+name = "qoi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "quick-xml"
+version = "0.37.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.16",
+]
+
+[[package]]
+name = "range-alloc"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
+
+[[package]]
+name = "rangemap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acbbbbea733ec66275512d0b9694f34102e7d5406fdbe2ad8d21b28dce92887c"
+
+[[package]]
+name = "raw-window-handle"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
+
+[[package]]
+name = "rayon"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "read-fonts"
+version = "0.22.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69aacb76b5c29acfb7f90155d39759a29496aebb49395830e928a9703d2eec2f"
+dependencies = [
+ "bytemuck",
+ "font-types",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags 2.10.0",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom 0.2.16",
+ "libredox",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
+
+[[package]]
+name = "renderdoc-sys"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
+
+[[package]]
+name = "roxmltree"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
+
+[[package]]
+name = "rust-ini"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
+dependencies = [
+ "cfg-if",
+ "ordered-multimap",
+]
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+
+[[package]]
+name = "rustix"
+version = "0.37.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6"
+dependencies = [
+ "bitflags 1.3.2",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys 0.3.8",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags 2.10.0",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.15",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
+dependencies = [
+ "bitflags 2.10.0",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.11.0",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustix-openpty"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1de16c7c59892b870a6336f185dc10943517f1327447096bbb7bb32cd85e2393"
+dependencies = [
+ "errno",
+ "libc",
+ "rustix 1.1.2",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "rustybuzz"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c"
+dependencies = [
+ "bitflags 2.10.0",
+ "bytemuck",
+ "libm",
+ "smallvec",
+ "ttf-parser 0.21.1",
+ "unicode-bidi-mirroring",
+ "unicode-ccc",
+ "unicode-properties",
+ "unicode-script",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scoped-tls"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "sctk-adwaita"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec"
+dependencies = [
+ "ab_glyph",
+ "log",
+ "memmap2",
+ "smithay-client-toolkit 0.19.2",
+ "tiny-skia",
+]
+
+[[package]]
+name = "self_cell"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "serde_repr"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "signal-hook"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+
+[[package]]
+name = "siphasher"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
+
+[[package]]
+name = "skrifa"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1c44ad1f6c5bdd4eefed8326711b7dbda9ea45dfd36068c427d332aa382cbe"
+dependencies = [
+ "bytemuck",
+ "read-fonts",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
+
+[[package]]
+name = "slotmap"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "smithay-client-toolkit"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
+dependencies = [
+ "bitflags 2.10.0",
+ "calloop 0.13.0",
+ "calloop-wayland-source 0.3.0",
+ "cursor-icon",
+ "libc",
+ "log",
+ "memmap2",
+ "rustix 0.38.44",
+ "thiserror 1.0.69",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-csd-frame",
+ "wayland-cursor",
+ "wayland-protocols",
+ "wayland-protocols-wlr",
+ "wayland-scanner",
+ "xkeysym",
+]
+
+[[package]]
+name = "smithay-client-toolkit"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0"
+dependencies = [
+ "bitflags 2.10.0",
+ "calloop 0.14.3",
+ "calloop-wayland-source 0.4.1",
+ "cursor-icon",
+ "libc",
+ "log",
+ "memmap2",
+ "rustix 1.1.2",
+ "thiserror 2.0.17",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-csd-frame",
+ "wayland-cursor",
+ "wayland-protocols",
+ "wayland-protocols-experimental",
+ "wayland-protocols-misc",
+ "wayland-protocols-wlr",
+ "wayland-scanner",
+ "xkeysym",
+]
+
+[[package]]
+name = "smithay-clipboard"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226"
+dependencies = [
+ "libc",
+ "smithay-client-toolkit 0.20.0",
+ "wayland-backend",
+]
+
+[[package]]
+name = "smol"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1"
+dependencies = [
+ "async-channel 1.9.0",
+ "async-executor",
+ "async-fs 1.6.0",
+ "async-io 1.13.0",
+ "async-lock 2.8.0",
+ "async-net",
+ "async-process 1.8.1",
+ "blocking",
+ "futures-lite 1.13.0",
+]
+
+[[package]]
+name = "smol_str"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "socket2"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "socket2"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
+dependencies = [
+ "libc",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "softbuffer"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
+dependencies = [
+ "as-raw-xcb-connection",
+ "bytemuck",
+ "cfg_aliases 0.2.1",
+ "core-graphics 0.24.0",
+ "drm",
+ "fastrand 2.3.0",
+ "foreign-types",
+ "js-sys",
+ "log",
+ "memmap2",
+ "objc2",
+ "objc2-foundation",
+ "objc2-quartz-core",
+ "raw-window-handle",
+ "redox_syscall 0.5.18",
+ "rustix 0.38.44",
+ "tiny-xlib",
+ "wasm-bindgen",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-sys",
+ "web-sys",
+ "windows-sys 0.59.0",
+ "x11rb",
+]
+
+[[package]]
+name = "spectrum-installer"
+version = "0.1.0"
+dependencies = [
+ "iced",
+ "iced_aw",
+ "iced_fonts 0.2.1",
+ "iced_term",
+ "lsblk",
+]
+
+[[package]]
+name = "spirv"
+version = "0.3.0+sdk-1.3.268.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
+dependencies = [
+ "bitflags 2.10.0",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strict-num"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
+
+[[package]]
+name = "svg_fmt"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"
+
+[[package]]
+name = "swash"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbd59f3f359ddd2c95af4758c18270eddd9c730dde98598023cdabff472c2ca2"
+dependencies = [
+ "skrifa",
+ "yazi",
+ "zeno",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.110"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sys-locale"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
+dependencies = [
+ "fastrand 2.3.0",
+ "getrandom 0.3.4",
+ "once_cell",
+ "rustix 1.1.2",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
+dependencies = [
+ "thiserror-impl 2.0.17",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "tiff"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
+dependencies = [
+ "flate2",
+ "jpeg-decoder",
+ "weezl",
+]
+
+[[package]]
+name = "tiny-skia"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if",
+ "log",
+ "png",
+ "tiny-skia-path",
+]
+
+[[package]]
+name = "tiny-skia-path"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "strict-num",
+]
+
+[[package]]
+name = "tiny-xlib"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e"
+dependencies = [
+ "as-raw-xcb-connection",
+ "ctor-lite",
+ "libloading 0.8.9",
+ "pkg-config",
+ "tracing",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "parking_lot 0.12.5",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2 0.6.1",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.23.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "toml_parser",
+ "winnow",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "ttf-parser"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
+
+[[package]]
+name = "ttf-parser"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8"
+
+[[package]]
+name = "ttf-parser"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
+
+[[package]]
+name = "typenum"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
+
+[[package]]
+name = "uds_windows"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
+dependencies = [
+ "memoffset",
+ "tempfile",
+ "winapi",
+]
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
+
+[[package]]
+name = "unicode-bidi-mirroring"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86"
+
+[[package]]
+name = "unicode-ccc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "unicode-linebreak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
+
+[[package]]
+name = "unicode-properties"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
+
+[[package]]
+name = "unicode-script"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "unicode-width"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "vte"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd"
+dependencies = [
+ "arrayvec",
+ "bitflags 2.10.0",
+ "cursor-icon",
+ "log",
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "waker-fn"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.1+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-timer"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
+dependencies = [
+ "futures",
+ "js-sys",
+ "parking_lot 0.11.2",
+ "pin-utils",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "wayland-backend"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
+dependencies = [
+ "cc",
+ "downcast-rs",
+ "rustix 1.1.2",
+ "scoped-tls",
+ "smallvec",
+ "wayland-sys",
+]
+
+[[package]]
+name = "wayland-client"
+version = "0.31.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
+dependencies = [
+ "bitflags 2.10.0",
+ "rustix 1.1.2",
+ "wayland-backend",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-csd-frame"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
+dependencies = [
+ "bitflags 2.10.0",
+ "cursor-icon",
+ "wayland-backend",
+]
+
+[[package]]
+name = "wayland-cursor"
+version = "0.31.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29"
+dependencies = [
+ "rustix 1.1.2",
+ "wayland-client",
+ "xcursor",
+]
+
+[[package]]
+name = "wayland-protocols"
+version = "0.32.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901"
+dependencies = [
+ "bitflags 2.10.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-experimental"
+version = "20250721.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1"
+dependencies = [
+ "bitflags 2.10.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-misc"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfe33d551eb8bffd03ff067a8b44bb963919157841a99957151299a6307d19c"
+dependencies = [
+ "bitflags 2.10.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-plasma"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a07a14257c077ab3279987c4f8bb987851bf57081b93710381daea94f2c2c032"
+dependencies = [
+ "bitflags 2.10.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-wlr"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec"
+dependencies = [
+ "bitflags 2.10.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-scanner"
+version = "0.31.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
+dependencies = [
+ "proc-macro2",
+ "quick-xml",
+ "quote",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.31.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
+dependencies = [
+ "dlib",
+ "log",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "weezl"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
+
+[[package]]
+name = "wgpu"
+version = "0.19.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbd7311dbd2abcfebaabf1841a2824ed7c8be443a0f29166e5d3c6a53a762c01"
+dependencies = [
+ "arrayvec",
+ "cfg-if",
+ "cfg_aliases 0.1.1",
+ "js-sys",
+ "log",
+ "naga",
+ "parking_lot 0.12.5",
+ "profiling",
+ "raw-window-handle",
+ "smallvec",
+ "static_assertions",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "wgpu-core",
+ "wgpu-hal",
+ "wgpu-types",
+]
+
+[[package]]
+name = "wgpu-core"
+version = "0.19.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a"
+dependencies = [
+ "arrayvec",
+ "bit-vec",
+ "bitflags 2.10.0",
+ "cfg_aliases 0.1.1",
+ "codespan-reporting",
+ "indexmap",
+ "log",
+ "naga",
+ "once_cell",
+ "parking_lot 0.12.5",
+ "profiling",
+ "raw-window-handle",
+ "rustc-hash 1.1.0",
+ "smallvec",
+ "thiserror 1.0.69",
+ "web-sys",
+ "wgpu-hal",
+ "wgpu-types",
+]
+
+[[package]]
+name = "wgpu-hal"
+version = "0.19.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfabcfc55fd86611a855816326b2d54c3b2fd7972c27ce414291562650552703"
+dependencies = [
+ "android_system_properties",
+ "arrayvec",
+ "ash",
+ "bit-set",
+ "bitflags 2.10.0",
+ "block",
+ "cfg_aliases 0.1.1",
+ "core-graphics-types 0.1.3",
+ "d3d12",
+ "glow",
+ "glutin_wgl_sys",
+ "gpu-alloc",
+ "gpu-allocator",
+ "gpu-descriptor",
+ "hassle-rs",
+ "js-sys",
+ "khronos-egl",
+ "libc",
+ "libloading 0.8.9",
+ "log",
+ "metal",
+ "naga",
+ "ndk-sys 0.5.0+25.2.9519653",
+ "objc",
+ "once_cell",
+ "parking_lot 0.12.5",
+ "profiling",
+ "range-alloc",
+ "raw-window-handle",
+ "renderdoc-sys",
+ "rustc-hash 1.1.0",
+ "smallvec",
+ "thiserror 1.0.69",
+ "wasm-bindgen",
+ "web-sys",
+ "wgpu-types",
+ "winapi",
+]
+
+[[package]]
+name = "wgpu-types"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805"
+dependencies = [
+ "bitflags 2.10.0",
+ "js-sys",
+ "web-sys",
+]
+
+[[package]]
+name = "widestring"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "window_clipboard"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6d692d46038c433f9daee7ad8757e002a4248c20b0a3fbc991d99521d3bcb6d"
+dependencies = [
+ "clipboard-win",
+ "clipboard_macos",
+ "clipboard_wayland",
+ "clipboard_x11",
+ "raw-window-handle",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "windows"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
+dependencies = [
+ "windows-core 0.52.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm 0.52.6",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
+dependencies = [
+ "windows-link",
+ "windows_aarch64_gnullvm 0.53.1",
+ "windows_aarch64_msvc 0.53.1",
+ "windows_i686_gnu 0.53.1",
+ "windows_i686_gnullvm 0.53.1",
+ "windows_i686_msvc 0.53.1",
+ "windows_x86_64_gnu 0.53.1",
+ "windows_x86_64_gnullvm 0.53.1",
+ "windows_x86_64_msvc 0.53.1",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
+
+[[package]]
+name = "winit"
+version = "0.30.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732"
+dependencies = [
+ "ahash 0.8.12",
+ "android-activity",
+ "atomic-waker",
+ "bitflags 2.10.0",
+ "block2",
+ "bytemuck",
+ "calloop 0.13.0",
+ "cfg_aliases 0.2.1",
+ "concurrent-queue",
+ "core-foundation 0.9.4",
+ "core-graphics 0.23.2",
+ "cursor-icon",
+ "dpi",
+ "js-sys",
+ "libc",
+ "memmap2",
+ "ndk",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "objc2-ui-kit",
+ "orbclient",
+ "percent-encoding",
+ "pin-project",
+ "raw-window-handle",
+ "redox_syscall 0.4.1",
+ "rustix 0.38.44",
+ "sctk-adwaita",
+ "smithay-client-toolkit 0.19.2",
+ "smol_str",
+ "tracing",
+ "unicode-segmentation",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-protocols-plasma",
+ "web-sys",
+ "web-time",
+ "windows-sys 0.52.0",
+ "x11-dl",
+ "x11rb",
+ "xkbcommon-dl",
+]
+
+[[package]]
+name = "winnow"
+version = "0.7.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winreg"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
+
+[[package]]
+name = "x11-dl"
+version = "2.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
+dependencies = [
+ "libc",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "x11rb"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
+dependencies = [
+ "as-raw-xcb-connection",
+ "gethostname",
+ "libc",
+ "libloading 0.8.9",
+ "once_cell",
+ "rustix 1.1.2",
+ "x11rb-protocol",
+]
+
+[[package]]
+name = "x11rb-protocol"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
+
+[[package]]
+name = "xcursor"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b"
+
+[[package]]
+name = "xdg-home"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "xkbcommon-dl"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5"
+dependencies = [
+ "bitflags 2.10.0",
+ "dlib",
+ "log",
+ "once_cell",
+ "xkeysym",
+]
+
+[[package]]
+name = "xkeysym"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
+
+[[package]]
+name = "xml-rs"
+version = "0.8.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
+
+[[package]]
+name = "yansi"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
+
+[[package]]
+name = "yazi"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
+
+[[package]]
+name = "zbus"
+version = "4.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725"
+dependencies = [
+ "async-broadcast",
+ "async-executor",
+ "async-fs 2.2.0",
+ "async-io 2.6.0",
+ "async-lock 3.4.1",
+ "async-process 2.5.0",
+ "async-recursion",
+ "async-task",
+ "async-trait",
+ "blocking",
+ "enumflags2",
+ "event-listener 5.4.1",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "hex",
+ "nix",
+ "ordered-stream",
+ "rand",
+ "serde",
+ "serde_repr",
+ "sha1",
+ "static_assertions",
+ "tracing",
+ "uds_windows",
+ "windows-sys 0.52.0",
+ "xdg-home",
+ "zbus_macros",
+ "zbus_names",
+ "zvariant",
+]
+
+[[package]]
+name = "zbus_macros"
+version = "4.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+ "zvariant_utils",
+]
+
+[[package]]
+name = "zbus_names"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
+dependencies = [
+ "serde",
+ "static_assertions",
+ "zvariant",
+]
+
+[[package]]
+name = "zeno"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
+
+[[package]]
+name = "zune-inflate"
+version = "0.2.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "zvariant"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe"
+dependencies = [
+ "endi",
+ "enumflags2",
+ "serde",
+ "static_assertions",
+ "zvariant_derive",
+]
+
+[[package]]
+name = "zvariant_derive"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+ "zvariant_utils",
+]
+
+[[package]]
+name = "zvariant_utils"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.110",
+]
diff --git a/tools/spectrum-installer/Cargo.lock.license b/tools/spectrum-installer/Cargo.lock.license
new file mode 100644
index 0000000..bfe02ea
--- /dev/null
+++ b/tools/spectrum-installer/Cargo.lock.license
@@ -0,0 +1,2 @@
+SPDX-License-Identifier: CC0-1.0
+SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
diff --git a/tools/spectrum-installer/Cargo.toml b/tools/spectrum-installer/Cargo.toml
new file mode 100644
index 0000000..4be4dcd
--- /dev/null
+++ b/tools/spectrum-installer/Cargo.toml
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+[package]
+name = "spectrum-installer"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+iced = { version = "0.13", features = ["image"] }
+iced_aw = { version = "0.12", features = ["spinner"] }
+iced_fonts = { version = "0.2", features = ["bootstrap"] }
+iced_term = { version = "0.6" }
+lsblk = { version = "0.6" }
diff --git a/tools/spectrum-installer/default.nix b/tools/spectrum-installer/default.nix
new file mode 100644
index 0000000..3ab028b
--- /dev/null
+++ b/tools/spectrum-installer/default.nix
@@ -0,0 +1,41 @@
+# SPDX-FileCopyrightText: 2024 Alyssa Ross <hi@alyssa.is>
+# SPDX-FileCopyrightText: 2025-2026 Johannes Süllner <johannes.suellner@mailbox.org>
+# SPDX-License-Identifier: MIT
+
+import ../../lib/call-package.nix (
+args@{ callPackage, config, src, lib, rustPlatform, libcosmicAppHook }:
+
+rustPlatform.buildRustPackage rec {
+ name = "spectrum-installer";
+
+ src = lib.fileset.toSource {
+ root = ../..;
+ fileset = lib.fileset.intersection args.src ./.;
+ };
+ sourceRoot = "source/tools/spectrum-installer";
+
+ cargoLock.lockFile = ./Cargo.lock;
+
+ nativeBuildInputs = [ libcosmicAppHook ];
+
+ icons = callPackage (
+ { runCommand, inkscape }:
+ runCommand "spectrum_installer_icons" {
+ nativeBuildInputs = [ inkscape ];
+ logoSvg = ./res/installer_logo_mesh.svg;
+ } ''
+ mkdir $out
+ inkscape -w 22 -h 22 -o $out/22x22.png "$logoSvg"
+ inkscape -w 400 -h 400 -o $out/400x400.png "$logoSvg"
+ ''
+ ) {};
+
+ postInstall = ''
+ mkdir -p "$out/share/spectrum-installer/repart.d"
+ for f in $(ls "./res/repart.d"); do
+ substitute "./res/repart.d/$f" "$out/share/spectrum-installer/repart.d/$f" --subst-var-by "version" "${config.version}"
+ done
+ install -D "${icons}/22x22.png" "$out/share/icons/hicolor/22x22/apps/${name}.png"
+ install -D "${icons}/400x400.png" "$out/share/icons/hicolor/400x400/apps/${name}.png"
+ '';
+}) (_: {})
diff --git a/tools/spectrum-installer/res/installer_logo_mesh.svg b/tools/spectrum-installer/res/installer_logo_mesh.svg
new file mode 100644
index 0000000..1e25829
--- /dev/null
+++ b/tools/spectrum-installer/res/installer_logo_mesh.svg
@@ -0,0 +1,85 @@
+<!-- SPDX-FileCopyrightText: 2020 hazelnot -->
+<!-- SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> -->
+<!-- SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org> -->
+<!-- SPDX-License-Identifier: CC0-1.0 -->
+<!-- Spectrum logo design by hazelnot, implementation by Alyssa Ross, installer icon by Johannes Süllner -->
+
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100">
+ <defs>
+ <filter id="ring-shadow" x="-10" y="-10" width="120" height="120" color-interpolation-filters="sRGB">
+ <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="blur" />
+ <feComposite in="SourceGraphic" in2="offset" operator="over" />
+ </filter>
+
+ <filter id="center-shadow" x="-10" y="-10" width="120" height="120" color-interpolation-filters="sRGB">
+ <feFlood flood-opacity="1" flood-color="#DDD" result="flood" />
+ <feComposite in="flood" in2="SourceGraphic" operator="in" result="composite1" />
+ <feGaussianBlur in="composite1" stdDeviation="6" result="blur" />
+ <feComposite in="SourceGraphic" in2="blur" operator="over" result="composite2" />
+ </filter>
+
+ <meshgradient id="ring-gradient" x="1.5" y="0.5">
+ <meshrow>
+ <meshpatch>
+ <stop path="L 1 -0.36603" stop-color="red" />
+ <stop path="L 0.5 0.5" stop-color="yellow" />
+ <stop path="L 0.5 0.5" stop-color="yellow" />
+ <stop path="L 1 0.5" stop-color="red" />
+ </meshpatch>
+ <meshpatch>
+ <stop path="L 0 -0.36603" />
+ <stop path="L 0.5 0.5" stop-color="lime" />
+ <stop path="L 0.5 0.5" stop-color="lime" />
+ </meshpatch>
+ <meshpatch>
+ <stop path="L -0.5 0.5" />
+ <stop path="L 0.5 0.5" stop-color="cyan" />
+ <stop path="L 0.5 0.5" stop-color="cyan" />
+ </meshpatch>
+ <meshpatch>
+ <stop path="L 0 1.36603" />
+ <stop path="L 0.5 0.5" stop-color="blue" />
+ <stop path="L 0.5 0.5" stop-color="blue" />
+ </meshpatch>
+ <meshpatch>
+ <stop path="L 1 1.36603" />
+ <stop path="L 0.5 0.5" stop-color="magenta" />
+ <stop path="L 0.5 0.5" stop-color="magenta" />
+ </meshpatch>
+ <meshpatch>
+ <stop path="L 1.5 0.5" />
+ <stop path="L 0.5 0.5" stop-color="red" />
+ <stop path="L 0.5 0.5" stop-color="red" />
+ </meshpatch>
+ </meshrow>
+ </meshgradient>
+
+ <marker
+ style="overflow:visible"
+ id="ArrowWideRounded"
+ refX="0"
+ refY="0"
+ orient="auto-start-reverse"
+ markerWidth="1"
+ markerHeight="1"
+ viewBox="0 0 1 1"
+ preserveAspectRatio="xMidYMid"
+ markerUnits="strokeWidth">
+ <path
+ style="fill:none;stroke:context-stroke;stroke-width:1;stroke-linecap:round"
+ d="M 3,-3 0,0 3,3"
+ transform="rotate(180,0.125,0)" />
+ </marker>
+ </defs>
+
+ <circle cx="50" cy="50" r="36" fill="none" stroke="url(#ring-gradient)" stroke-width="5" filter="url(#ring-shadow)" />
+
+ <circle cx="50" cy="50" r="27" fill="white" filter="url(#center-shadow)" />
+
+ <path
+ style="fill:none;stroke:#000000;stroke-width:4.5;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#ArrowWideRounded)"
+ d="M 50,29.5 V 54" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:4.5;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
+ d="M 65.419353,63.617021 H 34.580646" />
+</svg>
diff --git a/tools/spectrum-installer/res/repart.d/10-esp.conf b/tools/spectrum-installer/res/repart.d/10-esp.conf
new file mode 100644
index 0000000..1f3c5fc
--- /dev/null
+++ b/tools/spectrum-installer/res/repart.d/10-esp.conf
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+[Partition]
+Type=esp
+SizeMinBytes=500M
+SizeMaxBytes=500M
+CopyBlocks=/dev/disk/by-designator/esp
diff --git a/tools/spectrum-installer/res/repart.d/20-verity-A.conf b/tools/spectrum-installer/res/repart.d/20-verity-A.conf
new file mode 100644
index 0000000..6e688e3
--- /dev/null
+++ b/tools/spectrum-installer/res/repart.d/20-verity-A.conf
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+[Partition]
+Type=root-verity
+Label=Spectrum_@version@.verity
+SizeMinBytes=162M
+SizeMaxBytes=162M
+CopyBlocks=auto
diff --git a/tools/spectrum-installer/res/repart.d/21-rootfs-A.conf b/tools/spectrum-installer/res/repart.d/21-rootfs-A.conf
new file mode 100644
index 0000000..9d5ea6b
--- /dev/null
+++ b/tools/spectrum-installer/res/repart.d/21-rootfs-A.conf
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+[Partition]
+Type=root
+Label=Spectrum_@version@
+SizeMinBytes=20G
+SizeMaxBytes=20G
+CopyBlocks=auto
diff --git a/tools/spectrum-installer/res/repart.d/30-verity-B.conf b/tools/spectrum-installer/res/repart.d/30-verity-B.conf
new file mode 100644
index 0000000..3721ff0
--- /dev/null
+++ b/tools/spectrum-installer/res/repart.d/30-verity-B.conf
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+[Partition]
+Type=root-verity
+Label=_empty
+SizeMinBytes=162M
+SizeMaxBytes=162M
diff --git a/tools/spectrum-installer/res/repart.d/31-rootfs-B.conf b/tools/spectrum-installer/res/repart.d/31-rootfs-B.conf
new file mode 100644
index 0000000..84e9f57
--- /dev/null
+++ b/tools/spectrum-installer/res/repart.d/31-rootfs-B.conf
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+[Partition]
+Type=root
+Label=_empty
+SizeMinBytes=20G
+SizeMaxBytes=20G
diff --git a/tools/spectrum-installer/res/repart.d/40-home.conf b/tools/spectrum-installer/res/repart.d/40-home.conf
new file mode 100644
index 0000000..c487d34
--- /dev/null
+++ b/tools/spectrum-installer/res/repart.d/40-home.conf
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+[Partition]
+Type=home
+SizeMinBytes=500M
+Format=btrfs
diff --git a/tools/spectrum-installer/shell.nix b/tools/spectrum-installer/shell.nix
new file mode 100644
index 0000000..060009b
--- /dev/null
+++ b/tools/spectrum-installer/shell.nix
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: MIT
+# SPDX-FileCopyrightText: 2025 iced contributors
+
+# from https://github.com/iced-rs/iced/blob/master/DEPENDENCIES.md
+# last updated 2025-11-11
+
+{ pkgs ? import <nixpkgs> {} }:
+
+pkgs.mkShell rec {
+ buildInputs = with pkgs; [
+ cargo
+ lldb
+ expat
+ fontconfig
+ freetype
+ freetype.dev
+ libGL
+ pkg-config
+ rustfmt
+ xorg.libX11
+ xorg.libXcursor
+ xorg.libXi
+ xorg.libXrandr
+ wayland
+ libxkbcommon
+ ];
+
+ LD_LIBRARY_PATH =
+ builtins.foldl' (a: b: "${a}:${b}/lib") "${pkgs.vulkan-loader}/lib" buildInputs;
+}
diff --git a/tools/spectrum-installer/src/main.rs b/tools/spectrum-installer/src/main.rs
new file mode 100644
index 0000000..2ca9dfa
--- /dev/null
+++ b/tools/spectrum-installer/src/main.rs
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: EUPL-1.2+
+// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+mod pages;
+
+use iced::Element;
+use iced::Size;
+use iced::Subscription;
+use iced::Task;
+use pages::Event;
+
+fn main() -> iced::Result {
+ iced::application(
+ "Spectrum installer",
+ SpectrumInstaller::update,
+ SpectrumInstaller::view,
+ )
+ .window_size(Size::new(pages::WINDOW_WIDTH, pages::WINDOW_HEIGHT))
+ .font(iced_fonts::BOOTSTRAP_FONT_BYTES)
+ .resizable(false)
+ .subscription(SpectrumInstaller::subscription)
+ .run()
+}
+
+struct SpectrumInstaller {
+ current_page: Box<dyn pages::Page>,
+}
+impl Default for SpectrumInstaller {
+ fn default() -> Self {
+ Self {
+ current_page: Box::new(pages::INITAL_PAGE),
+ }
+ }
+}
+
+impl SpectrumInstaller {
+ fn update(&mut self, event: pages::Event) -> Task<Event> {
+ let (maybe_new_page, task) = self.current_page.update(event);
+ if let Some(new_page) = maybe_new_page {
+ self.current_page = new_page;
+ }
+ task
+ }
+
+ fn view(&self) -> Element<'_, pages::Event> {
+ self.current_page.view()
+ }
+
+ fn subscription(&self) -> Subscription<pages::Event> {
+ self.current_page.subscription()
+ }
+}
diff --git a/tools/spectrum-installer/src/pages/completion.rs b/tools/spectrum-installer/src/pages/completion.rs
new file mode 100644
index 0000000..2ea9734
--- /dev/null
+++ b/tools/spectrum-installer/src/pages/completion.rs
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: EUPL-1.2+
+// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+use super::{
+ BUTTON_TEXT_SIZE, Event, MARGIN_LR, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult,
+ WINDOW_WIDTH,
+};
+use crate::{center_horizontal_in_container, center_in_container};
+use iced::{
+ Element, Task,
+ widget::{
+ Scrollable, Space, column,
+ scrollable::{Direction, Scrollbar},
+ text,
+ },
+ window,
+};
+use std::process::Command;
+
+const S6_HPR_PATH: &str = "/bin/s6-linux-init-hpr";
+
+pub struct PageCompletion {
+ install_result: super::InstallResult,
+}
+
+impl PageCompletion {
+ pub fn new(install_result: super::InstallResult) -> Self {
+ Self { install_result }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum PageCompletionEvent {
+ Quit,
+ Poweroff,
+ Reboot,
+}
+
+impl PageCompletion {
+ fn close(id: window::Id) -> Task<Event> {
+ window::close(id)
+ }
+
+ fn spawn_s6_hpr(parameter: &str) {
+ let _ = Command::new(S6_HPR_PATH).arg(parameter).spawn();
+ }
+}
+
+impl Page for PageCompletion {
+ fn update(&mut self, event: Event) -> UpdateResult {
+ if let Event::PageCompletion(page_completion_event) = event {
+ match page_completion_event {
+ PageCompletionEvent::Quit => {
+ return (None, window::get_latest().and_then(Self::close));
+ }
+ PageCompletionEvent::Poweroff => {
+ Self::spawn_s6_hpr("-p");
+ }
+ PageCompletionEvent::Reboot => {
+ Self::spawn_s6_hpr("-r");
+ }
+ }
+ };
+
+ (None, Task::none())
+ }
+
+ fn view(&self) -> Element<'_, Event> {
+ let main_element = match &self.install_result {
+ Ok(_) => {
+ center_in_container!(text("Spectrum installation succeeded!").size(TITLE_TEXT_SIZE)).into()
+ }
+ Err((code, log)) => {
+ column![
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(text("Spectrum installation failed :( ").size(TITLE_TEXT_SIZE)),
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(Scrollable::new(text(format!("You can reach out to the team via Chat or the \"discuss\" mailing list.\n\
+ See https://spectrum-os.org/doc/contributing/communication.html for details.\n\
+ The following information may be relevant:\n\n\
+ Error code: {}\n\nError log:\n{}", code, log)))
+ .width(WINDOW_WIDTH - 2.0 * MARGIN_LR)
+ .height(500)
+ .direction(Direction::Vertical(Scrollbar::new()))),
+ ]
+ .into()
+ }
+ };
+
+ super::layout::bottom_buttons_layout(
+ [
+ vec![
+ (
+ text("Reboot").size(BUTTON_TEXT_SIZE).into(),
+ Some(Event::PageCompletion(PageCompletionEvent::Reboot)),
+ ),
+ (
+ text("Poweroff").size(BUTTON_TEXT_SIZE).into(),
+ Some(Event::PageCompletion(PageCompletionEvent::Poweroff)),
+ ),
+ ],
+ vec![(
+ text("Quit installer, stay in live environment")
+ .size(BUTTON_TEXT_SIZE)
+ .into(),
+ Some(Event::PageCompletion(PageCompletionEvent::Quit)),
+ )],
+ ],
+ main_element,
+ )
+ }
+}
diff --git a/tools/spectrum-installer/src/pages/confirmation.rs b/tools/spectrum-installer/src/pages/confirmation.rs
new file mode 100644
index 0000000..25084b6
--- /dev/null
+++ b/tools/spectrum-installer/src/pages/confirmation.rs
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: EUPL-1.2+
+// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+use super::{
+ BUTTON_TEXT_SIZE, Event, MARGIN_LR, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult,
+ WINDOW_WIDTH,
+};
+use crate::center_horizontal_in_container;
+use iced::{
+ Length, Task,
+ widget::{Space, checkbox, column, container, text},
+};
+use lsblk::BlockDevice;
+
+pub struct PageConfirmation {
+ device: BlockDevice,
+ install_confirmed: bool,
+}
+
+impl PageConfirmation {
+ pub fn new(device: BlockDevice) -> Self {
+ Self {
+ device,
+ install_confirmed: false,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum PageConfirmationEvent {
+ Back,
+ ConfirmCheckboxToggled(bool),
+ StartInstallation,
+}
+
+impl Page for PageConfirmation {
+ fn update(&mut self, event: Event) -> UpdateResult {
+ if let Event::PageConfirmation(page_event) = event {
+ match page_event {
+ PageConfirmationEvent::Back => {
+ return (
+ Some(Box::new(super::disk_selection::PageDiskSelection::new())),
+ Task::none(),
+ );
+ }
+ PageConfirmationEvent::ConfirmCheckboxToggled(bool) => {
+ self.install_confirmed = bool;
+ }
+ PageConfirmationEvent::StartInstallation => {
+ return (
+ Some(Box::new(super::installation::PageInstallation::new(
+ self.device.clone(),
+ ))),
+ Task::none(),
+ );
+ }
+ }
+ }
+ (None, Task::none())
+ }
+
+ fn view(&self) -> iced::Element<'_, Event> {
+ let main_content = column![
+ Space::with_height(Length::Fill),
+ center_horizontal_in_container!(text("Confirm Installation").size(TITLE_TEXT_SIZE)),
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(text(
+ "Erease all data on the following device and install Spectrum?"
+ )),
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(
+ container(super::layout::disk_element(&self.device))
+ .width(WINDOW_WIDTH - 2.0 * MARGIN_LR)
+ ),
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(
+ checkbox(
+ format!("I understand all data on {} will be lost", self.device.name),
+ self.install_confirmed
+ )
+ .on_toggle(|bool| Event::PageConfirmation(
+ PageConfirmationEvent::ConfirmCheckboxToggled(bool)
+ ))
+ ),
+ Space::with_height(Length::Fill),
+ ];
+
+ super::layout::bottom_buttons_layout(
+ [[
+ (
+ text("Back").size(BUTTON_TEXT_SIZE).into(),
+ Some(Event::PageConfirmation(PageConfirmationEvent::Back)),
+ ),
+ (
+ text("Start installation").size(BUTTON_TEXT_SIZE).into(),
+ if self.install_confirmed {
+ Some(Event::PageConfirmation(
+ PageConfirmationEvent::StartInstallation,
+ ))
+ } else {
+ None
+ },
+ ),
+ ]],
+ main_content.into(),
+ )
+ }
+}
diff --git a/tools/spectrum-installer/src/pages/disk_selection.rs b/tools/spectrum-installer/src/pages/disk_selection.rs
new file mode 100644
index 0000000..0d28022
--- /dev/null
+++ b/tools/spectrum-installer/src/pages/disk_selection.rs
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: EUPL-1.2+
+// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+use super::{
+ BUTTON_TEXT_SIZE, Event, MARGIN_LR, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult,
+ WINDOW_WIDTH,
+};
+use crate::center_horizontal_in_container;
+use iced::{
+ Length, Task,
+ widget::{
+ Scrollable, Space, button, column,
+ scrollable::{Direction, Scrollbar},
+ text,
+ },
+};
+use lsblk::BlockDevice;
+
+pub struct PageDiskSelection {
+ destination_device: Option<BlockDevice>,
+}
+
+impl PageDiskSelection {
+ pub fn new() -> Self {
+ Self {
+ destination_device: None,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum PageDiskSelectionEvent {
+ Back,
+ SelectDevice(BlockDevice),
+ ContinueWithDevice(BlockDevice),
+}
+
+impl Page for PageDiskSelection {
+ fn update(&mut self, event: Event) -> UpdateResult {
+ if let Event::PageDiskSelection(page_disk_selection_event) = event {
+ match page_disk_selection_event {
+ PageDiskSelectionEvent::Back => {
+ return (
+ Some(Box::new(super::welcome::PageWelcome::new())),
+ Task::none(),
+ );
+ }
+ PageDiskSelectionEvent::SelectDevice(device) => {
+ self.destination_device = Some(device);
+ }
+ PageDiskSelectionEvent::ContinueWithDevice(device) => {
+ return (
+ Some(Box::new(super::confirmation::PageConfirmation::new(device))),
+ Task::none(),
+ );
+ }
+ }
+ }
+ (None, Task::none())
+ }
+
+ fn view(&self) -> iced::Element<'_, Event> {
+ let mut block_devices = BlockDevice::list().expect("Failed to get block devices");
+ block_devices.sort_by_key(|device| device.name.clone());
+
+ let mut possible_block_devices = block_devices
+ .iter()
+ .filter(|device| {
+ BlockDevice::is_disk(device)
+ && !&device.name.starts_with("loop")
+ && !&device.name.starts_with("sr")
+ })
+ .peekable();
+
+ let destinations: iced::Element<Event> = if possible_block_devices.peek().is_none() {
+ text("No applicable devices to install Spectrum to found.").into()
+ } else {
+ column(possible_block_devices.map(|device| {
+ button(super::layout::disk_element(&device))
+ .on_press(Event::PageDiskSelection(
+ PageDiskSelectionEvent::SelectDevice(device.clone()),
+ ))
+ .width(WINDOW_WIDTH - 2.0 * MARGIN_LR)
+ .style({
+ if self
+ .destination_device
+ .as_ref()
+ .is_some_and(|d| d.fullname == device.fullname)
+ {
+ button::success
+ } else {
+ button::primary
+ }
+ })
+ .into()
+ }))
+ .spacing(8)
+ .into()
+ };
+
+ let main_content = column![
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(
+ text("Select the device to install Spectrum to").size(TITLE_TEXT_SIZE)
+ ),
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(
+ Scrollable::new(destinations)
+ .height(Length::Fill)
+ .direction(Direction::Vertical(Scrollbar::new()))
+ ),
+ Space::with_height(MARGIN_VERTICAL),
+ ];
+
+ super::layout::bottom_buttons_layout(
+ [[
+ (
+ text("Back").size(BUTTON_TEXT_SIZE).into(),
+ Some(Event::PageDiskSelection(PageDiskSelectionEvent::Back)),
+ ),
+ (
+ text("Next").size(BUTTON_TEXT_SIZE).into(),
+ match &self.destination_device {
+ None => None,
+ Some(device) => Some(Event::PageDiskSelection(
+ PageDiskSelectionEvent::ContinueWithDevice(device.clone()),
+ )),
+ },
+ ),
+ ]],
+ main_content.into(),
+ )
+ }
+}
diff --git a/tools/spectrum-installer/src/pages/installation.rs b/tools/spectrum-installer/src/pages/installation.rs
new file mode 100644
index 0000000..16da197
--- /dev/null
+++ b/tools/spectrum-installer/src/pages/installation.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: EUPL-1.2+
+// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+use super::{
+ BUTTON_TEXT_SIZE, Event, InstallResult, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult,
+};
+use crate::center_horizontal_in_container;
+use iced::{
+ Length, Subscription, Task,
+ widget::{Space, column, container, row, text},
+};
+use iced_aw::Spinner;
+use iced_term::Terminal;
+use lsblk::BlockDevice;
+use std::fs;
+
+const RESULT_CODE_FILE: &str = "/tmp/spectrum-installer_result-code";
+const LOG_FILE: &str = "/tmp/spectrum-installer_log";
+
+pub struct PageInstallation {
+ terminal: Option<Terminal>,
+ installation_completed: bool,
+ installation_result: Option<InstallResult>,
+}
+
+impl PageInstallation {
+ pub fn new(device: BlockDevice) -> Self {
+ let term = Terminal::new(
+ 0,
+ iced_term::settings::Settings {
+ backend: iced_term::settings::BackendSettings {
+ program: String::from("/usr/bin/sh"),
+ args: Vec::from([
+ String::from("-c"),
+ // Install enforcing a new partition table.
+ // HACK: Logging to /tmp as iced_term does not offer any other way of obtaining the commands result.
+ String::from(
+ [
+ "( /usr/bin/systemd-repart \
+ --definitions=/usr/share/spectrum-installer/repart.d \
+ --empty=force \
+ --dry-run=no ",
+ &device.fullname.display().to_string(),
+ "; echo $? > ",
+ RESULT_CODE_FILE,
+ ") 2>&1 | tee ",
+ LOG_FILE,
+ ]
+ .concat(),
+ ),
+ ]),
+ },
+ ..Default::default()
+ },
+ );
+
+ match term {
+ Ok(term) => Self {
+ terminal: Some(term),
+ installation_completed: false,
+ installation_result: None,
+ },
+ Err(e) => Self {
+ terminal: None,
+ installation_completed: true,
+ installation_result: Some(Err((0, e.to_string()))),
+ },
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum PageInstallationEvent {
+ Terminal(iced_term::Event),
+ Finish,
+}
+
+impl Page for PageInstallation {
+ fn update(&mut self, event: Event) -> UpdateResult {
+ if let Event::PageInstallation(page_event) = event {
+ match page_event {
+ PageInstallationEvent::Finish => {
+ if let Some(installation_result) = self.installation_result.clone() {
+ return (
+ Some(Box::new(super::completion::PageCompletion::new(
+ installation_result,
+ ))),
+ Task::none(),
+ );
+ }
+ }
+ PageInstallationEvent::Terminal(iced_term::Event::BackendCall(_, cmd)) => {
+ if let Some(term) = &mut self.terminal {
+ match term.handle(iced_term::Command::ProxyToBackend(cmd)) {
+ iced_term::actions::Action::Shutdown => {
+ let code = fs::read_to_string(RESULT_CODE_FILE);
+ let log = fs::read_to_string(LOG_FILE);
+ self.installation_result =
+ if let (Ok(code_as_str), Ok(log)) = (code, log) {
+ if let Ok(code) = code_as_str.trim().parse::<u32>() {
+ self.installation_completed = true;
+ if code == 0 {
+ Some(Ok(log))
+ } else {
+ Some(Err((code, log)))
+ }
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+ }
+ (None, Task::none())
+ }
+
+ fn subscription(&self) -> Subscription<Event> {
+ if let Some(term) = &self.terminal {
+ return Subscription::run_with_id(term.id, term.subscription())
+ .map::<_, _>(|t| Event::PageInstallation(PageInstallationEvent::Terminal(t)));
+ }
+
+ Subscription::none()
+ }
+
+ fn view(&self) -> iced::Element<'_, Event> {
+ let title_row: iced::Element<Event> = if !self.installation_completed {
+ row![
+ Spinner::new().height(25),
+ Space::with_width(MARGIN_VERTICAL),
+ text("Installing ...").size(TITLE_TEXT_SIZE)
+ ]
+ .into()
+ } else {
+ text(
+ if self.installation_result.as_ref().is_some_and(|r| r.is_ok()) {
+ "Installation completed."
+ } else {
+ "Installation failed."
+ },
+ )
+ .size(TITLE_TEXT_SIZE)
+ .into()
+ };
+
+ let installation_status: iced::Element<Event> = if let Some(term) = &self.terminal {
+ iced_term::TerminalView::show(term)
+ .map::<_>(|t| Event::PageInstallation(PageInstallationEvent::Terminal(t)))
+ .into()
+ } else {
+ text("Could not start installation.").into()
+ };
+
+ let main_content = column![
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(title_row),
+ Space::with_height(MARGIN_VERTICAL),
+ container(installation_status)
+ .width(Length::Fill)
+ .center_x(Length::Fill)
+ .height(Length::Fill),
+ ];
+
+ super::layout::bottom_buttons_layout(
+ [[(
+ text("Finish").size(BUTTON_TEXT_SIZE).into(),
+ if self.installation_completed {
+ Some(Event::PageInstallation(PageInstallationEvent::Finish))
+ } else {
+ None
+ },
+ )]],
+ main_content.into(),
+ )
+ }
+}
diff --git a/tools/spectrum-installer/src/pages/layout.rs b/tools/spectrum-installer/src/pages/layout.rs
new file mode 100644
index 0000000..e7095bd
--- /dev/null
+++ b/tools/spectrum-installer/src/pages/layout.rs
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: EUPL-1.2+
+// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+use iced::{
+ Element, Length,
+ widget::{Button, Column, Row, button, column, container, row, text},
+};
+use iced_fonts::{BOOTSTRAP_FONT as ICON_FONT, Bootstrap as Icon};
+use lsblk::BlockDevice;
+
+use super::Event;
+
+#[macro_export]
+macro_rules! center_horizontal_in_container {
+ ($e:expr) => {
+ iced::widget::container($e)
+ .width(iced::Length::Fill)
+ .center_x(iced::Length::Fill)
+ };
+}
+#[macro_export]
+macro_rules! center_in_container {
+ ($e:expr) => {
+ iced::widget::container($e)
+ .height(iced::Length::Fill)
+ .width(iced::Length::Fill)
+ .center_x(iced::Length::Fill)
+ .center_y(iced::Length::Fill)
+ };
+}
+
+const BOTTOM_BUTTON_SPACE: f32 = 2.0;
+const BOTTOM_BUTTON_ROW_HEIGHT: f32 = 50.0;
+const DISK_ICON_SIZE: u16 = 50;
+
+fn bottom_button<'a>(
+ button_content: Element<'a, Event>,
+ button_on_press: Option<Event>,
+) -> Button<'a, Event> {
+ button(
+ center_in_container!(button_content)
+ .height(Length::Fill)
+ .center_y(Length::Fill),
+ )
+ .on_press_maybe(button_on_press)
+ .width(Length::Fill)
+ .height(Length::Fill)
+}
+
+pub fn bottom_buttons_layout<'a>(
+ button_matrix: impl IntoIterator<
+ Item = impl IntoIterator<Item = (Element<'a, Event>, Option<Event>)>,
+ >,
+ main_element: Element<'a, Event>,
+) -> Element<'a, Event> {
+ let mut bottom_height = 0.0;
+ let mut bottom_element = Column::new().spacing(BOTTOM_BUTTON_SPACE);
+ for input_row in button_matrix.into_iter() {
+ let mut output_row = Row::new().spacing(BOTTOM_BUTTON_SPACE);
+ for (button_content, button_on_press) in input_row.into_iter() {
+ output_row = output_row.push(bottom_button(button_content, button_on_press));
+ }
+ bottom_element = bottom_element.push(output_row);
+ bottom_height += BOTTOM_BUTTON_ROW_HEIGHT;
+ }
+
+ column![
+ center_horizontal_in_container!(main_element).height(Length::Fill),
+ container(bottom_element).height(bottom_height)
+ ]
+ .into()
+}
+
+pub fn disk_element(device: &BlockDevice) -> Element<'static, Event> {
+ let icon: Element<Event> = text(Icon::Hdd.to_string())
+ .font(ICON_FONT)
+ .size(DISK_ICON_SIZE)
+ .into();
+
+ let disk_size = if let Ok(Some(capacity)) = device.capacity() {
+ let mut size_factor: f32 = (capacity * 512) as f32;
+ let mut exponent = 0; // base = 1024
+ while size_factor >= 1000.0 {
+ exponent += 1;
+ size_factor = size_factor / 1000.0;
+ }
+ let unit = match exponent {
+ 0 => "",
+ 1 => "K",
+ 2 => "M",
+ 3 => "G",
+ 4 => "T",
+ 5 => "P",
+ 6 => "E",
+ 7 => "Z",
+ 8 => "Y",
+ 9 => "R",
+ _ => "???",
+ };
+ Ok(format!("{:.2} {}B", size_factor, unit))
+ } else {
+ Err("Failed to get disk size")
+ };
+
+ let disk_id = if let Some(id) = &device.id { id } else { "" };
+
+ row![
+ icon,
+ text(format!(
+ "{}\n{}\n{}",
+ device.fullname.display(),
+ disk_id,
+ if let Ok(size) = disk_size {
+ size
+ } else {
+ String::from("(unknown size)")
+ }
+ ))
+ ]
+ .spacing(8)
+ .into()
+}
diff --git a/tools/spectrum-installer/src/pages/mod.rs b/tools/spectrum-installer/src/pages/mod.rs
new file mode 100644
index 0000000..cd020f1
--- /dev/null
+++ b/tools/spectrum-installer/src/pages/mod.rs
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: EUPL-1.2+
+// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+use iced::{Subscription, Task};
+
+mod completion;
+mod confirmation;
+mod disk_selection;
+mod installation;
+mod layout;
+mod welcome;
+
+pub const WINDOW_WIDTH: f32 = 750.0;
+pub const WINDOW_HEIGHT: f32 = 650.0;
+
+pub const MARGIN_VERTICAL: f32 = 25.0;
+pub const MARGIN_LR: f32 = 15.0;
+pub const BUTTON_TEXT_SIZE: u16 = 20;
+pub const TITLE_TEXT_SIZE: u16 = 24;
+
+type UpdateResult = (Option<Box<dyn Page>>, Task<Event>);
+
+type InstallResult = Result<String, (u32, String)>;
+
+pub trait Page {
+ fn update(&mut self, event: Event) -> UpdateResult;
+ fn view(&self) -> iced::Element<'_, Event>;
+ fn subscription(&self) -> Subscription<Event> {
+ Subscription::none()
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum Event {
+ /* Pages are ordered as they appear during the installation. */
+ PageWelcome(welcome::PageWelcomeEvent),
+ PageDiskSelection(disk_selection::PageDiskSelectionEvent),
+ PageConfirmation(confirmation::PageConfirmationEvent),
+ PageInstallation(installation::PageInstallationEvent),
+ PageCompletion(completion::PageCompletionEvent),
+}
+
+pub const INITAL_PAGE: welcome::PageWelcome = welcome::PageWelcome {};
diff --git a/tools/spectrum-installer/src/pages/welcome.rs b/tools/spectrum-installer/src/pages/welcome.rs
new file mode 100644
index 0000000..fb91fd1
--- /dev/null
+++ b/tools/spectrum-installer/src/pages/welcome.rs
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: EUPL-1.2+
+// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
+
+use super::{BUTTON_TEXT_SIZE, Event, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult};
+use crate::{center_horizontal_in_container, center_in_container};
+use iced::{
+ Element, Length, Task,
+ widget::{Space, column, image, text},
+};
+
+const LOGO_PATH_GLOBAL: &str = "/usr/share/icons/hicolor/400x400/apps/spectrum-installer.png";
+const LOGO_WIDTH: f32 = 400.0;
+
+pub struct PageWelcome {}
+
+impl PageWelcome {
+ pub fn new() -> Self {
+ Self {}
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum PageWelcomeEvent {
+ Continue,
+}
+
+impl Page for PageWelcome {
+ fn update(&mut self, event: Event) -> UpdateResult {
+ if let Event::PageWelcome(page_welcome_event) = event {
+ match page_welcome_event {
+ PageWelcomeEvent::Continue => {
+ return (
+ Some(Box::new(super::disk_selection::PageDiskSelection::new())),
+ Task::none(),
+ );
+ }
+ }
+ }
+ (None, Task::none())
+ }
+
+ fn view(&self) -> Element<'_, Event> {
+ let button_content = text("Next").size(BUTTON_TEXT_SIZE);
+
+ let main_content = column![
+ Space::with_height(MARGIN_VERTICAL),
+ center_horizontal_in_container!(
+ text("Welcome to the installation of Spectrum!").size(TITLE_TEXT_SIZE)
+ ),
+ Space::with_height(MARGIN_VERTICAL),
+ center_in_container!(image(LOGO_PATH_GLOBAL).width(Length::Fixed(LOGO_WIDTH)))
+ ];
+
+ super::layout::bottom_buttons_layout(
+ [[(
+ button_content.into(),
+ Some(Event::PageWelcome(PageWelcomeEvent::Continue)),
+ )]],
+ main_content.into(),
+ )
+ }
+}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/4] host/rootfs: integrate spectrum-installer
2026-01-04 14:00 [PATCH 1/4] tools: add spectrum-installer Johannes Süllner
@ 2026-01-04 14:00 ` Johannes Süllner
2026-01-04 14:00 ` [PATCH 3/4] release: drop combined and installer image Johannes Süllner
` (3 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Johannes Süllner @ 2026-01-04 14:00 UTC (permalink / raw)
To: devel; +Cc: Johannes Süllner
The installer needs to run as root, so that `systemd-repart` can write
to disks. Since Weston is not running as root (since b26f59e), just as
with the root terminal, we add a s6-sudod service for the installer.
Signed-off-by: Johannes Süllner <johannes.suellner@mailbox.org>
---
host/rootfs/default.nix | 4 ++--
host/rootfs/file-list.mk | 3 +++
.../spectrum-installer-as-root/notification-fd | 1 +
.../notification-fd.license | 2 ++
.../service/spectrum-installer-as-root/run | 17 +++++++++++++++++
host/rootfs/image/etc/s6-rc/weston/run | 1 +
host/rootfs/image/etc/xdg/weston/weston.ini | 5 +++++
.../image/usr/bin/spectrum-installer-as-root | 5 +++++
pkgs/default.nix | 2 ++
9 files changed, 38 insertions(+), 2 deletions(-)
create mode 100644 host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd
create mode 100644 host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd.license
create mode 100755 host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/run
create mode 100755 host/rootfs/image/usr/bin/spectrum-installer-as-root
diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix
index 66aa366..f53d3e3 100644
--- a/host/rootfs/default.nix
+++ b/host/rootfs/default.nix
@@ -4,7 +4,7 @@
import ../../lib/call-package.nix (
{ callSpectrumPackage, config, spectrum-build-tools
-, src, pkgsMusl, inkscape, linux_latest, xorg
+, src, pkgsMusl, inkscape, linux_latest, spectrum-installer, xorg
}:
pkgsMusl.callPackage (
@@ -62,7 +62,7 @@ let
# https://inbox.vuxu.org/musl/20251017-dlopen-use-rpath-of-caller-dso-v1-1-46c69eda1473@iscas.ac.cn/
usrPackages = [
appvm dejavu_fonts firmware kernel.modules kmod.lib lvm2 mesa
- netvm systemd westonLite
+ netvm spectrum-installer systemd westonLite
];
appvms = {
diff --git a/host/rootfs/file-list.mk b/host/rootfs/file-list.mk
index 3899d62..54d8e00 100644
--- a/host/rootfs/file-list.mk
+++ b/host/rootfs/file-list.mk
@@ -25,6 +25,8 @@ FILES = \
image/etc/s6-linux-init/run-image/service/serial-getty/notification-fd \
image/etc/s6-linux-init/run-image/service/serial-getty/run \
image/etc/s6-linux-init/run-image/service/serial-getty/template/run \
+ image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd \
+ image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/run \
image/etc/s6-linux-init/run-image/service/vm-services/notification-fd \
image/etc/s6-linux-init/run-image/service/vm-services/run \
image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd \
@@ -62,6 +64,7 @@ FILES = \
image/usr/bin/run-appimage \
image/usr/bin/run-flatpak \
image/usr/bin/run-vmm \
+ image/usr/bin/spectrum-installer-as-root \
image/usr/bin/spectrum-update \
image/usr/bin/vm-console \
image/usr/bin/vm-import \
diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd b/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd.license b/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd.license
new file mode 100644
index 0000000..0d3d47c
--- /dev/null
+++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/notification-fd.license
@@ -0,0 +1,2 @@
+SPDX-License-Identifier: CC0-1.0
+SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/run
new file mode 100755
index 0000000..a8ab652
--- /dev/null
+++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/spectrum-installer-as-root/run
@@ -0,0 +1,17 @@
+#!/bin/execlineb -PW
+# SPDX-License-Identifier: EUPL-1.2+
+# SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
+
+s6-ipcserver-socketbinder -a 0700 /run/spectrum-installer-as-root
+
+if { chown wayland /run/spectrum-installer-as-root }
+
+fdmove 1 3
+s6-ipcserverd -1P
+
+exec -c
+/bin/export PATH /usr/bin
+/bin/export WAYLAND_DISPLAY ""
+s6-sudod
+cd /
+spectrum-installer
diff --git a/host/rootfs/image/etc/s6-rc/weston/run b/host/rootfs/image/etc/s6-rc/weston/run
index 364c032..e677ec4 100644
--- a/host/rootfs/image/etc/s6-rc/weston/run
+++ b/host/rootfs/image/etc/s6-rc/weston/run
@@ -63,6 +63,7 @@ bwrap
# For udev
--ro-bind /run/udev /run/udev
--bind /run/root-terminal /run/root-terminal
+ --bind /run/spectrum-installer-as-root /run/spectrum-installer-as-root
--tmpfs /tmp
--tmpfs /dev/shm
# Filtered /proc (without nasty stuff)
diff --git a/host/rootfs/image/etc/xdg/weston/weston.ini b/host/rootfs/image/etc/xdg/weston/weston.ini
index a4763c6..f21041e 100644
--- a/host/rootfs/image/etc/xdg/weston/weston.ini
+++ b/host/rootfs/image/etc/xdg/weston/weston.ini
@@ -13,3 +13,8 @@ path=/bin/root-terminal
icon=/usr/share/icons/hicolor/20x20/apps/com.system76.CosmicFiles.png
displayname=Files
path=/bin/cosmic-files
+
+[launcher]
+icon=/usr/share/icons/hicolor/22x22/apps/spectrum-installer.png
+displayname=Spectrum installer
+path=/bin/spectrum-installer-as-root
diff --git a/host/rootfs/image/usr/bin/spectrum-installer-as-root b/host/rootfs/image/usr/bin/spectrum-installer-as-root
new file mode 100755
index 0000000..c03d3ac
--- /dev/null
+++ b/host/rootfs/image/usr/bin/spectrum-installer-as-root
@@ -0,0 +1,5 @@
+#!/bin/execlineb -Ws0
+# SPDX-License-Identifier: EUPL-1.2+
+# SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
+
+s6-sudo -- /run/spectrum-installer-as-root $@
diff --git a/pkgs/default.nix b/pkgs/default.nix
index a80c5b3..5849e58 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -50,6 +50,8 @@ let
appSupport = false;
driverSupport = true;
};
+ spectrum-installer =
+ self.callSpectrumPackage ../tools/spectrum-installer {};
spectrum-router = self.callSpectrumPackage ../tools/router {};
xdg-desktop-portal-spectrum-host =
self.callSpectrumPackage ../tools/xdg-desktop-portal-spectrum-host {};
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/4] release: drop combined and installer image
2026-01-04 14:00 [PATCH 1/4] tools: add spectrum-installer Johannes Süllner
2026-01-04 14:00 ` [PATCH 2/4] host/rootfs: integrate spectrum-installer Johannes Süllner
@ 2026-01-04 14:00 ` Johannes Süllner
2026-01-04 14:00 ` [PATCH 4/4] release/live: remove B slot from live image and reduce A slot size Johannes Süllner
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Johannes Süllner @ 2026-01-04 14:00 UTC (permalink / raw)
To: devel; +Cc: Johannes Süllner
Installer is now part of the live system.
Signed-off-by: Johannes Süllner <johannes.suellner@mailbox.org>
---
Documentation/development/uuid-reference.adoc | 22 ----
release/checks/default.nix | 2 -
release/checks/installer.nix | 16 ---
release/combined/default.nix | 123 ------------------
release/combined/eosimages.nix | 21 ---
release/combined/grub.cfg.in | 22 ----
release/combined/run-vm.nix | 31 -----
...ble-gpt-partition-attribute-55-check.patch | 37 ------
...pt-disable-partition-table-CRC-check.patch | 36 -----
.../0003-install-remove-Endless-OS-ad.patch | 99 --------------
...4-finished-don-t-run-eos-diagnostics.patch | 44 -------
...omote-spectrum-not-the-Endless-forum.patch | 32 -----
release/installer/app/default.nix | 26 ----
.../installer/app/vendor-customer-support.ini | 5 -
release/installer/configuration.nix | 69 ----------
release/installer/default.nix | 22 ----
release/installer/run-vm.nix | 47 -------
release/installer/seat.rules | 9 --
18 files changed, 663 deletions(-)
delete mode 100644 release/checks/installer.nix
delete mode 100644 release/combined/default.nix
delete mode 100644 release/combined/eosimages.nix
delete mode 100644 release/combined/grub.cfg.in
delete mode 100644 release/combined/run-vm.nix
delete mode 100644 release/installer/app/0001-gpt-disable-gpt-partition-attribute-55-check.patch
delete mode 100644 release/installer/app/0002-gpt-disable-partition-table-CRC-check.patch
delete mode 100644 release/installer/app/0003-install-remove-Endless-OS-ad.patch
delete mode 100644 release/installer/app/0004-finished-don-t-run-eos-diagnostics.patch
delete mode 100644 release/installer/app/0005-finished-promote-spectrum-not-the-Endless-forum.patch
delete mode 100644 release/installer/app/default.nix
delete mode 100644 release/installer/app/vendor-customer-support.ini
delete mode 100644 release/installer/configuration.nix
delete mode 100644 release/installer/default.nix
delete mode 100644 release/installer/run-vm.nix
delete mode 100644 release/installer/seat.rules
diff --git a/Documentation/development/uuid-reference.adoc b/Documentation/development/uuid-reference.adoc
index 16279c8..7e3641a 100644
--- a/Documentation/development/uuid-reference.adoc
+++ b/Documentation/development/uuid-reference.adoc
@@ -45,28 +45,6 @@ Specification].
https://uapi-group.org/specifications/specs/discoverable_partitions_specification/[Discoverable Partitions
Specification].
-=== `56a3bbc3-aefa-43d9-a64d-7b3fd59bbc4e`
-
-https://github.com/endlessm/eos-installer["eosimages"] partition on the
-Spectrum combined live system / installer image.
-
-== Combined Image Partition IDs
-
-These UUIDs are used as the unique partition identifiers for the
-Spectrum combined live system / installer image.
-
-=== `6e23b026-9f1e-479d-8a58-a0cda382e1ce`
-
-The Spectrum installer system.
-
-=== `18f2ccff-92f1-4bb1-a80e-24f76ecda90c`
-
-The not-yet-used B verity partition.
-
-=== `ec0c5ff3-f6b1-4adf-82b4-61336c4d135f`
-
-The not-yet-used B root filesystem partition.
-
'''
== Finding Undocumented UUIDs
diff --git a/release/checks/default.nix b/release/checks/default.nix
index 9d618dd..ac47cb3 100644
--- a/release/checks/default.nix
+++ b/release/checks/default.nix
@@ -14,8 +14,6 @@ import ../../lib/call-package.nix ({ callSpectrumPackage }:
doc-anchors = callSpectrumPackage ./doc-anchors.nix {};
- installer = callSpectrumPackage ./installer.nix {};
-
integration = callSpectrumPackage ./integration {};
pkg-tests = callSpectrumPackage ./pkg-tests.nix {};
diff --git a/release/checks/installer.nix b/release/checks/installer.nix
deleted file mode 100644
index d28a41b..0000000
--- a/release/checks/installer.nix
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
-
-import ../../lib/call-package.nix ({ testers }: testers.nixosTest ({ ... }: {
- name = "spectrum-test-installer";
- enableOCR = true;
-
- nodes = {
- machine = ../installer/configuration.nix;
- };
-
- testScript = ''
- start_all()
- machine.wait_for_text("Spectrum")
- '';
-})) (_: {})
diff --git a/release/combined/default.nix b/release/combined/default.nix
deleted file mode 100644
index 3be32d4..0000000
--- a/release/combined/default.nix
+++ /dev/null
@@ -1,123 +0,0 @@
-# SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2023 Alyssa Ross <hi@alyssa.is>
-# SPDX-FileCopyrightText: 2021 Yureka <yuka@yuka.dev>
-# SPDX-FileCopyrightText: 2022 Unikie
-
-import ../../lib/call-package.nix (
-{ callSpectrumPackage
-, lib, runCommand, stdenv, replaceVars, writeClosure
-, dosfstools, grub2_efi, jq, libfaketime, mtools, squashfs-tools-ng
-, systemdMinimal, util-linux
-}:
-
-let
- inherit (builtins) storeDir;
- inherit (lib) removePrefix toUpper;
-
- eosimages = callSpectrumPackage ./eosimages.nix {};
-
- installerPartUuid = "6e23b026-9f1e-479d-8a58-a0cda382e1ce";
- installer = callSpectrumPackage ../installer {
- extraConfig = {
- boot.initrd.availableKernelModules = [ "squashfs" ];
-
- fileSystems.${storeDir} = {
- device = "/dev/disk/by-partuuid/${installerPartUuid}";
- };
- };
- };
-
- rootfs = runCommand "installer.img" {
- nativeBuildInputs = [ squashfs-tools-ng ];
- __structuredAttrs = true;
- unsafeDiscardReferences = { out = true; };
- dontFixup = true;
- } ''
- sed 's,^${storeDir}/,,' ${writeClosure [ installer.store ]} |
- tar -C ${storeDir} -c --verbatim-files-from -T - \
- --owner 0 --group 0 | tar2sqfs $out
- '';
-
- efiArch = stdenv.hostPlatform.efiArch;
-
- grub = grub2_efi;
-
- grubCfg = replaceVars ./grub.cfg.in {
- linux = removePrefix storeDir installer.kernel;
- initrd = removePrefix storeDir installer.initramfs;
- inherit (installer) kernelParams;
- };
-
- esp = runCommand "esp.img" {
- nativeBuildInputs = [ grub libfaketime dosfstools mtools ];
-
- env = {
- grubTargetDir = "${grub}/lib/grub/${grub.grubTarget}";
- # Definition copied from util/grub-install-common.c.
- # Last checked: GRUB 2.06
- pkglib_DATA = lib.escapeShellArgs [
- "efiemu32.o" "efiemu64.o" "moddep.lst" "command.lst" "fs.lst"
- "partmap.lst" "parttool.lst" "video.lst" "crypto.lst" "terminal.lst"
- "modinfo.sh"
- ];
- };
-
- __structuredAttrs = true;
- unsafeDiscardReferences = { out = true; };
- dontFixup = true;
-
- passthru = { inherit grubCfg; };
- } ''
- truncate -s 15M $out
- faketime "1970-01-01 00:00:00" mkfs.vfat -i 0x2178694e -n EFI $out
- mmd -i $out ::/EFI ::/EFI/BOOT \
- ::/grub ::/grub/${grub.grubTarget} ::/grub/fonts
-
- mcopy -i $out ${grubCfg} ::/grub/grub.cfg
- mcopy -i $out $grubTargetDir/*.mod ::/grub/${grub.grubTarget}
- for file in $pkglib_DATA; do
- path="$grubTargetDir/$file"
- ! [ -e "$path" ] || mcopy -i $out "$path" ::/grub/${grub.grubTarget}
- done
- mcopy -i $out ${grub}/share/grub/unicode.pf2 ::/grub/fonts
-
- grub-mkimage -o grub${efiArch}.efi -p "(hd0,gpt1)/grub" -O ${grub.grubTarget} part_gpt fat
- mcopy -i $out grub${efiArch}.efi ::/EFI/BOOT/BOOT${toUpper efiArch}.EFI
-
- fsck.vfat -n $out
- '';
-in
-
-runCommand "spectrum-installer" {
- nativeBuildInputs = [ grub jq util-linux systemdMinimal ];
- __structuredAttrs = true;
- unsafeDiscardReferences = { out = true; };
- dontFixup = true;
- passthru = { inherit eosimages esp installer rootfs; };
-} ''
- blockSize() {
- wc -c "$1" | awk '{printf "%d\n", ($1 + 511) / 512}'
- }
-
- fillPartition() {
- read start size < <(sfdisk -J "$1" | jq -r --argjson index "$2" \
- '.partitiontable.partitions[$index] | "\(.start) \(.size)"')
- dd if="$3" of="$1" seek="$start" count="$size" conv=notrunc
- }
-
- espSize="$(blockSize ${esp})"
- installerSize="$(blockSize ${rootfs})"
- eosimagesSize="$(blockSize ${eosimages})"
-
- truncate -s $(((3 * 2048 + $espSize + $installerSize + $eosimagesSize) * 512)) $out
- sfdisk --no-reread --no-tell-kernel $out <<EOF
- label: gpt
- size=$espSize, type=U
- size=$installerSize, type=L, uuid=${installerPartUuid}
- size=$eosimagesSize, type=56a3bbc3-aefa-43d9-a64d-7b3fd59bbc4e
- EOF
-
- fillPartition $out 0 ${esp}
- fillPartition $out 1 ${rootfs}
- fillPartition $out 2 ${eosimages}
-'') (_: {})
diff --git a/release/combined/eosimages.nix b/release/combined/eosimages.nix
deleted file mode 100644
index 2f24a8f..0000000
--- a/release/combined/eosimages.nix
+++ /dev/null
@@ -1,21 +0,0 @@
-# SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2023 Alyssa Ross <hi@alyssa.is>
-
-import ../../lib/call-package.nix (
-{ callSpectrumPackage, runCommand, e2fsprogs, tar2ext4 }:
-
-runCommand "eosimages.img" {
- nativeBuildInputs = [ e2fsprogs tar2ext4 ];
- imageName = "Spectrum-0.0-x86_64-generic.0.Live.img";
- image = callSpectrumPackage ../live {};
- __structuredAttrs = true;
- unsafeDiscardReferences = { out = true; };
- dontFixup = true;
-} ''
- mkdir dir
- cd dir
- gzip -1 < $image > $imageName.gz
- sha256sum -- $imageName.gz > $imageName.gz.sha256
- tar -ch -- $imageName.gz $imageName.gz.sha256 | tar2ext4 -o $out
- e2label $out eosimages
-'') (_: {})
diff --git a/release/combined/grub.cfg.in b/release/combined/grub.cfg.in
deleted file mode 100644
index a22f5fc..0000000
--- a/release/combined/grub.cfg.in
+++ /dev/null
@@ -1,22 +0,0 @@
-# SPDX-License-Identifier: EUPL-1.2+
-# SPDX-FileCopyrightText: 2021-2022, 2024 Alyssa Ross <hi@alyssa.is>
-
-insmod efi_gop
-
-if [ "${grub_cpu}" == "x86_64" ]; then
- insmod efi_uga
-fi
-
-insmod font
-loadfont /grub/fonts/unicode.pf2
-
-insmod gfxterm
-set gfxpayload=keep
-terminal_output gfxterm
-terminal_output console
-
-menuentry "Install Spectrum" {
- set root=(hd0,gpt2)
- linux @linux@ @kernelParams@
- initrd @initrd@
-}
diff --git a/release/combined/run-vm.nix b/release/combined/run-vm.nix
deleted file mode 100644
index 16e00cd..0000000
--- a/release/combined/run-vm.nix
+++ /dev/null
@@ -1,31 +0,0 @@
-# SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021, 2023-2024 Alyssa Ross <hi@alyssa.is>
-
-import ../../lib/call-package.nix (
-{ callSpectrumPackage, lib, writeShellScript, coreutils, qemu_kvm, stdenv }:
-
-let
- image = callSpectrumPackage ./. {};
-in
-
-writeShellScript "run-spectrum-installer-vm.sh" ''
- export PATH=${lib.makeBinPath [ coreutils qemu_kvm ]}
- img="$(mktemp spectrum-installer-target.XXXXXXXXXX.img)"
- truncate -s 20G "$img"
- exec 3<>"$img"
- rm -f "$img"
- # usb-kbd is used here as edk2 does not support virtio-keyboard:
- # https://github.com/tianocore/edk2/pull/6444
- exec ${../../scripts/run-qemu.sh} -cpu max -m 4G \
- -machine virtualization=on \
- -device virtio-mouse \
- -device virtio-gpu \
- -parallel none \
- -vga none \
- -device qemu-xhci \
- -device usb-kbd \
- -device usb-storage,drive=drive1,removable=true \
- -drive file=${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd,format=raw,if=pflash,readonly=true \
- -drive file=${image},id=drive1,format=raw,if=none,readonly=true \
- -drive file=/proc/self/fd/3,format=raw,if=virtio
-'') (_: {})
diff --git a/release/installer/app/0001-gpt-disable-gpt-partition-attribute-55-check.patch b/release/installer/app/0001-gpt-disable-gpt-partition-attribute-55-check.patch
deleted file mode 100644
index 78bbc24..0000000
--- a/release/installer/app/0001-gpt-disable-gpt-partition-attribute-55-check.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 058050ee5ba6a8d8dae2ba7fa7334ee19f98dbf8 Mon Sep 17 00:00:00 2001
-SPDX-License-Identifier: GPL-2.0-or-later
-SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is>
-From: Alyssa Ross <hi@alyssa.is>
-Date: Thu, 9 Dec 2021 21:10:11 +0000
-Subject: [PATCH 1/5] gpt: disable gpt partition attribute 55 check
-
-Endless OS uses flag 55 to mean a partition should be auto-grown, and
-to identify Endless OS partitions. Both of these meanings of flag 55
-are specific to Endless OS though, so it doesn't make sense for
-installing other operating systems.
----
- gnome-image-installer/util/gpt.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/gnome-image-installer/util/gpt.c b/gnome-image-installer/util/gpt.c
-index 02926a5e..1261d9a0 100644
---- a/gnome-image-installer/util/gpt.c
-+++ b/gnome-image-installer/util/gpt.c
-@@ -253,12 +253,14 @@ int is_eos_gpt_valid(struct ptable *pt, uint64_t *size)
- || memcmp(&pt->partitions[i].type_guid, GPT_GUID_LINUX_ROOTFS_AARCH64, 16)==0
- || memcmp(&pt->partitions[i].type_guid, GPT_GUID_LINUX_ROOTFS_RISCV_32, 16)==0
- || memcmp(&pt->partitions[i].type_guid, GPT_GUID_LINUX_ROOTFS_RISCV_64, 16)==0) {
-+#if 0
- uint64_t flags = 0;
- memcpy(&flags, pt->partitions[i].attributes, 8);
- if(!is_nth_flag_set(flags, 55)) {
- // 55th flag must be 1 for EOS images
- continue ;
- }
-+#endif
- has_root=1;
- break ;
- }
---
-2.37.1
-
diff --git a/release/installer/app/0002-gpt-disable-partition-table-CRC-check.patch b/release/installer/app/0002-gpt-disable-partition-table-CRC-check.patch
deleted file mode 100644
index 1628355..0000000
--- a/release/installer/app/0002-gpt-disable-partition-table-CRC-check.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 56dff17022a2ca631ac2ea529a84cb424c913500 Mon Sep 17 00:00:00 2001
-SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is>
-SPDX-License-Identifier: GPL-2.0-or-later
-From: Alyssa Ross <hi@alyssa.is>
-Date: Thu, 9 Dec 2021 21:09:33 +0000
-Subject: [PATCH 2/5] gpt: disable partition table CRC check
-
-This is faulty, I think because eos-installer only looks at the first
-three entries in the partition table.
----
- gnome-image-installer/util/gpt.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/gnome-image-installer/util/gpt.c b/gnome-image-installer/util/gpt.c
-index 1261d9a0..fb8bab17 100644
---- a/gnome-image-installer/util/gpt.c
-+++ b/gnome-image-installer/util/gpt.c
-@@ -223,6 +223,7 @@ int is_eos_gpt_valid(struct ptable *pt, uint64_t *size)
- g_warning("invalid header crc");
- return 0;
- }
-+#if 0
- // crc32 of partition table
- int n = pt->header.ptable_count * pt->header.ptable_partition_size;
- uint8_t *buffer = (uint8_t*)malloc(n);
-@@ -236,6 +237,7 @@ int is_eos_gpt_valid(struct ptable *pt, uint64_t *size)
- return 0;
- }
- free(buffer);
-+#endif
-
- // The first partition must be an EFI System Partition
- if(memcmp(&pt->partitions[0].type_guid, GPT_GUID_EFI, 16)!=0) {
---
-2.37.1
-
diff --git a/release/installer/app/0003-install-remove-Endless-OS-ad.patch b/release/installer/app/0003-install-remove-Endless-OS-ad.patch
deleted file mode 100644
index 8881b00..0000000
--- a/release/installer/app/0003-install-remove-Endless-OS-ad.patch
+++ /dev/null
@@ -1,99 +0,0 @@
-From 1061a8c3cfb31dcc2519841360c6d14612898b2c Mon Sep 17 00:00:00 2001
-SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is>
-SPDX-License-Identifier: GPL-2.0-or-later
-From: Alyssa Ross <hi@alyssa.is>
-Date: Thu, 9 Dec 2021 21:06:16 +0000
-Subject: [PATCH 3/5] install: remove Endless OS ad
-
----
- .../pages/install/gis-install-page.ui | 74 -------------------
- 1 file changed, 74 deletions(-)
-
-diff --git a/gnome-image-installer/pages/install/gis-install-page.ui b/gnome-image-installer/pages/install/gis-install-page.ui
-index d3b7769c..2fcc31b9 100644
---- a/gnome-image-installer/pages/install/gis-install-page.ui
-+++ b/gnome-image-installer/pages/install/gis-install-page.ui
-@@ -45,80 +45,6 @@
- <property name="position">1</property>
- </packing>
- </child>
-- <child>
-- <object class="GtkOverlay" id="graphics_overlay">
-- <property name="visible">True</property>
-- <property name="can_focus">False</property>
-- <child>
-- <object class="GtkImage" id="infographics">
-- <property name="visible">True</property>
-- <property name="can_focus">False</property>
-- <property name="xpad">12</property>
-- <property name="ypad">12</property>
-- <property name="resource">/org/gnome/initial-setup/software_screens.png</property>
-- </object>
-- <packing>
-- <property name="index">-1</property>
-- </packing>
-- </child>
-- <child type="overlay">
-- <object class="GtkBox" id="infolabels">
-- <property name="visible">True</property>
-- <property name="can_focus">False</property>
-- <property name="halign">start</property>
-- <property name="margin_left">48</property>
-- <property name="margin_top">48</property>
-- <property name="orientation">vertical</property>
-- <child>
-- <object class="GtkLabel" id="label1">
-- <property name="visible">True</property>
-- <property name="can_focus">False</property>
-- <property name="halign">start</property>
-- <property name="label" translatable="yes">Endless OS</property>
-- <property name="xalign">0</property>
-- <attributes>
-- <attribute name="weight" value="bold"/>
-- <attribute name="scale" value="2"/>
-- <attribute name="foreground" value="#ffffffffffff"/>
-- </attributes>
-- </object>
-- <packing>
-- <property name="expand">False</property>
-- <property name="fill">True</property>
-- <property name="position">0</property>
-- </packing>
-- </child>
-- <child>
-- <object class="GtkLabel" id="label2">
-- <property name="visible">True</property>
-- <property name="can_focus">False</property>
-- <property name="halign">start</property>
-- <property name="margin_top">16</property>
-- <property name="label" translatable="yes">Fast, easy to use and powerful – with or without internet.
--
--Endless OS is preloaded with over 100 apps, making it useful from the moment you turn it on.</property>
-- <property name="wrap">True</property>
-- <property name="max_width_chars">26</property>
-- <property name="xalign">0</property>
-- <attributes>
-- <attribute name="foreground" value="#ffffffffffff"/>
-- </attributes>
-- </object>
-- <packing>
-- <property name="expand">False</property>
-- <property name="fill">True</property>
-- <property name="position">1</property>
-- </packing>
-- </child>
-- </object>
-- </child>
-- </object>
-- <packing>
-- <property name="expand">False</property>
-- <property name="fill">True</property>
-- <property name="position">2</property>
-- </packing>
-- </child>
- </object>
- <packing>
- <property name="expand">True</property>
---
-2.37.1
-
diff --git a/release/installer/app/0004-finished-don-t-run-eos-diagnostics.patch b/release/installer/app/0004-finished-don-t-run-eos-diagnostics.patch
deleted file mode 100644
index cf1b4ce..0000000
--- a/release/installer/app/0004-finished-don-t-run-eos-diagnostics.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From aefbf6a50097486616a7d0d3bc09e4efb0ed953b Mon Sep 17 00:00:00 2001
-SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is>
-SPDX-License-Identifier: GPL-2.0-or-later
-From: Alyssa Ross <hi@alyssa.is>
-Date: Thu, 9 Dec 2021 21:06:36 +0000
-Subject: [PATCH 4/5] finished: don't run eos-diagnostics
-
-This has to be installed separately from eos-installer, and we don't
-currently do that for the Spectrum installer. If there was an error,
-eos-installer would try to run it, and then display an additional
-error message about not being able to find it on the error screen.
----
- .../pages/finished/gis-finished-page.c | 15 ---------------
- 1 file changed, 15 deletions(-)
-
-diff --git a/gnome-image-installer/pages/finished/gis-finished-page.c b/gnome-image-installer/pages/finished/gis-finished-page.c
-index 6cd26ff2..47b60adb 100644
---- a/gnome-image-installer/pages/finished/gis-finished-page.c
-+++ b/gnome-image-installer/pages/finished/gis-finished-page.c
-@@ -285,21 +285,6 @@ gis_finished_page_shown (GisPage *page)
- gtk_widget_hide (priv->success_box);
- gis_assistant_locale_changed (assistant);
-
-- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-- {
-- /* Running eos-diagnostics can be slow enough that we can't do it
-- * synchronously on the UI thread.
-- */
-- GFile *image_dir = G_FILE (gis_store_get_object (GIS_STORE_IMAGE_DIR));
-- /* See implementation of gis_write_diagnostics_async for rationale. */
-- const gchar *home_dir = priv->gedit != NULL ? g_get_home_dir () : NULL;
--
-- g_application_hold (G_APPLICATION (page->driver));
-- gis_write_diagnostics_async (NULL, image_dir, home_dir,
-- NULL, write_diagnostics_cb,
-- g_object_ref (self));
-- }
--
- /* If running within a live session, hide the "Turn off" button on error,
- * since we have a perfectly good [X] button on the titlebar and we want
- * to encourage the user to notice the link to the diagnostics file.
---
-2.37.1
-
diff --git a/release/installer/app/0005-finished-promote-spectrum-not-the-Endless-forum.patch b/release/installer/app/0005-finished-promote-spectrum-not-the-Endless-forum.patch
deleted file mode 100644
index fc8c27d..0000000
--- a/release/installer/app/0005-finished-promote-spectrum-not-the-Endless-forum.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 786b48e3659db0a184600c5c7047d883b74c82cf Mon Sep 17 00:00:00 2001
-SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is>
-SPDX-License-Identifier: GPL-2.0-or-later
-From: Alyssa Ross <hi@alyssa.is>
-Date: Thu, 9 Dec 2021 21:07:38 +0000
-Subject: [PATCH 5/5] finished: promote #spectrum, not the Endless forum
-
----
- gnome-image-installer/pages/finished/gis-finished-page.c | 6 ++----
- 1 file changed, 2 insertions(+), 4 deletions(-)
-
-diff --git a/gnome-image-installer/pages/finished/gis-finished-page.c b/gnome-image-installer/pages/finished/gis-finished-page.c
-index 47b60adb..2fc1ccf3 100644
---- a/gnome-image-installer/pages/finished/gis-finished-page.c
-+++ b/gnome-image-installer/pages/finished/gis-finished-page.c
-@@ -461,11 +461,9 @@ gis_finished_page_locale_changed (GisPage *page)
- }
-
- support_email = get_customer_support_email ();
-- support_email_markup = g_strdup_printf ("<a href=\"mailto:%1$s\">%1$s</a>",
-- support_email);
- /* Translators: the %s is the customer support email address */
-- support_markup = g_strdup_printf (_("Please contact %s or join the <a href=\"https://community.endlessos.com/\">Endless Community</a> to troubleshoot."),
-- support_email_markup);
-+ support_markup = g_strdup_printf (_("Please contact %s or join #spectrum on irc.libera.chat to troubleshoot."),
-+ support_email);
- gtk_label_set_markup (priv->support_label, support_markup);
- }
-
---
-2.37.1
-
diff --git a/release/installer/app/default.nix b/release/installer/app/default.nix
deleted file mode 100644
index f0d739e..0000000
--- a/release/installer/app/default.nix
+++ /dev/null
@@ -1,26 +0,0 @@
-# SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is>
-
-{ eos-installer, fetchurl }:
-
-let
- logo = fetchurl {
- url = "https://spectrum-os.org/git/www/plain/logo/logo140.png?id=5ac2d787b12e05a9ea91e94ca9373ced55d7371a";
- sha256 = "008dkzapyrkbva3ziyb2fa1annjwfk28q9kwj1bgblgrq6sxllxk";
- };
-in
-
-eos-installer.overrideAttrs ({ patches ? [], postPatch ? "", ... }: {
- patches = patches ++ [
- ./0001-gpt-disable-gpt-partition-attribute-55-check.patch
- ./0002-gpt-disable-partition-table-CRC-check.patch
- ./0003-install-remove-Endless-OS-ad.patch
- ./0004-finished-don-t-run-eos-diagnostics.patch
- ./0005-finished-promote-spectrum-not-the-Endless-forum.patch
- ];
-
- postPatch = postPatch + ''
- find . -type f -print0 | xargs -0 sed -i 's/Endless OS/Spectrum/g'
- cp ${logo} gnome-image-installer/pages/finished/endless_logo.png
- '';
-})
diff --git a/release/installer/app/vendor-customer-support.ini b/release/installer/app/vendor-customer-support.ini
deleted file mode 100644
index 4c4e650..0000000
--- a/release/installer/app/vendor-customer-support.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: CC0-1.0
-# SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is>
-
-[Customer Support]
-Email = discuss@spectrum-os.org
diff --git a/release/installer/configuration.nix b/release/installer/configuration.nix
deleted file mode 100644
index 3f9ef24..0000000
--- a/release/installer/configuration.nix
+++ /dev/null
@@ -1,69 +0,0 @@
-# SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2023, 2025 Alyssa Ross <hi@alyssa.is>
-
-{ lib, modulesPath, pkgs, ... }:
-
-let
- inherit (builtins) readFile;
-in
-
-{
- imports = [ (modulesPath + "/profiles/all-hardware.nix") ];
-
- boot.consoleLogLevel = lib.mkDefault 2;
- boot.kernelParams = [ "udev.log_priority=5" ];
- boot.initrd.verbose = false;
-
- boot.kernelPackages = pkgs.linuxPackages_latest;
-
- boot.plymouth.enable = true;
- boot.plymouth.logo = pkgs.callPackage (
- { runCommand, fetchurl, inkscape }:
- runCommand "spectrum-logo.png" {
- nativeBuildInputs = [ inkscape ];
- svg = fetchurl {
- url = "https://spectrum-os.org/git/www/plain/logo/logo_mesh.svg?id=5ac2d787b12e05a9ea91e94ca9373ced55d7371a";
- sha256 = "1k5025nc5mxdls7bw7wk1734inadvibqxvg8b8yg6arr3y9yy46k";
- };
- } ''
- inkscape -w 48 -h 48 -o "$out" "$svg"
- ''
- ) {};
-
- fileSystems."/" = { fsType = "tmpfs"; };
-
- services.cage.enable = true;
- services.cage.program = lib.getExe (pkgs.callPackage ./app {});
-
- services.udev.extraRules = ''
- KERNEL=="card0", TAG+="systemd"
- '';
-
- systemd.services.cage-tty1.after = [ "dev-dri-card0.device" ];
- systemd.services.cage-tty1.wants = [ "dev-dri-card0.device" ];
-
- # Force eos-installer to stop artificially constraining its size.
- systemd.services.cage-tty1.environment.GIS_SMALL_SCREEN = "1";
-
- users.users.demo = { group = "demo"; isNormalUser = true; };
- users.groups.demo = {};
- security.polkit.extraConfig = readFile ./seat.rules;
-
- services.udisks2.enable = true;
-
- documentation.enable = false;
- networking.firewall.enable = false;
- networking.resolvconf.enable = false;
- nix.enable = false;
- services.timesyncd.enable = false;
-
- boot.loader.systemd-boot.enable = true;
-
- environment.systemPackages = with pkgs; [ adwaita-icon-theme ];
-
- systemd.tmpfiles.rules = [
- "L+ /var/lib/eos-image-defaults/vendor-customer-support.ini - - - - ${app/vendor-customer-support.ini}"
- ];
-
- system.stateVersion = lib.trivial.release;
-}
diff --git a/release/installer/default.nix b/release/installer/default.nix
deleted file mode 100644
index 845eb24..0000000
--- a/release/installer/default.nix
+++ /dev/null
@@ -1,22 +0,0 @@
-# SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is>
-
-import ../../lib/call-package.nix ({ extraConfig, nixos, writeClosure }:
-
-let
- inherit (nixos {
- imports = [ ./configuration.nix extraConfig ];
- }) config;
-in
-
-{
- kernel = "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
-
- initramfs = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
-
- kernelParams = toString ([
- "init=${config.system.build.toplevel}/init"
- ] ++ config.boot.kernelParams);
-
- store = writeClosure [ config.system.build.toplevel ];
-}) (_: { extraConfig = {}; })
diff --git a/release/installer/run-vm.nix b/release/installer/run-vm.nix
deleted file mode 100644
index b9907f7..0000000
--- a/release/installer/run-vm.nix
+++ /dev/null
@@ -1,47 +0,0 @@
-# SPDX-License-Identifier: MIT
-# SPDX-FileCopyrightText: 2021-2025 Alyssa Ross <hi@alyssa.is>
-
-import ../../lib/call-package.nix (
-{ callSpectrumPackage, lib, coreutils, qemu_kvm, stdenv, writeShellScript }:
-
-let
- inherit (builtins) storeDir;
- inherit (lib) makeBinPath escapeShellArg;
-
- eosimages = callSpectrumPackage ../combined/eosimages.nix {};
-
- installer = callSpectrumPackage ./. {
- extraConfig = {
- boot.initrd.availableKernelModules = [ "9p" "9pnet_virtio" ];
-
- fileSystems.${storeDir} = {
- fsType = "9p";
- device = "store";
- };
- };
- };
-in
-
-writeShellScript "run-spectrum-installer-vm.sh" ''
- export PATH=${makeBinPath [ coreutils qemu_kvm ]}
- img="$(mktemp spectrum-installer-target.XXXXXXXXXX.img)"
- truncate -s 40G "$img"
- exec 3<>"$img"
- rm -f "$img"
- exec ${../../scripts/run-qemu.sh} -cpu max -m 4G \
- -device virtio-keyboard \
- -device virtio-mouse \
- -device virtio-gpu \
- -parallel none \
- -vga none \
- -virtfs local,mount_tag=store,path=/nix/store,security_model=none,readonly=true \
- -drive file=${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd,format=raw,if=pflash,readonly=true \
- -drive file=${eosimages},format=raw,if=virtio,readonly=true \
- -drive file=/proc/self/fd/3,format=raw,if=virtio \
- -kernel ${installer.kernel} \
- -initrd ${installer.initramfs} \
- -append ${escapeShellArg (toString [
- installer.kernelParams
- "systemd.journald.forward_to_console"
- ])}
-'') (_: {})
diff --git a/release/installer/seat.rules b/release/installer/seat.rules
deleted file mode 100644
index 79ff400..0000000
--- a/release/installer/seat.rules
+++ /dev/null
@@ -1,9 +0,0 @@
-// SPDX-License-Identifier: EUPL-1.2+
-// SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is>
-
-polkit.addRule(function (action, subject) {
- // The user of the graphical session should be able to do anything.
- if (subject.seat) {
- return polkit.Result.YES;
- }
-});
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/4] release/live: remove B slot from live image and reduce A slot size
2026-01-04 14:00 [PATCH 1/4] tools: add spectrum-installer Johannes Süllner
2026-01-04 14:00 ` [PATCH 2/4] host/rootfs: integrate spectrum-installer Johannes Süllner
2026-01-04 14:00 ` [PATCH 3/4] release: drop combined and installer image Johannes Süllner
@ 2026-01-04 14:00 ` Johannes Süllner
2026-01-04 21:16 ` Demi Marie Obenour
2026-01-04 21:13 ` [PATCH 1/4] tools: add spectrum-installer Demi Marie Obenour
2026-01-10 21:04 ` Alyssa Ross
4 siblings, 1 reply; 9+ messages in thread
From: Johannes Süllner @ 2026-01-04 14:00 UTC (permalink / raw)
To: devel; +Cc: Johannes Süllner
In contrast to the old installer, with the new installer the live image
is not copied as a whole to the destination disk any more. Instead,
`systemd-repart` creates partitions with the desired size, and then
copies the individual partitions.
Signed-off-by: Johannes Süllner <johannes.suellner@mailbox.org>
---
release/live/Makefile | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/release/live/Makefile b/release/live/Makefile
index f5fe558..34a7d3f 100644
--- a/release/live/Makefile
+++ b/release/live/Makefile
@@ -11,9 +11,7 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf
../../scripts/make-gpt.sh $@.tmp \
build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \
$(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)"):Spectrum_'$(VERSION).verity:162' \
- $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))"):Spectrum_'$(VERSION):20000' \
- /dev/null:verity:18f2ccff-92f1-4bb1-a80e-24f76ecda90c:_empty:162 \
- /dev/null:root:ec0c5ff3-f6b1-4adf-82b4-61336c4d135f:_empty:20000
+ $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))"):Spectrum_'$(VERSION)'
mv $@.tmp $@
build/boot.fat: $(SYSTEMD_BOOT_EFI) $(SPECTRUM_EFI)
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] tools: add spectrum-installer
2026-01-04 14:00 [PATCH 1/4] tools: add spectrum-installer Johannes Süllner
` (2 preceding siblings ...)
2026-01-04 14:00 ` [PATCH 4/4] release/live: remove B slot from live image and reduce A slot size Johannes Süllner
@ 2026-01-04 21:13 ` Demi Marie Obenour
2026-01-11 18:30 ` Johannes Süllner
2026-01-10 21:04 ` Alyssa Ross
4 siblings, 1 reply; 9+ messages in thread
From: Demi Marie Obenour @ 2026-01-04 21:13 UTC (permalink / raw)
To: Johannes Süllner, devel
[-- Attachment #1.1.1: Type: text/plain, Size: 197150 bytes --]
On 1/4/26 09:00, Johannes Süllner wrote:
> Written in Rust using the Iced GUI library. Uses `lsblk-rs` to offer a
> list of disks where the user can choose one to install Spectrum on.
> Uses `systemd-repart` for the installation, which is running in an
> embedded terminal window using `iced-term`.
>
> Signed-off-by: Johannes Süllner <johannes.suellner@mailbox.org>
> ---
> pkgs/default.nix | 1 +
> tools/spectrum-installer/Cargo.lock | 5106 +++++++++++++++++
> tools/spectrum-installer/Cargo.lock.license | 2 +
> tools/spectrum-installer/Cargo.toml | 14 +
> tools/spectrum-installer/default.nix | 41 +
> .../res/installer_logo_mesh.svg | 85 +
> .../res/repart.d/10-esp.conf | 8 +
> .../res/repart.d/20-verity-A.conf | 9 +
> .../res/repart.d/21-rootfs-A.conf | 9 +
> .../res/repart.d/30-verity-B.conf | 8 +
> .../res/repart.d/31-rootfs-B.conf | 8 +
> .../res/repart.d/40-home.conf | 7 +
> tools/spectrum-installer/shell.nix | 30 +
> tools/spectrum-installer/src/main.rs | 52 +
> .../src/pages/completion.rs | 112 +
> .../src/pages/confirmation.rs | 108 +
> .../src/pages/disk_selection.rs | 134 +
> .../src/pages/installation.rs | 182 +
> tools/spectrum-installer/src/pages/layout.rs | 122 +
> tools/spectrum-installer/src/pages/mod.rs | 43 +
> tools/spectrum-installer/src/pages/welcome.rs | 62 +
> 21 files changed, 6143 insertions(+)
> create mode 100644 tools/spectrum-installer/Cargo.lock
> create mode 100644 tools/spectrum-installer/Cargo.lock.license
> create mode 100644 tools/spectrum-installer/Cargo.toml
> create mode 100644 tools/spectrum-installer/default.nix
> create mode 100644 tools/spectrum-installer/res/installer_logo_mesh.svg
> create mode 100644 tools/spectrum-installer/res/repart.d/10-esp.conf
> create mode 100644 tools/spectrum-installer/res/repart.d/20-verity-A.conf
> create mode 100644 tools/spectrum-installer/res/repart.d/21-rootfs-A.conf
> create mode 100644 tools/spectrum-installer/res/repart.d/30-verity-B.conf
> create mode 100644 tools/spectrum-installer/res/repart.d/31-rootfs-B.conf
> create mode 100644 tools/spectrum-installer/res/repart.d/40-home.conf
> create mode 100644 tools/spectrum-installer/shell.nix
> create mode 100644 tools/spectrum-installer/src/main.rs
> create mode 100644 tools/spectrum-installer/src/pages/completion.rs
> create mode 100644 tools/spectrum-installer/src/pages/confirmation.rs
> create mode 100644 tools/spectrum-installer/src/pages/disk_selection.rs
> create mode 100644 tools/spectrum-installer/src/pages/installation.rs
> create mode 100644 tools/spectrum-installer/src/pages/layout.rs
> create mode 100644 tools/spectrum-installer/src/pages/mod.rs
> create mode 100644 tools/spectrum-installer/src/pages/welcome.rs
>
> diff --git a/pkgs/default.nix b/pkgs/default.nix
> index 4dbdfee..a80c5b3 100644
> --- a/pkgs/default.nix
> +++ b/pkgs/default.nix
> @@ -74,6 +74,7 @@ let
> ../release/live/build
> ../tools/mount-flatpak/target
> ../tools/router/target
> + ../tools/spectrum-installer/target
> ../tools/xdg-desktop-portal-spectrum-host/target
> ../vm/sys/net/build
> ]));
> diff --git a/tools/spectrum-installer/Cargo.lock b/tools/spectrum-installer/Cargo.lock
> new file mode 100644
> index 0000000..4be50ef
> --- /dev/null
> +++ b/tools/spectrum-installer/Cargo.lock
> @@ -0,0 +1,5106 @@
> +# This file is automatically @generated by Cargo.
> +# It is not intended for manual editing.
> +version = 4
> +
> +[[package]]
> +name = "ab_glyph"
> +version = "0.2.32"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2"
> +dependencies = [
> + "ab_glyph_rasterizer",
> + "owned_ttf_parser",
> +]
> +
> +[[package]]
> +name = "ab_glyph_rasterizer"
> +version = "0.1.10"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
> +
> +[[package]]
> +name = "adler2"
> +version = "2.0.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
> +
> +[[package]]
> +name = "ahash"
> +version = "0.7.8"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
> +dependencies = [
> + "getrandom 0.2.16",
> + "once_cell",
> + "version_check",
> +]
> +
> +[[package]]
> +name = "ahash"
> +version = "0.8.12"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
> +dependencies = [
> + "cfg-if",
> + "getrandom 0.3.4",
> + "once_cell",
> + "version_check",
> + "zerocopy",
> +]
> +
> +[[package]]
> +name = "aho-corasick"
> +version = "1.1.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
> +dependencies = [
> + "memchr",
> +]
> +
> +[[package]]
> +name = "alacritty_terminal"
> +version = "0.25.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "46319972e74179d707445f64aaa2893bbf6a111de3a9af29b7eb382f8b39e282"
> +dependencies = [
> + "base64",
> + "bitflags 2.10.0",
> + "home",
> + "libc",
> + "log",
> + "miow",
> + "parking_lot 0.12.5",
> + "piper",
> + "polling 3.11.0",
> + "regex-automata",
> + "rustix 1.1.2",
> + "rustix-openpty",
> + "serde",
> + "signal-hook",
> + "unicode-width 0.2.2",
> + "vte",
> + "windows-sys 0.59.0",
> +]
> +
> +[[package]]
> +name = "aliasable"
> +version = "0.1.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
> +
> +[[package]]
> +name = "allocator-api2"
> +version = "0.2.21"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
> +
> +[[package]]
> +name = "android-activity"
> +version = "0.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046"
> +dependencies = [
> + "android-properties",
> + "bitflags 2.10.0",
> + "cc",
> + "cesu8",
> + "jni",
> + "jni-sys",
> + "libc",
> + "log",
> + "ndk",
> + "ndk-context",
> + "ndk-sys 0.6.0+11769913",
> + "num_enum",
> + "thiserror 1.0.69",
> +]
> +
> +[[package]]
> +name = "android-properties"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
> +
> +[[package]]
> +name = "android_system_properties"
> +version = "0.1.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
> +dependencies = [
> + "libc",
> +]
> +
> +[[package]]
> +name = "anyhow"
> +version = "1.0.100"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
> +
> +[[package]]
> +name = "approx"
> +version = "0.5.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
> +dependencies = [
> + "num-traits",
> +]
> +
> +[[package]]
> +name = "arrayref"
> +version = "0.3.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
> +
> +[[package]]
> +name = "arrayvec"
> +version = "0.7.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
> +
> +[[package]]
> +name = "as-raw-xcb-connection"
> +version = "1.0.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
> +
> +[[package]]
> +name = "ash"
> +version = "0.37.3+1.3.251"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a"
> +dependencies = [
> + "libloading 0.7.4",
> +]
> +
> +[[package]]
> +name = "async-broadcast"
> +version = "0.7.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
> +dependencies = [
> + "event-listener 5.4.1",
> + "event-listener-strategy",
> + "futures-core",
> + "pin-project-lite",
> +]
> +
> +[[package]]
> +name = "async-channel"
> +version = "1.9.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
> +dependencies = [
> + "concurrent-queue",
> + "event-listener 2.5.3",
> + "futures-core",
> +]
> +
> +[[package]]
> +name = "async-channel"
> +version = "2.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
> +dependencies = [
> + "concurrent-queue",
> + "event-listener-strategy",
> + "futures-core",
> + "pin-project-lite",
> +]
> +
> +[[package]]
> +name = "async-executor"
> +version = "1.13.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8"
> +dependencies = [
> + "async-task",
> + "concurrent-queue",
> + "fastrand 2.3.0",
> + "futures-lite 2.6.1",
> + "pin-project-lite",
> + "slab",
> +]
> +
> +[[package]]
> +name = "async-fs"
> +version = "1.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
> +dependencies = [
> + "async-lock 2.8.0",
> + "autocfg",
> + "blocking",
> + "futures-lite 1.13.0",
> +]
> +
> +[[package]]
> +name = "async-fs"
> +version = "2.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5"
> +dependencies = [
> + "async-lock 3.4.1",
> + "blocking",
> + "futures-lite 2.6.1",
> +]
> +
> +[[package]]
> +name = "async-io"
> +version = "1.13.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
> +dependencies = [
> + "async-lock 2.8.0",
> + "autocfg",
> + "cfg-if",
> + "concurrent-queue",
> + "futures-lite 1.13.0",
> + "log",
> + "parking",
> + "polling 2.8.0",
> + "rustix 0.37.28",
> + "slab",
> + "socket2 0.4.10",
> + "waker-fn",
> +]
> +
> +[[package]]
> +name = "async-io"
> +version = "2.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
> +dependencies = [
> + "autocfg",
> + "cfg-if",
> + "concurrent-queue",
> + "futures-io",
> + "futures-lite 2.6.1",
> + "parking",
> + "polling 3.11.0",
> + "rustix 1.1.2",
> + "slab",
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "async-lock"
> +version = "2.8.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
> +dependencies = [
> + "event-listener 2.5.3",
> +]
> +
> +[[package]]
> +name = "async-lock"
> +version = "3.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
> +dependencies = [
> + "event-listener 5.4.1",
> + "event-listener-strategy",
> + "pin-project-lite",
> +]
> +
> +[[package]]
> +name = "async-net"
> +version = "1.8.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f"
> +dependencies = [
> + "async-io 1.13.0",
> + "blocking",
> + "futures-lite 1.13.0",
> +]
> +
> +[[package]]
> +name = "async-process"
> +version = "1.8.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88"
> +dependencies = [
> + "async-io 1.13.0",
> + "async-lock 2.8.0",
> + "async-signal",
> + "blocking",
> + "cfg-if",
> + "event-listener 3.1.0",
> + "futures-lite 1.13.0",
> + "rustix 0.38.44",
> + "windows-sys 0.48.0",
> +]
> +
> +[[package]]
> +name = "async-process"
> +version = "2.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
> +dependencies = [
> + "async-channel 2.5.0",
> + "async-io 2.6.0",
> + "async-lock 3.4.1",
> + "async-signal",
> + "async-task",
> + "blocking",
> + "cfg-if",
> + "event-listener 5.4.1",
> + "futures-lite 2.6.1",
> + "rustix 1.1.2",
> +]
> +
> +[[package]]
> +name = "async-recursion"
> +version = "1.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "async-signal"
> +version = "0.2.13"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c"
> +dependencies = [
> + "async-io 2.6.0",
> + "async-lock 3.4.1",
> + "atomic-waker",
> + "cfg-if",
> + "futures-core",
> + "futures-io",
> + "rustix 1.1.2",
> + "signal-hook-registry",
> + "slab",
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "async-task"
> +version = "4.7.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
> +
> +[[package]]
> +name = "async-trait"
> +version = "0.1.89"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "atomic-waker"
> +version = "1.1.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
> +
> +[[package]]
> +name = "autocfg"
> +version = "1.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
> +
> +[[package]]
> +name = "base64"
> +version = "0.22.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
> +
> +[[package]]
> +name = "bit-set"
> +version = "0.5.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
> +dependencies = [
> + "bit-vec",
> +]
> +
> +[[package]]
> +name = "bit-vec"
> +version = "0.6.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
> +
> +[[package]]
> +name = "bit_field"
> +version = "0.10.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
> +
> +[[package]]
> +name = "bitflags"
> +version = "1.3.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
> +
> +[[package]]
> +name = "bitflags"
> +version = "2.10.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
> +dependencies = [
> + "serde_core",
> +]
> +
> +[[package]]
> +name = "block"
> +version = "0.1.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
> +
> +[[package]]
> +name = "block-buffer"
> +version = "0.10.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
> +dependencies = [
> + "generic-array",
> +]
> +
> +[[package]]
> +name = "block2"
> +version = "0.5.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
> +dependencies = [
> + "objc2",
> +]
> +
> +[[package]]
> +name = "blocking"
> +version = "1.6.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
> +dependencies = [
> + "async-channel 2.5.0",
> + "async-task",
> + "futures-io",
> + "futures-lite 2.6.1",
> + "piper",
> +]
> +
> +[[package]]
> +name = "bumpalo"
> +version = "3.19.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
> +
> +[[package]]
> +name = "by_address"
> +version = "1.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
> +
> +[[package]]
> +name = "bytemuck"
> +version = "1.24.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
> +dependencies = [
> + "bytemuck_derive",
> +]
> +
> +[[package]]
> +name = "bytemuck_derive"
> +version = "1.10.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "byteorder"
> +version = "1.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
> +
> +[[package]]
> +name = "bytes"
> +version = "1.11.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
> +
> +[[package]]
> +name = "calloop"
> +version = "0.13.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
> +dependencies = [
> + "bitflags 2.10.0",
> + "log",
> + "polling 3.11.0",
> + "rustix 0.38.44",
> + "slab",
> + "thiserror 1.0.69",
> +]
> +
> +[[package]]
> +name = "calloop"
> +version = "0.14.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cb9f6e1368bd4621d2c86baa7e37de77a938adf5221e5dd3d6133340101b309e"
> +dependencies = [
> + "bitflags 2.10.0",
> + "polling 3.11.0",
> + "rustix 1.1.2",
> + "slab",
> + "tracing",
> +]
> +
> +[[package]]
> +name = "calloop-wayland-source"
> +version = "0.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
> +dependencies = [
> + "calloop 0.13.0",
> + "rustix 0.38.44",
> + "wayland-backend",
> + "wayland-client",
> +]
> +
> +[[package]]
> +name = "calloop-wayland-source"
> +version = "0.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
> +dependencies = [
> + "calloop 0.14.3",
> + "rustix 1.1.2",
> + "wayland-backend",
> + "wayland-client",
> +]
> +
> +[[package]]
> +name = "cc"
> +version = "1.2.47"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
> +dependencies = [
> + "find-msvc-tools",
> + "jobserver",
> + "libc",
> + "shlex",
> +]
> +
> +[[package]]
> +name = "cesu8"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
> +
> +[[package]]
> +name = "cfg-if"
> +version = "1.0.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
> +
> +[[package]]
> +name = "cfg_aliases"
> +version = "0.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
> +
> +[[package]]
> +name = "cfg_aliases"
> +version = "0.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
> +
> +[[package]]
> +name = "chrono"
> +version = "0.4.42"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
> +dependencies = [
> + "iana-time-zone",
> + "js-sys",
> + "num-traits",
> + "wasm-bindgen",
> + "windows-link",
> +]
> +
> +[[package]]
> +name = "clipboard-win"
> +version = "5.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
> +dependencies = [
> + "error-code",
> +]
> +
> +[[package]]
> +name = "clipboard_macos"
> +version = "0.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f"
> +dependencies = [
> + "objc2",
> + "objc2-app-kit",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "clipboard_wayland"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "003f886bc4e2987729d10c1db3424e7f80809f3fc22dbc16c685738887cb37b8"
> +dependencies = [
> + "smithay-clipboard",
> +]
> +
> +[[package]]
> +name = "clipboard_x11"
> +version = "0.4.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c"
> +dependencies = [
> + "thiserror 1.0.69",
> + "x11rb",
> +]
> +
> +[[package]]
> +name = "codespan-reporting"
> +version = "0.11.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
> +dependencies = [
> + "termcolor",
> + "unicode-width 0.1.14",
> +]
> +
> +[[package]]
> +name = "color_quant"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
> +
> +[[package]]
> +name = "com"
> +version = "0.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6"
> +dependencies = [
> + "com_macros",
> +]
> +
> +[[package]]
> +name = "com_macros"
> +version = "0.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5"
> +dependencies = [
> + "com_macros_support",
> + "proc-macro2",
> + "syn 1.0.109",
> +]
> +
> +[[package]]
> +name = "com_macros_support"
> +version = "0.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 1.0.109",
> +]
> +
> +[[package]]
> +name = "combine"
> +version = "4.6.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
> +dependencies = [
> + "bytes",
> + "memchr",
> +]
> +
> +[[package]]
> +name = "concurrent-queue"
> +version = "2.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
> +dependencies = [
> + "crossbeam-utils",
> +]
> +
> +[[package]]
> +name = "core-foundation"
> +version = "0.9.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
> +dependencies = [
> + "core-foundation-sys",
> + "libc",
> +]
> +
> +[[package]]
> +name = "core-foundation"
> +version = "0.10.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
> +dependencies = [
> + "core-foundation-sys",
> + "libc",
> +]
> +
> +[[package]]
> +name = "core-foundation-sys"
> +version = "0.8.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
> +
> +[[package]]
> +name = "core-graphics"
> +version = "0.23.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
> +dependencies = [
> + "bitflags 1.3.2",
> + "core-foundation 0.9.4",
> + "core-graphics-types 0.1.3",
> + "foreign-types",
> + "libc",
> +]
> +
> +[[package]]
> +name = "core-graphics"
> +version = "0.24.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
> +dependencies = [
> + "bitflags 2.10.0",
> + "core-foundation 0.10.1",
> + "core-graphics-types 0.2.0",
> + "foreign-types",
> + "libc",
> +]
> +
> +[[package]]
> +name = "core-graphics-types"
> +version = "0.1.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
> +dependencies = [
> + "bitflags 1.3.2",
> + "core-foundation 0.9.4",
> + "libc",
> +]
> +
> +[[package]]
> +name = "core-graphics-types"
> +version = "0.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
> +dependencies = [
> + "bitflags 2.10.0",
> + "core-foundation 0.10.1",
> + "libc",
> +]
> +
> +[[package]]
> +name = "cosmic-text"
> +version = "0.12.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "59fd57d82eb4bfe7ffa9b1cec0c05e2fd378155b47f255a67983cb4afe0e80c2"
> +dependencies = [
> + "bitflags 2.10.0",
> + "fontdb",
> + "log",
> + "rangemap",
> + "rayon",
> + "rustc-hash 1.1.0",
> + "rustybuzz",
> + "self_cell",
> + "swash",
> + "sys-locale",
> + "ttf-parser 0.21.1",
> + "unicode-bidi",
> + "unicode-linebreak",
> + "unicode-script",
> + "unicode-segmentation",
> +]
> +
> +[[package]]
> +name = "cpufeatures"
> +version = "0.2.17"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
> +dependencies = [
> + "libc",
> +]
> +
> +[[package]]
> +name = "crc32fast"
> +version = "1.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
> +dependencies = [
> + "cfg-if",
> +]
> +
> +[[package]]
> +name = "crossbeam-deque"
> +version = "0.8.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
> +dependencies = [
> + "crossbeam-epoch",
> + "crossbeam-utils",
> +]
> +
> +[[package]]
> +name = "crossbeam-epoch"
> +version = "0.9.18"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
> +dependencies = [
> + "crossbeam-utils",
> +]
> +
> +[[package]]
> +name = "crossbeam-utils"
> +version = "0.8.21"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
> +
> +[[package]]
> +name = "crunchy"
> +version = "0.2.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
> +
> +[[package]]
> +name = "crypto-common"
> +version = "0.1.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
> +dependencies = [
> + "generic-array",
> + "typenum",
> +]
> +
> +[[package]]
> +name = "ctor-lite"
> +version = "0.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b"
> +
> +[[package]]
> +name = "cursor-icon"
> +version = "1.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
> +
> +[[package]]
> +name = "d3d12"
> +version = "0.19.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307"
> +dependencies = [
> + "bitflags 2.10.0",
> + "libloading 0.8.9",
> + "winapi",
> +]
> +
> +[[package]]
> +name = "dark-light"
> +version = "1.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2a76fa97167fa740dcdbfe18e8895601e1bc36525f09b044e00916e717c03a3c"
> +dependencies = [
> + "dconf_rs",
> + "detect-desktop-environment",
> + "dirs",
> + "objc",
> + "rust-ini",
> + "web-sys",
> + "winreg",
> + "zbus",
> +]
> +
> +[[package]]
> +name = "dconf_rs"
> +version = "0.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b"
> +
> +[[package]]
> +name = "detect-desktop-environment"
> +version = "0.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810"
> +
> +[[package]]
> +name = "digest"
> +version = "0.10.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
> +dependencies = [
> + "block-buffer",
> + "crypto-common",
> +]
> +
> +[[package]]
> +name = "dirs"
> +version = "4.0.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
> +dependencies = [
> + "dirs-sys",
> +]
> +
> +[[package]]
> +name = "dirs-sys"
> +version = "0.3.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
> +dependencies = [
> + "libc",
> + "redox_users",
> + "winapi",
> +]
> +
> +[[package]]
> +name = "dispatch"
> +version = "0.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
> +
> +[[package]]
> +name = "dlib"
> +version = "0.5.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
> +dependencies = [
> + "libloading 0.8.9",
> +]
> +
> +[[package]]
> +name = "dlv-list"
> +version = "0.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
> +
> +[[package]]
> +name = "downcast-rs"
> +version = "1.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
> +
> +[[package]]
> +name = "dpi"
> +version = "0.1.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
> +
> +[[package]]
> +name = "drm"
> +version = "0.12.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1"
> +dependencies = [
> + "bitflags 2.10.0",
> + "bytemuck",
> + "drm-ffi",
> + "drm-fourcc",
> + "rustix 0.38.44",
> +]
> +
> +[[package]]
> +name = "drm-ffi"
> +version = "0.8.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53"
> +dependencies = [
> + "drm-sys",
> + "rustix 0.38.44",
> +]
> +
> +[[package]]
> +name = "drm-fourcc"
> +version = "2.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
> +
> +[[package]]
> +name = "drm-sys"
> +version = "0.7.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986"
> +dependencies = [
> + "libc",
> + "linux-raw-sys 0.6.5",
> +]
> +
> +[[package]]
> +name = "either"
> +version = "1.15.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
> +
> +[[package]]
> +name = "endi"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
> +
> +[[package]]
> +name = "enumflags2"
> +version = "0.7.12"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
> +dependencies = [
> + "enumflags2_derive",
> + "serde",
> +]
> +
> +[[package]]
> +name = "enumflags2_derive"
> +version = "0.7.12"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "equivalent"
> +version = "1.0.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
> +
> +[[package]]
> +name = "errno"
> +version = "0.3.14"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
> +dependencies = [
> + "libc",
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "error-code"
> +version = "3.3.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
> +
> +[[package]]
> +name = "etagere"
> +version = "0.2.15"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fc89bf99e5dc15954a60f707c1e09d7540e5cd9af85fa75caa0b510bc08c5342"
> +dependencies = [
> + "euclid",
> + "svg_fmt",
> +]
> +
> +[[package]]
> +name = "euclid"
> +version = "0.22.11"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48"
> +dependencies = [
> + "num-traits",
> +]
> +
> +[[package]]
> +name = "event-listener"
> +version = "2.5.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
> +
> +[[package]]
> +name = "event-listener"
> +version = "3.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2"
> +dependencies = [
> + "concurrent-queue",
> + "parking",
> + "pin-project-lite",
> +]
> +
> +[[package]]
> +name = "event-listener"
> +version = "5.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
> +dependencies = [
> + "concurrent-queue",
> + "parking",
> + "pin-project-lite",
> +]
> +
> +[[package]]
> +name = "event-listener-strategy"
> +version = "0.5.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
> +dependencies = [
> + "event-listener 5.4.1",
> + "pin-project-lite",
> +]
> +
> +[[package]]
> +name = "exr"
> +version = "1.74.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
> +dependencies = [
> + "bit_field",
> + "half",
> + "lebe",
> + "miniz_oxide",
> + "rayon-core",
> + "smallvec",
> + "zune-inflate",
> +]
> +
> +[[package]]
> +name = "fast-srgb8"
> +version = "1.0.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
> +
> +[[package]]
> +name = "fastrand"
> +version = "1.9.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
> +dependencies = [
> + "instant",
> +]
> +
> +[[package]]
> +name = "fastrand"
> +version = "2.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
> +
> +[[package]]
> +name = "fdeflate"
> +version = "0.3.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
> +dependencies = [
> + "simd-adler32",
> +]
> +
> +[[package]]
> +name = "find-msvc-tools"
> +version = "0.1.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
> +
> +[[package]]
> +name = "flate2"
> +version = "1.1.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
> +dependencies = [
> + "crc32fast",
> + "miniz_oxide",
> +]
> +
> +[[package]]
> +name = "float_next_after"
> +version = "1.0.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8"
> +
> +[[package]]
> +name = "font-types"
> +version = "0.7.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b3971f9a5ca983419cdc386941ba3b9e1feba01a0ab888adf78739feb2798492"
> +dependencies = [
> + "bytemuck",
> +]
> +
> +[[package]]
> +name = "fontconfig-parser"
> +version = "0.5.8"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
> +dependencies = [
> + "roxmltree",
> +]
> +
> +[[package]]
> +name = "fontdb"
> +version = "0.16.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3"
> +dependencies = [
> + "fontconfig-parser",
> + "log",
> + "memmap2",
> + "slotmap",
> + "tinyvec",
> + "ttf-parser 0.20.0",
> +]
> +
> +[[package]]
> +name = "foreign-types"
> +version = "0.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
> +dependencies = [
> + "foreign-types-macros",
> + "foreign-types-shared",
> +]
> +
> +[[package]]
> +name = "foreign-types-macros"
> +version = "0.2.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "foreign-types-shared"
> +version = "0.3.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
> +
> +[[package]]
> +name = "futures"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
> +dependencies = [
> + "futures-channel",
> + "futures-core",
> + "futures-executor",
> + "futures-io",
> + "futures-sink",
> + "futures-task",
> + "futures-util",
> +]
> +
> +[[package]]
> +name = "futures-channel"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
> +dependencies = [
> + "futures-core",
> + "futures-sink",
> +]
> +
> +[[package]]
> +name = "futures-core"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
> +
> +[[package]]
> +name = "futures-executor"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
> +dependencies = [
> + "futures-core",
> + "futures-task",
> + "futures-util",
> + "num_cpus",
> +]
> +
> +[[package]]
> +name = "futures-io"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
> +
> +[[package]]
> +name = "futures-lite"
> +version = "1.13.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
> +dependencies = [
> + "fastrand 1.9.0",
> + "futures-core",
> + "futures-io",
> + "memchr",
> + "parking",
> + "pin-project-lite",
> + "waker-fn",
> +]
> +
> +[[package]]
> +name = "futures-lite"
> +version = "2.6.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
> +dependencies = [
> + "fastrand 2.3.0",
> + "futures-core",
> + "futures-io",
> + "parking",
> + "pin-project-lite",
> +]
> +
> +[[package]]
> +name = "futures-macro"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "futures-sink"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
> +
> +[[package]]
> +name = "futures-task"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
> +
> +[[package]]
> +name = "futures-util"
> +version = "0.3.31"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
> +dependencies = [
> + "futures-channel",
> + "futures-core",
> + "futures-io",
> + "futures-macro",
> + "futures-sink",
> + "futures-task",
> + "memchr",
> + "pin-project-lite",
> + "pin-utils",
> + "slab",
> +]
> +
> +[[package]]
> +name = "generic-array"
> +version = "0.14.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
> +dependencies = [
> + "typenum",
> + "version_check",
> +]
> +
> +[[package]]
> +name = "gethostname"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
> +dependencies = [
> + "rustix 1.1.2",
> + "windows-link",
> +]
> +
> +[[package]]
> +name = "getrandom"
> +version = "0.2.16"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
> +dependencies = [
> + "cfg-if",
> + "libc",
> + "wasi",
> +]
> +
> +[[package]]
> +name = "getrandom"
> +version = "0.3.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
> +dependencies = [
> + "cfg-if",
> + "libc",
> + "r-efi",
> + "wasip2",
> +]
> +
> +[[package]]
> +name = "gif"
> +version = "0.13.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
> +dependencies = [
> + "color_quant",
> + "weezl",
> +]
> +
> +[[package]]
> +name = "gl_generator"
> +version = "0.14.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
> +dependencies = [
> + "khronos_api",
> + "log",
> + "xml-rs",
> +]
> +
> +[[package]]
> +name = "glam"
> +version = "0.25.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
> +
> +[[package]]
> +name = "glow"
> +version = "0.13.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
> +dependencies = [
> + "js-sys",
> + "slotmap",
> + "wasm-bindgen",
> + "web-sys",
> +]
> +
> +[[package]]
> +name = "glutin_wgl_sys"
> +version = "0.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead"
> +dependencies = [
> + "gl_generator",
> +]
> +
> +[[package]]
> +name = "gpu-alloc"
> +version = "0.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
> +dependencies = [
> + "bitflags 2.10.0",
> + "gpu-alloc-types",
> +]
> +
> +[[package]]
> +name = "gpu-alloc-types"
> +version = "0.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
> +dependencies = [
> + "bitflags 2.10.0",
> +]
> +
> +[[package]]
> +name = "gpu-allocator"
> +version = "0.25.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
> +dependencies = [
> + "log",
> + "presser",
> + "thiserror 1.0.69",
> + "winapi",
> + "windows",
> +]
> +
> +[[package]]
> +name = "gpu-descriptor"
> +version = "0.2.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c"
> +dependencies = [
> + "bitflags 2.10.0",
> + "gpu-descriptor-types",
> + "hashbrown 0.14.5",
> +]
> +
> +[[package]]
> +name = "gpu-descriptor-types"
> +version = "0.1.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c"
> +dependencies = [
> + "bitflags 2.10.0",
> +]
> +
> +[[package]]
> +name = "guillotiere"
> +version = "0.6.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782"
> +dependencies = [
> + "euclid",
> + "svg_fmt",
> +]
> +
> +[[package]]
> +name = "half"
> +version = "2.7.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
> +dependencies = [
> + "cfg-if",
> + "crunchy",
> + "zerocopy",
> +]
> +
> +[[package]]
> +name = "hashbrown"
> +version = "0.12.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
> +dependencies = [
> + "ahash 0.7.8",
> +]
> +
> +[[package]]
> +name = "hashbrown"
> +version = "0.14.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
> +dependencies = [
> + "ahash 0.8.12",
> + "allocator-api2",
> +]
> +
> +[[package]]
> +name = "hashbrown"
> +version = "0.16.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
> +
> +[[package]]
> +name = "hassle-rs"
> +version = "0.11.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890"
> +dependencies = [
> + "bitflags 2.10.0",
> + "com",
> + "libc",
> + "libloading 0.8.9",
> + "thiserror 1.0.69",
> + "widestring",
> + "winapi",
> +]
> +
> +[[package]]
> +name = "heck"
> +version = "0.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
> +
> +[[package]]
> +name = "hermit-abi"
> +version = "0.3.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
> +
> +[[package]]
> +name = "hermit-abi"
> +version = "0.5.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
> +
> +[[package]]
> +name = "hex"
> +version = "0.4.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
> +
> +[[package]]
> +name = "hexf-parse"
> +version = "0.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
> +
> +[[package]]
> +name = "home"
> +version = "0.5.11"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
> +dependencies = [
> + "windows-sys 0.59.0",
> +]
> +
> +[[package]]
> +name = "iana-time-zone"
> +version = "0.1.64"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
> +dependencies = [
> + "android_system_properties",
> + "core-foundation-sys",
> + "iana-time-zone-haiku",
> + "js-sys",
> + "log",
> + "wasm-bindgen",
> + "windows-core 0.62.2",
> +]
> +
> +[[package]]
> +name = "iana-time-zone-haiku"
> +version = "0.1.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
> +dependencies = [
> + "cc",
> +]
> +
> +[[package]]
> +name = "iced"
> +version = "0.13.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "88acfabc84ec077eaf9ede3457ffa3a104626d79022a9bf7f296093b1d60c73f"
> +dependencies = [
> + "iced_core",
> + "iced_futures",
> + "iced_renderer",
> + "iced_widget",
> + "iced_winit",
> + "image",
> + "thiserror 1.0.69",
> +]
> +
> +[[package]]
> +name = "iced_aw"
> +version = "0.12.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "582c517a94ce3205da98e9c10b26bb71aa36b7d7d084441d826dc912711d1bac"
> +dependencies = [
> + "cfg-if",
> + "chrono",
> + "getrandom 0.3.4",
> + "iced",
> + "iced_fonts 0.1.1",
> + "itertools",
> + "num-format",
> + "num-traits",
> + "web-time",
> +]
> +
> +[[package]]
> +name = "iced_core"
> +version = "0.13.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0013a238275494641bf8f1732a23a808196540dc67b22ff97099c044ae4c8a1c"
> +dependencies = [
> + "bitflags 2.10.0",
> + "bytes",
> + "dark-light",
> + "glam",
> + "log",
> + "num-traits",
> + "once_cell",
> + "palette",
> + "rustc-hash 2.1.1",
> + "smol_str",
> + "thiserror 1.0.69",
> + "web-time",
> +]
> +
> +[[package]]
> +name = "iced_fonts"
> +version = "0.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "df7deb0800a850ee25c8a42559f72c0f249e577feb3aad37b9b65dc1e517e52a"
> +dependencies = [
> + "iced_core",
> +]
> +
> +[[package]]
> +name = "iced_fonts"
> +version = "0.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7db9d45e87bc3ac22ff82e2d9dea9139f1c055137f1e0f39df3d68110fcee7a9"
> +dependencies = [
> + "iced_core",
> + "iced_widget",
> +]
> +
> +[[package]]
> +name = "iced_futures"
> +version = "0.13.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0c04a6745ba2e80f32cf01e034fd00d853aa4f4cd8b91888099cb7aaee0d5d7c"
> +dependencies = [
> + "futures",
> + "iced_core",
> + "log",
> + "rustc-hash 2.1.1",
> + "smol",
> + "tokio",
> + "wasm-bindgen-futures",
> + "wasm-timer",
> +]
> +
> +[[package]]
> +name = "iced_glyphon"
> +version = "0.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "41c3bb56f1820ca252bc1d0994ece33d233a55657c0c263ea7cb16895adbde82"
> +dependencies = [
> + "cosmic-text",
> + "etagere",
> + "lru",
> + "rustc-hash 2.1.1",
> + "wgpu",
> +]
> +
> +[[package]]
> +name = "iced_graphics"
> +version = "0.13.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ba25a18cfa6d5cc160aca7e1b34f73ccdff21680fa8702168c09739767b6c66f"
> +dependencies = [
> + "bitflags 2.10.0",
> + "bytemuck",
> + "cosmic-text",
> + "half",
> + "iced_core",
> + "iced_futures",
> + "image",
> + "kamadak-exif",
> + "log",
> + "lyon_path",
> + "once_cell",
> + "raw-window-handle",
> + "rustc-hash 2.1.1",
> + "thiserror 1.0.69",
> + "unicode-segmentation",
> +]
> +
> +[[package]]
> +name = "iced_renderer"
> +version = "0.13.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "73558208059f9e622df2bf434e044ee2f838ce75201a023cf0ca3e1244f46c2a"
> +dependencies = [
> + "iced_graphics",
> + "iced_tiny_skia",
> + "iced_wgpu",
> + "log",
> + "thiserror 1.0.69",
> +]
> +
> +[[package]]
> +name = "iced_runtime"
> +version = "0.13.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "348b5b2c61c934d88ca3b0ed1ed913291e923d086a66fa288ce9669da9ef62b5"
> +dependencies = [
> + "bytes",
> + "iced_core",
> + "iced_futures",
> + "raw-window-handle",
> + "thiserror 1.0.69",
> +]
> +
> +[[package]]
> +name = "iced_term"
> +version = "0.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a75dd9ece683674e3d83f422516b08978eead151acec63aa3360bc38b75338b7"
> +dependencies = [
> + "alacritty_terminal",
> + "anyhow",
> + "iced",
> + "iced_core",
> + "iced_graphics",
> + "open",
> + "tokio",
> +]
> +
> +[[package]]
> +name = "iced_tiny_skia"
> +version = "0.13.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c625d368284fcc43b0b36b176f76eff1abebe7959dd58bd8ce6897d641962a50"
> +dependencies = [
> + "bytemuck",
> + "cosmic-text",
> + "iced_graphics",
> + "kurbo",
> + "log",
> + "rustc-hash 2.1.1",
> + "softbuffer",
> + "tiny-skia",
> +]
> +
> +[[package]]
> +name = "iced_wgpu"
> +version = "0.13.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "15708887133671d2bcc6c1d01d1f176f43a64d6cdc3b2bf893396c3ee498295f"
> +dependencies = [
> + "bitflags 2.10.0",
> + "bytemuck",
> + "futures",
> + "glam",
> + "guillotiere",
> + "iced_glyphon",
> + "iced_graphics",
> + "log",
> + "lyon",
> + "once_cell",
> + "rustc-hash 2.1.1",
> + "thiserror 1.0.69",
> + "wgpu",
> +]
> +
> +[[package]]
> +name = "iced_widget"
> +version = "0.13.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "81429e1b950b0e4bca65be4c4278fea6678ea782030a411778f26fa9f8983e1d"
> +dependencies = [
> + "iced_renderer",
> + "iced_runtime",
> + "num-traits",
> + "once_cell",
> + "ouroboros",
> + "rustc-hash 2.1.1",
> + "thiserror 1.0.69",
> + "unicode-segmentation",
> +]
> +
> +[[package]]
> +name = "iced_winit"
> +version = "0.13.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f44cd4e1c594b6334f409282937bf972ba14d31fedf03c23aa595d982a2fda28"
> +dependencies = [
> + "iced_futures",
> + "iced_graphics",
> + "iced_runtime",
> + "log",
> + "rustc-hash 2.1.1",
> + "thiserror 1.0.69",
> + "tracing",
> + "wasm-bindgen-futures",
> + "web-sys",
> + "winapi",
> + "window_clipboard",
> + "winit",
> +]
> +
> +[[package]]
> +name = "image"
> +version = "0.24.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
> +dependencies = [
> + "bytemuck",
> + "byteorder",
> + "color_quant",
> + "exr",
> + "gif",
> + "jpeg-decoder",
> + "num-traits",
> + "png",
> + "qoi",
> + "tiff",
> +]
> +
> +[[package]]
> +name = "indexmap"
> +version = "2.12.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
> +dependencies = [
> + "equivalent",
> + "hashbrown 0.16.1",
> +]
> +
> +[[package]]
> +name = "instant"
> +version = "0.1.13"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
> +dependencies = [
> + "cfg-if",
> +]
> +
> +[[package]]
> +name = "io-lifetimes"
> +version = "1.0.11"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
> +dependencies = [
> + "hermit-abi 0.3.9",
> + "libc",
> + "windows-sys 0.48.0",
> +]
> +
> +[[package]]
> +name = "is-docker"
> +version = "0.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
> +dependencies = [
> + "once_cell",
> +]
> +
> +[[package]]
> +name = "is-wsl"
> +version = "0.4.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
> +dependencies = [
> + "is-docker",
> + "once_cell",
> +]
> +
> +[[package]]
> +name = "itertools"
> +version = "0.14.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
> +dependencies = [
> + "either",
> +]
> +
> +[[package]]
> +name = "itoa"
> +version = "1.0.15"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
> +
> +[[package]]
> +name = "jni"
> +version = "0.21.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
> +dependencies = [
> + "cesu8",
> + "cfg-if",
> + "combine",
> + "jni-sys",
> + "log",
> + "thiserror 1.0.69",
> + "walkdir",
> + "windows-sys 0.45.0",
> +]
> +
> +[[package]]
> +name = "jni-sys"
> +version = "0.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
> +
> +[[package]]
> +name = "jobserver"
> +version = "0.1.34"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
> +dependencies = [
> + "getrandom 0.3.4",
> + "libc",
> +]
> +
> +[[package]]
> +name = "jpeg-decoder"
> +version = "0.3.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
> +dependencies = [
> + "rayon",
> +]
> +
> +[[package]]
> +name = "js-sys"
> +version = "0.3.82"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
> +dependencies = [
> + "once_cell",
> + "wasm-bindgen",
> +]
> +
> +[[package]]
> +name = "kamadak-exif"
> +version = "0.5.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ef4fc70d0ab7e5b6bafa30216a6b48705ea964cdfc29c050f2412295eba58077"
> +dependencies = [
> + "mutate_once",
> +]
> +
> +[[package]]
> +name = "khronos-egl"
> +version = "6.0.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
> +dependencies = [
> + "libc",
> + "libloading 0.8.9",
> + "pkg-config",
> +]
> +
> +[[package]]
> +name = "khronos_api"
> +version = "3.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
> +
> +[[package]]
> +name = "kurbo"
> +version = "0.10.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1618d4ebd923e97d67e7cd363d80aef35fe961005cbbbb3d2dad8bdd1bc63440"
> +dependencies = [
> + "arrayvec",
> + "smallvec",
> +]
> +
> +[[package]]
> +name = "lebe"
> +version = "0.5.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
> +
> +[[package]]
> +name = "libc"
> +version = "0.2.177"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
> +
> +[[package]]
> +name = "libloading"
> +version = "0.7.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
> +dependencies = [
> + "cfg-if",
> + "winapi",
> +]
> +
> +[[package]]
> +name = "libloading"
> +version = "0.8.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
> +dependencies = [
> + "cfg-if",
> + "windows-link",
> +]
> +
> +[[package]]
> +name = "libm"
> +version = "0.2.15"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
> +
> +[[package]]
> +name = "libredox"
> +version = "0.1.10"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
> +dependencies = [
> + "bitflags 2.10.0",
> + "libc",
> + "redox_syscall 0.5.18",
> +]
> +
> +[[package]]
> +name = "linux-raw-sys"
> +version = "0.3.8"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
> +
> +[[package]]
> +name = "linux-raw-sys"
> +version = "0.4.15"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
> +
> +[[package]]
> +name = "linux-raw-sys"
> +version = "0.6.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7"
> +
> +[[package]]
> +name = "linux-raw-sys"
> +version = "0.11.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
> +
> +[[package]]
> +name = "lock_api"
> +version = "0.4.14"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
> +dependencies = [
> + "scopeguard",
> +]
> +
> +[[package]]
> +name = "log"
> +version = "0.4.28"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
> +
> +[[package]]
> +name = "lru"
> +version = "0.12.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
> +
> +[[package]]
> +name = "lsblk"
> +version = "0.6.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "05f50cb1109b79638b78a02ac752040c3e6b649f06e00e4587660fd4408d6a26"
> +dependencies = [
> + "paste",
> + "thiserror 2.0.17",
> +]
> +
> +[[package]]
> +name = "lyon"
> +version = "1.0.16"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dbcb7d54d54c8937364c9d41902d066656817dce1e03a44e5533afebd1ef4352"
> +dependencies = [
> + "lyon_algorithms",
> + "lyon_tessellation",
> +]
> +
> +[[package]]
> +name = "lyon_algorithms"
> +version = "1.0.16"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f4c0829e28c4f336396f250d850c3987e16ce6db057ffe047ce0dd54aab6b647"
> +dependencies = [
> + "lyon_path",
> + "num-traits",
> +]
> +
> +[[package]]
> +name = "lyon_geom"
> +version = "1.0.18"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e260b6de923e6e47adfedf6243013a7a874684165a6a277594ee3906021b2343"
> +dependencies = [
> + "arrayvec",
> + "euclid",
> + "num-traits",
> +]
> +
> +[[package]]
> +name = "lyon_path"
> +version = "1.0.16"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1aeca86bcfd632a15984ba029b539ffb811e0a70bf55e814ef8b0f54f506fdeb"
> +dependencies = [
> + "lyon_geom",
> + "num-traits",
> +]
> +
> +[[package]]
> +name = "lyon_tessellation"
> +version = "1.0.16"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f3f586142e1280335b1bc89539f7c97dd80f08fc43e9ab1b74ef0a42b04aa353"
> +dependencies = [
> + "float_next_after",
> + "lyon_path",
> + "num-traits",
> +]
> +
> +[[package]]
> +name = "malloc_buf"
> +version = "0.0.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
> +dependencies = [
> + "libc",
> +]
> +
> +[[package]]
> +name = "memchr"
> +version = "2.7.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
> +
> +[[package]]
> +name = "memmap2"
> +version = "0.9.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
> +dependencies = [
> + "libc",
> +]
> +
> +[[package]]
> +name = "memoffset"
> +version = "0.9.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
> +dependencies = [
> + "autocfg",
> +]
> +
> +[[package]]
> +name = "metal"
> +version = "0.27.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block",
> + "core-graphics-types 0.1.3",
> + "foreign-types",
> + "log",
> + "objc",
> + "paste",
> +]
> +
> +[[package]]
> +name = "miniz_oxide"
> +version = "0.8.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
> +dependencies = [
> + "adler2",
> + "simd-adler32",
> +]
> +
> +[[package]]
> +name = "mio"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
> +dependencies = [
> + "libc",
> + "wasi",
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "miow"
> +version = "0.6.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08"
> +dependencies = [
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "mutate_once"
> +version = "0.1.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af"
> +
> +[[package]]
> +name = "naga"
> +version = "0.19.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843"
> +dependencies = [
> + "bit-set",
> + "bitflags 2.10.0",
> + "codespan-reporting",
> + "hexf-parse",
> + "indexmap",
> + "log",
> + "num-traits",
> + "rustc-hash 1.1.0",
> + "spirv",
> + "termcolor",
> + "thiserror 1.0.69",
> + "unicode-xid",
> +]
> +
> +[[package]]
> +name = "ndk"
> +version = "0.9.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
> +dependencies = [
> + "bitflags 2.10.0",
> + "jni-sys",
> + "log",
> + "ndk-sys 0.6.0+11769913",
> + "num_enum",
> + "raw-window-handle",
> + "thiserror 1.0.69",
> +]
> +
> +[[package]]
> +name = "ndk-context"
> +version = "0.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
> +
> +[[package]]
> +name = "ndk-sys"
> +version = "0.5.0+25.2.9519653"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
> +dependencies = [
> + "jni-sys",
> +]
> +
> +[[package]]
> +name = "ndk-sys"
> +version = "0.6.0+11769913"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
> +dependencies = [
> + "jni-sys",
> +]
> +
> +[[package]]
> +name = "nix"
> +version = "0.29.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
> +dependencies = [
> + "bitflags 2.10.0",
> + "cfg-if",
> + "cfg_aliases 0.2.1",
> + "libc",
> + "memoffset",
> +]
> +
> +[[package]]
> +name = "num-format"
> +version = "0.4.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
> +dependencies = [
> + "arrayvec",
> + "itoa",
> +]
> +
> +[[package]]
> +name = "num-traits"
> +version = "0.2.19"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
> +dependencies = [
> + "autocfg",
> + "libm",
> +]
> +
> +[[package]]
> +name = "num_cpus"
> +version = "1.17.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
> +dependencies = [
> + "hermit-abi 0.5.2",
> + "libc",
> +]
> +
> +[[package]]
> +name = "num_enum"
> +version = "0.7.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
> +dependencies = [
> + "num_enum_derive",
> + "rustversion",
> +]
> +
> +[[package]]
> +name = "num_enum_derive"
> +version = "0.7.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
> +dependencies = [
> + "proc-macro-crate",
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "objc"
> +version = "0.2.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
> +dependencies = [
> + "malloc_buf",
> + "objc_exception",
> +]
> +
> +[[package]]
> +name = "objc-sys"
> +version = "0.3.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
> +
> +[[package]]
> +name = "objc2"
> +version = "0.5.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
> +dependencies = [
> + "objc-sys",
> + "objc2-encode",
> +]
> +
> +[[package]]
> +name = "objc2-app-kit"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block2",
> + "libc",
> + "objc2",
> + "objc2-core-data",
> + "objc2-core-image",
> + "objc2-foundation",
> + "objc2-quartz-core",
> +]
> +
> +[[package]]
> +name = "objc2-cloud-kit"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block2",
> + "objc2",
> + "objc2-core-location",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc2-contacts"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
> +dependencies = [
> + "block2",
> + "objc2",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc2-core-data"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block2",
> + "objc2",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc2-core-image"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
> +dependencies = [
> + "block2",
> + "objc2",
> + "objc2-foundation",
> + "objc2-metal",
> +]
> +
> +[[package]]
> +name = "objc2-core-location"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
> +dependencies = [
> + "block2",
> + "objc2",
> + "objc2-contacts",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc2-encode"
> +version = "4.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
> +
> +[[package]]
> +name = "objc2-foundation"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block2",
> + "dispatch",
> + "libc",
> + "objc2",
> +]
> +
> +[[package]]
> +name = "objc2-link-presentation"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
> +dependencies = [
> + "block2",
> + "objc2",
> + "objc2-app-kit",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc2-metal"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block2",
> + "objc2",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc2-quartz-core"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block2",
> + "objc2",
> + "objc2-foundation",
> + "objc2-metal",
> +]
> +
> +[[package]]
> +name = "objc2-symbols"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
> +dependencies = [
> + "objc2",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc2-ui-kit"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block2",
> + "objc2",
> + "objc2-cloud-kit",
> + "objc2-core-data",
> + "objc2-core-image",
> + "objc2-core-location",
> + "objc2-foundation",
> + "objc2-link-presentation",
> + "objc2-quartz-core",
> + "objc2-symbols",
> + "objc2-uniform-type-identifiers",
> + "objc2-user-notifications",
> +]
> +
> +[[package]]
> +name = "objc2-uniform-type-identifiers"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
> +dependencies = [
> + "block2",
> + "objc2",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc2-user-notifications"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
> +dependencies = [
> + "bitflags 2.10.0",
> + "block2",
> + "objc2",
> + "objc2-core-location",
> + "objc2-foundation",
> +]
> +
> +[[package]]
> +name = "objc_exception"
> +version = "0.1.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
> +dependencies = [
> + "cc",
> +]
> +
> +[[package]]
> +name = "once_cell"
> +version = "1.21.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
> +
> +[[package]]
> +name = "open"
> +version = "5.3.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc"
> +dependencies = [
> + "is-wsl",
> + "libc",
> + "pathdiff",
> +]
> +
> +[[package]]
> +name = "orbclient"
> +version = "0.3.49"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "247ad146e19b9437f8604c21f8652423595cf710ad108af40e77d3ae6e96b827"
> +dependencies = [
> + "libredox",
> +]
> +
> +[[package]]
> +name = "ordered-multimap"
> +version = "0.4.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
> +dependencies = [
> + "dlv-list",
> + "hashbrown 0.12.3",
> +]
> +
> +[[package]]
> +name = "ordered-stream"
> +version = "0.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
> +dependencies = [
> + "futures-core",
> + "pin-project-lite",
> +]
> +
> +[[package]]
> +name = "ouroboros"
> +version = "0.18.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
> +dependencies = [
> + "aliasable",
> + "ouroboros_macro",
> + "static_assertions",
> +]
> +
> +[[package]]
> +name = "ouroboros_macro"
> +version = "0.18.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
> +dependencies = [
> + "heck",
> + "proc-macro2",
> + "proc-macro2-diagnostics",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "owned_ttf_parser"
> +version = "0.25.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b"
> +dependencies = [
> + "ttf-parser 0.25.1",
> +]
> +
> +[[package]]
> +name = "palette"
> +version = "0.7.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6"
> +dependencies = [
> + "approx",
> + "fast-srgb8",
> + "palette_derive",
> + "phf",
> +]
> +
> +[[package]]
> +name = "palette_derive"
> +version = "0.7.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30"
> +dependencies = [
> + "by_address",
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "parking"
> +version = "2.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
> +
> +[[package]]
> +name = "parking_lot"
> +version = "0.11.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
> +dependencies = [
> + "instant",
> + "lock_api",
> + "parking_lot_core 0.8.6",
> +]
> +
> +[[package]]
> +name = "parking_lot"
> +version = "0.12.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
> +dependencies = [
> + "lock_api",
> + "parking_lot_core 0.9.12",
> +]
> +
> +[[package]]
> +name = "parking_lot_core"
> +version = "0.8.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
> +dependencies = [
> + "cfg-if",
> + "instant",
> + "libc",
> + "redox_syscall 0.2.16",
> + "smallvec",
> + "winapi",
> +]
> +
> +[[package]]
> +name = "parking_lot_core"
> +version = "0.9.12"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
> +dependencies = [
> + "cfg-if",
> + "libc",
> + "redox_syscall 0.5.18",
> + "smallvec",
> + "windows-link",
> +]
> +
> +[[package]]
> +name = "paste"
> +version = "1.0.15"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
> +
> +[[package]]
> +name = "pathdiff"
> +version = "0.2.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
> +
> +[[package]]
> +name = "percent-encoding"
> +version = "2.3.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
> +
> +[[package]]
> +name = "phf"
> +version = "0.11.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
> +dependencies = [
> + "phf_macros",
> + "phf_shared",
> +]
> +
> +[[package]]
> +name = "phf_generator"
> +version = "0.11.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
> +dependencies = [
> + "phf_shared",
> + "rand",
> +]
> +
> +[[package]]
> +name = "phf_macros"
> +version = "0.11.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
> +dependencies = [
> + "phf_generator",
> + "phf_shared",
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "phf_shared"
> +version = "0.11.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
> +dependencies = [
> + "siphasher",
> +]
> +
> +[[package]]
> +name = "pin-project"
> +version = "1.1.10"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
> +dependencies = [
> + "pin-project-internal",
> +]
> +
> +[[package]]
> +name = "pin-project-internal"
> +version = "1.1.10"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "pin-project-lite"
> +version = "0.2.16"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
> +
> +[[package]]
> +name = "pin-utils"
> +version = "0.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
> +
> +[[package]]
> +name = "piper"
> +version = "0.2.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
> +dependencies = [
> + "atomic-waker",
> + "fastrand 2.3.0",
> + "futures-io",
> +]
> +
> +[[package]]
> +name = "pkg-config"
> +version = "0.3.32"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
> +
> +[[package]]
> +name = "png"
> +version = "0.17.16"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
> +dependencies = [
> + "bitflags 1.3.2",
> + "crc32fast",
> + "fdeflate",
> + "flate2",
> + "miniz_oxide",
> +]
> +
> +[[package]]
> +name = "polling"
> +version = "2.8.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
> +dependencies = [
> + "autocfg",
> + "bitflags 1.3.2",
> + "cfg-if",
> + "concurrent-queue",
> + "libc",
> + "log",
> + "pin-project-lite",
> + "windows-sys 0.48.0",
> +]
> +
> +[[package]]
> +name = "polling"
> +version = "3.11.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
> +dependencies = [
> + "cfg-if",
> + "concurrent-queue",
> + "hermit-abi 0.5.2",
> + "pin-project-lite",
> + "rustix 1.1.2",
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "ppv-lite86"
> +version = "0.2.21"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
> +dependencies = [
> + "zerocopy",
> +]
> +
> +[[package]]
> +name = "presser"
> +version = "0.3.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
> +
> +[[package]]
> +name = "proc-macro-crate"
> +version = "3.4.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
> +dependencies = [
> + "toml_edit",
> +]
> +
> +[[package]]
> +name = "proc-macro2"
> +version = "1.0.103"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
> +dependencies = [
> + "unicode-ident",
> +]
> +
> +[[package]]
> +name = "proc-macro2-diagnostics"
> +version = "0.10.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> + "version_check",
> + "yansi",
> +]
> +
> +[[package]]
> +name = "profiling"
> +version = "1.0.17"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
> +
> +[[package]]
> +name = "qoi"
> +version = "0.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
> +dependencies = [
> + "bytemuck",
> +]
> +
> +[[package]]
> +name = "quick-xml"
> +version = "0.37.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
> +dependencies = [
> + "memchr",
> +]
> +
> +[[package]]
> +name = "quote"
> +version = "1.0.42"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
> +dependencies = [
> + "proc-macro2",
> +]
> +
> +[[package]]
> +name = "r-efi"
> +version = "5.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
> +
> +[[package]]
> +name = "rand"
> +version = "0.8.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
> +dependencies = [
> + "libc",
> + "rand_chacha",
> + "rand_core",
> +]
> +
> +[[package]]
> +name = "rand_chacha"
> +version = "0.3.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
> +dependencies = [
> + "ppv-lite86",
> + "rand_core",
> +]
> +
> +[[package]]
> +name = "rand_core"
> +version = "0.6.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
> +dependencies = [
> + "getrandom 0.2.16",
> +]
> +
> +[[package]]
> +name = "range-alloc"
> +version = "0.1.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
> +
> +[[package]]
> +name = "rangemap"
> +version = "1.7.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "acbbbbea733ec66275512d0b9694f34102e7d5406fdbe2ad8d21b28dce92887c"
> +
> +[[package]]
> +name = "raw-window-handle"
> +version = "0.6.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
> +
> +[[package]]
> +name = "rayon"
> +version = "1.11.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
> +dependencies = [
> + "either",
> + "rayon-core",
> +]
> +
> +[[package]]
> +name = "rayon-core"
> +version = "1.13.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
> +dependencies = [
> + "crossbeam-deque",
> + "crossbeam-utils",
> +]
> +
> +[[package]]
> +name = "read-fonts"
> +version = "0.22.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "69aacb76b5c29acfb7f90155d39759a29496aebb49395830e928a9703d2eec2f"
> +dependencies = [
> + "bytemuck",
> + "font-types",
> +]
> +
> +[[package]]
> +name = "redox_syscall"
> +version = "0.2.16"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
> +dependencies = [
> + "bitflags 1.3.2",
> +]
> +
> +[[package]]
> +name = "redox_syscall"
> +version = "0.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
> +dependencies = [
> + "bitflags 1.3.2",
> +]
> +
> +[[package]]
> +name = "redox_syscall"
> +version = "0.5.18"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
> +dependencies = [
> + "bitflags 2.10.0",
> +]
> +
> +[[package]]
> +name = "redox_users"
> +version = "0.4.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
> +dependencies = [
> + "getrandom 0.2.16",
> + "libredox",
> + "thiserror 1.0.69",
> +]
> +
> +[[package]]
> +name = "regex-automata"
> +version = "0.4.13"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
> +dependencies = [
> + "aho-corasick",
> + "memchr",
> + "regex-syntax",
> +]
> +
> +[[package]]
> +name = "regex-syntax"
> +version = "0.8.8"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
> +
> +[[package]]
> +name = "renderdoc-sys"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
> +
> +[[package]]
> +name = "roxmltree"
> +version = "0.20.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
> +
> +[[package]]
> +name = "rust-ini"
> +version = "0.18.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
> +dependencies = [
> + "cfg-if",
> + "ordered-multimap",
> +]
> +
> +[[package]]
> +name = "rustc-hash"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
> +
> +[[package]]
> +name = "rustc-hash"
> +version = "2.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
> +
> +[[package]]
> +name = "rustix"
> +version = "0.37.28"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6"
> +dependencies = [
> + "bitflags 1.3.2",
> + "errno",
> + "io-lifetimes",
> + "libc",
> + "linux-raw-sys 0.3.8",
> + "windows-sys 0.48.0",
> +]
> +
> +[[package]]
> +name = "rustix"
> +version = "0.38.44"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
> +dependencies = [
> + "bitflags 2.10.0",
> + "errno",
> + "libc",
> + "linux-raw-sys 0.4.15",
> + "windows-sys 0.59.0",
> +]
> +
> +[[package]]
> +name = "rustix"
> +version = "1.1.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
> +dependencies = [
> + "bitflags 2.10.0",
> + "errno",
> + "libc",
> + "linux-raw-sys 0.11.0",
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "rustix-openpty"
> +version = "0.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1de16c7c59892b870a6336f185dc10943517f1327447096bbb7bb32cd85e2393"
> +dependencies = [
> + "errno",
> + "libc",
> + "rustix 1.1.2",
> +]
> +
> +[[package]]
> +name = "rustversion"
> +version = "1.0.22"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
> +
> +[[package]]
> +name = "rustybuzz"
> +version = "0.14.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c"
> +dependencies = [
> + "bitflags 2.10.0",
> + "bytemuck",
> + "libm",
> + "smallvec",
> + "ttf-parser 0.21.1",
> + "unicode-bidi-mirroring",
> + "unicode-ccc",
> + "unicode-properties",
> + "unicode-script",
> +]
> +
> +[[package]]
> +name = "same-file"
> +version = "1.0.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
> +dependencies = [
> + "winapi-util",
> +]
> +
> +[[package]]
> +name = "scoped-tls"
> +version = "1.0.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
> +
> +[[package]]
> +name = "scopeguard"
> +version = "1.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
> +
> +[[package]]
> +name = "sctk-adwaita"
> +version = "0.10.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec"
> +dependencies = [
> + "ab_glyph",
> + "log",
> + "memmap2",
> + "smithay-client-toolkit 0.19.2",
> + "tiny-skia",
> +]
> +
> +[[package]]
> +name = "self_cell"
> +version = "1.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33"
> +
> +[[package]]
> +name = "serde"
> +version = "1.0.228"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
> +dependencies = [
> + "serde_core",
> + "serde_derive",
> +]
> +
> +[[package]]
> +name = "serde_core"
> +version = "1.0.228"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
> +dependencies = [
> + "serde_derive",
> +]
> +
> +[[package]]
> +name = "serde_derive"
> +version = "1.0.228"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "serde_repr"
> +version = "0.1.20"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "sha1"
> +version = "0.10.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
> +dependencies = [
> + "cfg-if",
> + "cpufeatures",
> + "digest",
> +]
> +
> +[[package]]
> +name = "shlex"
> +version = "1.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
> +
> +[[package]]
> +name = "signal-hook"
> +version = "0.3.18"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
> +dependencies = [
> + "libc",
> + "signal-hook-registry",
> +]
> +
> +[[package]]
> +name = "signal-hook-registry"
> +version = "1.4.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
> +dependencies = [
> + "libc",
> +]
> +
> +[[package]]
> +name = "simd-adler32"
> +version = "0.3.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
> +
> +[[package]]
> +name = "siphasher"
> +version = "1.0.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
> +
> +[[package]]
> +name = "skrifa"
> +version = "0.22.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8e1c44ad1f6c5bdd4eefed8326711b7dbda9ea45dfd36068c427d332aa382cbe"
> +dependencies = [
> + "bytemuck",
> + "read-fonts",
> +]
> +
> +[[package]]
> +name = "slab"
> +version = "0.4.11"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
> +
> +[[package]]
> +name = "slotmap"
> +version = "1.0.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
> +dependencies = [
> + "version_check",
> +]
> +
> +[[package]]
> +name = "smallvec"
> +version = "1.15.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
> +
> +[[package]]
> +name = "smithay-client-toolkit"
> +version = "0.19.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
> +dependencies = [
> + "bitflags 2.10.0",
> + "calloop 0.13.0",
> + "calloop-wayland-source 0.3.0",
> + "cursor-icon",
> + "libc",
> + "log",
> + "memmap2",
> + "rustix 0.38.44",
> + "thiserror 1.0.69",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-csd-frame",
> + "wayland-cursor",
> + "wayland-protocols",
> + "wayland-protocols-wlr",
> + "wayland-scanner",
> + "xkeysym",
> +]
> +
> +[[package]]
> +name = "smithay-client-toolkit"
> +version = "0.20.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0"
> +dependencies = [
> + "bitflags 2.10.0",
> + "calloop 0.14.3",
> + "calloop-wayland-source 0.4.1",
> + "cursor-icon",
> + "libc",
> + "log",
> + "memmap2",
> + "rustix 1.1.2",
> + "thiserror 2.0.17",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-csd-frame",
> + "wayland-cursor",
> + "wayland-protocols",
> + "wayland-protocols-experimental",
> + "wayland-protocols-misc",
> + "wayland-protocols-wlr",
> + "wayland-scanner",
> + "xkeysym",
> +]
> +
> +[[package]]
> +name = "smithay-clipboard"
> +version = "0.7.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226"
> +dependencies = [
> + "libc",
> + "smithay-client-toolkit 0.20.0",
> + "wayland-backend",
> +]
> +
> +[[package]]
> +name = "smol"
> +version = "1.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1"
> +dependencies = [
> + "async-channel 1.9.0",
> + "async-executor",
> + "async-fs 1.6.0",
> + "async-io 1.13.0",
> + "async-lock 2.8.0",
> + "async-net",
> + "async-process 1.8.1",
> + "blocking",
> + "futures-lite 1.13.0",
> +]
> +
> +[[package]]
> +name = "smol_str"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
> +dependencies = [
> + "serde",
> +]
> +
> +[[package]]
> +name = "socket2"
> +version = "0.4.10"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
> +dependencies = [
> + "libc",
> + "winapi",
> +]
> +
> +[[package]]
> +name = "socket2"
> +version = "0.6.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
> +dependencies = [
> + "libc",
> + "windows-sys 0.60.2",
> +]
> +
> +[[package]]
> +name = "softbuffer"
> +version = "0.4.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
> +dependencies = [
> + "as-raw-xcb-connection",
> + "bytemuck",
> + "cfg_aliases 0.2.1",
> + "core-graphics 0.24.0",
> + "drm",
> + "fastrand 2.3.0",
> + "foreign-types",
> + "js-sys",
> + "log",
> + "memmap2",
> + "objc2",
> + "objc2-foundation",
> + "objc2-quartz-core",
> + "raw-window-handle",
> + "redox_syscall 0.5.18",
> + "rustix 0.38.44",
> + "tiny-xlib",
> + "wasm-bindgen",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-sys",
> + "web-sys",
> + "windows-sys 0.59.0",
> + "x11rb",
> +]
> +
> +[[package]]
> +name = "spectrum-installer"
> +version = "0.1.0"
> +dependencies = [
> + "iced",
> + "iced_aw",
> + "iced_fonts 0.2.1",
> + "iced_term",
> + "lsblk",
> +]
> +
> +[[package]]
> +name = "spirv"
> +version = "0.3.0+sdk-1.3.268.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
> +dependencies = [
> + "bitflags 2.10.0",
> +]
> +
> +[[package]]
> +name = "static_assertions"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
> +
> +[[package]]
> +name = "strict-num"
> +version = "0.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
> +
> +[[package]]
> +name = "svg_fmt"
> +version = "0.4.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"
> +
> +[[package]]
> +name = "swash"
> +version = "0.1.19"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cbd59f3f359ddd2c95af4758c18270eddd9c730dde98598023cdabff472c2ca2"
> +dependencies = [
> + "skrifa",
> + "yazi",
> + "zeno",
> +]
> +
> +[[package]]
> +name = "syn"
> +version = "1.0.109"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "unicode-ident",
> +]
> +
> +[[package]]
> +name = "syn"
> +version = "2.0.110"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "unicode-ident",
> +]
> +
> +[[package]]
> +name = "sys-locale"
> +version = "0.3.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
> +dependencies = [
> + "libc",
> +]
> +
> +[[package]]
> +name = "tempfile"
> +version = "3.23.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
> +dependencies = [
> + "fastrand 2.3.0",
> + "getrandom 0.3.4",
> + "once_cell",
> + "rustix 1.1.2",
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "termcolor"
> +version = "1.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
> +dependencies = [
> + "winapi-util",
> +]
> +
> +[[package]]
> +name = "thiserror"
> +version = "1.0.69"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
> +dependencies = [
> + "thiserror-impl 1.0.69",
> +]
> +
> +[[package]]
> +name = "thiserror"
> +version = "2.0.17"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
> +dependencies = [
> + "thiserror-impl 2.0.17",
> +]
> +
> +[[package]]
> +name = "thiserror-impl"
> +version = "1.0.69"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "thiserror-impl"
> +version = "2.0.17"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "tiff"
> +version = "0.9.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
> +dependencies = [
> + "flate2",
> + "jpeg-decoder",
> + "weezl",
> +]
> +
> +[[package]]
> +name = "tiny-skia"
> +version = "0.11.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
> +dependencies = [
> + "arrayref",
> + "arrayvec",
> + "bytemuck",
> + "cfg-if",
> + "log",
> + "png",
> + "tiny-skia-path",
> +]
> +
> +[[package]]
> +name = "tiny-skia-path"
> +version = "0.11.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
> +dependencies = [
> + "arrayref",
> + "bytemuck",
> + "strict-num",
> +]
> +
> +[[package]]
> +name = "tiny-xlib"
> +version = "0.2.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e"
> +dependencies = [
> + "as-raw-xcb-connection",
> + "ctor-lite",
> + "libloading 0.8.9",
> + "pkg-config",
> + "tracing",
> +]
> +
> +[[package]]
> +name = "tinyvec"
> +version = "1.10.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
> +dependencies = [
> + "tinyvec_macros",
> +]
> +
> +[[package]]
> +name = "tinyvec_macros"
> +version = "0.1.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
> +
> +[[package]]
> +name = "tokio"
> +version = "1.48.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
> +dependencies = [
> + "bytes",
> + "libc",
> + "mio",
> + "parking_lot 0.12.5",
> + "pin-project-lite",
> + "signal-hook-registry",
> + "socket2 0.6.1",
> + "tokio-macros",
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "tokio-macros"
> +version = "2.6.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "toml_datetime"
> +version = "0.7.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533"
> +dependencies = [
> + "serde_core",
> +]
> +
> +[[package]]
> +name = "toml_edit"
> +version = "0.23.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
> +dependencies = [
> + "indexmap",
> + "toml_datetime",
> + "toml_parser",
> + "winnow",
> +]
> +
> +[[package]]
> +name = "toml_parser"
> +version = "1.0.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
> +dependencies = [
> + "winnow",
> +]
> +
> +[[package]]
> +name = "tracing"
> +version = "0.1.41"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
> +dependencies = [
> + "log",
> + "pin-project-lite",
> + "tracing-attributes",
> + "tracing-core",
> +]
> +
> +[[package]]
> +name = "tracing-attributes"
> +version = "0.1.30"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "tracing-core"
> +version = "0.1.34"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
> +dependencies = [
> + "once_cell",
> +]
> +
> +[[package]]
> +name = "ttf-parser"
> +version = "0.20.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
> +
> +[[package]]
> +name = "ttf-parser"
> +version = "0.21.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8"
> +
> +[[package]]
> +name = "ttf-parser"
> +version = "0.25.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
> +
> +[[package]]
> +name = "typenum"
> +version = "1.19.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
> +
> +[[package]]
> +name = "uds_windows"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
> +dependencies = [
> + "memoffset",
> + "tempfile",
> + "winapi",
> +]
> +
> +[[package]]
> +name = "unicode-bidi"
> +version = "0.3.18"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
> +
> +[[package]]
> +name = "unicode-bidi-mirroring"
> +version = "0.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86"
> +
> +[[package]]
> +name = "unicode-ccc"
> +version = "0.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656"
> +
> +[[package]]
> +name = "unicode-ident"
> +version = "1.0.22"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
> +
> +[[package]]
> +name = "unicode-linebreak"
> +version = "0.1.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
> +
> +[[package]]
> +name = "unicode-properties"
> +version = "0.1.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
> +
> +[[package]]
> +name = "unicode-script"
> +version = "0.5.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f"
> +
> +[[package]]
> +name = "unicode-segmentation"
> +version = "1.12.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
> +
> +[[package]]
> +name = "unicode-width"
> +version = "0.1.14"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
> +
> +[[package]]
> +name = "unicode-width"
> +version = "0.2.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
> +
> +[[package]]
> +name = "unicode-xid"
> +version = "0.2.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
> +
> +[[package]]
> +name = "version_check"
> +version = "0.9.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
> +
> +[[package]]
> +name = "vte"
> +version = "0.15.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd"
> +dependencies = [
> + "arrayvec",
> + "bitflags 2.10.0",
> + "cursor-icon",
> + "log",
> + "memchr",
> + "serde",
> +]
> +
> +[[package]]
> +name = "waker-fn"
> +version = "1.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
> +
> +[[package]]
> +name = "walkdir"
> +version = "2.5.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
> +dependencies = [
> + "same-file",
> + "winapi-util",
> +]
> +
> +[[package]]
> +name = "wasi"
> +version = "0.11.1+wasi-snapshot-preview1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
> +
> +[[package]]
> +name = "wasip2"
> +version = "1.0.1+wasi-0.2.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
> +dependencies = [
> + "wit-bindgen",
> +]
> +
> +[[package]]
> +name = "wasm-bindgen"
> +version = "0.2.105"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
> +dependencies = [
> + "cfg-if",
> + "once_cell",
> + "rustversion",
> + "wasm-bindgen-macro",
> + "wasm-bindgen-shared",
> +]
> +
> +[[package]]
> +name = "wasm-bindgen-futures"
> +version = "0.4.55"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
> +dependencies = [
> + "cfg-if",
> + "js-sys",
> + "once_cell",
> + "wasm-bindgen",
> + "web-sys",
> +]
> +
> +[[package]]
> +name = "wasm-bindgen-macro"
> +version = "0.2.105"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
> +dependencies = [
> + "quote",
> + "wasm-bindgen-macro-support",
> +]
> +
> +[[package]]
> +name = "wasm-bindgen-macro-support"
> +version = "0.2.105"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
> +dependencies = [
> + "bumpalo",
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> + "wasm-bindgen-shared",
> +]
> +
> +[[package]]
> +name = "wasm-bindgen-shared"
> +version = "0.2.105"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
> +dependencies = [
> + "unicode-ident",
> +]
> +
> +[[package]]
> +name = "wasm-timer"
> +version = "0.2.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
> +dependencies = [
> + "futures",
> + "js-sys",
> + "parking_lot 0.11.2",
> + "pin-utils",
> + "wasm-bindgen",
> + "wasm-bindgen-futures",
> + "web-sys",
> +]
> +
> +[[package]]
> +name = "wayland-backend"
> +version = "0.3.11"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
> +dependencies = [
> + "cc",
> + "downcast-rs",
> + "rustix 1.1.2",
> + "scoped-tls",
> + "smallvec",
> + "wayland-sys",
> +]
> +
> +[[package]]
> +name = "wayland-client"
> +version = "0.31.11"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
> +dependencies = [
> + "bitflags 2.10.0",
> + "rustix 1.1.2",
> + "wayland-backend",
> + "wayland-scanner",
> +]
> +
> +[[package]]
> +name = "wayland-csd-frame"
> +version = "0.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
> +dependencies = [
> + "bitflags 2.10.0",
> + "cursor-icon",
> + "wayland-backend",
> +]
> +
> +[[package]]
> +name = "wayland-cursor"
> +version = "0.31.11"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29"
> +dependencies = [
> + "rustix 1.1.2",
> + "wayland-client",
> + "xcursor",
> +]
> +
> +[[package]]
> +name = "wayland-protocols"
> +version = "0.32.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901"
> +dependencies = [
> + "bitflags 2.10.0",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-scanner",
> +]
> +
> +[[package]]
> +name = "wayland-protocols-experimental"
> +version = "20250721.0.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1"
> +dependencies = [
> + "bitflags 2.10.0",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-protocols",
> + "wayland-scanner",
> +]
> +
> +[[package]]
> +name = "wayland-protocols-misc"
> +version = "0.3.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2dfe33d551eb8bffd03ff067a8b44bb963919157841a99957151299a6307d19c"
> +dependencies = [
> + "bitflags 2.10.0",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-protocols",
> + "wayland-scanner",
> +]
> +
> +[[package]]
> +name = "wayland-protocols-plasma"
> +version = "0.3.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a07a14257c077ab3279987c4f8bb987851bf57081b93710381daea94f2c2c032"
> +dependencies = [
> + "bitflags 2.10.0",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-protocols",
> + "wayland-scanner",
> +]
> +
> +[[package]]
> +name = "wayland-protocols-wlr"
> +version = "0.3.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec"
> +dependencies = [
> + "bitflags 2.10.0",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-protocols",
> + "wayland-scanner",
> +]
> +
> +[[package]]
> +name = "wayland-scanner"
> +version = "0.31.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
> +dependencies = [
> + "proc-macro2",
> + "quick-xml",
> + "quote",
> +]
> +
> +[[package]]
> +name = "wayland-sys"
> +version = "0.31.7"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
> +dependencies = [
> + "dlib",
> + "log",
> + "once_cell",
> + "pkg-config",
> +]
> +
> +[[package]]
> +name = "web-sys"
> +version = "0.3.82"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
> +dependencies = [
> + "js-sys",
> + "wasm-bindgen",
> +]
> +
> +[[package]]
> +name = "web-time"
> +version = "1.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
> +dependencies = [
> + "js-sys",
> + "wasm-bindgen",
> +]
> +
> +[[package]]
> +name = "weezl"
> +version = "0.1.12"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
> +
> +[[package]]
> +name = "wgpu"
> +version = "0.19.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cbd7311dbd2abcfebaabf1841a2824ed7c8be443a0f29166e5d3c6a53a762c01"
> +dependencies = [
> + "arrayvec",
> + "cfg-if",
> + "cfg_aliases 0.1.1",
> + "js-sys",
> + "log",
> + "naga",
> + "parking_lot 0.12.5",
> + "profiling",
> + "raw-window-handle",
> + "smallvec",
> + "static_assertions",
> + "wasm-bindgen",
> + "wasm-bindgen-futures",
> + "web-sys",
> + "wgpu-core",
> + "wgpu-hal",
> + "wgpu-types",
> +]
> +
> +[[package]]
> +name = "wgpu-core"
> +version = "0.19.4"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a"
> +dependencies = [
> + "arrayvec",
> + "bit-vec",
> + "bitflags 2.10.0",
> + "cfg_aliases 0.1.1",
> + "codespan-reporting",
> + "indexmap",
> + "log",
> + "naga",
> + "once_cell",
> + "parking_lot 0.12.5",
> + "profiling",
> + "raw-window-handle",
> + "rustc-hash 1.1.0",
> + "smallvec",
> + "thiserror 1.0.69",
> + "web-sys",
> + "wgpu-hal",
> + "wgpu-types",
> +]
> +
> +[[package]]
> +name = "wgpu-hal"
> +version = "0.19.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bfabcfc55fd86611a855816326b2d54c3b2fd7972c27ce414291562650552703"
> +dependencies = [
> + "android_system_properties",
> + "arrayvec",
> + "ash",
> + "bit-set",
> + "bitflags 2.10.0",
> + "block",
> + "cfg_aliases 0.1.1",
> + "core-graphics-types 0.1.3",
> + "d3d12",
> + "glow",
> + "glutin_wgl_sys",
> + "gpu-alloc",
> + "gpu-allocator",
> + "gpu-descriptor",
> + "hassle-rs",
> + "js-sys",
> + "khronos-egl",
> + "libc",
> + "libloading 0.8.9",
> + "log",
> + "metal",
> + "naga",
> + "ndk-sys 0.5.0+25.2.9519653",
> + "objc",
> + "once_cell",
> + "parking_lot 0.12.5",
> + "profiling",
> + "range-alloc",
> + "raw-window-handle",
> + "renderdoc-sys",
> + "rustc-hash 1.1.0",
> + "smallvec",
> + "thiserror 1.0.69",
> + "wasm-bindgen",
> + "web-sys",
> + "wgpu-types",
> + "winapi",
> +]
> +
> +[[package]]
> +name = "wgpu-types"
> +version = "0.19.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805"
> +dependencies = [
> + "bitflags 2.10.0",
> + "js-sys",
> + "web-sys",
> +]
> +
> +[[package]]
> +name = "widestring"
> +version = "1.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
> +
> +[[package]]
> +name = "winapi"
> +version = "0.3.9"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
> +dependencies = [
> + "winapi-i686-pc-windows-gnu",
> + "winapi-x86_64-pc-windows-gnu",
> +]
> +
> +[[package]]
> +name = "winapi-i686-pc-windows-gnu"
> +version = "0.4.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
> +
> +[[package]]
> +name = "winapi-util"
> +version = "0.1.11"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
> +dependencies = [
> + "windows-sys 0.61.2",
> +]
> +
> +[[package]]
> +name = "winapi-x86_64-pc-windows-gnu"
> +version = "0.4.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
> +
> +[[package]]
> +name = "window_clipboard"
> +version = "0.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f6d692d46038c433f9daee7ad8757e002a4248c20b0a3fbc991d99521d3bcb6d"
> +dependencies = [
> + "clipboard-win",
> + "clipboard_macos",
> + "clipboard_wayland",
> + "clipboard_x11",
> + "raw-window-handle",
> + "thiserror 1.0.69",
> +]
> +
> +[[package]]
> +name = "windows"
> +version = "0.52.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
> +dependencies = [
> + "windows-core 0.52.0",
> + "windows-targets 0.52.6",
> +]
> +
> +[[package]]
> +name = "windows-core"
> +version = "0.52.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
> +dependencies = [
> + "windows-targets 0.52.6",
> +]
> +
> +[[package]]
> +name = "windows-core"
> +version = "0.62.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
> +dependencies = [
> + "windows-implement",
> + "windows-interface",
> + "windows-link",
> + "windows-result",
> + "windows-strings",
> +]
> +
> +[[package]]
> +name = "windows-implement"
> +version = "0.60.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "windows-interface"
> +version = "0.59.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "windows-link"
> +version = "0.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
> +
> +[[package]]
> +name = "windows-result"
> +version = "0.4.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
> +dependencies = [
> + "windows-link",
> +]
> +
> +[[package]]
> +name = "windows-strings"
> +version = "0.5.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
> +dependencies = [
> + "windows-link",
> +]
> +
> +[[package]]
> +name = "windows-sys"
> +version = "0.45.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
> +dependencies = [
> + "windows-targets 0.42.2",
> +]
> +
> +[[package]]
> +name = "windows-sys"
> +version = "0.48.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
> +dependencies = [
> + "windows-targets 0.48.5",
> +]
> +
> +[[package]]
> +name = "windows-sys"
> +version = "0.52.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
> +dependencies = [
> + "windows-targets 0.52.6",
> +]
> +
> +[[package]]
> +name = "windows-sys"
> +version = "0.59.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
> +dependencies = [
> + "windows-targets 0.52.6",
> +]
> +
> +[[package]]
> +name = "windows-sys"
> +version = "0.60.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
> +dependencies = [
> + "windows-targets 0.53.5",
> +]
> +
> +[[package]]
> +name = "windows-sys"
> +version = "0.61.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
> +dependencies = [
> + "windows-link",
> +]
> +
> +[[package]]
> +name = "windows-targets"
> +version = "0.42.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
> +dependencies = [
> + "windows_aarch64_gnullvm 0.42.2",
> + "windows_aarch64_msvc 0.42.2",
> + "windows_i686_gnu 0.42.2",
> + "windows_i686_msvc 0.42.2",
> + "windows_x86_64_gnu 0.42.2",
> + "windows_x86_64_gnullvm 0.42.2",
> + "windows_x86_64_msvc 0.42.2",
> +]
> +
> +[[package]]
> +name = "windows-targets"
> +version = "0.48.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
> +dependencies = [
> + "windows_aarch64_gnullvm 0.48.5",
> + "windows_aarch64_msvc 0.48.5",
> + "windows_i686_gnu 0.48.5",
> + "windows_i686_msvc 0.48.5",
> + "windows_x86_64_gnu 0.48.5",
> + "windows_x86_64_gnullvm 0.48.5",
> + "windows_x86_64_msvc 0.48.5",
> +]
> +
> +[[package]]
> +name = "windows-targets"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
> +dependencies = [
> + "windows_aarch64_gnullvm 0.52.6",
> + "windows_aarch64_msvc 0.52.6",
> + "windows_i686_gnu 0.52.6",
> + "windows_i686_gnullvm 0.52.6",
> + "windows_i686_msvc 0.52.6",
> + "windows_x86_64_gnu 0.52.6",
> + "windows_x86_64_gnullvm 0.52.6",
> + "windows_x86_64_msvc 0.52.6",
> +]
> +
> +[[package]]
> +name = "windows-targets"
> +version = "0.53.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
> +dependencies = [
> + "windows-link",
> + "windows_aarch64_gnullvm 0.53.1",
> + "windows_aarch64_msvc 0.53.1",
> + "windows_i686_gnu 0.53.1",
> + "windows_i686_gnullvm 0.53.1",
> + "windows_i686_msvc 0.53.1",
> + "windows_x86_64_gnu 0.53.1",
> + "windows_x86_64_gnullvm 0.53.1",
> + "windows_x86_64_msvc 0.53.1",
> +]
> +
> +[[package]]
> +name = "windows_aarch64_gnullvm"
> +version = "0.42.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
> +
> +[[package]]
> +name = "windows_aarch64_gnullvm"
> +version = "0.48.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
> +
> +[[package]]
> +name = "windows_aarch64_gnullvm"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
> +
> +[[package]]
> +name = "windows_aarch64_gnullvm"
> +version = "0.53.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
> +
> +[[package]]
> +name = "windows_aarch64_msvc"
> +version = "0.42.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
> +
> +[[package]]
> +name = "windows_aarch64_msvc"
> +version = "0.48.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
> +
> +[[package]]
> +name = "windows_aarch64_msvc"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
> +
> +[[package]]
> +name = "windows_aarch64_msvc"
> +version = "0.53.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
> +
> +[[package]]
> +name = "windows_i686_gnu"
> +version = "0.42.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
> +
> +[[package]]
> +name = "windows_i686_gnu"
> +version = "0.48.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
> +
> +[[package]]
> +name = "windows_i686_gnu"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
> +
> +[[package]]
> +name = "windows_i686_gnu"
> +version = "0.53.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
> +
> +[[package]]
> +name = "windows_i686_gnullvm"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
> +
> +[[package]]
> +name = "windows_i686_gnullvm"
> +version = "0.53.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
> +
> +[[package]]
> +name = "windows_i686_msvc"
> +version = "0.42.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
> +
> +[[package]]
> +name = "windows_i686_msvc"
> +version = "0.48.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
> +
> +[[package]]
> +name = "windows_i686_msvc"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
> +
> +[[package]]
> +name = "windows_i686_msvc"
> +version = "0.53.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
> +
> +[[package]]
> +name = "windows_x86_64_gnu"
> +version = "0.42.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
> +
> +[[package]]
> +name = "windows_x86_64_gnu"
> +version = "0.48.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
> +
> +[[package]]
> +name = "windows_x86_64_gnu"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
> +
> +[[package]]
> +name = "windows_x86_64_gnu"
> +version = "0.53.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
> +
> +[[package]]
> +name = "windows_x86_64_gnullvm"
> +version = "0.42.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
> +
> +[[package]]
> +name = "windows_x86_64_gnullvm"
> +version = "0.48.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
> +
> +[[package]]
> +name = "windows_x86_64_gnullvm"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
> +
> +[[package]]
> +name = "windows_x86_64_gnullvm"
> +version = "0.53.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
> +
> +[[package]]
> +name = "windows_x86_64_msvc"
> +version = "0.42.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
> +
> +[[package]]
> +name = "windows_x86_64_msvc"
> +version = "0.48.5"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
> +
> +[[package]]
> +name = "windows_x86_64_msvc"
> +version = "0.52.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
> +
> +[[package]]
> +name = "windows_x86_64_msvc"
> +version = "0.53.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
> +
> +[[package]]
> +name = "winit"
> +version = "0.30.12"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732"
> +dependencies = [
> + "ahash 0.8.12",
> + "android-activity",
> + "atomic-waker",
> + "bitflags 2.10.0",
> + "block2",
> + "bytemuck",
> + "calloop 0.13.0",
> + "cfg_aliases 0.2.1",
> + "concurrent-queue",
> + "core-foundation 0.9.4",
> + "core-graphics 0.23.2",
> + "cursor-icon",
> + "dpi",
> + "js-sys",
> + "libc",
> + "memmap2",
> + "ndk",
> + "objc2",
> + "objc2-app-kit",
> + "objc2-foundation",
> + "objc2-ui-kit",
> + "orbclient",
> + "percent-encoding",
> + "pin-project",
> + "raw-window-handle",
> + "redox_syscall 0.4.1",
> + "rustix 0.38.44",
> + "sctk-adwaita",
> + "smithay-client-toolkit 0.19.2",
> + "smol_str",
> + "tracing",
> + "unicode-segmentation",
> + "wasm-bindgen",
> + "wasm-bindgen-futures",
> + "wayland-backend",
> + "wayland-client",
> + "wayland-protocols",
> + "wayland-protocols-plasma",
> + "web-sys",
> + "web-time",
> + "windows-sys 0.52.0",
> + "x11-dl",
> + "x11rb",
> + "xkbcommon-dl",
> +]
> +
> +[[package]]
> +name = "winnow"
> +version = "0.7.13"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
> +dependencies = [
> + "memchr",
> +]
> +
> +[[package]]
> +name = "winreg"
> +version = "0.10.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
> +dependencies = [
> + "winapi",
> +]
> +
> +[[package]]
> +name = "wit-bindgen"
> +version = "0.46.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
> +
> +[[package]]
> +name = "x11-dl"
> +version = "2.21.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
> +dependencies = [
> + "libc",
> + "once_cell",
> + "pkg-config",
> +]
> +
> +[[package]]
> +name = "x11rb"
> +version = "0.13.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
> +dependencies = [
> + "as-raw-xcb-connection",
> + "gethostname",
> + "libc",
> + "libloading 0.8.9",
> + "once_cell",
> + "rustix 1.1.2",
> + "x11rb-protocol",
> +]
> +
> +[[package]]
> +name = "x11rb-protocol"
> +version = "0.13.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
> +
> +[[package]]
> +name = "xcursor"
> +version = "0.3.10"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b"
> +
> +[[package]]
> +name = "xdg-home"
> +version = "1.3.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6"
> +dependencies = [
> + "libc",
> + "windows-sys 0.59.0",
> +]
> +
> +[[package]]
> +name = "xkbcommon-dl"
> +version = "0.4.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5"
> +dependencies = [
> + "bitflags 2.10.0",
> + "dlib",
> + "log",
> + "once_cell",
> + "xkeysym",
> +]
> +
> +[[package]]
> +name = "xkeysym"
> +version = "0.2.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
> +
> +[[package]]
> +name = "xml-rs"
> +version = "0.8.28"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
> +
> +[[package]]
> +name = "yansi"
> +version = "1.0.1"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
> +
> +[[package]]
> +name = "yazi"
> +version = "0.1.6"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
> +
> +[[package]]
> +name = "zbus"
> +version = "4.4.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725"
> +dependencies = [
> + "async-broadcast",
> + "async-executor",
> + "async-fs 2.2.0",
> + "async-io 2.6.0",
> + "async-lock 3.4.1",
> + "async-process 2.5.0",
> + "async-recursion",
> + "async-task",
> + "async-trait",
> + "blocking",
> + "enumflags2",
> + "event-listener 5.4.1",
> + "futures-core",
> + "futures-sink",
> + "futures-util",
> + "hex",
> + "nix",
> + "ordered-stream",
> + "rand",
> + "serde",
> + "serde_repr",
> + "sha1",
> + "static_assertions",
> + "tracing",
> + "uds_windows",
> + "windows-sys 0.52.0",
> + "xdg-home",
> + "zbus_macros",
> + "zbus_names",
> + "zvariant",
> +]
> +
> +[[package]]
> +name = "zbus_macros"
> +version = "4.4.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e"
> +dependencies = [
> + "proc-macro-crate",
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> + "zvariant_utils",
> +]
> +
> +[[package]]
> +name = "zbus_names"
> +version = "3.0.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
> +dependencies = [
> + "serde",
> + "static_assertions",
> + "zvariant",
> +]
> +
> +[[package]]
> +name = "zeno"
> +version = "0.2.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
> +
> +[[package]]
> +name = "zerocopy"
> +version = "0.8.28"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90"
> +dependencies = [
> + "zerocopy-derive",
> +]
> +
> +[[package]]
> +name = "zerocopy-derive"
> +version = "0.8.28"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> +
> +[[package]]
> +name = "zune-inflate"
> +version = "0.2.54"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
> +dependencies = [
> + "simd-adler32",
> +]
> +
> +[[package]]
> +name = "zvariant"
> +version = "4.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe"
> +dependencies = [
> + "endi",
> + "enumflags2",
> + "serde",
> + "static_assertions",
> + "zvariant_derive",
> +]
> +
> +[[package]]
> +name = "zvariant_derive"
> +version = "4.2.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449"
> +dependencies = [
> + "proc-macro-crate",
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> + "zvariant_utils",
> +]
> +
> +[[package]]
> +name = "zvariant_utils"
> +version = "2.1.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
> +dependencies = [
> + "proc-macro2",
> + "quote",
> + "syn 2.0.110",
> +]
> diff --git a/tools/spectrum-installer/Cargo.lock.license b/tools/spectrum-installer/Cargo.lock.license
> new file mode 100644
> index 0000000..bfe02ea
> --- /dev/null
> +++ b/tools/spectrum-installer/Cargo.lock.license
> @@ -0,0 +1,2 @@
> +SPDX-License-Identifier: CC0-1.0
> +SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> diff --git a/tools/spectrum-installer/Cargo.toml b/tools/spectrum-installer/Cargo.toml
> new file mode 100644
> index 0000000..4be4dcd
> --- /dev/null
> +++ b/tools/spectrum-installer/Cargo.toml
> @@ -0,0 +1,14 @@
> +# SPDX-License-Identifier: CC0-1.0
> +# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +[package]
> +name = "spectrum-installer"
> +version = "0.1.0"
> +edition = "2024"
> +
> +[dependencies]
> +iced = { version = "0.13", features = ["image"] }
> +iced_aw = { version = "0.12", features = ["spinner"] }
> +iced_fonts = { version = "0.2", features = ["bootstrap"] }
> +iced_term = { version = "0.6" }
> +lsblk = { version = "0.6" }
> diff --git a/tools/spectrum-installer/default.nix b/tools/spectrum-installer/default.nix
> new file mode 100644
> index 0000000..3ab028b
> --- /dev/null
> +++ b/tools/spectrum-installer/default.nix
> @@ -0,0 +1,41 @@
> +# SPDX-FileCopyrightText: 2024 Alyssa Ross <hi@alyssa.is>
> +# SPDX-FileCopyrightText: 2025-2026 Johannes Süllner <johannes.suellner@mailbox.org>
> +# SPDX-License-Identifier: MIT
> +
> +import ../../lib/call-package.nix (
> +args@{ callPackage, config, src, lib, rustPlatform, libcosmicAppHook }:
> +
> +rustPlatform.buildRustPackage rec {
> + name = "spectrum-installer";
> +
> + src = lib.fileset.toSource {
> + root = ../..;
> + fileset = lib.fileset.intersection args.src ./.;
> + };
> + sourceRoot = "source/tools/spectrum-installer";
> +
> + cargoLock.lockFile = ./Cargo.lock;
> +
> + nativeBuildInputs = [ libcosmicAppHook ];
> +
> + icons = callPackage (
> + { runCommand, inkscape }:
> + runCommand "spectrum_installer_icons" {
> + nativeBuildInputs = [ inkscape ];
> + logoSvg = ./res/installer_logo_mesh.svg;
> + } ''
> + mkdir $out
> + inkscape -w 22 -h 22 -o $out/22x22.png "$logoSvg"
> + inkscape -w 400 -h 400 -o $out/400x400.png "$logoSvg"
> + ''
> + ) {};
> +
> + postInstall = ''
> + mkdir -p "$out/share/spectrum-installer/repart.d"
> + for f in $(ls "./res/repart.d"); do
> + substitute "./res/repart.d/$f" "$out/share/spectrum-installer/repart.d/$f" --subst-var-by "version" "${config.version}"
> + done
> + install -D "${icons}/22x22.png" "$out/share/icons/hicolor/22x22/apps/${name}.png"
> + install -D "${icons}/400x400.png" "$out/share/icons/hicolor/400x400/apps/${name}.png"
> + '';
> +}) (_: {})
> diff --git a/tools/spectrum-installer/res/installer_logo_mesh.svg b/tools/spectrum-installer/res/installer_logo_mesh.svg
> new file mode 100644
> index 0000000..1e25829
> --- /dev/null
> +++ b/tools/spectrum-installer/res/installer_logo_mesh.svg
> @@ -0,0 +1,85 @@
> +<!-- SPDX-FileCopyrightText: 2020 hazelnot -->
> +<!-- SPDX-FileCopyrightText: 2020 Alyssa Ross <hi@alyssa.is> -->
> +<!-- SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org> -->
> +<!-- SPDX-License-Identifier: CC0-1.0 -->
> +<!-- Spectrum logo design by hazelnot, implementation by Alyssa Ross, installer icon by Johannes Süllner -->
> +
> +<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100">
> + <defs>
> + <filter id="ring-shadow" x="-10" y="-10" width="120" height="120" color-interpolation-filters="sRGB">
> + <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="blur" />
> + <feComposite in="SourceGraphic" in2="offset" operator="over" />
> + </filter>
> +
> + <filter id="center-shadow" x="-10" y="-10" width="120" height="120" color-interpolation-filters="sRGB">
> + <feFlood flood-opacity="1" flood-color="#DDD" result="flood" />
> + <feComposite in="flood" in2="SourceGraphic" operator="in" result="composite1" />
> + <feGaussianBlur in="composite1" stdDeviation="6" result="blur" />
> + <feComposite in="SourceGraphic" in2="blur" operator="over" result="composite2" />
> + </filter>
> +
> + <meshgradient id="ring-gradient" x="1.5" y="0.5">
> + <meshrow>
> + <meshpatch>
> + <stop path="L 1 -0.36603" stop-color="red" />
> + <stop path="L 0.5 0.5" stop-color="yellow" />
> + <stop path="L 0.5 0.5" stop-color="yellow" />
> + <stop path="L 1 0.5" stop-color="red" />
> + </meshpatch>
> + <meshpatch>
> + <stop path="L 0 -0.36603" />
> + <stop path="L 0.5 0.5" stop-color="lime" />
> + <stop path="L 0.5 0.5" stop-color="lime" />
> + </meshpatch>
> + <meshpatch>
> + <stop path="L -0.5 0.5" />
> + <stop path="L 0.5 0.5" stop-color="cyan" />
> + <stop path="L 0.5 0.5" stop-color="cyan" />
> + </meshpatch>
> + <meshpatch>
> + <stop path="L 0 1.36603" />
> + <stop path="L 0.5 0.5" stop-color="blue" />
> + <stop path="L 0.5 0.5" stop-color="blue" />
> + </meshpatch>
> + <meshpatch>
> + <stop path="L 1 1.36603" />
> + <stop path="L 0.5 0.5" stop-color="magenta" />
> + <stop path="L 0.5 0.5" stop-color="magenta" />
> + </meshpatch>
> + <meshpatch>
> + <stop path="L 1.5 0.5" />
> + <stop path="L 0.5 0.5" stop-color="red" />
> + <stop path="L 0.5 0.5" stop-color="red" />
> + </meshpatch>
> + </meshrow>
> + </meshgradient>
> +
> + <marker
> + style="overflow:visible"
> + id="ArrowWideRounded"
> + refX="0"
> + refY="0"
> + orient="auto-start-reverse"
> + markerWidth="1"
> + markerHeight="1"
> + viewBox="0 0 1 1"
> + preserveAspectRatio="xMidYMid"
> + markerUnits="strokeWidth">
> + <path
> + style="fill:none;stroke:context-stroke;stroke-width:1;stroke-linecap:round"
> + d="M 3,-3 0,0 3,3"
> + transform="rotate(180,0.125,0)" />
> + </marker>
> + </defs>
> +
> + <circle cx="50" cy="50" r="36" fill="none" stroke="url(#ring-gradient)" stroke-width="5" filter="url(#ring-shadow)" />
> +
> + <circle cx="50" cy="50" r="27" fill="white" filter="url(#center-shadow)" />
> +
> + <path
> + style="fill:none;stroke:#000000;stroke-width:4.5;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#ArrowWideRounded)"
> + d="M 50,29.5 V 54" />
> + <path
> + style="fill:none;stroke:#000000;stroke-width:4.5;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
> + d="M 65.419353,63.617021 H 34.580646" />
> +</svg>
> diff --git a/tools/spectrum-installer/res/repart.d/10-esp.conf b/tools/spectrum-installer/res/repart.d/10-esp.conf
> new file mode 100644
> index 0000000..1f3c5fc
> --- /dev/null
> +++ b/tools/spectrum-installer/res/repart.d/10-esp.conf
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: CC0-1.0
> +# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +[Partition]
> +Type=esp
> +SizeMinBytes=500M
> +SizeMaxBytes=500M
> +CopyBlocks=/dev/disk/by-designator/esp
> diff --git a/tools/spectrum-installer/res/repart.d/20-verity-A.conf b/tools/spectrum-installer/res/repart.d/20-verity-A.conf
> new file mode 100644
> index 0000000..6e688e3
> --- /dev/null
> +++ b/tools/spectrum-installer/res/repart.d/20-verity-A.conf
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: CC0-1.0
> +# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +[Partition]
> +Type=root-verity
> +Label=Spectrum_@version@.verity
> +SizeMinBytes=162M
> +SizeMaxBytes=162M
> +CopyBlocks=auto
> diff --git a/tools/spectrum-installer/res/repart.d/21-rootfs-A.conf b/tools/spectrum-installer/res/repart.d/21-rootfs-A.conf
> new file mode 100644
> index 0000000..9d5ea6b
> --- /dev/null
> +++ b/tools/spectrum-installer/res/repart.d/21-rootfs-A.conf
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: CC0-1.0
> +# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +[Partition]
> +Type=root
> +Label=Spectrum_@version@
> +SizeMinBytes=20G
> +SizeMaxBytes=20G
> +CopyBlocks=auto
> diff --git a/tools/spectrum-installer/res/repart.d/30-verity-B.conf b/tools/spectrum-installer/res/repart.d/30-verity-B.conf
> new file mode 100644
> index 0000000..3721ff0
> --- /dev/null
> +++ b/tools/spectrum-installer/res/repart.d/30-verity-B.conf
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: CC0-1.0
> +# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +[Partition]
> +Type=root-verity
> +Label=_empty
> +SizeMinBytes=162M
> +SizeMaxBytes=162M
> diff --git a/tools/spectrum-installer/res/repart.d/31-rootfs-B.conf b/tools/spectrum-installer/res/repart.d/31-rootfs-B.conf
> new file mode 100644
> index 0000000..84e9f57
> --- /dev/null
> +++ b/tools/spectrum-installer/res/repart.d/31-rootfs-B.conf
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: CC0-1.0
> +# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +[Partition]
> +Type=root
> +Label=_empty
> +SizeMinBytes=20G
> +SizeMaxBytes=20G
> diff --git a/tools/spectrum-installer/res/repart.d/40-home.conf b/tools/spectrum-installer/res/repart.d/40-home.conf
> new file mode 100644
> index 0000000..c487d34
> --- /dev/null
> +++ b/tools/spectrum-installer/res/repart.d/40-home.conf
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: CC0-1.0
> +# SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +[Partition]
> +Type=home
> +SizeMinBytes=500M
> +Format=btrfs
> diff --git a/tools/spectrum-installer/shell.nix b/tools/spectrum-installer/shell.nix
> new file mode 100644
> index 0000000..060009b
> --- /dev/null
> +++ b/tools/spectrum-installer/shell.nix
> @@ -0,0 +1,30 @@
> +# SPDX-License-Identifier: MIT
> +# SPDX-FileCopyrightText: 2025 iced contributors
> +
> +# from https://github.com/iced-rs/iced/blob/master/DEPENDENCIES.md
> +# last updated 2025-11-11
> +
> +{ pkgs ? import <nixpkgs> {} }:
> +
> +pkgs.mkShell rec {
> + buildInputs = with pkgs; [
> + cargo
> + lldb
> + expat
> + fontconfig
> + freetype
> + freetype.dev
> + libGL
> + pkg-config
> + rustfmt
> + xorg.libX11
> + xorg.libXcursor
> + xorg.libXi
> + xorg.libXrandr
> + wayland
> + libxkbcommon
> + ];
Is it possible to drop the X11 libraries? The installer should be
Wayland-only. If upstream Iced can't be built without X11 support,
feel free to ignore this.
> + LD_LIBRARY_PATH =
> + builtins.foldl' (a: b: "${a}:${b}/lib") "${pkgs.vulkan-loader}/lib" buildInputs;
> +}
> diff --git a/tools/spectrum-installer/src/main.rs b/tools/spectrum-installer/src/main.rs
> new file mode 100644
> index 0000000..2ca9dfa
> --- /dev/null
> +++ b/tools/spectrum-installer/src/main.rs
> @@ -0,0 +1,52 @@
> +// SPDX-License-Identifier: EUPL-1.2+
> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +mod pages;
> +
> +use iced::Element;
> +use iced::Size;
> +use iced::Subscription;
> +use iced::Task;
> +use pages::Event;
> +
> +fn main() -> iced::Result {
> + iced::application(
> + "Spectrum installer",
> + SpectrumInstaller::update,
> + SpectrumInstaller::view,
> + )
> + .window_size(Size::new(pages::WINDOW_WIDTH, pages::WINDOW_HEIGHT))
> + .font(iced_fonts::BOOTSTRAP_FONT_BYTES)
> + .resizable(false)
> + .subscription(SpectrumInstaller::subscription)
> + .run()
> +}
Have you tested with HiDPI displays? I think it would be better for
the installer to be fullscreen, or at least have a size proportional
to the display it is on.
I suspect that hard-coded sizes are an antipattern, though I don't know
what the best alternative would be. Ideally there would be an option
to zoom in and out, so that those who need larger buttons and text can
get that. Is there a way to ask Iced to size things automatically?
> +struct SpectrumInstaller {
> + current_page: Box<dyn pages::Page>,
> +}
> +impl Default for SpectrumInstaller {
> + fn default() -> Self {
> + Self {
> + current_page: Box::new(pages::INITAL_PAGE),
> + }
> + }
> +}
> +
> +impl SpectrumInstaller {
> + fn update(&mut self, event: pages::Event) -> Task<Event> {
> + let (maybe_new_page, task) = self.current_page.update(event);
> + if let Some(new_page) = maybe_new_page {
> + self.current_page = new_page;
> + }
> + task
> + }
> +
> + fn view(&self) -> Element<'_, pages::Event> {
> + self.current_page.view()
> + }
> +
> + fn subscription(&self) -> Subscription<pages::Event> {
> + self.current_page.subscription()
> + }
> +}
> diff --git a/tools/spectrum-installer/src/pages/completion.rs b/tools/spectrum-installer/src/pages/completion.rs
> new file mode 100644
> index 0000000..2ea9734
> --- /dev/null
> +++ b/tools/spectrum-installer/src/pages/completion.rs
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: EUPL-1.2+
> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +use super::{
> + BUTTON_TEXT_SIZE, Event, MARGIN_LR, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult,
> + WINDOW_WIDTH,
> +};
> +use crate::{center_horizontal_in_container, center_in_container};
> +use iced::{
> + Element, Task,
> + widget::{
> + Scrollable, Space, column,
> + scrollable::{Direction, Scrollbar},
> + text,
> + },
> + window,
> +};
> +use std::process::Command;
> +
> +const S6_HPR_PATH: &str = "/bin/s6-linux-init-hpr";
> +
> +pub struct PageCompletion {
> + install_result: super::InstallResult,
> +}
> +
> +impl PageCompletion {
> + pub fn new(install_result: super::InstallResult) -> Self {
> + Self { install_result }
> + }
> +}
> +
> +#[derive(Clone, Debug)]
> +pub enum PageCompletionEvent {
> + Quit,
> + Poweroff,
> + Reboot,
> +}
> +
> +impl PageCompletion {
> + fn close(id: window::Id) -> Task<Event> {
> + window::close(id)
> + }
> +
> + fn spawn_s6_hpr(parameter: &str) {
> + let _ = Command::new(S6_HPR_PATH).arg(parameter).spawn();
> + }
> +}
> +
> +impl Page for PageCompletion {
> + fn update(&mut self, event: Event) -> UpdateResult {
> + if let Event::PageCompletion(page_completion_event) = event {
> + match page_completion_event {
> + PageCompletionEvent::Quit => {
> + return (None, window::get_latest().and_then(Self::close));
> + }
> + PageCompletionEvent::Poweroff => {
> + Self::spawn_s6_hpr("-p");
> + }
> + PageCompletionEvent::Reboot => {
> + Self::spawn_s6_hpr("-r");
> + }
> + }
> + };
> +
> + (None, Task::none())
> + }
> +
> + fn view(&self) -> Element<'_, Event> {
> + let main_element = match &self.install_result {
> + Ok(_) => {
> + center_in_container!(text("Spectrum installation succeeded!").size(TITLE_TEXT_SIZE)).into()
> + }
> + Err((code, log)) => {
> + column![
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(text("Spectrum installation failed :( ").size(TITLE_TEXT_SIZE)),
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(Scrollable::new(text(format!("You can reach out to the team via Chat or the \"discuss\" mailing list.\n\
> + See https://spectrum-os.org/doc/contributing/communication.html for details.\n\
> + The following information may be relevant:\n\n\
> + Error code: {}\n\nError log:\n{}", code, log)))
> + .width(WINDOW_WIDTH - 2.0 * MARGIN_LR)
> + .height(500)
> + .direction(Direction::Vertical(Scrollbar::new()))),
> + ]
> + .into()
> + }
> + };
I see no harm in including the full email address of the discuss
mailing list (discuss@spectrum-os.org). Also, it would be useful to
display a QR code that someone can scan using their mobile device.
This avoids having to do clumsy and error-prone manual transcription,
and may allow for including more lines of output.
> + super::layout::bottom_buttons_layout(
> + [
> + vec![
> + (
> + text("Reboot").size(BUTTON_TEXT_SIZE).into(),
> + Some(Event::PageCompletion(PageCompletionEvent::Reboot)),
> + ),
> + (
> + text("Poweroff").size(BUTTON_TEXT_SIZE).into(),
> + Some(Event::PageCompletion(PageCompletionEvent::Poweroff)),
> + ),
> + ],
> + vec![(
> + text("Quit installer, stay in live environment")
> + .size(BUTTON_TEXT_SIZE)
> + .into(),
> + Some(Event::PageCompletion(PageCompletionEvent::Quit)),
> + )],
> + ],
> + main_element,
> + )
> + }
> +}
> diff --git a/tools/spectrum-installer/src/pages/confirmation.rs b/tools/spectrum-installer/src/pages/confirmation.rs
> new file mode 100644
> index 0000000..25084b6
> --- /dev/null
> +++ b/tools/spectrum-installer/src/pages/confirmation.rs
> @@ -0,0 +1,108 @@
> +// SPDX-License-Identifier: EUPL-1.2+
> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +use super::{
> + BUTTON_TEXT_SIZE, Event, MARGIN_LR, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult,
> + WINDOW_WIDTH,
> +};
> +use crate::center_horizontal_in_container;
> +use iced::{
> + Length, Task,
> + widget::{Space, checkbox, column, container, text},
> +};
> +use lsblk::BlockDevice;
> +
> +pub struct PageConfirmation {
> + device: BlockDevice,
> + install_confirmed: bool,
> +}
> +
> +impl PageConfirmation {
> + pub fn new(device: BlockDevice) -> Self {
> + Self {
> + device,
> + install_confirmed: false,
> + }
> + }
> +}
> +
> +#[derive(Clone, Debug)]
> +pub enum PageConfirmationEvent {
> + Back,
> + ConfirmCheckboxToggled(bool),
> + StartInstallation,
> +}
> +
> +impl Page for PageConfirmation {
> + fn update(&mut self, event: Event) -> UpdateResult {
> + if let Event::PageConfirmation(page_event) = event {
> + match page_event {
> + PageConfirmationEvent::Back => {
> + return (
> + Some(Box::new(super::disk_selection::PageDiskSelection::new())),
> + Task::none(),
> + );
> + }
> + PageConfirmationEvent::ConfirmCheckboxToggled(bool) => {
> + self.install_confirmed = bool;
> + }
> + PageConfirmationEvent::StartInstallation => {
> + return (
> + Some(Box::new(super::installation::PageInstallation::new(
> + self.device.clone(),
> + ))),
> + Task::none(),
> + );
> + }
> + }
> + }
> + (None, Task::none())
> + }
> +
> + fn view(&self) -> iced::Element<'_, Event> {
> + let main_content = column![
> + Space::with_height(Length::Fill),
> + center_horizontal_in_container!(text("Confirm Installation").size(TITLE_TEXT_SIZE)),
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(text(
> + "Erease all data on the following device and install Spectrum?"
> + )),
Typo: Erease ⇒ Erase
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(
> + container(super::layout::disk_element(&self.device))
> + .width(WINDOW_WIDTH - 2.0 * MARGIN_LR)
> + ),
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(
> + checkbox(
> + format!("I understand all data on {} will be lost", self.device.name),
> + self.install_confirmed
> + )
> + .on_toggle(|bool| Event::PageConfirmation(
> + PageConfirmationEvent::ConfirmCheckboxToggled(bool)
> + ))
> + ),
> + Space::with_height(Length::Fill),
> + ];
> +
> + super::layout::bottom_buttons_layout(
> + [[
> + (
> + text("Back").size(BUTTON_TEXT_SIZE).into(),
> + Some(Event::PageConfirmation(PageConfirmationEvent::Back)),
> + ),
> + (
> + text("Start installation").size(BUTTON_TEXT_SIZE).into(),
> + if self.install_confirmed {
> + Some(Event::PageConfirmation(
> + PageConfirmationEvent::StartInstallation,
> + ))
> + } else {
> + None
> + },
> + ),
> + ]],
> + main_content.into(),
> + )
> + }
> +}
> diff --git a/tools/spectrum-installer/src/pages/disk_selection.rs b/tools/spectrum-installer/src/pages/disk_selection.rs
> new file mode 100644
> index 0000000..0d28022
> --- /dev/null
> +++ b/tools/spectrum-installer/src/pages/disk_selection.rs
> @@ -0,0 +1,134 @@
> +// SPDX-License-Identifier: EUPL-1.2+
> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +use super::{
> + BUTTON_TEXT_SIZE, Event, MARGIN_LR, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult,
> + WINDOW_WIDTH,
> +};
> +use crate::center_horizontal_in_container;
> +use iced::{
> + Length, Task,
> + widget::{
> + Scrollable, Space, button, column,
> + scrollable::{Direction, Scrollbar},
> + text,
> + },
> +};
> +use lsblk::BlockDevice;
> +
> +pub struct PageDiskSelection {
> + destination_device: Option<BlockDevice>,
> +}
> +
> +impl PageDiskSelection {
> + pub fn new() -> Self {
> + Self {
> + destination_device: None,
> + }
> + }
> +}
> +
> +#[derive(Clone, Debug)]
> +pub enum PageDiskSelectionEvent {
> + Back,
> + SelectDevice(BlockDevice),
> + ContinueWithDevice(BlockDevice),
> +}
> +
> +impl Page for PageDiskSelection {
> + fn update(&mut self, event: Event) -> UpdateResult {
> + if let Event::PageDiskSelection(page_disk_selection_event) = event {
> + match page_disk_selection_event {
> + PageDiskSelectionEvent::Back => {
> + return (
> + Some(Box::new(super::welcome::PageWelcome::new())),
> + Task::none(),
> + );
> + }
> + PageDiskSelectionEvent::SelectDevice(device) => {
> + self.destination_device = Some(device);
> + }
> + PageDiskSelectionEvent::ContinueWithDevice(device) => {
> + return (
> + Some(Box::new(super::confirmation::PageConfirmation::new(device))),
> + Task::none(),
> + );
> + }
> + }
> + }
> + (None, Task::none())
> + }
> +
> + fn view(&self) -> iced::Element<'_, Event> {
> + let mut block_devices = BlockDevice::list().expect("Failed to get block devices");
> + block_devices.sort_by_key(|device| device.name.clone());
> +
> + let mut possible_block_devices = block_devices
> + .iter()
> + .filter(|device| {
> + BlockDevice::is_disk(device)
> + && !&device.name.starts_with("loop")
> + && !&device.name.starts_with("sr")
> + })
> + .peekable();
> +
> + let destinations: iced::Element<Event> = if possible_block_devices.peek().is_none() {
> + text("No applicable devices to install Spectrum to found.").into()
> + } else {
> + column(possible_block_devices.map(|device| {
> + button(super::layout::disk_element(&device))
> + .on_press(Event::PageDiskSelection(
> + PageDiskSelectionEvent::SelectDevice(device.clone()),
> + ))
> + .width(WINDOW_WIDTH - 2.0 * MARGIN_LR)
> + .style({
> + if self
> + .destination_device
> + .as_ref()
> + .is_some_and(|d| d.fullname == device.fullname)
> + {
> + button::success
> + } else {
> + button::primary
> + }
> + })
> + .into()
> + }))
> + .spacing(8)
> + .into()
> + };
> +
> + let main_content = column![
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(
> + text("Select the device to install Spectrum to").size(TITLE_TEXT_SIZE)
> + ),
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(
> + Scrollable::new(destinations)
> + .height(Length::Fill)
> + .direction(Direction::Vertical(Scrollbar::new()))
> + ),
> + Space::with_height(MARGIN_VERTICAL),
> + ];
> +
> + super::layout::bottom_buttons_layout(
> + [[
> + (
> + text("Back").size(BUTTON_TEXT_SIZE).into(),
> + Some(Event::PageDiskSelection(PageDiskSelectionEvent::Back)),
> + ),
> + (
> + text("Next").size(BUTTON_TEXT_SIZE).into(),
> + match &self.destination_device {
> + None => None,
> + Some(device) => Some(Event::PageDiskSelection(
> + PageDiskSelectionEvent::ContinueWithDevice(device.clone()),
> + )),
> + },
> + ),
> + ]],
> + main_content.into(),
> + )
> + }
> +}
> diff --git a/tools/spectrum-installer/src/pages/installation.rs b/tools/spectrum-installer/src/pages/installation.rs
> new file mode 100644
> index 0000000..16da197
> --- /dev/null
> +++ b/tools/spectrum-installer/src/pages/installation.rs
> @@ -0,0 +1,182 @@
> +// SPDX-License-Identifier: EUPL-1.2+
> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +use super::{
> + BUTTON_TEXT_SIZE, Event, InstallResult, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult,
> +};
> +use crate::center_horizontal_in_container;
> +use iced::{
> + Length, Subscription, Task,
> + widget::{Space, column, container, row, text},
> +};
> +use iced_aw::Spinner;
> +use iced_term::Terminal;
> +use lsblk::BlockDevice;
> +use std::fs;
> +
> +const RESULT_CODE_FILE: &str = "/tmp/spectrum-installer_result-code";
> +const LOG_FILE: &str = "/tmp/spectrum-installer_log";
> +
> +pub struct PageInstallation {
> + terminal: Option<Terminal>,
> + installation_completed: bool,
> + installation_result: Option<InstallResult>,
> +}
> +
> +impl PageInstallation {
> + pub fn new(device: BlockDevice) -> Self {
> + let term = Terminal::new(
> + 0,
> + iced_term::settings::Settings {
> + backend: iced_term::settings::BackendSettings {
> + program: String::from("/usr/bin/sh"),
> + args: Vec::from([
> + String::from("-c"),
> + // Install enforcing a new partition table.
> + // HACK: Logging to /tmp as iced_term does not offer any other way of obtaining the commands result.
Nits:
- Comment line too long I think.
- Missing apostrophe: either "commands' results" or "command's result".
> + String::from(
> + [
> + "( /usr/bin/systemd-repart \
> + --definitions=/usr/share/spectrum-installer/repart.d \
> + --empty=force \
> + --dry-run=no ",
> + &device.fullname.display().to_string(),
Missing shell argument escaping and '-o pipefail'. The latter might
require bash instead of sh.
> + "; echo $? > ",
> + RESULT_CODE_FILE,
> + ") 2>&1 | tee ",
> + LOG_FILE,
> + ]
> + .concat(),
> + ),
> + ]),
> + },
> + ..Default::default()
> + },
> + );
> +
> + match term {
> + Ok(term) => Self {
> + terminal: Some(term),
> + installation_completed: false,
> + installation_result: None,
> + },
> + Err(e) => Self {
> + terminal: None,
> + installation_completed: true,
> + installation_result: Some(Err((0, e.to_string()))),
> + },
> + }
> + }
> +}
> +
> +#[derive(Clone, Debug)]
> +pub enum PageInstallationEvent {
> + Terminal(iced_term::Event),
> + Finish,
> +}
> +
> +impl Page for PageInstallation {
> + fn update(&mut self, event: Event) -> UpdateResult {
> + if let Event::PageInstallation(page_event) = event {
> + match page_event {
> + PageInstallationEvent::Finish => {
> + if let Some(installation_result) = self.installation_result.clone() {
> + return (
> + Some(Box::new(super::completion::PageCompletion::new(
> + installation_result,
> + ))),
> + Task::none(),
> + );
> + }
> + }
> + PageInstallationEvent::Terminal(iced_term::Event::BackendCall(_, cmd)) => {
> + if let Some(term) = &mut self.terminal {
> + match term.handle(iced_term::Command::ProxyToBackend(cmd)) {
> + iced_term::actions::Action::Shutdown => {
> + let code = fs::read_to_string(RESULT_CODE_FILE);
> + let log = fs::read_to_string(LOG_FILE);
> + self.installation_result =
> + if let (Ok(code_as_str), Ok(log)) = (code, log) {
> + if let Ok(code) = code_as_str.trim().parse::<u32>() {
> + self.installation_completed = true;
> + if code == 0 {
> + Some(Ok(log))
> + } else {
> + Some(Err((code, log)))
> + }
> + } else {
> + None
> + }
> + } else {
> + None
> + };
> + }
> + _ => {}
> + }
> + }
> + }
> + }
> + }
> + (None, Task::none())
> + }
> +
> + fn subscription(&self) -> Subscription<Event> {
> + if let Some(term) = &self.terminal {
> + return Subscription::run_with_id(term.id, term.subscription())
> + .map::<_, _>(|t| Event::PageInstallation(PageInstallationEvent::Terminal(t)));
> + }
> +
> + Subscription::none()
> + }
> +
> + fn view(&self) -> iced::Element<'_, Event> {
> + let title_row: iced::Element<Event> = if !self.installation_completed {
> + row![
> + Spinner::new().height(25),
> + Space::with_width(MARGIN_VERTICAL),
> + text("Installing ...").size(TITLE_TEXT_SIZE)
> + ]
> + .into()
> + } else {
> + text(
> + if self.installation_result.as_ref().is_some_and(|r| r.is_ok()) {
> + "Installation completed."
> + } else {
> + "Installation failed."
> + },
> + )
> + .size(TITLE_TEXT_SIZE)
> + .into()
> + };
> +
> + let installation_status: iced::Element<Event> = if let Some(term) = &self.terminal {
> + iced_term::TerminalView::show(term)
> + .map::<_>(|t| Event::PageInstallation(PageInstallationEvent::Terminal(t)))
> + .into()
> + } else {
> + text("Could not start installation.").into()
> + };
> +
> + let main_content = column![
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(title_row),
> + Space::with_height(MARGIN_VERTICAL),
> + container(installation_status)
> + .width(Length::Fill)
> + .center_x(Length::Fill)
> + .height(Length::Fill),
> + ];
> +
> + super::layout::bottom_buttons_layout(
> + [[(
> + text("Finish").size(BUTTON_TEXT_SIZE).into(),
> + if self.installation_completed {
> + Some(Event::PageInstallation(PageInstallationEvent::Finish))
> + } else {
> + None
> + },
> + )]],
> + main_content.into(),
> + )
> + }
> +}
> diff --git a/tools/spectrum-installer/src/pages/layout.rs b/tools/spectrum-installer/src/pages/layout.rs
> new file mode 100644
> index 0000000..e7095bd
> --- /dev/null
> +++ b/tools/spectrum-installer/src/pages/layout.rs
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: EUPL-1.2+
> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +use iced::{
> + Element, Length,
> + widget::{Button, Column, Row, button, column, container, row, text},
> +};
> +use iced_fonts::{BOOTSTRAP_FONT as ICON_FONT, Bootstrap as Icon};
> +use lsblk::BlockDevice;
> +
> +use super::Event;
> +
> +#[macro_export]
> +macro_rules! center_horizontal_in_container {
> + ($e:expr) => {
> + iced::widget::container($e)
> + .width(iced::Length::Fill)
> + .center_x(iced::Length::Fill)
> + };
> +}
> +#[macro_export]
> +macro_rules! center_in_container {
> + ($e:expr) => {
> + iced::widget::container($e)
> + .height(iced::Length::Fill)
> + .width(iced::Length::Fill)
> + .center_x(iced::Length::Fill)
> + .center_y(iced::Length::Fill)
> + };
> +}
> +
> +const BOTTOM_BUTTON_SPACE: f32 = 2.0;
> +const BOTTOM_BUTTON_ROW_HEIGHT: f32 = 50.0;
> +const DISK_ICON_SIZE: u16 = 50;
> +
> +fn bottom_button<'a>(
> + button_content: Element<'a, Event>,
> + button_on_press: Option<Event>,
> +) -> Button<'a, Event> {
> + button(
> + center_in_container!(button_content)
> + .height(Length::Fill)
> + .center_y(Length::Fill),
> + )
> + .on_press_maybe(button_on_press)
> + .width(Length::Fill)
> + .height(Length::Fill)
> +}
> +
> +pub fn bottom_buttons_layout<'a>(
> + button_matrix: impl IntoIterator<
> + Item = impl IntoIterator<Item = (Element<'a, Event>, Option<Event>)>,
> + >,
> + main_element: Element<'a, Event>,
> +) -> Element<'a, Event> {
> + let mut bottom_height = 0.0;
> + let mut bottom_element = Column::new().spacing(BOTTOM_BUTTON_SPACE);
> + for input_row in button_matrix.into_iter() {
> + let mut output_row = Row::new().spacing(BOTTOM_BUTTON_SPACE);
> + for (button_content, button_on_press) in input_row.into_iter() {
> + output_row = output_row.push(bottom_button(button_content, button_on_press));
> + }
> + bottom_element = bottom_element.push(output_row);
> + bottom_height += BOTTOM_BUTTON_ROW_HEIGHT;
> + }
> +
> + column![
> + center_horizontal_in_container!(main_element).height(Length::Fill),
> + container(bottom_element).height(bottom_height)
> + ]
> + .into()
> +}
> +
> +pub fn disk_element(device: &BlockDevice) -> Element<'static, Event> {
> + let icon: Element<Event> = text(Icon::Hdd.to_string())
> + .font(ICON_FONT)
> + .size(DISK_ICON_SIZE)
> + .into();
> +
> + let disk_size = if let Ok(Some(capacity)) = device.capacity() {
> + let mut size_factor: f32 = (capacity * 512) as f32;
Why f32 and not f64?
> + let mut exponent = 0; // base = 1024
> + while size_factor >= 1000.0 {
> + exponent += 1;
> + size_factor = size_factor / 1000.0;
> + }
> + let unit = match exponent {
> + 0 => "",
> + 1 => "K",
> + 2 => "M",
> + 3 => "G",
> + 4 => "T",
> + 5 => "P",
> + 6 => "E",
> + 7 => "Z",
> + 8 => "Y",
> + 9 => "R",
> + _ => "???",
> + };
> + Ok(format!("{:.2} {}B", size_factor, unit))
> + } else {
> + Err("Failed to get disk size")
> + };
> +
> + let disk_id = if let Some(id) = &device.id { id } else { "" };
> +
> + row![
> + icon,
> + text(format!(
> + "{}\n{}\n{}",
> + device.fullname.display(),
> + disk_id,
> + if let Ok(size) = disk_size {
> + size
> + } else {
> + String::from("(unknown size)")
> + }
> + ))
> + ]
> + .spacing(8)
> + .into()
> +}
> diff --git a/tools/spectrum-installer/src/pages/mod.rs b/tools/spectrum-installer/src/pages/mod.rs
> new file mode 100644
> index 0000000..cd020f1
> --- /dev/null
> +++ b/tools/spectrum-installer/src/pages/mod.rs
> @@ -0,0 +1,43 @@
> +// SPDX-License-Identifier: EUPL-1.2+
> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +use iced::{Subscription, Task};
> +
> +mod completion;
> +mod confirmation;
> +mod disk_selection;
> +mod installation;
> +mod layout;
> +mod welcome;
> +
> +pub const WINDOW_WIDTH: f32 = 750.0;
> +pub const WINDOW_HEIGHT: f32 = 650.0;
> +
> +pub const MARGIN_VERTICAL: f32 = 25.0;
> +pub const MARGIN_LR: f32 = 15.0;
Why f32 and not f64?
> +pub const BUTTON_TEXT_SIZE: u16 = 20;
> +pub const TITLE_TEXT_SIZE: u16 = 24;
> +
> +type UpdateResult = (Option<Box<dyn Page>>, Task<Event>);
> +
> +type InstallResult = Result<String, (u32, String)>;
> +
> +pub trait Page {
> + fn update(&mut self, event: Event) -> UpdateResult;
> + fn view(&self) -> iced::Element<'_, Event>;
> + fn subscription(&self) -> Subscription<Event> {
> + Subscription::none()
> + }
> +}
> +
> +#[derive(Clone, Debug)]
> +pub enum Event {
> + /* Pages are ordered as they appear during the installation. */
> + PageWelcome(welcome::PageWelcomeEvent),
> + PageDiskSelection(disk_selection::PageDiskSelectionEvent),
> + PageConfirmation(confirmation::PageConfirmationEvent),
> + PageInstallation(installation::PageInstallationEvent),
> + PageCompletion(completion::PageCompletionEvent),
> +}
> +
> +pub const INITAL_PAGE: welcome::PageWelcome = welcome::PageWelcome {};
> diff --git a/tools/spectrum-installer/src/pages/welcome.rs b/tools/spectrum-installer/src/pages/welcome.rs
> new file mode 100644
> index 0000000..fb91fd1
> --- /dev/null
> +++ b/tools/spectrum-installer/src/pages/welcome.rs
> @@ -0,0 +1,62 @@
> +// SPDX-License-Identifier: EUPL-1.2+
> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
> +
> +use super::{BUTTON_TEXT_SIZE, Event, MARGIN_VERTICAL, Page, TITLE_TEXT_SIZE, UpdateResult};
> +use crate::{center_horizontal_in_container, center_in_container};
> +use iced::{
> + Element, Length, Task,
> + widget::{Space, column, image, text},
> +};
> +
> +const LOGO_PATH_GLOBAL: &str = "/usr/share/icons/hicolor/400x400/apps/spectrum-installer.png";
> +const LOGO_WIDTH: f32 = 400.0;
> +
> +pub struct PageWelcome {}
> +
> +impl PageWelcome {
> + pub fn new() -> Self {
> + Self {}
> + }
> +}
> +
> +#[derive(Clone, Debug)]
> +pub enum PageWelcomeEvent {
> + Continue,
> +}
> +
> +impl Page for PageWelcome {
> + fn update(&mut self, event: Event) -> UpdateResult {
> + if let Event::PageWelcome(page_welcome_event) = event {
> + match page_welcome_event {
> + PageWelcomeEvent::Continue => {
> + return (
> + Some(Box::new(super::disk_selection::PageDiskSelection::new())),
> + Task::none(),
> + );
> + }
> + }
> + }
> + (None, Task::none())
> + }
> +
> + fn view(&self) -> Element<'_, Event> {
> + let button_content = text("Next").size(BUTTON_TEXT_SIZE);
> +
> + let main_content = column![
> + Space::with_height(MARGIN_VERTICAL),
> + center_horizontal_in_container!(
> + text("Welcome to the installation of Spectrum!").size(TITLE_TEXT_SIZE)
> + ),
> + Space::with_height(MARGIN_VERTICAL),
> + center_in_container!(image(LOGO_PATH_GLOBAL).width(Length::Fixed(LOGO_WIDTH)))
> + ];
> +
> + super::layout::bottom_buttons_layout(
> + [[(
> + button_content.into(),
> + Some(Event::PageWelcome(PageWelcomeEvent::Continue)),
> + )]],
> + main_content.into(),
> + )
> + }
> +}
Very good idea!
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/4] release/live: remove B slot from live image and reduce A slot size
2026-01-04 14:00 ` [PATCH 4/4] release/live: remove B slot from live image and reduce A slot size Johannes Süllner
@ 2026-01-04 21:16 ` Demi Marie Obenour
0 siblings, 0 replies; 9+ messages in thread
From: Demi Marie Obenour @ 2026-01-04 21:16 UTC (permalink / raw)
To: Johannes Süllner, devel
[-- Attachment #1.1.1: Type: text/plain, Size: 1732 bytes --]
On 1/4/26 09:00, Johannes Süllner wrote:
> In contrast to the old installer, with the new installer the live image
> is not copied as a whole to the destination disk any more. Instead,
> `systemd-repart` creates partitions with the desired size, and then
> copies the individual partitions.
>
> Signed-off-by: Johannes Süllner <johannes.suellner@mailbox.org>
> ---
> release/live/Makefile | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/release/live/Makefile b/release/live/Makefile
> index f5fe558..34a7d3f 100644
> --- a/release/live/Makefile
> +++ b/release/live/Makefile
> @@ -11,9 +11,7 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf
> ../../scripts/make-gpt.sh $@.tmp \
> build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \
> $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)"):Spectrum_'$(VERSION).verity:162' \
> - $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))"):Spectrum_'$(VERSION):20000' \
> - /dev/null:verity:18f2ccff-92f1-4bb1-a80e-24f76ecda90c:_empty:162 \
> - /dev/null:root:ec0c5ff3-f6b1-4adf-82b4-61336c4d135f:_empty:20000
> + $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))"):Spectrum_'$(VERSION)'
> mv $@.tmp $@
>
> build/boot.fat: $(SYSTEMD_BOOT_EFI) $(SPECTRUM_EFI)
After this, are there any places left that pass explicit sizes to make_gpt.sh?
If not, the change to add support for this can be reverted.
Thanks for this awesome improvement!
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] tools: add spectrum-installer
2026-01-04 14:00 [PATCH 1/4] tools: add spectrum-installer Johannes Süllner
` (3 preceding siblings ...)
2026-01-04 21:13 ` [PATCH 1/4] tools: add spectrum-installer Demi Marie Obenour
@ 2026-01-10 21:04 ` Alyssa Ross
2026-01-18 8:54 ` Johannes Süllner
4 siblings, 1 reply; 9+ messages in thread
From: Alyssa Ross @ 2026-01-10 21:04 UTC (permalink / raw)
To: Johannes Süllner; +Cc: devel
[-- Attachment #1: Type: text/plain, Size: 804 bytes --]
Johannes Süllner <johannes.suellner@mailbox.org> writes:
> Written in Rust using the Iced GUI library. Uses `lsblk-rs` to offer a
> list of disks where the user can choose one to install Spectrum on.
> Uses `systemd-repart` for the installation, which is running in an
> embedded terminal window using `iced-term`.
>
> Signed-off-by: Johannes Süllner <johannes.suellner@mailbox.org>
Just wanted to say I'm really excited that you've done this work, and
apologise for not having had a chance to look at it yet. I only got one
good day of catching up on mail in between coming back to work after a
holiday break and getting sick with something. I'm looking forward to
giving this the attention it deserves once I've got over that and my
brain is functioning at full capacity again. :)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] tools: add spectrum-installer
2026-01-04 21:13 ` [PATCH 1/4] tools: add spectrum-installer Demi Marie Obenour
@ 2026-01-11 18:30 ` Johannes Süllner
0 siblings, 0 replies; 9+ messages in thread
From: Johannes Süllner @ 2026-01-11 18:30 UTC (permalink / raw)
To: Demi Marie Obenour, Johannes Süllner, devel
[-- Attachment #1: Type: text/plain, Size: 7939 bytes --]
On Sun Jan 4, 2026 at 10:13 PM CET, Demi Marie Obenour wrote:
> On 1/4/26 09:00, Johannes Süllner wrote:
>> Written in Rust using the Iced GUI library. Uses `lsblk-rs` to offer a
>> list of disks where the user can choose one to install Spectrum on.
>> Uses `systemd-repart` for the installation, which is running in an
>> embedded terminal window using `iced-term`.
>>
>> Signed-off-by: Johannes Süllner <johannes.suellner@mailbox.org>
>> ---
...
>> diff --git a/tools/spectrum-installer/shell.nix b/tools/spectrum-installer/shell.nix
>> new file mode 100644
>> index 0000000..060009b
>> --- /dev/null
>> +++ b/tools/spectrum-installer/shell.nix
>> @@ -0,0 +1,30 @@
>> +# SPDX-License-Identifier: MIT
>> +# SPDX-FileCopyrightText: 2025 iced contributors
>> +
>> +# from https://github.com/iced-rs/iced/blob/master/DEPENDENCIES.md
>> +# last updated 2025-11-11
>> +{ pkgs ? import <nixpkgs> {} }:
>> +
>> +pkgs.mkShell rec {
>> + buildInputs = with pkgs; [
>> + cargo
>> + lldb
>> + expat
>> + fontconfig
>> + freetype
>> + freetype.dev
>> + libGL
>> + pkg-config
>> + rustfmt
>> + xorg.libX11
>> + xorg.libXcursor
>> + xorg.libXi
>> + xorg.libXrandr
>> + wayland
>> + libxkbcommon
>> + ];
>
> Is it possible to drop the X11 libraries? The installer should be
> Wayland-only. If upstream Iced can't be built without X11 support,
> feel free to ignore this.
Yes, it is possible to drop them. I just did not tried until now,
but building without them in a `nix-shell --pure` environment works.
They are gone now; I also updated the whole develompent shell file as
the upstream reference (https://github.com/iced-rs/iced/blob/master/DEPENDENCIES.md)
also changed.
>> diff --git a/tools/spectrum-installer/src/main.rs b/tools/spectrum-installer/src/main.rs
>> new file mode 100644
>> index 0000000..2ca9dfa
>> --- /dev/null
>> +++ b/tools/spectrum-installer/src/main.rs
>> @@ -0,0 +1,52 @@
>> +// SPDX-License-Identifier: EUPL-1.2+
>> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
>> +
>> +mod pages;
>> +
>> +use iced::Element;
>> +use iced::Size;
>> +use iced::Subscription;
>> +use iced::Task;
>> +use pages::Event;
>> +
>> +fn main() -> iced::Result {
>> + iced::application(
>> + "Spectrum installer",
>> + SpectrumInstaller::update,
>> + SpectrumInstaller::view,
>> + )
>> + .window_size(Size::new(pages::WINDOW_WIDTH, pages::WINDOW_HEIGHT))
>> + .font(iced_fonts::BOOTSTRAP_FONT_BYTES)
>> + .resizable(false)
>> + .subscription(SpectrumInstaller::subscription)
>> + .run()
>> +}
>
> Have you tested with HiDPI displays? I think it would be better for
> the installer to be fullscreen, or at least have a size proportional
> to the display it is on.
>
> I suspect that hard-coded sizes are an antipattern, though I don't know
> what the best alternative would be. Ideally there would be an option
> to zoom in and out, so that those who need larger buttons and text can
> get that. Is there a way to ask Iced to size things automatically?
I did not test on a HiDPI screen this before, but did so now and it
would scale just fine in latest PopOS with Cosmic.
I agree a large font mode or zoom-options would be good for
accessibility. I'm happy to implement this at some future point.
Personally, I do not like fullscreen installers too much, perhaps
because I think there is not enough content that would justify
fullscreen. Not a strong opinion though.
As a sidenote, resizing of the installer already causes the widgets
to resize as well (font size stays the same, though). You can
currently resize the window in Weston, where the application's wish to
not be resizable is not honored.
>> diff --git a/tools/spectrum-installer/src/pages/completion.rs b/tools/spectrum-installer/src/pages/completion.rs
>> new file mode 100644
>> index 0000000..2ea9734
>> --- /dev/null
>> +++ b/tools/spectrum-installer/src/pages/completion.rs
...
>> + fn view(&self) -> Element<'_, Event> {
>> + let main_element = match &self.install_result {
>> + Ok(_) => {
>> + center_in_container!(text("Spectrum installation succeeded!").size(TITLE_TEXT_SIZE)).into()
>> + }
>> + Err((code, log)) => {
>> + column![
>> + Space::with_height(MARGIN_VERTICAL),
>> + center_horizontal_in_container!(text("Spectrum installation failed :( ").size(TITLE_TEXT_SIZE)),
>> + Space::with_height(MARGIN_VERTICAL),
>> + center_horizontal_in_container!(Scrollable::new(text(format!("You can reach out to the team via Chat or the \"discuss\" mailing list.\n\
>> + See https://spectrum-os.org/doc/contributing/communication.html for details.\n\
>> + The following information may be relevant:\n\n\
>> + Error code: {}\n\nError log:\n{}", code, log)))
>> + .width(WINDOW_WIDTH - 2.0 * MARGIN_LR)
>> + .height(500)
>> + .direction(Direction::Vertical(Scrollbar::new()))),
>> + ]
>> + .into()
>> + }
>> + };
>
> I see no harm in including the full email address of the discuss
> mailing list (discuss@spectrum-os.org). Also, it would be useful to
> display a QR code that someone can scan using their mobile device.
> This avoids having to do clumsy and error-prone manual transcription,
> and may allow for including more lines of output.
I guess you're right, I've included the full email address now.
I like your idea to have a QR code for the error log and just
implemented it.
>> + String::from(
>> + [
>> + "( /usr/bin/systemd-repart \
>> + --definitions=/usr/share/spectrum-installer/repart.d \
>> + --empty=force \
>> + --dry-run=no ",
>> + &device.fullname.display().to_string(),
>
> Missing shell argument escaping and '-o pipefail'. The latter might
> require bash instead of sh.
Good catch, fixed. Works with sh as well.
>> diff --git a/tools/spectrum-installer/src/pages/layout.rs b/tools/spectrum-installer/src/pages/layout.rs
>> new file mode 100644
>> index 0000000..e7095bd
>> --- /dev/null
>> +++ b/tools/spectrum-installer/src/pages/layout.rs
...
>> +
>> +pub fn disk_element(device: &BlockDevice) -> Element<'static, Event> {
>> + let icon: Element<Event> = text(Icon::Hdd.to_string())
>> + .font(ICON_FONT)
>> + .size(DISK_ICON_SIZE)
>> + .into();
>> +
>> + let disk_size = if let Ok(Some(capacity)) = device.capacity() {
>> + let mut size_factor: f32 = (capacity * 512) as f32;
>
> Why f32 and not f64?
No particular reason, I changed it to f64.
>> diff --git a/tools/spectrum-installer/src/pages/mod.rs b/tools/spectrum-installer/src/pages/mod.rs
>> new file mode 100644
>> index 0000000..cd020f1
>> --- /dev/null
>> +++ b/tools/spectrum-installer/src/pages/mod.rs
>> @@ -0,0 +1,43 @@
>> +// SPDX-License-Identifier: EUPL-1.2+
>> +// SPDX-FileCopyrightText: 2025 Johannes Süllner <johannes.suellner@mailbox.org>
>> +
>> +use iced::{Subscription, Task};
>> +
>> +mod completion;
>> +mod confirmation;
>> +mod disk_selection;
>> +mod installation;
>> +mod layout;
>> +mod welcome;
>> +
>> +pub const WINDOW_WIDTH: f32 = 750.0;
>> +pub const WINDOW_HEIGHT: f32 = 650.0;
>> +
>> +pub const MARGIN_VERTICAL: f32 = 25.0;
>> +pub const MARGIN_LR: f32 = 15.0;
>
> Why f32 and not f64?
Iced expects 32 bit floats for sizes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 269 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] tools: add spectrum-installer
2026-01-10 21:04 ` Alyssa Ross
@ 2026-01-18 8:54 ` Johannes Süllner
0 siblings, 0 replies; 9+ messages in thread
From: Johannes Süllner @ 2026-01-18 8:54 UTC (permalink / raw)
To: Alyssa Ross, Johannes Süllner; +Cc: devel
[-- Attachment #1: Type: text/plain, Size: 760 bytes --]
On Sat Jan 10, 2026 at 10:04 PM CET, Alyssa Ross wrote:
> Just wanted to say I'm really excited that you've done this work, and
> apologise for not having had a chance to look at it yet. I only got one
> good day of catching up on mail in between coming back to work after a
> holiday break and getting sick with something. I'm looking forward to
> giving this the attention it deserves once I've got over that and my
> brain is functioning at full capacity again. :)
No need to apologize, I hope you'll get well soon!
Just wanted to let you know that I'll likely send a v2 of the
installer patches to the mailing list next week. I incorporated
Demi's comments and changed some more things, so I'd suggest to wait
with the review until then.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 269 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-01-23 15:22 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-04 14:00 [PATCH 1/4] tools: add spectrum-installer Johannes Süllner
2026-01-04 14:00 ` [PATCH 2/4] host/rootfs: integrate spectrum-installer Johannes Süllner
2026-01-04 14:00 ` [PATCH 3/4] release: drop combined and installer image Johannes Süllner
2026-01-04 14:00 ` [PATCH 4/4] release/live: remove B slot from live image and reduce A slot size Johannes Süllner
2026-01-04 21:16 ` Demi Marie Obenour
2026-01-04 21:13 ` [PATCH 1/4] tools: add spectrum-installer Demi Marie Obenour
2026-01-11 18:30 ` Johannes Süllner
2026-01-10 21:04 ` Alyssa Ross
2026-01-18 8:54 ` Johannes Süllner
Code repositories for project(s) associated with this public inbox
https://spectrum-os.org/git/crosvm
https://spectrum-os.org/git/doc
https://spectrum-os.org/git/mktuntap
https://spectrum-os.org/git/nixpkgs
https://spectrum-os.org/git/spectrum
https://spectrum-os.org/git/ucspi-vsock
https://spectrum-os.org/git/www
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).