From b9f562d9d3f74cbfa4a0e442557c9e68a4fe453c Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 17:32:31 +0200 Subject: [PATCH 01/22] The toolchain builds clang and ld.lld that run on ToyOS, statically linked `cargo run -- --hosted-clang` builds clang and LLD for x86_64-unknown-toyos (src/hostedclang.rs) from the LLVM commit the host's LLVM is, with the toolchain's clang against its C sysroot, into the host store under a key of their own: the host LLVM's key, the sysroot's, the recipe and the CMake options. The sources are the commit's, written from the fork's LLVM repository through an index of their own, never a checkout's files. The binaries say the version, revision and repository the host's clang says, `22.1.8-rust-dev` with bootstrap's suffix among them, since every object a clang compiles carries that in its `.comment`. Each is refused unless it is an x86-64 ELF naming no library it needs. Made only when asked for: its build is LLVM's, and its key moves with every sysroot's. On this host it took 23 minutes and gave a 147,533,968-byte clang and an 85,568,488-byte ld.lld, static PIEs; stripped, 121,926,824 and 70,926,168. What the build for a ToyOS host stopped on, measured with the tree's own toolchain on the clang and lld targets alone: Support's `alarm`, `wait` and `wait4` (Watchdog.inc, Program.inc), and clang's `std::ifstream`, which libc++ has only with `std::filesystem`; at the link, clangBasic's `lround`. No archive of either tool names ORC's `shm_open`, the interpreter's `scanf` or llvm-objdump's `ctime`, so libc gains none of them. Neither tool starts a child for `clang -c` or `ld.lld`: clang runs cc1 in its own process (`CLANG_SPAWN_CC1` off), and LLD starts one only for `--error-handling-script`. libc gains: - `wait` and `wait4`, answering ECHILD as `waitpid` does: libc starts no child. - `alarm`, kept by a thread of libc's that ends the process with SIGALRM's default action, exit 142, once it is due. A handler never runs, since `sigaction` keeps none: that is stage 3 of the child-process track. The seconds left, rounded up, are `alarmreq.rs`'s rule, held on the host. - `lround`, and `round` on the same rule, a half away from zero, held to the host's C library. `round` was `floor(x + 0.5)`, which answered -2 for -2.5 and 1 for 0.49999999999999994. - what libc++'s `src/filesystem` and `` call: `setbuf`, `fseeko`, `ftello`, `truncate`, `pathconf`'s `_PC_PATH_MAX`, and `utimes`, refused ENOSYS: no call sets a file's times. libc++ is built with `std::filesystem`. `open` refuses every directory, so no descriptor names one for `openat`: `remove_all` walks a directory iterator, as libc++'s Windows does. `issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md` is closed: ToyOS's build, with nothing supplied by hand, makes a clang and an `ld.lld` for x86_64-unknown-toyos, by CMake and not bootstrap. What bootstrap still owes is M3's (`issues/rustc-llvm-cannot-build-for-a-toyos-host.md`). The alarm and libc++ issues are renamed to what stays true of them, and the track records the owner's ruling of 2026-10-09. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- ...nt-and-a-parent-takes-its-children-down.md | 4 +- ...-link-against-the-c-sysroot-with-z-defs.md | 12 +- ...figured-as-running-on-the-build-machine.md | 26 +- issues/an-alarm-reaches-no-sigalrm-handler.md | 26 ++ ...ild-llvm-clang-and-lld-for-a-toyos-host.md | 37 -- issues/libc-has-no-alarm.md | 26 -- ...lacks-names-llvm-for-a-toyos-host-calls.md | 16 +- ...bc-refuses-what-toyos-cannot-yet-answer.md | 2 + .../libcxx-is-built-without-std-filesystem.md | 17 - issues/no-guest-case-reads-std-filesystem.md | 18 + issues/toyos-builds-itself.md | 26 +- src/buildlock.rs | 18 +- src/flags.rs | 3 + src/hostedclang.rs | 366 ++++++++++++++++++ src/lib.rs | 1 + src/libcxx.rs | 7 +- src/llvm.rs | 27 +- src/main.rs | 5 + src/release.rs | 6 + tests/libc-arch/src/alarm_requests.rs | 27 ++ tests/libc-arch/src/fparts_differential.rs | 48 ++- tests/libc-arch/src/lib.rs | 5 + userland/libc/include/math.h | 1 + userland/libc/include/stdio.h | 4 + userland/libc/include/sys/time.h | 1 + userland/libc/include/sys/wait.h | 4 + userland/libc/include/unistd.h | 5 + userland/libc/src/alarm.rs | 71 ++++ userland/libc/src/alarmreq.rs | 21 + userland/libc/src/errno.rs | 1 + userland/libc/src/fparts.rs | 30 +- userland/libc/src/lib.rs | 2 + userland/libc/src/math.rs | 11 +- userland/libc/src/misc.rs | 12 + userland/libc/src/posix_io.rs | 28 ++ userland/libc/src/refused.rs | 6 + userland/libc/src/stdio.rs | 29 ++ 37 files changed, 814 insertions(+), 135 deletions(-) create mode 100644 issues/an-alarm-reaches-no-sigalrm-handler.md delete mode 100644 issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md delete mode 100644 issues/libc-has-no-alarm.md delete mode 100644 issues/libcxx-is-built-without-std-filesystem.md create mode 100644 issues/no-guest-case-reads-std-filesystem.md create mode 100644 src/hostedclang.rs create mode 100644 tests/libc-arch/src/alarm_requests.rs create mode 100644 userland/libc/src/alarm.rs create mode 100644 userland/libc/src/alarmreq.rs diff --git a/issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md b/issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md index b86c3e49ab2..5ebc580d9a1 100644 --- a/issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md +++ b/issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md @@ -6,8 +6,8 @@ opened: 2026-09-29 # A child's end is an event, and a parent takes its children down -libc cannot start a child: `fork` and `execvp` answer `ENOSYS`, `waitpid` -`ECHILD` and `system` `-1` (`userland/libc/src/misc.rs`, +libc cannot start a child: `fork` and `execvp` answer `ENOSYS`, `waitpid`, +`wait` and `wait4` `ECHILD`, and `system` `-1` (`userland/libc/src/misc.rs`, `userland/libc/src/stdio.rs`), and there is no `posix_spawn`. M2 and M4 of `issues/toyos-builds-itself.md` and the exit of `issues/toyos-runs-on-arm64.md` need it. diff --git a/issues/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md b/issues/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md index 91fb411845f..70dfafc68c8 100644 --- a/issues/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md +++ b/issues/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md @@ -9,12 +9,12 @@ opened: 2026-10-01 ToyOS loads shared objects, a program's `DT_NEEDED` and `dlopen`'s, and its clang links one with `-shared`. None links against the C sysroot with `-z defs`. A C one linked without it leaves `__tls_get_addr` undefined, and -lld refuses the executable that links it for that name. LLVM built for -`x86_64-unknown-toyos` -(`issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md`) -builds `libLTO`, `libRemarks`, `libclang` and `libclang-cpp`, linked -`-shared -z defs`, and each stops on what the sysroot's archives were built -for, an executable: +lld refuses the executable that links it for that name. LLVM built whole for +`x86_64-unknown-toyos`, as M3's rustc needs it +(`issues/rustc-llvm-cannot-build-for-a-toyos-host.md`), builds `libLTO`, +`libRemarks`, `libclang` and `libclang-cpp`, linked `-shared -z defs`, none +of which the ToyOS-hosted clang and LLD (`src/hostedclang.rs`) need, and +each stops on what the sysroot's archives were built for, an executable: - `main`, undefined: `libtoyos_c.a`'s entry point, `start_c`, sits in an object the link takes for other names. diff --git a/issues/a-toyos-hosted-llvm-is-configured-as-running-on-the-build-machine.md b/issues/a-toyos-hosted-llvm-is-configured-as-running-on-the-build-machine.md index 283db974f3d..73a0e53f190 100644 --- a/issues/a-toyos-hosted-llvm-is-configured-as-running-on-the-build-machine.md +++ b/issues/a-toyos-hosted-llvm-is-configured-as-running-on-the-build-machine.md @@ -8,14 +8,16 @@ opened: 2026-10-03 LLVM takes `LLVM_HOST_TRIPLE` from `config.guess`, run by the CMake that configures it (`llvm/cmake/modules/GetHostTriple.cmake`, -`llvm/cmake/config-ix.cmake`), unless the configuration names one, and -bootstrap names none: the `rust/` fork's -`src/bootstrap/src/core/build_steps/llvm.rs` defines -`LLVM_DEFAULT_TARGET_TRIPLE` and no `LLVM_HOST_TRIPLE`. So the LLVM that M2 -cross-builds to run on ToyOS (`issues/toyos-builds-itself.md`) records -the machine that built it as its host. The configure of that build on the -development Mac, the fork at the commit `main` pins (`95960d6c214`), logged -(#682, comment 5968053849) +`llvm/cmake/config-ix.cmake`), unless the configuration names one. The +ToyOS-hosted clang and LLD name it (`src/hostedclang.rs`), and their +configure logs `LLVM host triple: x86_64-unknown-toyos`. Bootstrap names none: +the `rust/` fork's `src/bootstrap/src/core/build_steps/llvm.rs` defines +`LLVM_DEFAULT_TARGET_TRIPLE` and no `LLVM_HOST_TRIPLE`. So the LLVM that M3's +rustc carries, built by bootstrap for a ToyOS host +(`issues/rustc-llvm-cannot-build-for-a-toyos-host.md`), records the machine +that built it as its host. The configure of that build on the development +Mac, the fork at the commit `main` pinned then (`95960d6c214`), logged (#682, +comment 5968053849) ``` -- LLVM host triple: arm64-apple-darwin27.0.0 @@ -26,8 +28,8 @@ development Mac, the fork at the commit `main` pins (`95960d6c214`), logged it exits non-zero, so a configure run inside ToyOS stops there. That half is read from `GetHostTriple.cmake`, not run. -Owner: `issues/toyos-builds-itself.md`: M2 for the triple the host -build records, M5 for the configure inside ToyOS. +Owner: `issues/toyos-builds-itself.md`: M3 for the triple bootstrap's build +records, M5 for the configure inside ToyOS. -Exit condition: the configure of a ToyOS-hosted LLVM logs `LLVM host triple: -x86_64-unknown-toyos`, and a configure inside ToyOS reaches its end. +Exit condition: bootstrap's configure of a ToyOS-hosted LLVM logs `LLVM host +triple: x86_64-unknown-toyos`, and a configure inside ToyOS reaches its end. diff --git a/issues/an-alarm-reaches-no-sigalrm-handler.md b/issues/an-alarm-reaches-no-sigalrm-handler.md new file mode 100644 index 00000000000..76ec1f667f7 --- /dev/null +++ b/issues/an-alarm-reaches-no-sigalrm-handler.md @@ -0,0 +1,26 @@ +--- +status: open +kind: defect +opened: 2026-09-30 +--- + +# An alarm reaches no SIGALRM handler + +libc's `alarm` (`userland/libc/src/alarm.rs`) arms one alarm per process and +answers the seconds the one it replaces had left, and when it is due a thread +of libc's ends the process with exit code 142, `SIGALRM`'s default action. A +handler for `SIGALRM` never runs: `sigaction` keeps none, and answers 0 +whatever it is given. LLVM bounds its wait on a child with one: a `SIGALRM` +handler makes `wait4` answer `EINTR` (`llvm/lib/Support/Unix/Program.inc`, +`Wait`). POSIX gives `alarm` no refusal, and its `SIGALRM` reaches a handler +only through the signals libc imitates from stage 3 of +`issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md` +on; the handler waits on that stage. + +The seconds left are held to their rule on the host +(`tests/libc-arch/src/alarm_requests.rs`); no guest case runs an alarm. + +**Exit**: `alarm` arms and disarms `SIGALRM` as POSIX says, which a guest C +case shows: a handler installed without `SA_RESTART` runs, and a `wait4` on a +child that has not ended answers `EINTR`; and after `alarm(5)`, `alarm(0)` +answers from 1 to 5 and a second `alarm(0)` answers 0. diff --git a/issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md b/issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md deleted file mode 100644 index ec3e0ee320c..00000000000 --- a/issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -status: open -kind: defect -opened: 2026-09-30 ---- - -# Bootstrap cannot build LLVM, clang and lld for a ToyOS host - -M2's clang and lld (`issues/toyos-builds-itself.md`) are bootstrap's -`Llvm` step, with `clang = true`, and its `Lld` step for -`x86_64-unknown-toyos`, in a bootstrap build that names no `llvm-config` for -the build triple and so builds that triple's LLVM, and its `clang-tblgen`, -itself. CMake takes its toolchain file from -`CMAKE_TOOLCHAIN_FILE_x86_64_unknown_toyos`: one that includes the C sysroot's -`toolchain.cmake` and adds the ToyOS LLVM's install to `CMAKE_FIND_ROOT_PATH`, -because the `Lld` step names that LLVM to `find_package` by a hint, and the -sysroot's file has CMake find a package under a root alone. What stops the -build, in the order it stops it: - -- **Compile.** The first errors are `Support`'s: `Unix/Watchdog.inc` and - `Unix/Program.inc` call `alarm` (`issues/libc-has-no-alarm.md`), and - `Program.inc` stage 3's `wait` and `wait4` - (`issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md`). - Then ORC's `shm_open` and `shm_unlink`, the interpreter's `scanf` and - `llvm-objdump`'s `ctime` - (`issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md`), and - clang's `std::ifstream`, which libc++ has only with `std::filesystem` - (`issues/libcxx-is-built-without-std-filesystem.md`). -- **Link.** clang needs `lround`, which libc does not define - (`issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md`), beside - those above. LLVM's shared libraries, `libLTO`, `libRemarks`, `libclang` and - `libclang-cpp`, do not link against the C sysroot - (`issues/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md`). - clang and lld use none of them, and ToyOS's build turns them off. - -**Exit**: ToyOS's build, with nothing supplied by hand, has bootstrap install -a clang and an `ld.lld` for `x86_64-unknown-toyos`. diff --git a/issues/libc-has-no-alarm.md b/issues/libc-has-no-alarm.md deleted file mode 100644 index 4b2966567e8..00000000000 --- a/issues/libc-has-no-alarm.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -status: open -kind: defect -opened: 2026-09-30 ---- - -# libc has no alarm - -libc neither declares nor defines `alarm`, and LLVM bounds its wait on a child -with one: a `SIGALRM` handler makes `wait4` answer `EINTR` -(`llvm/lib/Support/Unix/Program.inc`, `Wait`), so an LLVM built for ToyOS does -not link without it: rustc's LLVM wrapper linked `-shared -z defs` with the -libraries it needs leaves it undefined, beside stage 3's `wait` and `wait4`. -POSIX gives `alarm` no refusal, and its `SIGALRM` reaches -a handler only through the signals libc imitates from stage 3 of -`issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md` -on; this waits on that stage. - -LLVM's `Wait` disarms it with `alarm(0)` and then restores the old `SIGALRM` -action (`llvm/lib/Support/Unix/Program.inc`), so an `alarm(0)` that disarms -nothing ends the process when the alarm fires under the default action. - -**Exit**: `alarm` arms and disarms `SIGALRM` as POSIX says, which a guest C -case shows: a handler installed without `SA_RESTART` runs, and a `wait4` on a -child that has not ended answers `EINTR`; and after `alarm(5)`, `alarm(0)` -answers from 1 to 5 and a second `alarm(0)` answers 0. diff --git a/issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md b/issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md index eab41ae32f8..2c3c955a071 100644 --- a/issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md +++ b/issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md @@ -6,9 +6,10 @@ opened: 2026-10-01 # libc lacks names LLVM for a ToyOS host calls -LLVM, clang and lld built for `x86_64-unknown-toyos` -(`issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md`) -call five names libc neither declares nor defines: +LLVM's tools built for `x86_64-unknown-toyos` call names libc neither +declares nor defines. None is in the clang and `ld.lld` the build makes for +ToyOS (`src/hostedclang.rs`), which compile and link without them; each +stops a build of LLVM's other tools: - `shm_open` and `shm_unlink`, with which ORC maps memory on every Unix but Android (`llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp`, @@ -16,8 +17,11 @@ call five names libc neither declares nor defines: - `scanf`, which LLVM's interpreter hands an interpreted program (`llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp`). - `ctime`, with which `llvm-objdump` prints a file's time stamp. -- `lround`, which libc++'s `std::lround` calls, from clang's `Basic` and its - static analyzer: clang does not link without it. + +`lround`, which clang calls through libc++'s `std::lround`, is defined +(`userland/libc/src/math.rs`) and held to the host's on the host +(`tests/libc-arch/src/fparts_differential.rs`); no guest case reads it. **Exit**: libc declares and defines each, doing what POSIX says or refusing in -POSIX's form, asserted by a guest C case that reads its effect back. +POSIX's form, asserted by a guest C case that reads its effect back, `lround` +among them. diff --git a/issues/libc-refuses-what-toyos-cannot-yet-answer.md b/issues/libc-refuses-what-toyos-cannot-yet-answer.md index ac3977bd623..a2d65210d5c 100644 --- a/issues/libc-refuses-what-toyos-cannot-yet-answer.md +++ b/issues/libc-refuses-what-toyos-cannot-yet-answer.md @@ -14,6 +14,8 @@ These answer failure in their POSIX form and do nothing - `symlink`, `ENOSYS`: `SYS_SYMLINK` displaces what its name held (`issues/a-symbolic-link-on-tmp-displaces-its-name-and-lists-nowhere.md`). - `chmod` and `fchmod`, `ENOSYS`: a file has no mode bits to set. +- `utimes`, `ENOSYS`: no call sets a file's times. The one refusal here + `206_libc_refusals.c` does not yet assert. - `statvfs` and `fstatvfs`, `ENOSYS`: no call answers a filesystem's size or free space. - `getrlimit` and `setrlimit`, `ENOSYS`: no call answers a process's limits. diff --git a/issues/libcxx-is-built-without-std-filesystem.md b/issues/libcxx-is-built-without-std-filesystem.md deleted file mode 100644 index 7a98601903e..00000000000 --- a/issues/libcxx-is-built-without-std-filesystem.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -status: open -kind: defect -opened: 2026-09-30 ---- - -# libc++ for ToyOS is built without `std::filesystem` - -`src/libcxx.rs` configures the C++ runtime with `LIBCXX_ENABLE_FILESYSTEM=OFF`, -so a ToyOS C++ program that includes `` does not compile, and -`` goes with the option: `std::ifstream` and `std::ofstream` are -undefined templates. Built with it, libc++ asks libc for `setbuf`, `fseeko`, -`ftello`, `utimes`, `truncate`, `pathconf`, `openat`, `unlinkat`, `fdopendir`, -`_PC_PATH_MAX`, `O_DIRECTORY`, `O_NOFOLLOW`, `AT_FDCWD` and `AT_REMOVEDIR`. - -**Exit**: libc carries what libc++'s `src/filesystem` calls, the option goes, -and a guest test lists a directory through `std::filesystem`. diff --git a/issues/no-guest-case-reads-std-filesystem.md b/issues/no-guest-case-reads-std-filesystem.md new file mode 100644 index 00000000000..486729c372c --- /dev/null +++ b/issues/no-guest-case-reads-std-filesystem.md @@ -0,0 +1,18 @@ +--- +status: open +kind: defect +opened: 2026-09-30 +--- + +# No guest case reads `std::filesystem` + +libc++ for ToyOS is built with `std::filesystem`, and `` with it, +over what libc gives `src/filesystem`: `setbuf`, `fseeko`, `ftello`, +`truncate`, `pathconf`'s `_PC_PATH_MAX`, and `utimes`, which refuses +`ENOSYS`, so `last_write_time` sets no time. `open` refuses every directory, +so no descriptor names one: `remove_all` walks a directory iterator +(`src/libcxx.rs`), which a link swapped in under it mid-walk can redirect, as +on libc++'s Windows. No C++ program in a guest uses any of it. + +**Exit**: a guest test lists a directory through `std::filesystem`, and reads +a file back through `std::ifstream`. diff --git a/issues/toyos-builds-itself.md b/issues/toyos-builds-itself.md index 02a51e6940b..2aeabff1000 100644 --- a/issues/toyos-builds-itself.md +++ b/issues/toyos-builds-itself.md @@ -38,6 +38,10 @@ AArch64 one step behind, on `issues/toyos-runs-on-arm64.md`'s track. - Make it work, then optimise, then compare: no performance study now, and no comparison before a compilation inside ToyOS succeeds. +**Decided** (owner, 2026-10-09). M2 installs clang and lld from a local file +first, without waiting for packages over HTTPS, and links them statically: +"Yes, decoupled and static (Recommended)". + **To build** (2026-10-01), in an order that is open. Where a stage names libc's state it is `userland/libc` at `15625e0cb`. - **The `libc` crate gains a ToyOS module**, checked by `ctest` against @@ -99,12 +103,14 @@ libc's state it is `userland/libc` at `15625e0cb`. how it is split into packages, and how a self-host test's guest reaches them. -**Blocked on other tracks.** M2 needs packages over HTTPS +**Blocked on other tracks.** M2 needs room for about a gigabyte of toolchain, +and threads and `mmap` mature enough for LLVM +(`issues/std-and-libc-drop-the-answer-thread-join-gives.md`); its package over +HTTPS (`issues/a-package-is-a-directory-under-apps-and-the-installer-is-a-program.md`) -and the network stack under it (`issues/the-lan-is-not-yet-production-grade.md`, -`issues/the-internet-clients-work-unchanged.md`), room for about a -gigabyte of toolchain, and threads and `mmap` mature enough for LLVM -(`issues/std-and-libc-drop-the-answer-thread-join-gives.md`). +waits on the network stack under it +(`issues/the-lan-is-not-yet-production-grade.md`, +`issues/the-internet-clients-work-unchanged.md`). M2 and M4 also need libc to start a child process (`issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md`). M4 needs git in the guest, storage durable and fast enough for an LLVM build tree @@ -119,10 +125,10 @@ the ToyOS-hosted rustc names no linker the guest has (`issues/the-hosted-rustc-names-a-linker-toyos-does-not-have.md`). *Exit*: the commit that lands M2's compile-and-run test, which links inside the guest. -**What stops M2: LLVM, clang and lld built for a ToyOS host**, in the order -each blocks the next, as -`issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md` -measures it. +**What stops M2: clang and lld running inside ToyOS.** `cargo run -- +--hosted-clang` makes a clang and an `ld.lld` for `x86_64-unknown-toyos`, +static PIEs that name no library (`src/hostedclang.rs`): 147.5 MB and +85.6 MB, 121.9 MB and 70.9 MB stripped. No guest has run either. - Run: what `issues/libc-refuses-what-toyos-cannot-yet-answer.md` lists, `issues/libc-has-no-pread-or-pwrite.md`, and `issues/libc-stat-answers-one-serial-number-for-every-file.md`. @@ -136,7 +142,7 @@ M3's exit then waits on a linker in the guest (`issues/the-hosted-rustc-names-a-linker-toyos-does-not-have.md`). **Also owed, by milestone.** -- M2: the host triple a ToyOS-hosted LLVM records +- M3: the host triple the ToyOS-hosted LLVM bootstrap builds records (`issues/a-toyos-hosted-llvm-is-configured-as-running-on-the-build-machine.md`, whose other half, the configure inside ToyOS, is M5's). - M3: `issues/the-hosted-rustcs-stage2-carries-seventeen-proc-macro-libraries-no-image-needs.md`. diff --git a/src/buildlock.rs b/src/buildlock.rs index 95920dbee39..ee6a4af25ab 100644 --- a/src/buildlock.rs +++ b/src/buildlock.rs @@ -28,11 +28,13 @@ //! removed, and its modification time is when the key was last used or made. //! //! A compiler key's lock → a sysroot key's lock → a freestanding key's lock → the -//! worktree build lock → an LLVM key's lock → artifact. A compiler's, a -//! sysroot's or a freestanding key lock is taken with the worktree lock put -//! down ([`Held::without_shared`]), because the key's builder takes the -//! worktree lock exclusively; an LLVM key's is taken inside the worktree lock -//! covering the fork build directory its builder writes. +//! worktree build lock → an LLVM key's lock → a ToyOS-hosted clang key's lock +//! → artifact. A compiler's, a sysroot's or a freestanding key lock is taken +//! with the worktree lock put down ([`Held::without_shared`]), because the +//! key's builder takes the worktree lock exclusively; an LLVM key's is taken +//! inside the worktree lock covering the fork build directory its builder +//! writes; a ToyOS-hosted clang key's inside the worktree lock and the use of +//! the sysroot it builds against, writing only the store. //! //! Holder death: `flock` is released by the kernel when the open file //! description closes, so a builder that is SIGKILLed mid-phase — routine here @@ -171,13 +173,15 @@ pub fn artifact(root: &Path) -> Guard { /// A content-addressed product of the host, locked per key: a sysroot, the /// freestanding targets' libraries it carries (`src/sysroot.rs`), a compiler -/// (`src/compiler.rs`), or the LLVM a compiler links (`src/llvm.rs`). +/// (`src/compiler.rs`), the LLVM a compiler links (`src/llvm.rs`), or the +/// clang and LLD built to run on ToyOS (`src/hostedclang.rs`). #[derive(Clone, Copy)] pub enum Keyed { Sysroot, Freestanding, Compiler, Llvm, + HostedClang, } impl Keyed { @@ -187,6 +191,7 @@ impl Keyed { Keyed::Freestanding => "freestanding", Keyed::Compiler => "compilers", Keyed::Llvm => "llvm", + Keyed::HostedClang => "hosted-clang", } } @@ -201,6 +206,7 @@ impl Keyed { Keyed::Freestanding => "freestanding libraries", Keyed::Compiler => "compiler", Keyed::Llvm => "LLVM", + Keyed::HostedClang => "ToyOS-hosted clang", } } } diff --git a/src/flags.rs b/src/flags.rs index d9173d79433..d5d4e3178b4 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -52,6 +52,9 @@ declare_flags!(pub CARGO_RUN = { pub HELP = "--help", None; pub CI = "--ci", Rest; pub CLIPPY = "--clippy", None; + /// Make the clang and `ld.lld` that run on ToyOS (`src/hostedclang.rs`), + /// and say where they are. + pub HOSTED_CLANG = "--hosted-clang", None; pub DEBUG = "--debug", None; pub BUILD_ONLY = "--build-only", None; pub DUMP_AUDIO = "--dump-audio", None; diff --git a/src/hostedclang.rs b/src/hostedclang.rs new file mode 100644 index 00000000000..27c72a220f2 --- /dev/null +++ b/src/hostedclang.rs @@ -0,0 +1,366 @@ +//! clang and `ld.lld` that run on ToyOS: built for `x86_64-unknown-toyos` from +//! the LLVM commit the host's LLVM is (`src/llvm.rs`), by the toolchain's own +//! clang against its C sysroot (`clang::CSysroot`), and linked statically. +//! +//! **Made only when asked for** (`cargo run -- --hosted-clang`): its build is +//! LLVM's, and its key moves with every sysroot's, so no other build makes it. +//! +//! **A function of its key** ([`key`]): the host LLVM's key, which names the +//! commit, the revision and repository it says it was built from, and the +//! host's tools, n2 and CMake among them; the sysroot's, which names the C +//! library, the C++ runtime and the clang that builds against them; and +//! [`RECIPE`] with [`OPTIONS`]. Its sources are the commit's, written from the +//! fork's LLVM repository ([`export`]), never a checkout's files. CMake builds +//! LLVM's tablegens for the build machine first, in a nested build of its own +//! (`NATIVE`), with the C and C++ compilers the LLVM key names. +//! +//! `hosted-clang//` in the store holds `bin/clang`, `bin/ld.lld` and +//! clang's resource headers in `lib/clang//include`, where clang looks +//! beside itself; once its [`SOURCE`] file exists it is read-only. Each binary +//! names no library it needs ([`static_elf`]). + +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use crate::arch::Arch; +use crate::buildlock::{Guard, Keyed}; +use crate::clang::CSysroot; +use crate::compiler::LLVM; +use crate::keystore::{self, Key}; +use crate::sysroot::{clone_tree, git_out, gitlink}; + +/// What changes how the key's sources become this product and is none of the +/// other parts. Moving it moves every key. +const RECIPE: &str = "CMake and n2 build of clang and lld from the LLVM commit's SOURCES, for the TARGET \ + against its C sysroot, saying the version, revision and repository the host's clang \ + says; of the build, clang as bin/clang, lld as bin/ld.lld and clang's resource \ + headers; 2"; + +/// The ToyOS the binaries run on. +const TARGET: Arch = Arch::X86_64; + +/// What of the commit the build reads, as git's pathspecs: LLVM, clang and +/// LLD, the CMake modules they share, the third-party sources LLVM compiles in, +/// and libunwind's headers, which LLD's Mach-O port reads. No test, which the +/// configuration builds none of. +const SOURCES: [&str; 12] = [ + "llvm", + "clang", + "lld", + "cmake", + "third-party", + "libunwind/include", + ":(exclude)llvm/test", + ":(exclude)llvm/unittests", + ":(exclude)clang/test", + ":(exclude)clang/unittests", + ":(exclude)lld/test", + ":(exclude)lld/unittests", +]; + +/// The CMake options beyond the compilers', the sysroot's and the host +/// libraries [`crate::llvm`] turns off, each with its reason. +const OPTIONS: [(&str, &str); 11] = [ + ("CMAKE_BUILD_TYPE", "Release"), + ("LLVM_ENABLE_PROJECTS", "clang;lld"), + // The two architectures ToyOS runs on, as the host's LLVM targets them + // (`clang::LLVM_CONFIG`). + ("LLVM_TARGETS_TO_BUILD", "AArch64;X86"), + // What the binaries run on and compile for, where LLVM otherwise asks + // `config.guess` about the build machine. + ("LLVM_HOST_TRIPLE", TARGET.userland()), + ("LLVM_DEFAULT_TARGET_TRIPLE", TARGET.userland()), + ("LLVM_INCLUDE_TESTS", "OFF"), + ("LLVM_INCLUDE_BENCHMARKS", "OFF"), + ("LLVM_INCLUDE_EXAMPLES", "OFF"), + ("LLVM_INCLUDE_DOCS", "OFF"), + ("CLANG_INCLUDE_TESTS", "OFF"), + ("CLANG_INCLUDE_DOCS", "OFF"), +]; + +/// The file a finished product carries last, naming its key. +const SOURCE: &str = "SOURCE"; + +/// The binaries it keeps, each as the build names it and as it is kept: lld +/// takes its flavour from the name it is run by. +const BINARIES: [(&str, &str); 2] = [("clang", "clang"), ("lld", "ld.lld")]; + +/// A ToyOS-hosted clang and LLD, held in use for as long as this lives. +pub struct HostedClang { + pub dir: PathBuf, + _using: Guard, +} + +/// `cargo run -- --hosted-clang`: make this tree's, and name each binary with +/// its size. +pub fn dispatch(root: &Path) { + let mut lock = crate::buildlock::shared(root, "the ToyOS-hosted clang"); + let sysroot = crate::toolchain::ensure(root, &mut lock); + let fork = crate::sysroot::fork_checkout(root, &mut lock); + let hosted = resolve(&keystore::host(), &fork, sysroot.dir(), &crate::n2::ninja(root)); + for (_, kept) in BINARIES { + let binary = hosted.dir.join("bin").join(kept); + let size = fs::metadata(&binary).unwrap_or_else(|e| panic!("stat {}: {e}", binary.display())).len(); + println!("{} ({size} bytes)", binary.display()); + } +} + +/// The product the LLVM fork `fork` names and the sysroot `sysroot` holds, in +/// `store`: made if nobody on this host has made it, under `ninja`. +pub fn resolve(store: &Path, fork: &Path, sysroot: &Path, ninja: &Path) -> HostedClang { + let key = key(fork, sysroot); + let dir = Keyed::HostedClang.store(store).join(&key); + let make = || place(fork, sysroot, ninja, &key, &dir); + let using = keystore::made(store, Keyed::HostedClang, &key, || defect(&dir), make); + HostedClang { dir, _using: using } +} + +/// The key of what `fork`'s LLVM and the sysroot at `sysroot` make. +fn key(fork: &Path, sysroot: &Path) -> Key { + let named = sysroot.file_name().and_then(|n| n.to_str()).and_then(Key::parse); + let sysroot = + named.unwrap_or_else(|| panic!("{} is no sysroot of the store: its name is no key", sysroot.display())); + key_of(&crate::llvm::key(fork), &sysroot, &options()) +} + +fn key_of(llvm: &Key, sysroot: &Key, options: &[(String, String)]) -> Key { + let options: Vec = options.iter().map(|(name, value)| format!("{name}={value}")).collect(); + let parts = [RECIPE, TARGET.userland(), &SOURCES.join(" "), &options.join("\n"), llvm.as_str(), sysroot.as_str()]; + Key::of(parts.join("\n\0\n").as_bytes()) +} + +/// [`OPTIONS`], and every host library off. +fn options() -> Vec<(String, String)> { + let off = crate::llvm::NO_HOST_LIBRARIES.iter().map(|name| (*name, "OFF")); + OPTIONS.into_iter().chain(off).map(|(name, value)| (name.to_string(), value.to_string())).collect() +} + +/// Why `dir` is not a finished product, if it is not. +fn defect(dir: &Path) -> Option { + if !dir.join(SOURCE).is_file() { + return Some(format!("{} carries no {SOURCE}", dir.display())); + } + let binaries = BINARIES.iter().map(|(_, kept)| dir.join("bin").join(kept)); + let mut gone: Vec = binaries.filter(|p| !p.is_file()).map(|p| p.display().to_string()).collect(); + let headers = fs::read_dir(dir.join("lib/clang")).ok().and_then(|mut d| d.next()).and_then(Result::ok); + if !headers.is_some_and(|version| version.path().join("include/stddef.h").is_file()) { + gone.push(dir.join("lib/clang//include").display().to_string()); + } + (!gone.is_empty()).then(|| format!("{} carries no {}", dir.display(), gone.join(", "))) +} + +/// Build what `key` names and put it at `dir`. The caller holds the key's lock. +fn place(fork: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { + eprintln!("Building the ToyOS-hosted clang and LLD {key}: nobody on this host has"); + let scratch = dir.with_extension("build"); + keystore::remove(&scratch); + let sources = scratch.join("src"); + export(fork, &sources); + let built = scratch.join("build"); + build(fork, &sources, &built, &CSysroot::of(sysroot, TARGET), ninja, &scratch); + + let partial = dir.with_extension("partial"); + keystore::remove(&partial); + let bin = partial.join("bin"); + fs::create_dir_all(&bin).unwrap_or_else(|e| panic!("create {}: {e}", bin.display())); + for (name, kept) in BINARIES { + // `fs::copy` follows the link the build installs clang as. + let (from, to) = (built.join("bin").join(name), bin.join(kept)); + fs::copy(&from, &to).unwrap_or_else(|e| panic!("copy {} -> {}: {e}", from.display(), to.display())); + static_elf(&to); + } + let resource = crate::clang::resource_version(&built); + let version = resource.file_name().unwrap_or_else(|| panic!("{} names no version", resource.display())); + clone_tree(&resource.join("include"), &partial.join("lib/clang").join(version).join("include")); + // What was built is what the key names, or it is not that key's. + let again = self::key(fork, sysroot); + assert!(again == *key, "the sources moved while {key} was being built (they now name {again}); nothing was kept"); + let source = partial.join(SOURCE); + fs::write(&source, format!("{key}\n")).unwrap_or_else(|e| panic!("write {}: {e}", source.display())); + crate::llvm::read_only(&partial); + keystore::retire(dir); + fs::rename(&partial, dir).unwrap_or_else(|e| panic!("rename {} -> {}: {e}", partial.display(), dir.display())); + keystore::remove(&scratch); +} + +/// Write [`SOURCES`] as the commit `fork`'s LLVM gitlink names holds them into +/// `dest`, from the LLVM repository of `fork`'s git directory, through an index +/// of their own: no checkout's files reach them. +fn export(fork: &Path, dest: &Path) { + let commit = gitlink(fork, LLVM); + let common = git_out(fork, &["rev-parse", "--path-format=absolute", "--git-common-dir"]); + let repository = Path::new(common.trim()).join("modules").join(LLVM); + fs::create_dir_all(dest).unwrap_or_else(|e| panic!("create {}: {e}", dest.display())); + let index = toyos_tmpdir::TempDir::new("hosted-clang-index"); + let out = Command::new("git") + .env("GIT_DIR", &repository) + .env("GIT_INDEX_FILE", index.join("index")) + .args(["-c", "core.sparseCheckout=false", "--work-tree"]) + .arg(dest) + .args(["checkout", &commit, "--"]) + .args(SOURCES) + .output() + .unwrap_or_else(|e| panic!("run git in {}: {e}", repository.display())); + assert!( + out.status.success(), + "git checkout {commit} from {} into {}: {}", + repository.display(), + dest.display(), + String::from_utf8_lossy(&out.stderr).trim(), + ); +} + +/// Configure LLVM at `sources`, the commit `fork` names, for `c`'s target, +/// in `built`, and build clang and LLD there under `ninja`; `scratch` holds +/// the links CMake runs the compilers by. +fn build(fork: &Path, sources: &Path, built: &Path, c: &CSysroot, ninja: &Path, scratch: &Path) { + // The driver links C++ when run as `clang++`, and LLVM's archiver indexes + // as `ranlib` when run by that name. + let links = scratch.join("bin"); + fs::create_dir_all(&links).unwrap_or_else(|e| panic!("create {}: {e}", links.display())); + let (cxx, ranlib) = (links.join("clang++"), links.join("llvm-ranlib")); + for (link, to) in [(&cxx, &c.clang), (&ranlib, &c.ar)] { + std::os::unix::fs::symlink(to, link) + .unwrap_or_else(|e| panic!("symlink {} -> {}: {e}", link.display(), to.display())); + } + let path = |p: &Path| p.display().to_string(); + let (cc, cxx_native) = crate::llvm::host_compilers(); + let mut native = vec![format!("-DCMAKE_C_COMPILER={}", path(&cc)), format!("-DCMAKE_CXX_COMPILER={}", path(&cxx_native))]; + native.extend(crate::llvm::NO_HOST_LIBRARIES.iter().map(|name| format!("-D{name}=OFF"))); + let mut definitions = options(); + definitions.extend(crate::llvm::stamp_options(fork)); + definitions.push(("LLVM_VERSION_SUFFIX".to_string(), version_suffix(&c.clang))); + definitions.extend([ + ("CMAKE_TOOLCHAIN_FILE".to_string(), path(&c.cmake_toolchain())), + ("CMAKE_C_COMPILER".to_string(), path(&c.clang)), + ("CMAKE_ASM_COMPILER".to_string(), path(&c.clang)), + ("CMAKE_CXX_COMPILER".to_string(), path(&cxx)), + ("CMAKE_AR".to_string(), path(&c.ar)), + ("CMAKE_RANLIB".to_string(), path(&ranlib)), + ("CMAKE_MAKE_PROGRAM".to_string(), path(ninja)), + ("CROSS_TOOLCHAIN_FLAGS_NATIVE".to_string(), native.join(";")), + ]); + let mut configure = Command::new("cmake"); + configure.args(["-G", "Ninja", "-Wno-dev", "-S"]).arg(sources.join("llvm")).arg("-B").arg(built); + configure.args(definitions.iter().map(|(name, value)| format!("-D{name}={value}"))); + run(configure, "configuration", ninja); + let mut make = Command::new(ninja); + make.arg("-C").arg(built).args(BINARIES.map(|(name, _)| name)); + run(make, "build", ninja); +} + +/// What the host's clang, the sysroot's, says it is beyond LLVM's version: +/// bootstrap's `LLVM_VERSION_SUFFIX`. Every object a clang compiles carries +/// what it says in its `.comment`, so this one says it too. +fn version_suffix(clang: &Path) -> String { + let mut command = Command::new(clang); + command.arg("--version"); + crate::llvm::clear(&mut command); + let out = command.output().unwrap_or_else(|e| panic!("run {command:?}: {e}")); + assert!(out.status.success(), "{command:?} failed: {}", String::from_utf8_lossy(&out.stderr)); + let said = String::from_utf8_lossy(&out.stdout); + let first = said.lines().next().unwrap_or_default(); + suffix(first).unwrap_or_else(|| panic!("{} says no version: {said}", clang.display())) +} + +/// The suffix of the version `line`, clang's first line of `--version`, names: +/// what follows its first `-`, and none without one. +fn suffix(line: &str) -> Option { + let version = line.strip_prefix("clang version ")?.split_whitespace().next()?; + Some(version.find('-').map_or(String::new(), |at| version[at..].to_string())) +} + +/// Run `command` seeing nothing of this process's environment but what the +/// LLVM build does (`llvm::clear`), with `ninja`'s directory first on `PATH` +/// for the nested build CMake runs, and refuse its failure. +fn run(mut command: Command, what: &str, ninja: &Path) { + crate::llvm::clear(&mut command); + let dir = ninja.parent().unwrap_or_else(|| panic!("{} is in no directory", ninja.display())); + let caller = std::env::var_os("PATH").unwrap_or_default(); + let path = std::env::join_paths(std::iter::once(dir.to_path_buf()).chain(std::env::split_paths(&caller))) + .unwrap_or_else(|e| panic!("{} cannot lead PATH: {e}", dir.display())); + command.env("PATH", path); + let status = command.status().unwrap_or_else(|e| panic!("run {command:?}: {e}")); + assert!(status.success(), "the ToyOS-hosted clang's {what} failed ({status}): its output above says why"); +} + +/// Refuse `elf` unless it is an executable for [`TARGET`] that names no +/// library it needs. +fn static_elf(elf: &Path) { + let bytes = fs::read(elf).unwrap_or_else(|e| panic!("read {}: {e}", elf.display())); + let machine = match TARGET { + Arch::X86_64 => toyos_elf::Machine::X86_64, + Arch::Aarch64 => toyos_elf::Machine::Aarch64, + }; + let layout = toyos_elf::Layout::parse(&bytes, machine) + .unwrap_or_else(|e| panic!("{} is no {} executable: {e:?}", elf.display(), TARGET.userland())); + let needed = layout.dynamic().map_or(0, |dynamic| { + let start = dynamic.file_offset() as usize; + let table = bytes.get(start..start + dynamic.image().len() as usize); + let table = table.unwrap_or_else(|| panic!("{}'s PT_DYNAMIC is past its end", elf.display())); + toyos_elf::Dynamic::needed(table).count() + }); + assert_eq!(needed, 0, "{} names {needed} libraries it needs, and it is linked statically", elf.display()); +} + +#[cfg(test)] +mod tests { + use toyos_tmpdir::TempDir; + + use super::*; + + fn key(text: &str) -> Key { + Key::of(text.as_bytes()) + } + + /// **The key moves with each input and with nothing else**: the host + /// LLVM's key, the sysroot's and every CMake option. + #[test] + fn the_key_moves_with_the_llvm_the_sysroot_and_the_options() { + let (llvm, sysroot) = (key("llvm"), key("sysroot")); + let base = key_of(&llvm, &sysroot, &options()); + assert_eq!(key_of(&llvm, &sysroot, &options()), base); + let mut moved = options(); + moved[0].1 = "Debug".to_string(); + for (what, other) in [ + ("the LLVM", key_of(&key("another llvm"), &sysroot, &options())), + ("the sysroot", key_of(&llvm, &key("another sysroot"), &options())), + ("an option", key_of(&llvm, &sysroot, &moved)), + ] { + assert_ne!(other, base, "{what} did not move the key"); + } + } + + /// **The suffix is what follows the version's first `-`**, none without + /// one, and a line that names no clang version names none. + #[test] + fn the_suffix_is_what_follows_the_version() { + let rev = "(https://github.com/ToyOSOrg/llvm-project.git ceaf0fbb8440)"; + assert_eq!(suffix(&format!("clang version 22.1.8-rust-dev {rev}")).as_deref(), Some("-rust-dev")); + assert_eq!(suffix(&format!("clang version 22.1.8 {rev}")).as_deref(), Some("")); + assert_eq!(suffix("Apple clang version 17.0.0 (clang-1700.0.13.5)"), None); + } + + /// **A product missing a binary or clang's headers is not whole**, nor one + /// without its `SOURCE`. + #[test] + fn a_product_without_a_binary_or_its_headers_is_not_whole() { + let dir = TempDir::new("hosted-clang"); + let write = |rel: &str| { + let path = dir.join(rel); + fs::create_dir_all(path.parent().unwrap()).unwrap(); + fs::write(path, rel).unwrap(); + }; + assert!(defect(&dir).is_some_and(|d| d.contains(SOURCE))); + for rel in [SOURCE, "bin/clang", "bin/ld.lld", "lib/clang/22/include/stddef.h"] { + write(rel); + } + assert_eq!(defect(&dir), None); + for gone in ["bin/ld.lld", "lib/clang/22/include/stddef.h"] { + fs::remove_file(dir.join(gone)).unwrap(); + assert!(defect(&dir).is_some_and(|d| d.contains(gone.split("22").next().unwrap())), "{gone}: {:?}", defect(&dir)); + write(gone); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 45229856279..7bc624b9505 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ pub mod compiler; pub mod firmware; #[cfg(test)] pub mod gitfixture; +pub mod hostedclang; pub mod flags; pub mod hostws; pub mod identity; diff --git a/src/libcxx.rs b/src/libcxx.rs index f714b9f94b8..c3ff6107ed6 100644 --- a/src/libcxx.rs +++ b/src/libcxx.rs @@ -40,9 +40,10 @@ pub(crate) const OPTIONS: [(&str, &str); 18] = [ ("LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL", "ON"), // The C library has no `dladdr`, so libunwind names no function it unwinds. ("LIBUNWIND_ADDITIONAL_COMPILE_FLAGS", "-D_LIBUNWIND_USE_DLADDR=0"), - // The C library has no directory, `stat` or path surface for it - // (`issues/libcxx-is-built-without-std-filesystem.md`). - ("LIBCXX_ENABLE_FILESYSTEM", "OFF"), + // `open` refuses every directory, so no descriptor names one for `openat` + // and `unlinkat` to resolve against: `remove_all` walks a directory + // iterator, as libc++'s Windows does. + ("LIBCXX_ADDITIONAL_COMPILE_FLAGS", "-DREMOVE_ALL_USE_DIRECTORY_ITERATOR"), ("LIBCXX_INCLUDE_BENCHMARKS", "OFF"), ("LIBCXX_INCLUDE_TESTS", "OFF"), ]; diff --git a/src/llvm.rs b/src/llvm.rs index cb55f7a3998..0b41e8c9980 100644 --- a/src/llvm.rs +++ b/src/llvm.rs @@ -71,7 +71,7 @@ const ENVIRONMENT: [&str; 2] = ["PATH", "TMPDIR"]; /// what a host has installed never decides what is built. Bootstrap's LLD step /// takes none of these: LLD looks for no library unless asked, and links what this /// LLVM chose. -const NO_HOST_LIBRARIES: [&str; 12] = [ +pub(crate) const NO_HOST_LIBRARIES: [&str; 12] = [ "LLVM_ENABLE_ZLIB", "LLVM_ENABLE_ZSTD", "LLVM_ENABLE_LIBXML2", @@ -147,6 +147,26 @@ fn stamp(fork: &Path) -> Stamp { Stamp { revision: gitlink(fork, LLVM), repository: url.trim().to_string() } } +impl Stamp { + /// The CMake options that make LLVM say it. + fn options(&self) -> [(&'static str, &str); 2] { + [("LLVM_FORCE_VC_REVISION", &self.revision), ("LLVM_FORCE_VC_REPOSITORY", &self.repository)] + } +} + +/// The CMake options that make an LLVM built from `fork`'s say what it says +/// (`src/hostedclang.rs`). +pub(crate) fn stamp_options(fork: &Path) -> Vec<(String, String)> { + stamp(fork).options().iter().map(|(name, value)| (name.to_string(), value.to_string())).collect() +} + +/// The C and C++ compilers an LLVM is built with on this host, as its key +/// names them (`src/hostedclang.rs` builds its tablegens with them). +pub(crate) fn host_compilers() -> (PathBuf, PathBuf) { + let tools = host_tools(); + (tools.cc.clone(), tools.cxx.clone()) +} + /// [`key`], with what it reads beside `fork`'s committed `src/bootstrap`: /// `config` names the LLVM's commit ([`stamp`]). fn key_of(fork: &Path, recipe: &str, config: &str, tools: &str) -> Key { @@ -377,7 +397,7 @@ fn check_out_committed(checkout: &Path, commit: &str, paths: &[&str], dest: &Pat /// Take write permission from every file and directory under `dir`, and from /// `dir`. -fn read_only(dir: &Path) { +pub(crate) fn read_only(dir: &Path) { for entry in fs::read_dir(dir).unwrap_or_else(|e| panic!("read {}: {e}", dir.display())) { let path = entry.unwrap_or_else(|e| panic!("read {}: {e}", dir.display())).path(); let meta = fs::symlink_metadata(&path).unwrap_or_else(|e| panic!("stat {}: {e}", path.display())); @@ -454,8 +474,7 @@ fn build_in_fork(root: &Path, fork: &Path) -> PathBuf { /// host alone. fn config_text(build_dir: &Path, host: &str, tools: &HostTools, stamp: &Stamp) -> String { let off = NO_HOST_LIBRARIES.iter().map(|option| format!("{option} = \"OFF\"")); - let stamped = [("LLVM_FORCE_VC_REVISION", &stamp.revision), ("LLVM_FORCE_VC_REPOSITORY", &stamp.repository)]; - let defines: Vec = off.chain(stamped.map(|(option, value)| format!("{option} = \"{value}\""))).collect(); + let defines: Vec = off.chain(stamp.options().map(|(option, value)| format!("{option} = \"{value}\""))).collect(); format!( r#"change-id = "ignore" profile = "compiler" diff --git a/src/main.rs b/src/main.rs index fb9ccd2ed8a..ebdcc055648 100644 --- a/src/main.rs +++ b/src/main.rs @@ -107,6 +107,11 @@ fn main() { toyos_build::clippy::dispatch(&root); return; } + // Builds no image, and runs no guest. + if asked(&flags::HOSTED_CLANG) { + toyos_build::hostedclang::dispatch(&root); + return; + } // Writes one file outside the checkout and builds nothing. if asked(&flags::SIGNING_KEY_NEW) { match toyos_build::signing::mint_owner_key() { diff --git a/src/release.rs b/src/release.rs index 06dc9c1730c..87d5826f6b8 100644 --- a/src/release.rs +++ b/src/release.rs @@ -54,6 +54,10 @@ const LAYERS: [(Keyed, &str); 4] = [ (Keyed::Sysroot, "sysroot"), ]; +/// Why no layer is the ToyOS-hosted clang: it is made only when asked for +/// (`src/hostedclang.rs`), and a release carries what every build reads. +const NOT_A_LAYER: &str = "a toolchain release carries no ToyOS-hosted clang: it is made only when asked for"; + /// One of [`LAYERS`] of this tree's toolchain: the key the build system files /// it under, and where it is, relative to the checkout. struct Layer { @@ -135,6 +139,7 @@ fn layers(root: &Path) -> Vec { Keyed::Compiler => &compiler, Keyed::Freestanding => &freestanding, Keyed::Sysroot => &sysroot, + Keyed::HostedClang => unreachable!("{NOT_A_LAYER}"), }; let dir = kind.store(&store(root)).join(key); let path = dir.strip_prefix(root).expect("a runner's store is in its checkout").to_path_buf(); @@ -154,6 +159,7 @@ fn defect(root: &Path, layer: &Layer) -> Option { } Keyed::Freestanding => crate::sysroot::unpublished(&dir), Keyed::Sysroot => crate::sysroot::unfinished(&dir), + Keyed::HostedClang => unreachable!("{NOT_A_LAYER}"), } } diff --git a/tests/libc-arch/src/alarm_requests.rs b/tests/libc-arch/src/alarm_requests.rs new file mode 100644 index 00000000000..5971595d361 --- /dev/null +++ b/tests/libc-arch/src/alarm_requests.rs @@ -0,0 +1,27 @@ +//! What `alarm` answers and arms: the seconds an earlier alarm has left, +//! rounded up and 0 once it is due or when there is none; and 0 seconds arm +//! nothing. + +use crate::alarmreq::{due, left}; + +const SEC: u64 = 1_000_000_000; + +#[test] +fn an_alarm_is_due_its_seconds_after_it_is_armed_and_zero_arms_none() { + assert_eq!(due(7, 0), None); + assert_eq!(due(7, 1), Some(7 + SEC)); + assert_eq!(due(u64::from(u32::MAX), u32::MAX), Some(u64::from(u32::MAX) * (SEC + 1))); +} + +#[test] +fn the_seconds_left_round_up_and_end_at_zero() { + let armed = due(100, 5); + assert_eq!(left(armed, 100), 5); + assert_eq!(left(armed, 100 + 1), 5, "a second begun is a second left"); + assert_eq!(left(armed, 100 + SEC), 4); + assert_eq!(left(armed, 100 + 5 * SEC - 1), 1, "an alarm not yet due answers at least 1"); + assert_eq!(left(armed, 100 + 5 * SEC), 0, "an alarm due answers 0"); + assert_eq!(left(armed, 100 + 6 * SEC), 0, "an alarm past due answers 0"); + assert_eq!(left(None, 100), 0); + assert_eq!(left(due(0, u32::MAX), 0), u32::MAX); +} diff --git a/tests/libc-arch/src/fparts_differential.rs b/tests/libc-arch/src/fparts_differential.rs index 43f513e8c6a..6b9b1433489 100644 --- a/tests/libc-arch/src/fparts_differential.rs +++ b/tests/libc-arch/src/fparts_differential.rs @@ -1,12 +1,17 @@ -//! `modf` and `logb` against the host C library's, bit for bit: every special -//! value, the edges of the subnormals and of the integers a double holds, and -//! a spread of bit patterns across every exponent. +//! `modf`, `round`, `lround` and `logb` against the host C library's, bit for +//! bit: every special value, the edges of the subnormals, of the halves and of +//! the integers a double and a `long` hold, and a spread of bit patterns across +//! every exponent. use crate::fparts; extern "C" { #[link_name = "modf"] fn host_modf(x: f64, int: *mut f64) -> f64; + #[link_name = "round"] + fn host_round(x: f64) -> f64; + #[link_name = "lround"] + fn host_lround(x: f64) -> i64; #[link_name = "logb"] fn host_logb(x: f64) -> f64; } @@ -30,9 +35,15 @@ fn inputs() -> Vec { f64::MIN_POSITIVE / 2.0, f64::from_bits(1), f64::from_bits(0x000f_ffff_ffff_ffff), + 0.49999999999999994, + 3.5, 4_503_599_627_370_495.5, 4_503_599_627_370_496.0, 9_007_199_254_740_993.0, + // The last double below 2^63, 2^63 itself, and -2^63. + 9_223_372_036_854_774_784.0, + 9_223_372_036_854_775_808.0, + -9_223_372_036_854_775_808.0, f64::INFINITY, f64::NAN, ]; @@ -62,6 +73,37 @@ fn modf_is_the_host_libraries() { } } +#[test] +fn round_is_the_host_libraries() { + for x in inputs() { + // SAFETY: a pure function of its argument. + let host = unsafe { host_round(x) }; + let ours = fparts::round(x); + assert!(same(ours, host), "round({x:e} = {:#x}): {ours:e}, the host {host:e}", x.to_bits()); + } +} + +/// Where the rounding is a `long`, the host's; where it is not, a NaN among +/// them, the domain error, whose value the host leaves unspecified. +#[test] +fn lround_is_the_host_libraries_and_out_of_range_its_domain_error() { + let mut refused = 0; + for x in inputs() { + // SAFETY: a pure function of its argument. + let rounded = unsafe { host_round(x) }; + let fits = (-9_223_372_036_854_775_808.0..9_223_372_036_854_775_808.0).contains(&rounded); + match fparts::lround(x) { + // SAFETY: a pure function of its argument, here inside its domain. + Ok(ours) => assert!(fits && ours == unsafe { host_lround(x) }, "lround({x:e}): {ours}"), + Err(fparts::Domain) => { + assert!(!fits, "lround({x:e}) refused a rounding {rounded:e} that is a long"); + refused += 1; + } + } + } + assert!(refused > 0, "no input was outside a long"); +} + #[test] fn logb_is_the_host_libraries_and_a_zero_its_pole() { for x in inputs() { diff --git a/tests/libc-arch/src/lib.rs b/tests/libc-arch/src/lib.rs index a6fa47e5dfd..f55943a5421 100644 --- a/tests/libc-arch/src/lib.rs +++ b/tests/libc-arch/src/lib.rs @@ -14,6 +14,9 @@ #[cfg(test)] extern crate alloc; +#[cfg(test)] +#[path = "../../../userland/libc/src/alarmreq.rs"] +mod alarmreq; #[cfg(test)] #[path = "../../../userland/libc/src/arch/mod.rs"] mod arch; @@ -57,6 +60,8 @@ mod text; #[path = "../../../userland/libc/src/utf8.rs"] mod utf8; +#[cfg(test)] +mod alarm_requests; #[cfg(test)] mod descriptor_requests; #[cfg(test)] diff --git a/userland/libc/include/math.h b/userland/libc/include/math.h index a8b572551a6..3ca45b1e729 100644 --- a/userland/libc/include/math.h +++ b/userland/libc/include/math.h @@ -61,6 +61,7 @@ double sinh(double x); double cosh(double x); double tanh(double x); double round(double x); +long lround(double x); double trunc(double x); double modf(double x, double *iptr); double logb(double x); diff --git a/userland/libc/include/stdio.h b/userland/libc/include/stdio.h index 27f39a1c48f..900f7424aa8 100644 --- a/userland/libc/include/stdio.h +++ b/userland/libc/include/stdio.h @@ -3,6 +3,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -40,6 +41,9 @@ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); int fseek(FILE *stream, long offset, int whence); long ftell(FILE *stream); +int fseeko(FILE *stream, off_t offset, int whence); +off_t ftello(FILE *stream); +void setbuf(FILE *stream, char *buf); void rewind(FILE *stream); int fflush(FILE *stream); int feof(FILE *stream); diff --git a/userland/libc/include/sys/time.h b/userland/libc/include/sys/time.h index 2dec877691f..2c9f97ea789 100644 --- a/userland/libc/include/sys/time.h +++ b/userland/libc/include/sys/time.h @@ -18,6 +18,7 @@ struct timezone { }; int gettimeofday(struct timeval *tv, struct timezone *tz); +int utimes(const char *path, const struct timeval times[2]); #ifdef __cplusplus } diff --git a/userland/libc/include/sys/wait.h b/userland/libc/include/sys/wait.h index f60449eb1c3..f87db19b441 100644 --- a/userland/libc/include/sys/wait.h +++ b/userland/libc/include/sys/wait.h @@ -15,7 +15,11 @@ extern "C" { #define WIFEXITED(s) (WTERMSIG(s) == 0) #define WIFSIGNALED(s) (WTERMSIG(s) != 0) +struct rusage; + pid_t waitpid(pid_t pid, int *status, int options); +pid_t wait(int *status); +pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage); #ifdef __cplusplus } diff --git a/userland/libc/include/unistd.h b/userland/libc/include/unistd.h index c93aa56e297..6024325d058 100644 --- a/userland/libc/include/unistd.h +++ b/userland/libc/include/unistd.h @@ -24,6 +24,7 @@ char *getcwd(char *buf, size_t size); int chdir(const char *path); int access(const char *path, int mode); unsigned int sleep(unsigned int seconds); +unsigned int alarm(unsigned int seconds); int usleep(unsigned int usec); int isatty(int fd); int execvp(const char *file, char *const argv[]); @@ -34,6 +35,8 @@ int pipe(int pipefd[2]); void _exit(int status); int fsync(int fd); int ftruncate(int fd, off_t length); +int truncate(const char *path, off_t length); +long pathconf(const char *path, int name); ssize_t readlink(const char *path, char *buf, size_t size); int symlink(const char *target, const char *linkpath); int link(const char *existing, const char *newpath); @@ -59,6 +62,8 @@ long sysconf(int name); #define _SC_CLK_TCK 2 #define _SC_NPROCESSORS_ONLN 84 +#define _PC_PATH_MAX 4 + #define F_OK 0 #define R_OK 4 #define W_OK 2 diff --git a/userland/libc/src/alarm.rs b/userland/libc/src/alarm.rs new file mode 100644 index 00000000000..bdc1de4f097 --- /dev/null +++ b/userland/libc/src/alarm.rs @@ -0,0 +1,71 @@ +//! `alarm`: one per process, kept by a thread of this library's, started by +//! the first alarm armed, that sleeps until it is due and then does what +//! `SIGALRM`'s default action does, ending the process. A handler `sigaction` +//! is given never runs: this library keeps none +//! (`issues/an-alarm-reaches-no-sigalrm-handler.md`). + +use core::ptr; +use core::sync::atomic::{AtomicU32, Ordering}; + +use toyos_abi::syscall; + +use crate::alarmreq; +use crate::pthread::Lock; + +/// What the process ends with when its alarm is due: the code of an end by +/// `SIGALRM` (14), as `abort`'s is `SIGABRT`'s. +const ALARM_END: i32 = 128 + 14; + +struct Alarm { + /// When the alarm is due, in the monotonic clock's nanoseconds. + due: Option, + /// Whether the keeper runs. + kept: bool, +} + +static ALARM: Lock = Lock::new(Alarm { due: None, kept: false }); + +/// Moved at every `alarm`, so a keeper asleep on an older one wakes. +static TURN: AtomicU32 = AtomicU32::new(0); + +fn now() -> u64 { + toyos_abi::clock::nanos_since_boot() +} + +#[no_mangle] +pub extern "C" fn alarm(seconds: u32) -> u32 { + let now = now(); + let mut alarm = ALARM.lock(); + let left = alarmreq::left(alarm.due, now); + alarm.due = alarmreq::due(now, seconds); + if alarm.due.is_some() && !alarm.kept { + // Never joined: it lives as long as the process. + let mut thread = 0u64; + // SAFETY: `keep` is a thread entry that takes and returns nothing. + let refused = unsafe { crate::pthread::pthread_create(&mut thread, ptr::null(), keep, ptr::null_mut()) }; + assert_eq!(refused, 0, "alarm: no thread to keep it"); + alarm.kept = true; + } + TURN.fetch_add(1, Ordering::Release); + // SAFETY: `TURN` is a live, aligned u32. + unsafe { syscall::futex_wake(TURN.as_ptr(), 1) }; + left +} + +/// Sleep until the alarm is due or moved, and end the process once it is due. +unsafe extern "C" fn keep(_: *mut u8) -> *mut u8 { + loop { + // Read before the alarm, so an `alarm` between the two moves it and + // the wait below returns at once. + let turn = TURN.load(Ordering::Acquire); + let wait = match ALARM.lock().due { + None => None, + Some(due) => match due.checked_sub(now()) { + Some(wait) if wait > 0 => Some(wait), + _ => syscall::exit(ALARM_END), + }, + }; + // SAFETY: `TURN` is a live, aligned u32. + unsafe { syscall::futex_wait(TURN.as_ptr(), turn, wait) }; + } +} diff --git a/userland/libc/src/alarmreq.rs b/userland/libc/src/alarmreq.rs new file mode 100644 index 00000000000..e5653b00be0 --- /dev/null +++ b/userland/libc/src/alarmreq.rs @@ -0,0 +1,21 @@ +//! What `alarm` answers and arms, in nanoseconds of the monotonic clock. It +//! reads nothing but what it is handed, so the host tests it +//! (`toyos-libc-copies`). + +const NANOS_PER_SEC: u64 = 1_000_000_000; + +/// When an alarm of `seconds` armed at `now` is due; none for 0, which +/// disarms. +pub(crate) fn due(now: u64, seconds: u32) -> Option { + // No overflow: `u32::MAX` seconds are under 2^62 nanoseconds, and `now` + // counts from boot. + (seconds != 0).then(|| now + u64::from(seconds) * NANOS_PER_SEC) +} + +/// The seconds an alarm due at `due` has left at `now`, rounded up: one that +/// has any time left answers at least 1, and none, or one already due, 0. +pub(crate) fn left(due: Option, now: u64) -> u32 { + let Some(due) = due.filter(|&due| due > now) else { return 0 }; + // At most the `u32` seconds `due` was armed with. + (due - now).div_ceil(NANOS_PER_SEC) as u32 +} diff --git a/userland/libc/src/errno.rs b/userland/libc/src/errno.rs index 6bd30ef43b2..a6bd0f10ba6 100644 --- a/userland/libc/src/errno.rs +++ b/userland/libc/src/errno.rs @@ -33,6 +33,7 @@ pub(crate) const ENODEV: i32 = 19; pub(crate) const EINVAL: i32 = 22; pub(crate) const ENOSPC: i32 = 28; pub(crate) const EPIPE: i32 = 32; +pub(crate) const EDOM: i32 = 33; pub(crate) const ERANGE: i32 = 34; pub(crate) const EDEADLK: i32 = 35; pub(crate) const ENOSYS: i32 = 38; diff --git a/userland/libc/src/fparts.rs b/userland/libc/src/fparts.rs index ff89184e8eb..2531f2ae82e 100644 --- a/userland/libc/src/fparts.rs +++ b/userland/libc/src/fparts.rs @@ -1,5 +1,6 @@ -//! A double's parts: `modf`'s integral and fractional parts and `logb`'s -//! exponent, read off its bits. It reads and sets nothing but what it is +//! A double's parts: `modf`'s integral and fractional parts, the integer +//! `round` and `lround` take from them, and `logb`'s exponent, read off its +//! bits. It reads and sets nothing but what it is //! handed, so the host holds it to its own C library's (`toyos-libc-copies`). const MANTISSA_BITS: u32 = 52; @@ -37,6 +38,31 @@ pub(crate) fn modf(x: f64) -> (f64, f64) { (int, x - int) } +/// `round`: `x` to the nearest integer, a half away from zero, keeping its +/// sign; an integer, an infinity or a NaN is itself. +pub(crate) fn round(x: f64) -> f64 { + let (int, fraction) = modf(x); + if fraction.abs() < 0.5 { + return int; + } + // Exact: below 2^52 every integer and its successor are doubles, and at or + // above it `modf` answers no fraction. + if x.is_sign_negative() { int - 1.0 } else { int + 1.0 } +} + +/// `lround` of a value whose rounding is no `long`, a NaN among them: POSIX's +/// domain error, `errno` `EDOM`. +#[derive(Debug, PartialEq, Eq)] +pub(crate) struct Domain; + +/// `lround`: [`round`] as a `long`. +pub(crate) fn lround(x: f64) -> Result { + // `long`'s range as doubles, `[-2^63, 2^63)`; a NaN is in neither half. + const LIMIT: f64 = 9_223_372_036_854_775_808.0; + let rounded = round(x); + if (-LIMIT..LIMIT).contains(&rounded) { Ok(rounded as i64) } else { Err(Domain) } +} + /// `logb` at a zero: POSIX's pole error, `-inf` with `errno` `ERANGE`. #[derive(Debug, PartialEq, Eq)] pub(crate) struct Pole; diff --git a/userland/libc/src/lib.rs b/userland/libc/src/lib.rs index 94e87be16c6..027601e23e6 100644 --- a/userland/libc/src/lib.rs +++ b/userland/libc/src/lib.rs @@ -4,6 +4,8 @@ extern crate alloc; +mod alarm; +mod alarmreq; mod arch; mod ctype; mod elfsym; diff --git a/userland/libc/src/math.rs b/userland/libc/src/math.rs index 3176755636b..434535b97b7 100644 --- a/userland/libc/src/math.rs +++ b/userland/libc/src/math.rs @@ -210,7 +210,16 @@ pub extern "C" fn trunc(x: f64) -> f64 { #[no_mangle] pub extern "C" fn round(x: f64) -> f64 { - floor(x + 0.5) + crate::fparts::round(x) +} + +/// A domain error answers `long`'s least value, as x86-64's conversion does. +#[no_mangle] +pub extern "C" fn lround(x: f64) -> i64 { + crate::fparts::lround(x).unwrap_or_else(|crate::fparts::Domain| { + crate::errno::set(crate::errno::EDOM); + i64::MIN + }) } #[no_mangle] diff --git a/userland/libc/src/misc.rs b/userland/libc/src/misc.rs index ba2b635eeb6..e38e12ec1f2 100644 --- a/userland/libc/src/misc.rs +++ b/userland/libc/src/misc.rs @@ -122,6 +122,18 @@ pub unsafe extern "C" fn waitpid(_pid: i32, _status: *mut i32, _options: i32) -> -1 } +/// `waitpid(-1, status, 0)`. +#[no_mangle] +pub unsafe extern "C" fn wait(status: *mut i32) -> i32 { + unsafe { waitpid(-1, status, 0) } +} + +/// [`waitpid`]: it answers no child, so no usage is written. +#[no_mangle] +pub unsafe extern "C" fn wait4(pid: i32, status: *mut i32, options: i32, _usage: *mut u8) -> i32 { + unsafe { waitpid(pid, status, options) } +} + // Exit / abort / atexit /// A handler `exit` runs: `atexit`'s takes nothing, `__cxa_atexit`'s its object. diff --git a/userland/libc/src/posix_io.rs b/userland/libc/src/posix_io.rs index 47dfd48e70f..154ce1ca7f5 100644 --- a/userland/libc/src/posix_io.rs +++ b/userland/libc/src/posix_io.rs @@ -178,6 +178,34 @@ pub unsafe extern "C" fn ftruncate(raw_fd: i32, length: i64) -> i32 { } } +/// [`ftruncate`] of `path` opened for writing. +#[no_mangle] +pub unsafe extern "C" fn truncate(path: *const u8, length: i64) -> i32 { + let fd = unsafe { open(path, O_WRONLY, 0) }; + if fd < 0 { + return -1; + } + let truncated = unsafe { ftruncate(fd, length) }; + unsafe { close(fd) }; + truncated +} + +/// `_PC_PATH_MAX`, `unistd.h`'s. +const PC_PATH_MAX: i32 = 4; + +/// The longest path the kernel resolves, for every path; no other limit is +/// answered. +#[no_mangle] +pub unsafe extern "C" fn pathconf(_path: *const u8, name: i32) -> i64 { + match name { + PC_PATH_MAX => toyos::fs::MAX_PATH as i64, + _ => { + crate::errno::set(EINVAL); + -1 + } + } +} + #[no_mangle] pub unsafe extern "C" fn fsync(raw_fd: i32) -> i32 { match syscall::fsync(fd(raw_fd)) { diff --git a/userland/libc/src/refused.rs b/userland/libc/src/refused.rs index b6f1531c8a9..972236f0198 100644 --- a/userland/libc/src/refused.rs +++ b/userland/libc/src/refused.rs @@ -71,6 +71,12 @@ pub extern "C" fn fchmod(_fd: i32, _mode: u32) -> i32 { refuse() } +/// No call sets a file's times. +#[no_mangle] +pub unsafe extern "C" fn utimes(_path: *const u8, _times: *const u8) -> i32 { + refuse() +} + /// No call answers a filesystem's size or free space. #[no_mangle] pub unsafe extern "C" fn statvfs(_path: *const u8, _buf: *mut u8) -> i32 { diff --git a/userland/libc/src/stdio.rs b/userland/libc/src/stdio.rs index 00e558458a8..c9d6fcf62f0 100644 --- a/userland/libc/src/stdio.rs +++ b/userland/libc/src/stdio.rs @@ -458,6 +458,35 @@ pub unsafe extern "C" fn ftell(f: *mut FILE) -> i64 { if at < 0 { at } else { at - unsafe { (*f).unget_len } as i64 } } +/// [`fseek`]: an `off_t` is a `long`. +#[no_mangle] +pub unsafe extern "C" fn fseeko(f: *mut FILE, offset: i64, whence: i32) -> i32 { + unsafe { fseek(f, offset, whence) } +} + +/// [`ftell`]: an `off_t` is a `long`. +#[no_mangle] +pub unsafe extern "C" fn ftello(f: *mut FILE) -> i64 { + unsafe { ftell(f) } +} + +/// `buf`, `BUFSIZ` bytes its caller keeps, as `f`'s buffer, fully buffered; a +/// null `buf` leaves `f` unbuffered. What `f` held pending is written first, so +/// the buffer it replaces is free to go. +#[no_mangle] +pub unsafe extern "C" fn setbuf(f: *mut FILE, buf: *mut u8) { + unsafe { + flush_buf(f); + if (*f).owned { + super::memory::free((*f).buf); + } + (*f).buf = buf; + (*f).owned = false; + (*f).cap = if buf.is_null() { 0 } else { BUFSIZ }; + (*f).mode = if buf.is_null() { IONBF } else { IOFBF }; + } +} + #[no_mangle] pub unsafe extern "C" fn rewind(f: *mut FILE) { if !f.is_null() { From 6ce9eac22594c9b2e03177abe2db0d62410d28bf Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 17:55:59 +0200 Subject: [PATCH 02/22] The wallpaper ships as src/wallpaper.rs draws it, with no JPEG between, and `image` leaves the build The build drew the wallpaper, a committed JPEG at quality 99 held it, and `src/assets.rs` decoded that JPEG back into `share/wallpaper.rgb`. Measured on this host against `draw(1920, 1080)`: 3,491,059 of 6,220,800 channel values differed after the round trip, by at most 6 levels, PSNR 48.34 dB, and the committed file was exactly `encoded()` of that drawing. Now the build writes `wallpaper::rgb()`, the same width/height header and `draw`'s triples unencoded, so the shipped file is the drawing itself. It ships to an image that builds its one reader, the compositor; it went with the `assets/` sweep before, so an image with no compositor no longer carries 6.2 MB nothing opens. Gone with it: `assets/wallpaper.jpg` and its licence row, `--regen-wallpaper`, the encoder's QUALITY, the blocking bound (a measure of a block codec the file no longer passes through) and the committed-file check. The band bound now reads the file that ships; with GRAIN at 0.0 it reds, 636 rows of one red value against the bound of 40. `image`, `zune-jpeg`, `zune-core`, `moxcms`, `pxfm` and `byteorder-lite` leave the root Cargo.lock, 700 packages to 694. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.lock | 52 ---------------- Cargo.toml | 1 - assets/wallpaper.jpg | Bin 761404 -> 0 bytes src/assets.rs | 19 +----- src/build.rs | 3 + src/flags.rs | 1 - src/licence.rs | 6 -- src/main.rs | 5 -- src/wallpaper.rs | 141 ++++++++----------------------------------- 9 files changed, 29 insertions(+), 199 deletions(-) delete mode 100644 assets/wallpaper.jpg diff --git a/Cargo.lock b/Cargo.lock index 75516233810..150f17d9bea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -420,12 +420,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - [[package]] name = "byteorder_slice" version = "3.0.0" @@ -2757,20 +2751,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" -[[package]] -name = "image" -version = "0.25.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" -dependencies = [ - "bytemuck", - "byteorder-lite", - "moxcms", - "num-traits", - "zune-core", - "zune-jpeg", -] - [[package]] name = "imagesize" version = "0.14.0" @@ -3312,16 +3292,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "moxcms" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" -dependencies = [ - "num-traits", - "pxfm", -] - [[package]] name = "multiversion_no_op" version = "1.0.0" @@ -4343,12 +4313,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "pxfm" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" - [[package]] name = "quick-xml" version = "0.41.0" @@ -5760,7 +5724,6 @@ dependencies = [ "getrandom 0.3.4", "gix", "gpt", - "image", "kernel", "libc", "serde", @@ -7204,18 +7167,3 @@ name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[package]] -name = "zune-core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" - -[[package]] -name = "zune-jpeg" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" -dependencies = [ - "zune-core", -] diff --git a/Cargo.toml b/Cargo.toml index 983504f7503..6f22bf5d2ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -202,7 +202,6 @@ getrandom = "0.3" # `classify`, so the host reading a log volume and `logkeeper` writing it cannot # disagree about which files on it are `logkeeper`'s. toyos-wallclock = { path = "toyos-wallclock" } -image = { version = "0.25", default-features = false, features = ["jpeg"] } # The digest behind `NOTICE`'s record of every committed binary file # (`src/sourcegate.rs`). sha2 = "0.10" diff --git a/assets/wallpaper.jpg b/assets/wallpaper.jpg deleted file mode 100644 index b0863088b14e9fe073162bfc51847baca8412388..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 761404 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 z zdpKD4(i|E0Ajy9U3M8TcVYDsm9*kiO62^AvNDG?F`DN&MQahmMPTpu8IryYGwI}=O zGa0DWggFV|LO^WbG1QKmgt5|Wi4l$QnBlj^dR=D~J^uKnLpfi-=iY7#7MQfML?Aez z^H{F}bxz*Rep-*go?I%DN44Xvoke_|Zy)j*U|8j>(NhmdRoP{c{*+A09RSxzz&qr- z;u`>lat}FH_gtOqpwVu?}9GO>dFgQJoz^%5E32w<9fES>HJt9m^`&_B0w=T`eUef)Q}KDWPwfB$XGvlB{lr?vu2-a1Myh8v~D z=aZhRMsfheEV#YxSCOzE1|QZVRSc-pWJcV7gcbQ1*j|IST}p8rFv(KM^vpPkmS~*$ z2X~P+7^JzKP|xT;QZ&_g0oVDZ2!g1r4PHdl(S{h3Sf0M!n0K>Uu35jrrL#!c5T1ok(b({ zQmaNEd@mkV+O)Ch+lXFKGmMof7&_!FK-bPck<4Xmky{P<#4#708Zvsr0~5=_#28qY zhq6a{{GlXF2{!)?cb8i36P!L*U+xsz1Ehszs~n3)$dRI*NkB+QOvdb*<2af-vGb4w z+xFq{+WTIoD5m57Cn>P3#Z46#i-xfiOY!{!ZU6N9*b{Y~O2YiFD;WMnlHS-&qr6b$ z`@OmSxOuKrDlM52VW_y_=#i;*;1bJm2#ML6+pX+upj}x0XR}siRYOHVqN~s0!^WuQ z2@eCI#^jH3y@^l2$sPK07lT3z1aCSlmQu#urd3{ZL{j?a>+5g15!@wMzt|Z$rTTv`o z-(vLL1nH^X6WMF|4&+vl(hnBO6<#rVUuO>b1AIX>bJ0(TTfBqzt-MCeDtUj&YR3yO zry=9wZyz4VKY(y^GM|ge5oJblx)-A1@`cu)a8B<6GE!JjV+S4-x&?)cg(wz-?}aD2 zCMV$0Y1uQ>>ah{E)riJTl(SZ&&Lbx}1{Er~2piT>!$r@Vi#i%JYdF0?QewK9$WHY+ zv`Zj>iVfhM>Cm{i9q-%J;)7KtP1w=4Ze|+~gL~B*RWd~Nk5%UN*xW@df`9{{sgasPN6+413&LwJhF z$yaxdV=xLf)iz|V^=U*lJ8;07NYzhlw~QY4qV#^(p&_5mZi~su-)~B%0M3)y~ER9qLMa^8TwP2Q&4^Nj57RZ$mB|C`;Vg?p$MyP_(aweQ4rU4kX z8p?U&{kR$~w<~ZF)i9j~C;+!eb!Fl|<2|tY>mm_xj#l4eqb}sFHdPgqqPd(HM2&Gw zJ)rhyKno_ngU(~E2jnRZdI%E!uovdV=}uBcPE9=U4Pu1PmMU5YfAq@29okK?O22J9 zt{JxTm4{F)7nW|oFWW$e5!Vn*YQ?AomgrG3!FIr%nWlhHWLbKj#4{L}`@wMGcFs-g z_hGc%D@`7J8hR`?$W>CU1p=XuFl-H!VN5dL#)B`7YW`B2N|4ReKY$UG{mYuSqcOF) zo?294qJF^dHYkhM7|x*pAi7Uy7UZ$z;5O>}(2IdTOl=BvcN#jlxhB}X+QL@6JdLvL z7x*Q-LzeqUJJa0~x(E_tOl)#!Jsvsjhnv7OEZ>bVg%r*;&>aY)YMZ7Olqob18@~mc z!diNcwyl+ug?ObhcJ@dbVRGubKjs^28G-0-lC5vY9t;t^Prq%%+vy&PuCUSryyuPc z3*TpC&J|Q=Ym9XVjP$eDz4D=iJ$BzJEo%X+FShS&PLYFz7#q0GVdvmqYyC^C7)`X( zlcE)u%5aulJ>2gfUS7KH);FKQTXe0F2Y}fR3er0Lb;>F^9d|#0wCQ2-?;0y04`|b+ zU<@QXy8J)48LkPdNrstz=WVAS=JSGg z)VB6PZi=DWT%U_%BkJ%y4dfyOplefAg&mD)KXO-b2!(Lit|m;3OA6~PdG!o37daiV z`wWI4z|XOi)}doevL4}Y?Z6a>1;ZOUP%}xl+3XTRRYo|{%H+Q}UNWO7c`G0Q-Qv4r z(5_7C6?t3rYSqjQF@N%cI?ag|7We^XVlK?$CeavibT6(B3yM|Xj(&R;#WrX9 z08&BKLyRbgVT*$D>MJvo{h=SJi7SIYX1rVqO}HLh=xr%DpH@t(g#x=>PBuiU)#{g_ zz^h>@r|~AL3F_~}LWdsTpPgF&1V&kbO$B&g|3w(VEe%|!9eE$@+le0hCu$Ef-gQ_j zf|=vLZCc|!LRK(>$0df=Y&v`s%xH`X{wADVLFdr<=?RshEmt1BB9grjnHO@=gx17; z1?(efA^-W%i*el1R|)5wawwC%f< zL@Ug~l`W`~4=L@H!pN9QgwjZ5v-{B&htWa|sOm7=`!HM;MJAvpNfL44*I%Ed3wX5A zdlwcA7E-ojV?#J!RQEOYNBxpWV86z%l9A37SGpH49n8td(%3`GfXjfdWs_fS!NJb6 zi3bZ2unA`X&4AmZMf*-nZb0EgeYKJkz(8MlcA=)N^VnMe>~j9lXytHsLg6|isQ9_0 z>ve#I$@;UEcmXY0c72xNTij(XFb>gyl6-O!w8OO{r0uSQSR4Yb`K+K=tjaSqJezK1 zeCbS_L_;<%lL!hvk2VJRXw1{%Me&en>)f*v)jE8O6e8}4xlldIt3v$dRF{UQS>Ug+aAViY1vG1Bp*Vv9hh2KH+ded1WKAafKId1+<_;d zS%2!R5=QQ!en6X58*)&KBy$6^QyB$@9$jAySyKBpzJF?`-qK?g&kdjT5@srd=1lHe zsazMffPRV-t)?GCfvnAp_64zcR=rvqWYZUH)Bf^p#Nk&OMsfH9&-t?B;@Xz*63pGL#OxHz3xt+tbE|mCDbOT$0nbZYL|qF*935yAug?|IIDcY$$6j>N)x)Twp}NFD^sK znjd?xP9Ub-l?woIni9S*g~3nhqx{XUk09&eF5!mym?hO>xTU>Pp6nr#kKnaqp-fF~J^eTBC4382$PPk#aO(LcQL z9@zi9R;@R6`{+SQqr5Rb~+9l zH&2$5-%ccqiPR^H4Q@b%#XIA%8*NO-Jw651Cuw>+?p_jJe;O`WfCJoo_xIEAS?Wri zOMY3oA4+R1*JS)MB&~@{>5uL2ID3`Q4W?FvU*t%FbJ=}}_BKY8R_4SXs}ljF#jJu@ z-`dPutggt}HQ3Ll={?2F53Bk@UM`Q{jbh@?MB5tGr2d|pV%}*YyOtxC&l(;X!5YMG zijlSWk_IOzrczk34AJ$a`d0l$d4@e}z4yg$wk4Svd@>pRfXoEej587PRsH zO3k^WJzK+ALN@oy3Sb`{&?Zlq^9}xeyp?$hi63coRD6WgQ?9P<5LT5sYC9PMBe7%D zN?-?#!2kY>g~uNld2=)kMmKwGE6EK8$%7;6lQX;~?pG7pc|QpJF=gr8rz_buXm-;6 zIB8>w>d|$0;!54OsH56b>oZ=KngRc@FN@5pOu&5!$Y73vSAvXl`G`X4iqzN`JH)ud zdlq|_U5jiLmCsJ)-IuD!9a`mKDqH*8^SM#kOa+2SMx%#?Eqy_IIa_Dxhs;#m-e_=< zYGypUZCHK#+++!UPk|H-4c5p^zIv(>>imQjPf_F>Rv>psHQa5z7}Bb6){#$jv{gz0 z{r;tN!D>T_aKWog1vuUyK~{y0Lh(=DBWiAMIF;|R2jyV(y}mlDKj_AH9EnS$}3uL;2#=ChViX&IX;+ueA%QOIzL6*RsNgCNCyG_e5 z#9`un_@>NF#nIa0YZP@}TqQV#(-oAHW1^%KP)5uSzh5@%%sY|ym$ zqk5BczfsK;<)7E&NFW_e>{Ebw!re%iaw+m3LI--A4Dc5Z->;fYjBcRExk1(>0iy9~ zH@rGpkvA1KjTo^XUE{{SAGqnd1}@evG_=o}5Q%~NLR0&C;>a|Cd z>}t6SXZP5_@RDNuDi~oeY_Rtj=2RqBf^Xyuz|yKY<#2*aOF`zU5D_s+E=5)8i(74= zxo}_~)3<7@@Eg@TopJf^WU?11A6p^*vS#jeClwBlQk3(@J6)Oo-2GhVc&d?2LjVrsx`$o*0E4Skw!>MhW zQq$x{g=&R>h=MykGdV(?K1B&dYz1$ImprIrth|{pjVIFW;5hSPpv(YYi)42l-Qm(NfR~ieqFo!Q z8oog_KHwQbeLwO5`Z8P5w>G|0aOSb3H7zpu@ddn~M?71&;|8S*pqXN^9mKHQf%~fQ zh#sz>GI8n>VbY_lExZ3aB)E{j%@}=1AZ9j@8qz0I117q7j@!^fD6LTV&B{-6zMJ`61M}$8vqAyug_-eR*Cqy!RB#NqxXy(a&BA zk$DqsaLmZ@Q*d1wH`qj5&Hv8Xv#E+X8Fn)db7CNx;)l+c!mN?f0dX(xr)9x!?XhA~ zU@mx&yuePR@@@!wQ_A|EAsZ{9@q+VvSrnQNwud81d1Bao{t^LVKm&?lTuqTZg}|pE zcZ%)n@MspA`58gkPg;&BiCDkR6WGV^XoD1_JdRKVS=|3jxwYleN8{ZRb~(Q!r^wuj zhQRDZ)&Ea?A)(a0$q28Q=^D_b*;F${)xYl~dV@;~8pMY{MI29_1D~r0rHPWZyZnKh zXDIoiR-O{}T7Gt6yf=5}uiY?9+tD34%C-O2&Ick^LmcG#yHO{Mgc!$0mjT?M$n5P* zGch(UAeW?p)5R;t#&`Z`cEF1(Z1X9r--V~R8rakc%n)-ri(4cPhh=cW?!}vH^e>D} z-}VxKm!#pitSef5#3T2ocZ8MW>pRg>pg>J*n5vBfvj)x|2sK}(?TYU7bL-sz+ywLZ z3pOj;Y29y=M;~f=MpTT67>1L9w#)2@9l8Xinr`{k{K4Bnrw3vz#0DM*jGHNQg%L6u>ZxG$)PzmV~dIS5vq$yq;ls5UzOcAB7bPRNS_OXaAPoR8 zgxd6B#A)z1u(i=!tg0U*FufOnSb^u@+o51w#y>XzTie`JtiJZOQk|(uV3Yk{ZVoGgtLoqtKBjLRg}hFikqlZYEf7P zr%lwon-)WAO=3(W?gIn~(lt&(LgD7BjQ9zgB2DsOE zeU{Ih2=@Y5f9h8N%2un(7lHu9xw-VpyxBDnc}MHmruVmHK;em`NYYu3;YkO~tx~aVM|LZULp`SNaaPYvRz}pvzY9sP zRx?Xcc)n0kjgTCD07Y}#2@7VMm0mDxvvmG!j4c6B`6b{1ZLW5<^7Fr#kqc2YZW19L z%RQo$b^lXi~R+2bdv1tAF4SWN5C$e6eUv6(roM8DEq6CSceyC-=OAiBLe( z2qRSb(R6ng++)MDmu@8}W}{nNZsEFjjg^hOiwk(>%v>@948pPTN(%bU3b|`0AktD+ z=c{tK#MkZxQb-p(Yp|fa!v^e7#G8uMM_5}Y+n6&a>i>IN z$_!#xD#z@=p0j@5)AB?CI`w4@Vvvjy#}VWJ*TpGeKhU3&a`?Vgk`~iOf6c6cdhb#} z41PEqQ5jU5Apdi>;+KyfPPA6w9o8b2($Y1V=oaySae-{K;F-5ymdtan6K*t^+SjjI zj?e6r0`A^T@JYs4OZF<1)!d!%^iM!a4mr9C&<2hYxPRZm{H_ zmMz1ra4j&vlB8h167|)iXR;Yk)~9^(K!SV3piYNjUk34;Df*&km`~N!1>8Q?gM+g< zar;Nx1*d_|ONPws%u5H$G}n}5_mAL>*R@Wt+mM{`!~!w-p)`Z=1~I;B!X18tIXkmX zuSe_`i-k|_h0A37OS<4EuLG2iH95h8WAP)+T``zRCP-2&Xy0D9e}gfBCPqCuayLbJ zT%Ch+enqR6vL|LVsA5rylb#u;_a6p6an!i_FZQy^ICT2tkoa{^y}_NC+B)&SyDA2iN1c zeUAMWZiW6t91e{G(+LjT!FYO5Vz;w%W|j+5r4K1i z8?*|L*`9POw)dyeA@EK4T`I$6~L+nRKvSakp-SQq{Fg@UQ?)U$8^wA zr3^=TMu2LC{OQLPSjB)`!Az38ov^PTj)u0i#>w-agF+kBQf<((CnZ}@x-rWDk1T%^ zA_v<-#(ME?=*dVnaiAqZ1x<$fno(PNY1>-trw<{o+B*-|8Z?~DU!eo>dh)URXJV5( zK>2&0044S2ES*cylDA@~VFXQuzUxIF_rfa@_PmWw^NfLig(3|7^C!u zWzi69;s82Ntyox5KTK?QPEM}YDFRi)E?^qK@ zRrW6%Lry6~N}toC&k=-?_&K4FYaSU`XUf%o9h1$pYQ#{?{LbQH5Wa$@A;IPR@((_W zWnw|g-N@Bk#vR%iIkKLPxQAeirtIT`N&5;RuIUD89<7YnF+u?QVT$1rT)Z%K@?PE7 zo8q^lsnaKM+rN4v32=$u_VNDUhAusr|OoMIuP+kQAnGL(rTk_b4Auruw82ir9Ymc&RdrmytNF(3CSh)mJJA z9^UJPTd3En=0g_^GH(zT{za=KzG!5qmAT@`$OXJ1%1o4?UsNlV-?8NwJdg9tf;?{M zr~AEH8YbNm_`C8Hb7r=nK2Zgk&L?x=1o$Cs3wMOTrLAV;LI|MYVe%{KuBH5<50U;4 z^VYt_0uthVLD}<$YECWsJMKXiNs{W!8C@7z%Nq>Pfpov@1fsvB2=!3hnOB z(n?PlBE?518#MG^Fc%$(8Og3gZu#tL9q0l8l31#_XLH0#NS8Su`DUypi)q+46Oh=5 zdOJvE1pBW8Bhr`?3i7FqkFo>VWdB>p4m0idgxz!GVcOhV$X@yJUex;;tNyK}30oAbL!>a39ipz9*WVqG zeRcYdW6s#uWZU6>m@t^PK71^AFXkpQKfoe%S!KLt_8ohLJ&^>;s%3xwJCoj=ovWw) zx#-^Ue1=xSHdz9P;{;6;{O{UpARyFo&*;0of@6;rWT!d?H{MH-Om+Exd~b2woN5}> zd49F+n*1ZC;WefUu^^V-aX&HFgJbI+XFqkuI09kKx4;-ov5qkLMhj9w+YzVzF;`3e z2~5KttLzOEyAIbNS@4|Sj4MW}hrc!#Vhr{Ky8Q=#fewyQbND8GK&=T&-_{)F-G9q*e9Jn$ zu>Q|{txop<+AK~%R|`#a;mMP|Ix9>n8@V%;w!T4@k*!!oBEb|sk0B1^*{@A@WJMT3 zM1|ogED>d9TXdrX!E{ARf}yuGtfZjE^6RElslAT&g5;lZ^JwNdBwz5S-5)nUVh!+e zFivKsHZX3cp?76+R+;#WY#bJ;rbn9~$FOMkWMT?8l2`2w1yeU?MMZHW9DV`Us_<~4 zBjD)_gU*06ZkEeZ967a^DYBQ0fwB_1JBpZEK6t*)ZI6$PxN`XVQl~#& zLDB!c?X_DNm%A(I_wsS+3o|##YDT)_vt)Mzdy1e64s4ayfmt*=o zXv?Ba+%Ic`F2O0QAKA+Y7g~!7WCJsi_M{u4`Nu0n!B- zX}Ez=vUP}ZftY#Z+G4vw02yeqyF>_>sJ_~jNT*O1X*&41Jh)iRn?W^+lHM=N$FApK z0zKUa$b+L5Zh`^s=hk#dhD8*}Yx^vs9}u)nT9AERO~R1LmGGc8*#olF)S9g9#6@Do zUf1Y`-iBJ3@02$WC4Lw|u|tmj^_`+>)WrF~e{VZKFO#7e#?qgjKDC|mTel8bQ4;Vt zmT<0pusQVm#RAHbvr@LO*WfF8rX{#G6Js2lEjM7E@ksuNRZRW=d z+sdNhpf!(sKh)3wul?pL+Z$TIX8S#K{eYL;F$|+8Fke(xyMrE?@rdu@{5xU<{3tC9 zo|SkBs#jL$nP7*|E?0OQSvZf)TGSvKTt~yO!?Z^zO~5f%rXewlD4;bN)oNqa7B9)A zogg2HKLm<0>N!I@+XaY5(cEtV{*eB`+6+P~9K}pr97h{TU4Ij70jL_e$zgtXdzc%< zZdrDJSzRX5erN(}KKL_d#nuX37e?1gD7&@*!JfLU|q`VyFpGD}| z!}YB<6oEtlBnQBn(&(1#?ycv>IH4UiA+9gvI#Ha$INMat$H$OP3~{q;e2VL}x4w+r<&%Mpu;I$5AKEkA#5iW1`~T?VYGM zW56Z?29I*D*W`%%V5h5>{0U`oLnOIt*q!UQ1&cw?u@+~Y{4?^-o`Lb0PEyI=ya6_k zFitj|v`i?XyB$>XNsnAmgT`o~?H0xPz44XG&NS6feDbnO&jnh8QP05;8e_pD{wMSf z^{D0rat!o5p>q|4>BF(*tUZlZdBB$`ef)8AfhMmRC69xG$QR2wuhpPV^72Zr9#bQ& z3q~;J%glK`PUCt4SVYHXyF7siH|M0b&+xPxc6@^-OHQy~K^nIU^Tv+E4(>voJpeM) zh&MvxGOpi`WF=Q?{iWi}QDD~OvR@}2!0lg$G6|H1ER1Y{j+NC`=2Pd@H;KbAV(Zv# zV}vE@8aH?P5@B>fW#E{x4jS@k$nheCIuUHDFs2?hx;eGF(z<4iRhiL>vf~`S zQX0jdFmrWoabypV2%H+=C(UZAMP4R{4P-4EVYE!6y9;F)yEOWcTS9GGKLpL%-6JPS zYXSlAYRxptrfPL9g!Z8{Ue<<7CJTPQS2k&+=Qdqm=s6ns+jk(TAOunpf7@i#yfw+# z|3QLeqU{elkK+qTtMkC7vE9kn| zt-Ee9YJ|giJ!#q@ah5rFDyX3DenIHzqh>y+0QmV zhus;=)*>!`C{6Rux!Mw+<_tz|hwtLj5(y_x&Ctco4NK885p}Nt6XqB;Fx$yQm~CUJ z?gRE%?TERsjiKLZhm|X^(b13?`)aQje3ye*ZHf+1zvM*-y>YT%EO{6BlBC8~awjfG zK(4iTCf{_b(f(50a3KjCxU;a{koOH<$U^`E6F44pYL*jj5*Zh~J?q`FWB)eEtMHV)L) zOYO=Glt9e&`jY1}$n*l4X|{-?^?%59f0paeb{ z(6?q5P$~B>=_Bp<%h(ACw>nETpwuVcF$q~h}#D6x6Q>qnW^?AcNqsqZZRZ$e!?j^k9EdhW7uA<`2ybA0~bAGw!y9kpgg zz&-v?>6z-Y9=$%2=y2;Tf(#B3+*=p{ah#M{6$`2*X}5BtNX9r$SZQ-9c~4sjGo@T2 z%uu&Zj3i*G9e=^|Ih@h8xOIQ6HL$|Lc>X zOW$vJ4V?#C@XNflG{{2+^zqE(78&Ty;T3)#uTi)%b!~o>KKfyV^IzkmhiKLn2Fx|S z@~kfEaq}O~HZwyx3zW9nSwSfcmf_eT@Xmlf)bb=!Pk+{VY<^ipf_X=%;c3jEbOSDr z?v2sJGz&bbg|E)lNzQ%G2*mVO6@GUxB5mXLr%)J<7brNG3(EkDM=a^Q}*N6f)!I@q=C?t zf1kAqrqT*Th#`IlvhdDgr=+qfckB^it1{sD44^3-LdNzihm=w5mp zL(rpvn>y0?hFl32wt0S(jgVox<8>6UzF-Nz=&1yWzz%=ii%W zlM3EJhYdS~c!mO9d zVq8p$cs!o8*M;JpiLb z5aR?LP~rebiv8R&wWh;hw+37`c)EoTBzoW$He~tu`rw zY~A(0jI2}}%fdkMzzG~XoM?fvK6{BE{Sb{q-qyv3J$B|OT_+-(l%9goQfnAdg4RgK zBx_w9Jp;?mF62~%8AuQXfisIp%fw-f-pM**E6TtW03;$8YQfv@wb>9q|J=i9BcerD;796* z3g@_Y@nW5W=%v)WlN(RjKyu@=+l6@!CiyY7%5;jp&Vgw0+Irn$QZ38x5e$K9zlupV zy#AQHarQ0y?U=~=5fC9T)FAwM?1k3GYmfGF0VSII6Rb)9GSMFox?9+tIHIRR&UhJU z;SnLp%JgXepZo-a63i9f6qr5RuB_g!zSf8 zh=|ilwAqPecoB6PJJe|Cl%=wu1CIR#oBdbjua& z^96Ctag7KG`g2R;nh1Dyi@q-&1~*{vaveZls;PelGSx=p=DPV0iqGV<_kiEoSeE@x z$RNlA4;9E4n4%AWrom`as(#@S94-K6Sqgs@=J_Qrp;-OUJ`W$XL(~5oJYNZ{d;*B` zkkXO5kf2;Aha#cw?$J`2M|9_@9joF@EtEG>(Ivam@t0b1Bn2{$zh!@TiNJlc`MjTN z{pWd?l^Y9r(a(LZ{nSdFBOA%|DbJ3BO&R^FtpQWOE&-NnAoi5(0W-Y;W@9%h?BUDZ z;8#5aEz<;#&c8DUId^3I%5_2X*U0WgGpn)9Ds|s!D`X`K(+L)=0!-`r?QNKB*Zig0 z`!V@j)R`Cv12_HKgFxd1>WukoM(BmD3JHv$)(Zqk4|h!_x?f_`ak!mwuu(0c1o>zW z8;JPi%0{%yAkZAtj<)jpqg@D_LcC)kj(fd9cqz{V;Td1@G%-=KnrkcB!1Xz%QuMC{ zG!+5AGTsw+_o1Z#{GE)t+xxU!ar9i}r8Z1K{<8_5{WE(!!I3{fz6xtmW5b^x+=&k$ zHRp=41!i_FFiMCK-}x2pv-2wTJ5NI_^F2$kw<&8*cL<4%{ri(#U1PyquGDvl&+I(;Ai&Mp)8llpYHj(leiGL|036&Y{E zW}JM`?v;_2SqLra2}WRhDiKee#FKqTakBa!>jWDUiCw}8q0Z8XU8r5Xyg~?K<)R}K z4O0$N+Ws0+gtngZGXq|20|f8gye-dW<>SR|51DDR%NjV?b5!R;;}xhNRU|^kQjt*0 z0W#VHGUkxx5i#}n_&V!P{SP5%Qy$oJ|HNx6wMRvFE|o&nq|hTok|P4ZFB5+KWHP1Q z3K*D~$o{{JN*FExda#B%Dgt$Q)fI5BUJeIL)dsZyC6%jHUp{3dw1tUEi&lXOQtt@* zFU}&{cQN#PbM+V;xerCiC(1lzf*%DGs1PL1ymGaXq{a@zcH4e1@6vb#b8uh(y(NAJ zG1vK_9f?+PY5s1?x(PAMSyY+PU-D|t1= zQ&dNiEenj2_h=6{_i`O4o45m`a7fU$C6tTvJlF{7?7n<4opD?Hn3GkXOtwjy9I`)e zW37D{{j{8F9D%7Ge9(?-MbX0iQ#duW*p~1%5uMFD0uI0@5|CTK@6tBt;X^u z$8akhnar{jG+c5$Oq>4X=E-)Q#df_EmTsU?rR9h^$4EJ?0swj6SEI{NR-e9d-8yIo z5_w<(;y*BnOl~ga733%S-^9=a;X)mXMQ*J*{q`G9I`4eDnuJOg#XdVs!08%OpJc8w z3p&O7K;C7uN#glB9Xy7V$F;~{iTgRn^cD>`QSxX`eWq+iUrj7_)aEe^bm}|i>@t#? z5#ZB@e1AliXDaVea&{s=1b3Y&%pBvi0_i6O-O=k7)VSoM9=1=ds`*Glv8R8ws5}mf zN$VI^|>`7ktewXKFlD+RT7|#aOn$~SS0(bO_;=?@AO!I*{r2FJy)1df3^n#J&dK(-&oU%3q*h9j-waJh+nbI zpt?AEp0}MHLh9CYGkkF~Y2X&s{lGL_pjd@s;tweuMX;OL?CuA>4bT}ksC*r{!ywFw zJt)hmT;K}kjn*Lc;jS`;AIAo8E6}aCc^H)ou-K+PgAKkcxxv!Cveq|PT7LJ$h^=)C!WJ78eU+~I7kJWbCc8a#K{)28e-mjsDOMP!a z7j8tumnO5O;pWuh%QSs6pe^=i^mvGk9VpHAwf6soaiz4GfVEoN2!Jg~av3@?>6PiA zhm;v}{~C@nqKx%?z6kwsTJhR-2Ew8LlltcK9nkOqE>?)adB_H~4JyyGqFOWfd?zt+ zPu6+dfjIdxUbWePB9e3HehP@*0G@x__Y{=rt0DKtwCATkxsjB{DWylGi*@!OifRG7 z|Kp`nMS=|O3M0I>s^t^vA{0&{(2GzBT?e&L5E$mUNr!$rI3jdijC+K0{R9|h(fZlg zdtFo(Q=Xs%#!Vm38u41|IoraITolIr1_z&{T~W`_1?1nfcBIeTr&oYY%n3l}BNh=l z7_B~Cmzf3TAO3EhjnWV#aX$NfM=Po>!T3G6%pPmXGmz?+p;RCcC&aOArsk47jV^Sp z@8#p7HBBBLsThrpW%GneR80cz2%$Tz!eX^1gl2*J;h?rNnVYj>cvygqo=?OSaHgK( zBgj<*`=4j*>d)ZvI@?C%@-xn$hGDFOP6+DJqD)jOW@j$sNi~ zX_c+3{s=0JLG$l_8b%u7>qqLMJU(9ExJ)k~uqv3$`7WBLAX$*D$fMrsn`q=K8n!wAG-ans)bJfE`ksBb@B1f&dc!fIGaX6d(W@CEITmdAHz2fwUTeRuOUd;qGK|r$ znN<{O9?c&R)@MqCk$J((oJq0;0i+x1WxMN!k|H8gD_VQ0l4qRlfM=^uG=lsr>J`sY zO+e<~J>H5FPIh+hT;LZ}qiOj3F6cqmE4s%e86kd z?+4*9*J!^!_3Jet-c*!YtxTTY37!<0I8s^jdb8=abO~PB@|zzYFynSzf0P(wh>NEb zl=fA*^br&Dv~uFN+WroABxYW}jrnX?#GbxwTnyxuK{Co;g7^~Q&>i1n?;5_SW@=Mo zA?SbZ>R?){c>-MV)-OwuLvZUboUferH@9NvCTY7TdO+ym+Jddf;eW2@8U;1|S;1aV zEDwu1J3Ay-SE!lMooRcD3L#bWP{wG$dbqyY5MkNf!^6taetb+vd9prO1x8mBJh2?s z#-$$n277{2W70LB6Z|NLB9X)Es^4>Z*qd^hb3O$uA!da>+Yg^V=eZA6$~9ml<=RG~ zoN+n_AGKhJ4;UtS8CQD}<`I>9U9@o2rmhj>NnU+ibV2SOT5X0=+?eR)KdRxzXuf|= z^XQPP{R#Mg=5>J)GxdI3av%ilPj!w9*-@R72dCKJoA^n7MMQVV4jcGIHK-(j=h4C_ z)La-n7h8I;jRMQvA@V|_TEqRs{52iK_QR`iUSE{Ed>TIvlh*#5!60Dl*VNu)GGQ&C zB8Ec>Lv0v9#cI8QwTk=p+!zjCsWzh#?f_ERvHNk?at7;{^=BHa`V$OGyZZ||6({^} z%!aBkgMv7EBm0&#WSs(0$;q5rtHBUieHk9T!80ViHK7WVF7|(kjlr#T0fY_nAoh>P zr}23FL6x;KE(K7E&-j3+I0v)pA08pQ+!%R{jyNNMS>dVx*uVLd_J8w6h2@lEn)ZK zRsP^Q;?XmLbgqPN?!{FooEMO7n9SPk8NVtjn@p4|Y4bG&Tu33%gljf7X@8rEaS2Mq z42-mB4@RW7Gqr+AD*t|nEvhG6!0q00WNA>YED)^Mrx5ebHNbVmS7f!%j;Yyrr;9%GkK?5Irmt zy=0VQ)`d-Wj{-&>aSwPxD{;&8OdAta1+xV^L)wp*@3pvzPENGHj@_vY?qkrJ8?P z;c`B>5e!2XhH?IwiHIB#Wm!6f=-}MFj;nxF1k(^JK>B=5vfR?}=FBpM`w82Pwu87q zoqC`+$?hvdQn5$Q>1YAEe`K<#>)SaSNMLO#&qky*?X4y+lb>X9X^I}I>Bmh*C=K*3 zGC-el*&pIVnze`wa#L%pAV-9Vqeaa%d-)QsPI+L%6VhgpLeXgtZw>BA?(S*ghj{Mw z2((IeT|kLXF9@viVoTQ~&4hj8Jw3&@IpKm^8DpAzA=QL6EEq`7o~}~&&O~E81e|Jq zvjz6#I4R7H*8pFSP2@D?X>IWeXEL+^@a%Z;-XHRS6!*5 z)&^3M9JhgLvj8I~Z0b|QA_1@uJtGY_7Nerv#^W3&tvQFEO&2;_;b7z(M@E8EjR%md z7O$jtCHQm5Wvl2}QIm!FJ(MjSQ5EhRF7kPOI%N$IP#BqYfLsEFVb5dPJbAi$ivxq| z1eIaA;*r+amQLMXNUw_DrQu<*{G6U!r@9TkP6y2WfV?_#u$|VSE|iYg4LilW! zHX^~YoRlxO6K)}M6(l9@p|e?FPWBVM9ek1#pm7Q_Mzz*pGc%_`v6dngXksi@Pd|7c zi`Y*{VPcDXWCQ_o*z})N+A4)4rmh(b!iO}){{cc?MduECURmE6tfPTJ{@W&lM%t#c zp3Yz_KKxp8xcR_Xj%v-OtXe0*NnMk8ZcfxU%i;T%yg{-KEo0P?s zyoZchQEutUJ>39ma0dpKiKr_nPZg^fw_@9C$I|4W;Pw}vg2Q1~sH;f!Do`&F%X$ZM z0BOqY>p*pb!@F;l86oclZ?L~~q0_3&wBSRTJ|_?+w;Cu`dL%~Q*=x1@jO0BeaW``^ zxNqlhc>k~UGE?gdyJEjCn{4liBw9kjk^AG=-0YcZ?%PVnO@aoFk2hid<$qu`<7$s_ zA3lAVl%n35g9z7+;Yu?-_>6T|=yYY+rPsbU?p-f7Aw52c5jtDyvyLam+$9r+j%ZSV z#Kmr-xv-Tvd3Gj48LUODOB*3{0#W!j=KBN^Z>Y-PLb@lKfh3^raob%HG+G?A#Yw%< ztZUo|{UQ3$4RqBmg5Ij8LxzGFE33Za-%&0Ef`YHkFn>8`>uo2zJ2}2e^CvscE@TN8 z#T>TF_}Bj<>1)87sM5Cm@2&`4Us065$oejdO+F+!jz4Uo1&X+ubdG;NY;GLxCv?;gJE zS}*sq?aZ8Wp7Z?P&;8inMy=?^$PZp<=bN_lCY4R$J zKQOqzdlgGEno_3jhAy2}^&%VQetjP3QSMgDLKG+=-XGnOkrs`A?ej&wfspur1`v%4 zW~cMm$ssOza2PpM_mJ|hRnnNw|5Ipt*EFja>gM2q-)M$b{ax_?&W{dV2ah6h*2~S< zHq1HeSV~s_mt$0UZqm?^jsfi`puBbMB4!LIU}3iP+MuAC9>8Kak^O1*I#n~edDjcI zfT!^RWdSA)D)&?x;SjrRuTMs%EDO08{|TrVaRKZZs=gr(JkR!KG192|U7$#H_=hPA z9w@%iciF_!JPMMF66N@w1+&#?K{@@$B@%PIXp~yX@eg9;E*^ph>mmyCTh-^HdjI|L z-P?`}pZ@Q?^`U-Oy}N z8+FdSzO?!~&dX24cW!`K_;qdo6u1UQssW7=n86@I)pdp~I{hUqWg8d6?D6KExIOkM z2m|2O%b7<5XrgWC0ADU=U|yLD3@d5Fx7DmCoadx`Ujq6MPFKYvq?+itrIwsuT+ zt#=3_Icg|GRzzDsB{Y@w*bFg0``K?~Xi-jOAs6$MF=rl=63}ja?I0tB=6i#Y9>faf zgc>U;kDlQE=<7DVuORrMCT~+}ffME)Vq-}JazQZv9L6f69a>Qc8@|(vmzExW#)6~o zl%6H4d2$6{a{0H{{Ae*J`gMz1%n>(E=)sSqRXnnyc(5V&;CeCk%1*TcQW3sdq6a8- zqw;V3ge^|q#!`oDgj6a&hT@rfhL&&TY#-(>BlOa;WERBydsD=p(-#V#jxdTHm ziuIQDWu_k5o7#V_3Nc?SIb2Pxp3l_D20u*8671FZ*3aS+{C7|PqM1Oc4k`_o^RAAQ z(g$EosfXrlyg_EB+XvEnC3-0{y6W%3rg2EdglxUeUI*S}DNhH`%8fXZ8M;qo)IPiW z4Te_8tbcOVV$6Pq0j_0w_g#Q<1RriGIrEeQxSbCmDe#tUFDMaY$F~*0@_ggS&w90z zh{?8KCN<{SY>cDe9Sc|}$*r-`FjX2mCT{U##ign(_Sd21?2+S9NDw~?vWt3ZoF>#m=e$$487%?e?mm|1^@&_kSW}|v@u&S@6Hyp%G_&gJc>w~N^}x7!e+k{UbD zU40!D5aHpKUbl#D)WB`cVV@gZtmuit%t?Ia_9q0XS#mDKebq6##aCaZb#fY-lvb~V zHb+pCwgAOME8o)eIVwvoPAIyd!=F7!azBB>bGY40M*C4$WOQxse4hET+{_^k@!Xo4 zrg49(Qca*a)eaaRW@;|~DI7+@-bJjx{p%?qGlt|Ze?kIy1?tPHX zb|J7{VgW3pRizw^AI57^=EZ~n^MF#5%Xj5KKk z=3`qi%0YM440k*~%0{CLnZdPLm`@p_lfXA$f)4%1zfc`NTc|HlXI^A|Qh-JrC5zrWiMoLi zxtGWeF&jvYrO#{Zsu5AXsRXFc$(k!4mXR51cntl@+xW~B*gHbv>pf9oC#{x~$Y;Qm*OC+}6T}H0TEyZuQ--D?y02W}_0K*|-V%p~D_o6EASn#pQWEzer zWbbqw^Nz9-rD-qlqo=%LN`4?y*N4gT3gy`f9b19_F};ZmGYB3XK6=gx5x}2my-1Oo zw=uOm=vu!Xc-}B=7;1*sju>_S*1 zVnw|!lprgilp+BV((92f)u=v)AI$;;Lw*0kNAK#hNaB%9#=~oZju)6(pvb7NAnZx~ zt>5DI3VrdQ<>)aE%(aZcb4cyb=u}qkdIoE&NSbrq!|=$en@wkhyr|E7+#df#W+ppX zmE9(eqdO#mlvOTRyjyVL<9T>Z2duD^xqx!*Q6eEj;xBcTBMZS?!(a@78aN7vvWZpD za>Gv|srAU1E80BRK`giACnFUi*&BsNm7KCd)VWNX%J376LDmoTF+BF{$n#hhjPM7c z`%s z0l%bz+mu(OOy^z-x4`j7W>g-d<~;9J`A)JJ<#e^_B!5hCM!1M3=SBQG_9U`|5G5*D zkGY4ej!NF&%-LYS)8%);K@;P+1Nt3sOkZnNT2`O{8Nc3|E-2r51bNZ)l9Y66G*w3< zZPWG%jJT>V$={!whZWZ{Q=kmaLQ0ZZpYC$$akV8gELEeJV65FWE&1Xus-H%~l@`<2 zZTwrD;k?9yIrbo&R$^Oi4XQg=Uazu;7B`iLYdYO;{||LuDV65dsCVJkDufs-L)bX? z(37R&W{HuDv_M(#3*>B&Z;=*{Z?rrSZi(gD(V%IGPyC*>8xyLeR0nx zz!%F|k+%1cN`)*|1Y4Z{xhFc#?pan{67|RK45bOUGPH3c(Ze1YPKOf)yuDSKbE?v4 z`mIr(WkK#pz;*j*Y5Z~?xXZl!K!ygx4}%TJVq+v*IWxh;cJ^Zg1x}D}`(_E^JSY5O zJRO&E%4YQN#E&pHFm2b+kz*wLx~ZCe${>U;QWS2>DxQ-!_=HDeA-gR&z-ufvmH3f* zO-=j1?*!G3D5b62T{WymIm>uG#_5(bk0KtG&41mGUwj6Ox74gMv>H6(+i)E{o7tev z)>+jcn~CrCq>WG829NFLbibnE*?_Ze z1P&8}eSf&PY=e?(W1Z zKO!NyWE`MQ4x#Qqx2OQ z;ag!+uBA+6>+ryXH6BO;#^m%3dSLYiZiZs;=yv;o*}+XH z)YPnC+_$tqQl_orLdsl^5Q+f0jIQLKKGj{@!3c8;d>Yk?>C3EMAsPBLeH| z{|v1`F0u3GRuA??QXcxIn;PxZ1D`w&zKoze(=gGDoL`lN!+Q^rRjQs*9{3PWo44i( zTox?)Y;?5s0t@oQX1p;dl?EFJ!oYef8s|Axa<|5Ow=&kpWuhGp{i)f=bF6p=lpo~E zDR1nG|JA#ueYZvMR+)A!u3y7x(Exu$LO( z*8@hsbR2}0x1ifEFl&;`R7ZAeyee#d?WqsOqZ?vgtig;{=HdOkEbZ#l0t72~3$$5Or{=fZtH zF4^aR*nesm@G#QoR2pW(^5T?Y0^R9>TH#NfMlA}wjyIOG*sYhTydKp+R?zE`S#kOJKYkcUAiAJ~de6SIv-%A*QRH+ZY-G#0YD0 z4hA*55!O%c2zv=Fpc`nr43G`=Xffm(j&taT3~Y4{Iiih*qeh4mbEuhs7%Al1Gy_jU zhb4&dM{r9j1}4l(YT$c9(*+oF74}u`ZhEMi?4yU$kf5CF>h*BT*u9K?pbw~oplF_R z4G}S<-@1B+!3sBH;3kln8RpC%{5a%M5PeS; z&f_ z1esw!tTD_mWt5JJc$EoAay`^j?POu1>W*8B7z5Bw!Zt+>=+^qn2<`rCO-mt0Pa;p; zmK6rc;gB!^FU-Y`-*|iHCR`d{ywyNq>giyY?l&STD{Dlhy8g8+m{_acx(|cQQB#bC zPu_0Ug>IW#jP#q~&(<*8*dZL}baCeeiA9T_`I(0Jzh8}q{mi7SgSdYz#u9b{SrkbU zwFxr)_6yVO0??cAVJ89>i|y^%P<*kPaq|*o+XVQnaU)9mztcfjU&L-lIyPFMB_S3! z=Dw6K8@XiB0|})`6@wdEYnbzTw<)HqgO}Z`4tnG*(51-#1&XJr%z)%(uC(Pf@HIuF z9i+$^u`Vr>K90(B;Sgp0Qym?q%CK#%7EA@Gz*`l}p~`u8Kh@4cxek0@MWN1ma`y+J zeR>7gLB>T1!?jrVh+18Vn$iehjm-1&7H0$&73!~wnA^Hnf*l)qiv9H-q zJF^}U!8q2z+pLFu1r4LCTY0f0$Z{dD1FbIIMtt4i<=`OjS>0Rj{5l}bQLH+Q*+BUX zru!qL@-mM_!%*quObHrVor-)<&Gb^(%Fe@vXzKfG;V{^E`lQ~~>`?iLkQgTbg%^#E z!%OW$o=MCe#g10L7$UAol$~p7m=H)A3C~z#iNh$A`3EHzX>Die-rL*OJLV=_AW_*J z|BD1GcRck`Dj)eSbyJN-aUCz3Ry2fcwQzpV>mz{sm6@Nw6w2fX_Ea{$M2?qu@y!*} zB@tX<+tv$bl*8U3{=yS-CUJ{{VGN~!E%hrX|rFMj40y2Pya7wJAQBzz2rHs6` zhNe8jj-STiSJL>=GzbaFLHR-a5)y4my#SG z+0#uU*onLF%F1{of!ux0Vp$8UgaO4&CK&zSsR*^@IoXu!(o&>H=@@wH|0e4lw=x9L z2v?%;zUr%TrcxDCN@oaW=8!2h0t;3A*!o^i6gkv3kWjeAt`h8mRLxFlekqh(hZS7W zLFOEufc$g>fZ?j*xA(&~=n532D)c_?);T#NA!!Qy{-xUxvZas!0Y?vFrrTIM<8zz9 zA`j&{jH>VDw-||9N*)h+e?s-c*#f`2b9e5()#NpILCc&;aHX@cvZid5mIRF@R)d+0 zk~3(33%x;L9l^0%_`Z;*|JMP~;%zKuj^EZ`T#otPlh|DRP-HRl(=?CheL{u$0bAuY zI;|fi0@Y7^1b)ytG30)j+!(7t66cmd&(FG$WXIIH!$o6IXw z$w?`5Ba50ad&3Sw4lz>CEE$}vhm=qif!D69)~l@~Qii86Q|>0mZ&2sQwq!+?^|C{& z@6tl9D=ynC&|hhkZ>yj6!yCbFoV+?43eav}LYAF-S7Se-wk%%IMzN+}*+L!15inOf zQqB^i@^V-Nl!U1Wz$07&e0}OOxJ9;CKs+@18q@(c4h4w-iV8Xa9+R4(n|DSKxqw!V zU|Ntl^C4O&=OuamrAh)hz2bKWFVtfE9OGM%@B48i1p#${)(7}`oEqj3;2JYIM8!nF z1AKD!7EIdm`J~|`UwX3@trzj!hnbH0CKLy|LzfCzmpT?bt#28NS&|M~nv26WG~a4n zpWCGYdhh051W&C)^1b;-5^yy_55m8I(VQ!$Vt+(d5dIBBy@1`DL2}V*_L^MLBxl6s z2mDEL_ZGH1AN1}Y2TZ9bi4^?JWy@V&Fl$OtRK`!~U?+9nxXNP;4@0kxOx+uAq4J}0K zNF0E!<$(y{j(k+Q9(ReC@%Pm~G^v98KPU#()24d<((90~l_1JNL*`yZIjhp@WZMo^ z{*Mtt8MJ#ZT`^B6PG1J?IqOZI{~tZAo8z3?jj$$aIG^nu1^*Bu(0 z9l&hT3Hltn;WQIdY6A_&rPc!Yj5we`Pp(DOU%|pZV)(Bk46(j(w_iM==J-oU}Ets09`--laW^gNWh!?3mzyjj>1jhQAU@;$AOcv71@Zn7w&+ z^(&NZNbHNt&jQE`?mwf&;1W-4Uw}NeDo5^`)zw!?#*Ym5< z9D)1M%iQxUa=onWnU<+7z&{~*X~Vc{2M=D9BS^*y%4h6Mwp{}SH)f6@)vcB>A{TVs zL1h_2&o0V-8PKvFJ;pL+Zam&cpWA_PXM9Sgj%3Ja+j{CG0vuwinF$6z86EjYyH6JZ z&#Lkvd%$yZqxdA$hF`o?&_g`%kLR1$W{ZMpM5!CcNKed}%mh&lf1x%gCek?r-Sx2x z1x}F5ShXNfI>qqER+pCU^3$z;O@+_i7hVEy2rU-dWr`V89HU#(knpe+`~&mtB3x`j zgF~7jGNDHh#_yIX#Cu~Q6LZwG-gBvZN8EaID%GZX0N#e@W~jXt*}Ih`A|p-iSvUJ` zm{xi?m-b=)d;o!a{~QC3mg@hbV_y}~4xDwYoMSMc5;Cl8eiixx`4Q&ktJic{Qj>Wq6MRqJ1oELQfz9&;v>bAM0@WE;@JSXG`#pHVNhpbutkGsFb(9sgYo5(8$_ zDU6MgfslK#5hzq7^rRRjuDPMS7YH&?{i#P>yrlEOQL&;K+`)U-3dLCYR$s(_s8!C) zOlpF4&*iJ=PBv#7Fm$9A48V%%+g*rSsTcFhjF^uxutL@8qlBU-7vuXgo59Kh{sy4D zNv=@@8Q*RbrW_i#_(UC_EJrpq%^{$S@iRavFmsJOc!c%Enas=Bjw>7eNBaJt>7~Jo zX?lrj1&x!dkjRbQ!tbDK*SjDr zn`Gw3E-DD|&#HQ^9PClY%P$Q&bAWd&Z)?+d9l1txA*M`={A9+L1NcwvLyrz_!MvZ+ z(DEn;{W?0RtaH+|o{QeWI6NG5vO_RWA=9DRTgtCU|5|KO2TRtvgcq1PJNmlP%+*fh zC;p5LrCRCO^}Y3gRk@W1oA!3#H|M=aMq0+NDSLD|#e> zKC>hz%>nPhKt-7x8Hzi1;Zd~0zzU-;9m1>o9t7)&c&Op<&%|L%%m=Kcc@n98L4F9% zMj$WGu@sw|Zev!fiDoM=Kg~8oFk>v(|NN6759|-r(#(2owjQ?S+6A5k>5(U$2Ce5&0X-L;(8ks!QsAq_;RUw1WhFnWjv`ilT5KE$0_@}%=67A z%43Vu9ByUw$t^ycaFNp5oTGIsAbr{4;E7`XZl~M>pQtZUON?JELF$!Hgq>DaOf`hW zN6;=woyQ$&2bfnU4z|Xa0;M6O7$3n7pz(|Gyr=;mQu#JJd|Sey*L&LdO`T0{g z3^*sx%r^$PB@P}4hHVb3n%XN}gD=$qDfdfT1a^E$Is@Ey{NtxdHJILn9~RR$UJM3o z`ew1@_piScWLX@D7)qczP4fdUCh|~_IyN}>2h$vw%>Z{biNbgY*KRV^ieIcohMP~4 z*I&Scz5SF_O=Zz?!Ctt`85_ZM761ZD+4EH?mn3{6^zBREC@4eRBNc_^EF`V^h6SVi zyi2pDY{lY$P%u6YqdtgCXB5N|p~db9oLfEWWExANB?)K}y1XEU0=P3hvQL7UdK z!kh(u#!FOhdl zhLtTAySLiBt%e#9%hlXWiC@QgA|Zj9>|)V05m~DBpr*->;}!F^6y|ms)9r?HRg6Aq zcG4Bd`lz`^e_rD18vu6zaT&k)4cpm6U#T3>`1<6+P;BD89$b^jS5`XWO%&%C7>{n( zTDkmFc+S4tvm)2G3k(Mz=fhFnJb>c@9p)}Cs=wc>2fgCZ4d$oaRhX@eKeUoJ+0N^F zESw6Z`z@{5DQ@`cm26ZSnm1^!Fdjo_Cm5Tk{`KPWa3U|1D3N~?A3aXbd41XD-*45y z;e42s@U}iB8&Dd!@flNIhNEIju6Mk4+^h+-CsIyX&G4D~&WYxO=!np%Q%kmyR`E^~ zk{i;C3}|C;(oadSs+rp}vQh5`(=Lh1l;*VAqc9GvGwVtK;1VBydCI^@iCm@y48G@d z5d?jH;Y(vvICGPhw5-V{s|9mr=7WB$feK2yXI)1F75ouWYpej*5CZOJMq)fin_-v^ z6r+Mg`6AOIUK^{dbXX5Hn_9}?7Fajcc)^_;k9l#mkN=mNUulB)26X2~SVRunulL~c z00SPQV@V6B`UEjsjm2gqI^mJjUd_STiOuHn&1ZwLkWK{PuNb#0mmE->%l@R4LqWh> z;l6Re=dXpI_yrep+wqmB%2kMFWd-fn2(wRJN0Vu5hBX(3d7Zexaw;{gF7eA~(c9%CS;0IY6fIY{;2IykA&hhuLYk1-4v&MW| zcXHGT3((0-I_Di522#EA_7WzPEW(R+tZOhs#kH-o;~H{byB)PMRo5BU^ulq`2M1<) zQ2z7{Cqig-lqt?9Ay!J4VUM!&p7smrAZP*cz#sZTTU8EMovTA{SLqK|ht?KPROp+O z2N7#0Qc2Q}tD%a$;)yWb=hF1T=KOMJVLhulm-g=rV1oi=ecU^ghqO9;;_`sv%qF=n z6JgFx<~V76_^~6D6&3}<7C?$cio4U;Xp5ABQ91I}N#A6;4Mxni9!20_a;F%HM!fpa zm}~w+%AdX?_EyO+4jUe;p|SO8KjH@4^`1zF ze#ls=Oi0^D&CH_dxb)K3JI+f&KrJnK?@5A>%ZDIzlEQiDjcFO@j z8HuDCK=^pzvN)dS?;~F*##r0oeLdBfu{S}DG_%-GB3gL7RImmee<%(fSD0H9o`;7J zeb(;)r=Zjf4O`cwV)t-^R_B=YC5Iwd_lM0HF!;-|{(%_?b~oyZ07$?gxL?htmW}W> zx17hcVSX0^n9?*W;#jmvS&-HeaHDo8P3C(8X#ERfm9N@qgHP|dMI|*pJ`mGuy;wWl zs-ogPibY3V!`QKxWXdXxRSkOkD9#R;pZF;tq(O-eF4iu)j@r>Z5^PEC){_!Kf#-^a zQluZunklLpM9VHP#uE#nTa+hj@>j!GzCl{Yi~viTDF6N%@(5eJL${FU)o~;?Nloep^Z8eSBPBgh9SRdZzmHY&O3|I?B|^PzWQcCo7o&li)TW_ zslcsq>AykJwRR#Pyy{iX`GflE zi%R9E0shR0RDp5#2a5f6h@!sp)18>54JzixeuUE(E#)u}(139WFzvMzx~z+EQ#*0P zYr&Po`@joo2OMNiDM6BgezThX^y^M91mk$5gg{+Et6FcA67{CdH;;u<$YE+?`Y)Nq ziE>0`NJrAkWr|Y1b@%+|o_=5xVwA2Kdt&(TOyGladx&wunS+ynqZ!!H4sr^1W?84Hdm#B)q zMNJ3+S>G3{u$xi#)`a)wVsq)f&t5V>Ih%jU==F4Wf~=nE!C%-F6H`6POnmmZ^_2`b z2}`_#(Z*`MnF;Qm2Ta0I4EcmNwAIlQiTX|ImToRCGooNjmbEmhP1bu)BVDS+z*+(v z`>z9dQ=3)Q#Sr?PfHh*!QIwQ~kgN|Kx~7!EU8ZauVBtWw&h2q=<@ATPiO90fvv|S5fkeTG zxn&+YD}MX)JCH>HwNM0ymP}9Jl1u>-h^f1=PJxrFQJnMI1F3VIdVZrH3VT2t4E}cv zmdUfV;p9iM(5@mGkv>UC;2^eC`b;aEXBA_$W#l0Fd?xapjxIbO<|exCwKB6lC4jrwFh_&ruwZ{Gh0M5{ujmKq$_^e>0`8de* zg49NX#vS2d{5QJVlTY0{D~yD~VgV#kisn!R5%%hQB!p4x0lW242PDoTF+V*)`;M^S z@_}v~mSjrJ8-oG1NHd2Q@du@MW_mp6xJBEuV4khicTr0te)rH-AmqAmjXh)W8JxJ$ z_;3OelAQE==x&gY0V28qO32Pd#*?8U^-gtG?(js3h;OIB>MyE-Fy%;#hBpDL?uBim zf|tvi{Jf)Eo@ul0ODMJ8!LFsW=Y-U3&XhMa0GCPlx;{Lz)ook*IyOd5bHt&+6%9!~ zl0(^(rt!{}c|Sj?+U94tMKsS0jEteLK*teXX7N%w2!xquEOJASo8~K6c$AHerrXqQ z-}(m(Tq$7f=w`q;LqjOhb6uZj@dmsGSO3(X`h0$@#twJl!V__QAUR8%j!Xb_gajmn z4AHKijtCzCcp)@duM-DM4S-kz$!0z-je@SFiSA7HMn=-0JXmls%@Bnau6lw8-&485 z{X>Mqxm75nf*{$jT~&h08%TZeLY9ml6)rpy9ZP8IM>_P_2Y zBPM*43h5r?l<~JjbQ@&z&SA~%7TBY@&;5e(6qp)h=#G$5qp|0NnL6iAhehAUkulh3?n>T1U*XeEf5{Oc|l~cJdW-OA;nwizs$K0Zs zUPHcEj37BGSg@$4FV121HY})Frwe7oBZd$rF+|Him^k;C1Guzl-Dy1zj{QG) zEE60Wg&}Z8ed-MrwnGPO1;c}8L97ugrq)mgW6xbou+j)Z- zbwc&_bj`qRqnRHRQGY|0a0QI>Bbe&df|*5?Wrh9g;~va4y^T-;RuB9K_5#EsxKf$l z(oyx{0olA2z=3~FS?;%m)cGw|o>hK^#yw1x_nrZG%#`0+3wQkzaMU?`Z#I zdO7DivH`jXH zsvG32pgiReR4iJE+D5)Q4&qi|VF`?@Y35Yw{F9IixA%I!h(1FYn-~00>JuEkG>g}- zHebBVA_1W+2mrhujo-mIV7OB+_Xm%1VWIec!*E`l;TO9~6dF?#e=5NO7>|8Hc(FDZ zRf+rlOx0NoI#;m%V@Mh89mX(|+JIvpbA{1P;ZF+Xc(o^I)jM}E>H=%qkLQ`ro0)c8 zB6}uN_w~ECbwcQNTCYW^*R(54#%(=s_vDbe!>{$BsxC<1oz)L@&uk&~r=8tpT!L5! zkUzECybb~EEKNpC#1K!MW-^eE5`je);xAfeUXc3N`Mh^g|KJSw9>4S2o}8 zWD$V-_BB5;-H+I0`y3E=VDc7&Jf42&0hhpsx?(8Cpdg;!z(A*q2SwbxAh27Y@q9ug;GPUlf}h>7n*B_NO- z?FSq5e9O?|vtf)kX)tbYX#C>PK~mwk2_C3ELrBa_lMBPm61D8yIzK+!mBnmd+$U=p z?kry`lL0K1KqvfnG5aY~=!RIw!jmXdQN_B@bm+|#8H_}lv01+G; zb7fUEzXzWt8?sL6qw0~l(BpJwZP0Ji>kS0-(8oB=A54}rZFZ#DSzdn15|n4{iXkr9 zgv2cJSB>RzQ8t;r51j%hNN0Rr?27-W!v5p!zp~}9VmE#qw;VfyLwI30^;vmCN z>r9QA?uVs66O~$C98WIdj-qr3d8>djK3?%hUo_*Su!ZSac&-VC&t$R+!AGa#yPs3PTFT{vusccmR~BRx4@Ku z-B>aN)Xt#N{3w3ghF;5>0=D=p%)Wi5U;chQVt9$E&Ja5kNT~kv27Ws7Adf&!I;GUe z0Hv?hCiCD*pkg7Gm$qxHlx=x=8GnDB5qTl5d%b< z<8r|(@JRc1v#Tp)T=sOU{VjpNTmyfo5RtK|T@NLAd;d_I_1Xf&61Tr<-p za7B$ksd}*<4RrnPG;e63??`u3(P(1Vx{kI2)Ku`C%9QVaxrylCHxm8F>jAdJ8htHG z;c9T_u?fA~{ubn*=W{ZD)`rasVp+9|_px5YSHhpMsPty#XXny`>c$3r|LaG1)-wBQ z$x57-Vyb_Vr28C(ThA-6k2G$?s0PkP1}>8?{q{@n=Dr~}?5<&lA(Vl4K{x$miBT23 zeuitW@xvEHdt!k?6XBXcc;yv%x#=-)rxl>{BQ#<=T};Y>{9S+-&7-XK2>F;}!I9RE zI1?onJ9xbIJ)=r^W{Z5R7{k@WM?NtrIYdJZbiV=kl*|Egyxix}ag8LKWIuXv z3#@HKD6E0b!@Tlq_7=kx9bNgfQ?&NeQ;eu3L($)q5%$8(i$SlhxEXTQHk_IjzBj+HiVLWSR3y4vKclgxIt|1N~Vlo;r1#LVgPb+(8i} z!s+g%=Rs%CY6oNQ-wATr=>f&~8TLR=)X{fmSyf?IEIA|*tx^w~k{n4c?85e1t+e#~ zBxyJ<7JCG46;vz=;nMdC!inbpN(bvMCyq>3^EpVIxi=#Pl2g$a4@VBdFU;y%k&V`5 z`}b8CS#L)ENUu70Lo;q;-Vw@;j3-b$Un>M9>QQA&aab zstoh|w>FDgbWX-<-J{1;dXOaFa8_Saa|IQQdcx5tNBMM1&~h~Fh5XRNeLeusLDZRs zA{#ktxkm+%+YPu>8JSHH1}3i(7as4uQUO9@l^13H74&@>V(Cf4jQL7$3L3ygxv%du zpr(bdMdw{n`0I&d%P{^;e8+C}ij0sZQQfE!CDwd^{5nzy&)zM=)qR!RC~Likf&9g7 z$U>dCov9s%dDm-Ewg9DFbX^pm?H5*L4`D|Kf`3go*#pX{iD^P4ge<-F$&l_OgrED9 z1|8+MG7MN9N867Ekw1lDe_Ig8-0!d_4-P$73lGyLAYR_4tmZ?3OM9jz6MZNE)Mk{( zR959E#{O5S9yY@FQ*lpbqgWgdxoR`=WAe(gB&S5d^xZvLNAzY@H3Bs15K|k++;HZn zV$V>RL&jO}0x6pGhM80&=bO)Vdl$mk#=?GJ#E=iIqdP}n+pIVKFcxW4XO*iD5IGWr zCv|^7(EdH8R@QIqbYxO?{Vm})Re|rwt~{Hugj3g_(gE&JM8^|cWFp&w!IiRy8Z~?>SCd zV%mau_rZtZ$?8iCr$Gs3c3^9#!EfhDb)!_47~Agumua4bF{sUR$2VjcI^O>P-`U$) zb?O>Gq|&{G5~*W-hr$dRY5=NT9-F0JLk~Rcz*zlezWV5MBbkTOLMALnU61puv4@0he0-?XkH)TaQel*;Qx|^lugQ7CgXf7&ev`Naw z-&%@B=|BOio#Hn!z)=I(s<(oa2?YHEa)YqL(<)`r!J#{0jDhh*8?kZCZprF-vz#$t z!hy2pvb-^WPWsGF<@5;q-nBSJEKvE2ol5w-dLpq?ZgGJL zVsM;4@$Lu?96qXNj4Ee*!m1jYOX%arj0cl)@bZuN`BpjKapY*pHL1Gg6g&XC75$iC zDrGuTI~WRk8n9#bA^D!n%nZG6N19ijsX_dR5kGa+YZ2PfQR?Cb$6asb2lGCdrR?HZ z`frRFTJDz;m>i4=TbT5Sz;OGuWC^Z3r9!@bgyU+nO22?=+u>w=tZAWJ6CCc}>`Gc{ zo)AQNWK<~RU^^CS?q-Z*7qavmlAQ4eSVVajr8=;RV|a0 zmjz(6tAIdVtVQgvpV|8pQ)?o6-K^P!#+MEZ{JI{?50K=2{B@bwec&gk;1TqZq-I9J zDqb#;)Ukmg+wW~)GmRDzv!dz338*cApGqBcn!S{ngf=U^#H7DjjFr0}edE_K6;`BB zYMW^v&;w_FP>f_ZSbD9zOhq48BCVoOo_K6M@#1jgHOmn^wy5y^>~HIssSaX^ceXrq z=MHs|U~FhDTA)Gn#QQHHLntkN*L8@OLXDW@;;UgpsLD(jZv72o8Oh)E$8g9Hvq3#p8^6ch5sTlh?tObRP;lx|DOj%Xw#f& z5jdoB?pA=d#l2X+A^Avwr`48grh~&Et|x9SW!pxZMkU~YZ9H*b{c z<>BKK#k1doL!k>KOD@dJiC}YbwidVJd>CZ85AhrX8<#S*+z~(BTm(I%f!fo<;UZtC z(ud|c{@U(pnF8~b=nX{CZALZ6_299_6i4OoL^WSqy`A~rRDOSh zklnumCaH;yk?E$sVu*;8?6cS6cA{nDo_Bc#9k4bBv(9?ntgnJ!cuvvJF*{47``5?& z7}fppMvno8fsHta(gW({lV%(7K_0*wmIrhI$naN>3q^vEhkHGmw&6n3uCae1OGJzT zM&(Aa8@``y#><8Q2V28H5%bJ@2$?efTnXF|9}g=}AiJN1Pl0Jg_QnzwfdQ!CwXnBieYB5K>Z(H7C!6lc;S1Oh8yn@PRod{% zD^M#_Jq8_zSOO{WYvhdlntC1<{x>+&pctBgFi&op0C~y<1fR0U5W=AM{Zj|- zU%Iz`8U*$aT8z(#j$eLv4lMxe#0l>`#pJfCx)75maZ(VvFGI@Iy|~3iqY~=)>d^-u zAzvnu5l8;))(Z#`uxN^D#P4QiZd8l#R(^B01dq(|m^< zWw56nv>|kFXf~x`3q5^{9E}lm9N|p)l`!sVmXkpEu;nVVcoPimN`P%{Rg|gCl zx4vrUZ2YCiF5^zm5b}JwH)qQx#uG%czphff#jOl}p7{3RGP54Ny41c^0XtXF!}LQL zlU1SqnVwknmXJ(UJ)uUJ;#GZCH35LP35@gc8aUoKSOxPi(O5J3S!Gglv2>SLjCaJh z;ivXy-G%JI`w$>lT$4Ng9u2qEbEG2q~=wUoQ4y8sumOvPUAyAm65-v*OA(( zkhIcr(7HMJ8m6YPl3bjnlwsnccZlH|^%$l*$FP=_zzEo`diyy}JF{W#37pXqIbvc|JXV?XeuJgs)!H$!Z$^0^n z`BchGzC_?N;Q#z8&R8*jccZ-+^E~#-W<9YDOuZOHab=7V^HBHJvPW8&+QhgyEBw)G zGe9J=l!MY2ofwgPrYqiV#thuvbtFE!oHd?AiX?S=!9t^yXRZAIns zQ6=XEUZV?T2b5KzwX=sKp4`nsObP*8g(-x9O*&UeD-Rc&X}O&2e*Pl$Vj^sUtZwxx zPtLCe?OdZ;hN^C%&L1WN*CCq~4!FFUXzJf#z%HJND|GL2mHpYt?m}@8wtv1KI z#X&Sopk`CR9@4{s@!8*O#KArSg{8wJw2-2|l`#mhOKRxu&9mWH!K?d>1{PZ`812Lu z)ar$QfMQu!T@_0f_D#xwXZ3%`59`tU`A+L@TtTMbpM8gJ9&zgiI{$Oe9H9sWlipZI z!R3%kQ2tVbmKaGBUC5wuQe)}b9}c6_fbkC1tQS>_sfS~)WsqRz+we&oUOqRnL>bRk zJDW!}T+frW99W|NbI&^3CMf^-d&EY*luTuh6K!Z(&>u&4ID8Z0?UvcyRT;{?2^8ah z0VpM?v@1)CS$KT#odGN<{{+vaeYDQY9(buF1>jso4gx&xP}e$O%dn$-?0X5rLgaFn zP^8q4Uu-uRh7w#7ZgU<`eN3C(BmN(Hsny2q$=z9W|DVDD&9R7 z)5c~G$!Xvwd<}2Qb+Yc=)QdogHb*-0fM?&BDDFJJAB#jJm>jz&Y!X?n#Ll1q? z2J#Vci)6X)@R4SclUO1lHun0;cDed4zNDNo?-T{|B5>@BzFd07FMir=@i}~mXZUud zRxz)Y|1y*I37?}za{GCo_mH&d-R4rV@=^(i+LL~_G7-eZ5OTzCElc3INP2Wj{|>wr zJT%kL1PAA5X%$dD9vh-)bThZdomCh`<&zrTp19 z__blRvX}V{u_yCBa`gI?CsB78;(W0FV`=_cDR63w;3Dvjqg{kn9G9T12h3rWE6R7M z6ofZ|+`aE#&mb^Y7+#t?HV=ba=6@uXM3q`$!*4B$gNaJcy_!HYk_ZVEZVYIP{8B~Z zQt0`swH;VZvMoxQna4kFk-3I#!}4W%D7`KBISAv|M=y<=Y|Cn8INy}%PSJs zOtSLwWJJL>3^*72JA^?-i!AP#2E-UCCHyn6TA+JM`rw#K+Dh-iZCHwY(XMTBW)?h5 zm0s8SJ|O4#f`L}t21_up_0Vj9G;dAFa^e7*pFCJmr6>tRIkIbdy%xQSaf}I&SMy}iep|E+O z&K@-UbDVtu{puM+v@9HCy1m0)c_Ko$d8MU~ppqn-)A+|V78HRhD^wd+LcjmKvY24} zX=k=JX}~*M2UpQ`Y=+;>NWX1W%8+Kbc*N~nQNw6CsTJWf!PMbjK25NkRw*d_5oU~+ zP(ptLtJWtCx&7}_9t11V1b@tI)|L3hNW+1DG#SYm{QM`ts5qbB(Qb z;~Vys6^0%K%ZD(cte97dZ}9EW2L*5tN3QI82JXj2)9~`BfaJyPKRT?EMwd~-40t?r zK2tTrl!cSEwY{iRLOD!-<0%y62Hj&WK0lVy=h%Wiv{b zwZDJHkA1M*(&<)Pkgaw54BsQIl0{Q1)^!d0(`?B;uN2$$j`KJ?tR0wc9nYF>moik) zq>Gmq3u0ktmAtVZC&AQxjJQ8NiX%cLMem{AObyklqj}cJ<+!|YbYZ?aST|ogiSlT?Oy)*~_*ly!U{Hu-f41=;ZihZeVDZc}#t|UL_ z1WSxUHd9EUmd^O}9_jsgrVl)~=dB>CYg-mN__A_f=c_q+$Q5Mbtq#%`E*s8 zO=j}m4LFXnnXb+11fRD*zR>VDl?+mOa*q~-m6k&nRxrKJw~016AuklmDb(y%7{z|^ z<4>6a%oUSor2wu#*T8dd>$Lm2QAM&V8;U70*(VnDd6|jBD+=6^5{1bU!DG2TY3goH z_XA%~z}&$g2Gd*qI*D<=nSvjWv~=+iWG&vzOPDiL@Y^~*(0DPSXtPUrJRc+-luv+) z9QuB%**5f4kPTUaOSJ=HzFai8Ep|st9|ahkDFjc(M<0bDvGN`7P5Ra^DVfyyBi0}a zR6t1PZ1)A>Ra|l91GX1CUXS3$oMVkQOv80OUS8)4&o6=)1mhQ;@PfI(SSab;V8!IS zuOe%xSD1hY1G4*1DOS@WutAEFx%X^_Ip^EB3w>{qMa*&i5Sh78+Kv%VDpcl|OPM`E zSSCUW8XwO&l~clgi_ED{>NzlSmq5;ooMz{%KENXFu@EEz!j&Hq86%IM&o1!-vA{bA8;WvEvQ%(+6CzK0f`Pa8=WY#E1}(>fblyqmv@N z6|y`%p>bd?0r8YCN3Ww9o?n|biAMaW|JHo%C3H=u$m(LV>9h>%H12DknW?zwH@_WL zsu1b;vbvvx%FZ>n$P0=QfM(7MHQrfY{ZHsmjIC@gJZx3c<39w}lOHjG4VYEiG8#^U zU0%8h=#LaL>Oo}?mx&kuyauY6m|Ks97Xu=n9)x2<{_q~^kd8^l)bfVz5{at2Nvc%Q z79&UDGzXGfgknHM^=N*`zuV&~!x$Y3J6-;5u#lP{bKf^?#Q_M&4f6t-SPhpq-Q_H& zYBDkT@(R@ZG}f!WDmng9ZfFqD3D9&JX6nMQ6m!j~n-46=e-o-O& zWwHlZZ0*2*?)fBNVzi3myE`9D`leQ<7%?0>(Zsmwk=RXc_RkxJ;;@wywKdY9D)y~S z3uGfU8LTu=Klk1?n*S7zU5SHL*wm;05>3-58}1Iw!t}i9xk!`5uZvxetz?ySyRd1R zH7tW~%pS89Ao^$?N-4diBo|6%!P!hkk3#4xRn4W>-N7WJ@6V*&t7}FcU{$)7K0>AY zZc`fL3|!NG4eEmW=;#*8GmX{-Uqd#?JD6_QFY7k)0{Oz>58Xj*gM7?Pl)H>+Ru;r) zx25=Kx;LztPrq$RjxUGarhcJ-xCx!r=!~X<4b)`j(9PXBlnyet@0^ z&A$Z=zL@pLv>tZVKD?L;&Imc*TqD;_5m$tMpp4VO?H%v-d z`ci5I+5mm4HqS0mvqsGMxi=52RA^Q%9L&HGv|j^Wa@0xivEU8H@s&vBAj>&)R;H5q z;;55;=oo6*Ki)^{?&B#S55kQglEliW{<85il6fl3Gi2+JG^?<=8)Pr$CpA3J;$vxm zl`+9a>u$^`wI>a_&>CcST3-28qTdw7Ug-I49Y-4ZVj_eM z1nqb;Dfg~>KfvQ5OI-#=qgtXKyI82XOmKkz0Ink{O$%I>*5^N4?$P0w|Ih^FFaT1= zi93h^S#4pLo&~&$y}gKcX!{iA?xs*2ngvBe&xJeZ;EJ1%MKi_`Wt4mFybbn=)=KGZ zjEC`&BgpkeKt8Ur2#eqSb=3u|+bxU@+V<;NwGg^6mTp}(JChGo&*W-r&BD#G|J7XZ zj%_#fOFApv)E)tNtu;|+k*b`eYAo>Z(Vs5zwydtMi?|%#HxXi<+FuP(ocop=Kz>!~ z%(5BwJ=-v6RF>cbQaM}iXv+8#VOY--?G2Yo7XnCqK`DjpK=?tO46OT&E|AVg7j4UWqOuQ zDjGbB&{ds@%R;ktC>}Ye9tE_+L_!|+efg|k1;OR)aD?7O^LyJ+$7jO38J}mIaCof}_-%R#Lm0mx1c9jWpC$0{QC8y4Xeng|LklJyhM5x7m zH!AqwMh%tl9otA2jz9tKG}Q)gfMjG|;l%pG+z8i;dgs=5CgM&%3;6MHG({vHAs9YS z9WFqzd!>HKkrVA6FI&8rLvgzpXK{_j&6)&|T>9X*wKxUh-$z+6E_7yk6IklY;3`Zf z_V5FR5%fYMtkz#H=$c>)6O}fdSi2ZDtL;Pwo;GCutwdBU{4C^i<2%@Q(jX{m&3)P2 zI~BVV0L2O;DN*1x07-I7=TwfwUzkVC|H_gyxT1dYYXeu{eH~ z|K;>O6zkKYcC?nu#X|`E;3Ml5D~wYVvP`Fkxq=v+>QmRNIh7q z7OJ;*@f*EzwC^z**#u70uVy2zh9v%Q3RO$kwo@%d3tW^t1uK+=wgKZt1zjr_iXmFs zh-Y7OIjZ5awkP9`#<5(aKQ;{C)7YPXP=PcBifU&!9n=%5(%{vWZ2{*gejL^P&x<$$ z9qFa8xM{QUqro@~=CLlGNF-aEH2Q}siv>xY<>{c$T1Bqi0lPB_*PiTJp%8bh%+`L^ z*&Po-m)799!JFECh04BBbCJBbvQNt(wdpRhX<4DhQNp$VA+TADDePw!z2AuTb605V zCnnn2&Hy0~bXPWVzFz&iKVU0AFvh?RFmL&A>X<_fcJK&G>ytt2C&G+sY;j zw4mh6M!#Pdm+ZOJQWVRC=7Jq{ub`C9It*=2y5sA~NX@vKB&5qA zh3GKxy)zc8ZBe+YkrREO{eV8QD_>&*c=vHWfH=WN^?s^cokWZM%g6{$j6*08+nJ&? zSjyn|-hv;e0@8wkD9$HufzUJUBCNlWGV1Fc;6 zgk|ctxL8li8KAveXlQ%8W%ZS3V8U*FFCc62g?5AS0?alSU{Y-9d@mF~vns7LRkf2~ z2~zZtxsW~)16#+*i@l1oqerWU^z{fI1GJ@9!9$G6vF0q-SQ7sfncHHu1d(kaJUw^Gt9rGI>lY7H_$*|O{nbnBtDxYc87 z)ePbGd5^$cj$n(u8vVxen$yKOdMvBtUr8Rf;xhKobaFxJ`ANZmT0&axS1BPxI==Qr zbwVHWV(@jmc2NCfBwoLY_s6AsHuU@C56(LE>;Y>r-GpGd170-~m;I}=fu3URDtPY= zjpa>`Z9!FDl7B7W!22U}Ae94blsyD(Vepg4dd4AMs6`tY(iZt^7#DRCA9GHR$hDYG zAx4m{fm{!+39-jt&e520O~ntRZ((xRWI(5w6-JJ2q}K>;S#ix17T_EWB&OQ}$i-?; zKY%FJ-S{_>yB4@lap2mMRB{XRqBhZhcT_%4EcfM36J+b!nLQek<_v0r(gxS|DeU)0 zb8OJ&u>}MXvp}ey7qUu5D@yVyg#B^EJlONJ#8;)-#57b%n$pxG5U>&Vzp?^( z=d_fCRGO%5?wpi}9#G49C~OPP*T{D3{H=%^M=jhhA5SCOwH1Q~^wL7>7W3-(o`oyC>QCSpFM?v|$2D39-!0TVL!6&Gh_0y~~=%z@t z9mM`VU4K@)5AF}WND{Qh(axyU8ju@dD`c=$GntN6Vh9Jk*+}{zOA9m0+7@c~Pn8o{i8iDE;dDq^J`2 z0WZDx@=_17fV;@LF}Pda&<SJ)w)b!w3MJ1G_pI1~5mff8q%qZsDax`I-gC5x_dGzrgDbpL7R#3XfE63V=gd zOW>`b$)A+&$v6NP6 zsI$X?nyHNlEE*s79!ug3c7#%%>Zrzv?U$0x!F-6B^?djDWpG3}y%{9+n`Xk!8qXBx zRaI>pVfJg5DKPW%MnDDG3dTIaOGT7F-mJ<%wx|;w9Wu>C8}CO~U6ebW{S#u3ULeUl zpGI=^^>4QTL6=H5peKOBN(X9F8_QiG!F+h}nbW24cM>3U3Y|55gbL$2fbi?a$dbpO z(2e1H-gatFC%IA#9StMXmRpJeh4}APi%2bK93=i3cf}~23PrE$g%1a%?bNY!oNov3 z=PI`ty$}n1a5|xn!2eIZ`tb%r{diX<(;Z*xxv3n_Lgh!t^oJ_C$T8K1(2{%%U&bCU zL~O1O{s7nr)Cffft>4#us^_f3PXtrekuEglW9_cL0+84uFF5M}OQztLVmw&wlBS%{ zgVRxza~QtP<%~jZefTN;o|j9_&OH?B7vSjF6I7-C{uqh^@C^s-u_IQB zp)hl}kTvQ;fjbyRy!zLqxK$r3f=bJ9;o@@bpr};L$MN~<8e=+z>zP{)o})d^>g#_U zb-#rmCu^BUa=>byoVYcLt}5e4cOa`1YBI%~l5rfuD1?q@{5%99u!nUKd+odW^}UGM zr$31TyqfiT9g!ZT1SX|+@mBui71ytWARYCLTu3Y8&=saf*Zq=gJO-i&^}pBE5}db$#+sJ2?)Gkx)tfDZigRc zQ5A|pVq}B1v_Gzs%Uk5K+)vP}j)Ct3lshQycShyQR2{Qto4l@73boEc^>)+i(2sTc zFK5yNyx)21r!9CL_gRJ^*vFdT7^5po>wv+B+~)99M_klugNMKpB}V`N9f9VwZsU|A z)f-VzKc4#;tus}^zy9w^Pq3Fbf>HVZ2?eu#_)Xe27tK{ZviEwa<@F%&WY*ZyX8L*U zRz#@c0|Qer&lB9jIor8YdgEE{s{)G5=-@^c=t;3G^?0_aZ zk$_TpD~``b&UXb!3bv|8&G(*8Aj^7UdldWfu33<;8^e)A>oEA!GLqLB^yz+Vgc%eW z`^*9^XQWRn({qaKZ@C(x*Qk)+;A8&}jf|4ewYHSi!L`2>aRC)4XM|=#0s>b=y;0QQ zTZH`~S=DF~L4rH()!{&y_K-6}_M;zyn6y8lNmPE*%F}Q`!Znyp{L`~tdCZ>9v~n@U z=kOXB&)LdGcw3qcexT^PDm1hVVz-}ibhj_NycFuwj^FTKXJrCOW9cohe26Nn5`uUs zBNqxQnK?;J3g_|GWVW^?73Q2KX5!AsF*% ze{3>!Ygi-9_6UY=Ar`GmgZ#}Dy=o~Sqx9mtCvgsm%o%w}b5)fp_#{a!i)dwPiK9S8 zYLq(^WL081)RdN(uiO;ncYXg=s0paZmwhtD*zF6W;g|exSFQ_ysQJ*1@ow)xtHa;V z*Fs9gzlWo?a94tAAqIWIYn`?A9Yp}1VfKVZ6_EEK6618VA=1Y0${;MV#oVMN3fIDR z&wxd5bY2_lW1$Lgd^p;Y6zxG}%r^w{amiZ*V7{exNB?dv^$=?A)`N&@&Jg|_hyOS5 z&BH-$Sr9G19*lv64gc6DCA?7WYOwqp?i3Kj z!Hh~d*^N=UFAUcV8?KW(=V(m}W5rsX zQ4n)E_W04~uu6M~`&{75%p6@2gZn_uw0?M9Gz6G}^K<&uJl^}tD6P3%own8wZEuuZ z2L;osYN6BbC|m6n)g^W~RwHic3p_V>YojgJP&jyTxZI4do#?+%#LtrMil7{m}YxX?b=S>{Ejt!F(${pU-#eJsIVt7=ivl}tJ_V*z#P9hBJ#jgY01<0}(vighN zq8HjJD%_>p!%f*aUG8f%3k8=};|1vW=(T=1IUq$s+EU1eF46L~4qm=DgftyP1yv5o z(RZZkX{Tg7?u!n`VYD)0mZTu#=0;*9E)WPXv=!h#Cymn;SiJT zKaI9DbFCm)X0aT@OV(Wq6!?IWS1x(-3=%T1NLowFIWM6$ZA;ORW_w>OvK}VP8%5f| z`lgsUK%PZF>GR3|`oYJUBI<-U_zbR%GX)PQg?&%D+rsJ)mE1Yb90C90mjeE47uqj> zUh60FnrVb79j93=R_${%@yyVbdHZj?3TzrnBQ_kh*p(5PdE`p~>*xs*%9v&h>k)A^acd8=WLY-2yW9^e?xSlve~C zxwsK{c2v>btzK4=-~CLEhH(aO=LfK`Il;XTHsMRn!Pfe*Ir1D|G*O=%pLO?_bI#MUQV|y->O{qLa}wm6HKw93bCZre{5;&d zTq6U;cycH~i*5uye=%#|?A!|9wyO2}5S32Nws6~Yf-^^}P}-O~dJ zL@Hpze7Lih1T_~6H!jH|11U=^nY;jZ2S9aO$AuwaCXIlU8J_;Fi#8NvBrWu|4a-3_ z$+)>oVnQ9QZCQe8;aWNQ+KB1Exc8r~kMsleLk0}g0`a>!j_IQ4#4aV<;0dL#Pf(bL zeN&q4tkkSc3-JRSdSR9?gL9j$9DsD3K-pV;gB$w?u*Hj=|JK%bGHra4H-)kORxTA;b;A-wJPV6 zksVsSSMK81=ewN&urJkMHjli%^bhqef2_o6)P{6c$~R9eLsUeS1bBnTgP=_T+z~B47ekw(6wn@loI5AFW|J>``6(nhwClUF3phbzo(?(%=5FLumwGdl5 z0f~Iznr6)zzeQHwSFU|h+^@~)19IB$<8_*W_^UY%O*?;NB;u38jr*w;H)%y%p3XT; z?PbNh(nL({3*UspfGIknySip@on?49`{lHLH9H}wOP=)f2u<#jXVHbBMHX7si@apWM|K-5q(LTiGNl^xYg43qG z%IcZGv5jE^5;&890g+|abfl@%EYJ8LtPp~*zUV-zE#0wBzsDOKcn@JFr+bnCT(;{5 zg?W>R&8rVoV}mpCjdC+rcd1G8g-~VcO@sY*=;sQW-YiT*9Ik5})-hYQSvYs?1N^mv z{Ec&>_yC<(IaT;-Gj^m+dvGo~tq{|q{Y#ss|2EalVM5YEd_O*-J%hRe z>)N!++-pI-P#Hskt~S~KAry6r)Uq4Tvy#RHsO%#ChA0I6PU#N>M3#9?P+Wtj)tn$Z z=DdJRo8;`AR0U0w(F=8#BT6MBVc;j?YYrS}T>mI$?Sx14AteZSoghr+p~lt1okz>Xt9 z7H6=c<5dtc4xHt#4jSx|(u)r(NnUKNvT)T0I$cLBlsgaYN;#ULga6lDg)$r|@TkC_br4EbsnP>PNo;^5WHwYjfcTB>DHl!x2%47`We zp%bRq))|w5i}XELK-^(BVEVPV?B%rm0I%kA`+Y3^)5m-y8uH1XJ*~fHTR6GRj}l+e z!!JJA>h~D}ytnp&kV>`8)6yYr&fr8}n2+pNDpD6wHL8AW=h1GRVpQaLZxA58N68pS z`!$@{3=*%?e7Hv0=nYtz0dnOw`pr_Z9fsJvuUO&)8H2r@7@^Rh+&&*CL*~@-vj`Pz zcx(u>pNMzIS+sCTq~iWbVKM;t$vQSFA~H69@+6Poj-zze7Dv4Qg<_fR4PUwt6Lq4(~lxat=b12L?t08aGB(pq2RxHy|+B_1CJY-|_dFy!>c6EVHYi&vr z`wpU=IAfblCrilo&*syTMkDWx;2 z9aL_=$7j%36#mWrhZo_i=^}Kk7JCQ6&aAC>wF+2R_ivd8VO-%0IDT$X3LQB8BW6e$ zA|VEgq8&z5C{o5(ka(KU(}tn|;8+V8GR!1u#Jj#pjNlU-`wZpy_SRnHTh%a)#}DG) z&iC(EUeh=3{nE0+>KMtw+h3iFtBrI|e`}Hl8v$bqipNc2zB9q}^p2J4!`R*{l<~2q zvV?^KC+1wEmJ0FFEg`cf{P({v??=C$b&LEC$sxJZWsp^$S2N~6A;Eq1x%F@iNcD4H zj;Pg#FMPGGsyR(-MlohqxZ_feHUc7E6IBYoIxb^8%0_rT?K|y7C}?0P<&EG6VUb7a zH2AlI*QURHv>IoYyxyDUn|ZhaQVJhKHG}gGWKi-=-0}L&p0))zJ9QXJgSlqzNOZRh zUl+55=~9@W_Tb0UR^i1cCSJ4;^@Lnj&6&-CkSO*(m%1gSWldOzy)S=<+fvNSfKBK< zzuprk3_wPQ?9J*JgR{!i@fG~yoj`jneHLv~z^ z{_;2lkU<}|TX*_?HM{4%GMIhV7$`kr-D}404%WNWj6Yt0h#*nlY0@ki6O&E2mI{mS znM?*wP)9Uf3Z%P2H;dYYj?o6FYQ%@`Rs?&m`7cx?2x$D9Mnc<8C*w-jNjUGm)Qqy5 zU>qBF?ky{^qK1ERZsM?u#;CLT4lHX%@|&~uI(;c}1MUh)(m{1Hf1pKaEPKay%Bzqo zRQo8%8p&e&ypYrb7ryMYk<*otekw-R=@5VY?-L9ve;$mMUJR$C&Es(;k}uE8;~;;e z%`~|`Y$|We#+V7~Ofc`fEVc=kW@{O}xUGJpBN^X3#syZ!0ai$LYsxPoTy# zWHJuB=C?K(btb`Mi~|jQ%n64x7hN_-lv5nhorSw$!}db0vLpnpmpP?qVnQUFaO=Fb zL}5ISKc`nODfC1?L$dLW6_+!sD(hh`pS*^Z-(IR(q-uRJ*LAJbwe!4{jd!&YsK=rt zR+}l1mQDUR9Ad{$f45L)GPq>_47h~4o;><|Lh$6RqTJT1^I%Dfe$UP83w`GJGot!O zUwVR6bun*Lc@x}~3zSh

@)B_1Tq|3&kj+Q~J54L6qWMc`t`^ue*L95-f7AZ;1wi zVC+Y#0eIYI3_hSMl55$iH+BzboT~c(;pN}b2OrsuKhL}%--&c7sx%(ZxIZH$i~aBX zD&9l@Mmaf#EhEfJWmXmzc+vK5fB$s~H{@)F1#&7C8L+@fQOURSarkstTQk){pd;98 z62ru6`qN*NB#eP`f$RROhh1HdLs{4BE#g&E6@WwF@)88=mEbBCAU4$|ZTFct$ew^2E=KU=+|rBJ3H z@8IIYKf?DPf;dLxL|M@zg|bJPOe&zX2s0Ao^Ox7(Wi?zSa>Dw2LYs?>|DPEy;ti^c zx+o;9H8+*gPs(0I^)^+uD6aGplaST2IPDvO@(v*cNjYC^n(egF02?{00nZ{ zpHHAyBM?E0pk!?b9%$023f@2OXo*fvg*)3X6>DJmJ*q+8pXv-7*75d-eyhZUWjv{M zXTXx)$O4JZSJZ}`OK)+e z0Itk1owqL{H=*j9hWlmkI(w%KMX!JX1of#N#GCom#aDy~1Umjp1t3xho-cLRt;UCaBe4r3zNWVwug=T#X0MEDXAcVkcc_}5zS-Q08+zjlBa0|W?YS`XCt2Wb@*Q3SY@)=ILsu8Amkc|mHrp_I}3BZHf1QV=tIEf_czqYXIsM1hD`r`$eETSlnHQ&@%JI` zrWGnwt(>n{O=zr6+NuUA@z7Xwa*^}d0tQOi$~x>(JD88mj>bo08|eY;{?(g z8RhWv1yx+}yrn_Fis{xTF2C(t&f$8~YaGuQ1#j4(vm#Ot<0!)+wIF)id$}4*%YkV( z8I6Mu7TOnbV|ls7;oOP6{U6}9PIZJweM}4vE@ zGRBGiK+NDZLmwLkmcC%4uO4~=R%Dg9x?!NGXW&!11*cRX8@p<5qOW7MmbcBU7Uk-4 z*HfUY2njryquWgZHM6GyI$%MYS^Hi<)kQG~Ckb^jmkSsI5l!!`Pd*D@S(W{-<#@WZ zbw0ShDKZf;WTYC1=1VxMP^G%NV;0Aph(ly?o zKTz9vVZ4T2@(SFp|so~3gS-bK9FdG7U9hm3=%8v9Hg18sf zgHdxaFq^b@zGK8oyjR?1F2bVcxc!Ukfb+}5Xx@!kH0L#HpgZo$9_Tz;46wOuFfSQpW+qt|fa$6ZgDeyihLO1^CIg2fzH5k|a`#IxgeNOtX8za(W3>xFk$N|X!a*2H)tFkyYl^X9(I^K`ZVayd z!RK^DTl1ix_ah_<^+ag3X04Gg-vy;KlL^v}S-cH>bbm@Q0BFejd`aq-U{Eump_BW? zsOn?EY!QVUe*{=BEy(k%ZCn-OUHS)Ng5Y|jV{N9d6A5AW0Ugj#|8LkbFiG`qf z5H--gdy;|@PyzzBpYb6Jn7K!BDt0Xi20eQ|afyslnq{T{8kG8@o5!3v>XL97+O^5|YiZR_3%;suJEl_K8M(u4*fN8)kt5*Hk^VI^MGKgMi+1ca2ybym1xx}BwiZNJK#xr4` z!@sACTgNRML0z#{(dXCSr%ZqlFv+XW#Be8H!79D$#7bSA42cQe;0Ao++y!Jh9Qu(M z1=%a>q6*@C_#?}NSDP_>63~wIr4ka53!}#&9RmJ;8bHPwHwB=@8tYY}gWq~jb<$$& zPPj(9sLgZwU}CKW7UVj^pj8}!7eg6B+_7z$@`H_q$4!wOZ86+j{*#L+P}!h7uOvoX z)GWe@-&(mP?!8=re?_Gj6$Fg*AtUDJZvl#L=m=h zq_&mD@KH#tNIeRuvzP?qZ0HAt_`Nrm$KZE&D%7UTyi4Oq^48P_v^ub|_t3Ud{iM44 zC`jZFMln~Ocgw)A2JSU`Zl!z+!XXT;6P?{38-=-QX>;knoDxAxUln%+LqBxebaoFj;DdbKBpH69j<}cT4W7w@9Ja9N>tH%M<`)gN zMoyH%xo1ADPP1-Crg1;+Ax${gc`KbPu};vYJ5AN&xZ1?R;Et$Pdr8LmTNR&dt}7*s z03s)(ztxf$(wGrw{Cw2c8UQ^Z5})m#>%-OYPlh$Z4?*XP_pH|CJd#RdOO zcB36)ud>UC+_Ywn2Bgh#TBvCb9L@jD&A9k!n? z)R-416)Kie1kJo{$jQBzA=8Eto&`@Hm2r)wD&PyZI!#UT4Gt;1hlMv>uE)H{Zo5nm zj8iRF>;jkt%oiPWq-!16C}2~8ih;x0LM#6s{ll#?(W4|CBxORT$C714!^)8J+J$X6 zX+f=|+Wa$V8Fc?XkIqa6s?N~9` zXCU)jPFvK|hSB4!nFI8R;D(<}+0~WHbvN0NML#x4O~%QKXeCq2%3Vkj>xzK?{1w;#nV|jkBBQ?%|gy6NOtF^rMO_3Jh@|leEWk0~ZJQ z>zVii$a)8&q3L1)=joS6&f5RZ6 zYi8sxlQfsM>dvYprz04z>RfFYSYq%p*BTPIeT>z}1~HYH^+uO#t*qYtln=TKi!}?x z#5^~n>cSiuhDm!rlelg>GNuvjlae7NZ*Z?;s-A}L_qcC__OeK*+4hh5cC01-w|&-P zTwZU%208NBaUg0GJP6SF%oI3Q4s+fb4!{+$ZP7PByFHDJZ*`U%PB}O|!ybD-?ytDt z+?ei6LEnuHpW?_j>p^x>GP}#tQYtVg|nbFuG1LcYRfbefOu^&?u{*g;vtRIuxe>*I;ol}pCyn< z^&PN|;C`h~xx;kXq(m|>obC>r4rGYElsBrTb0=S-?kbGIFrxeFSt*mjdk(y8HpMBF z`#V8fJ*VZ8O@<1`6)t(3&oW#OKi>bO!gC?4#Bp2rg>BMCyZEQhy~LUP&|8gG>pkJv z-n+r=hL_hxBuY}6;|9~fK8+h)QnC>Iy_m%ZPx{!mR>-NfO0oZo&e+3v+eC?qf27jL zBPIpBhBkw{jyzkAttc10{|-Dsb9#%r$%iMktv`)2SxTCfUSFM0 zQuHR}--qlaEnp0Fa9^LeA1{|EtK!=t`#k6)HA@$h;EMDOz4};6TzloFd#7$$urq_* zj`_o^Pz<~1dv+vmYEhVh)r5q%9dMx&0rJ6&y1GIeMs{lLnCIy;* z&q0V}vjRJtYf`OD$JKl#u0ES&_DCOYYC^UE6iRm1InQ>{Wc{&>36L;{xIid~n$XGg z<_9?Jysi7k(S&gi$W_neMESQ8-cAq)dM9x1tc-nWgZN5~#z0YQ)f%s-0AjhwMQUV_ zyWd#5Fc6Mj;vZ*m5OTrhb+^h3ZifC!2XMdtjWy2(ek`Go>knF2kE1|X?C44B!P=s* znpc__cqWI#sVI<>L>_;iagxJ7y^5$#LwVN`bad|0#gU=y)H6k$s%IMFUJ&2#r`vid zlO4Jqb<>>`yJQ(&1XJ(AIvOAz7>@(1ChB<46OR_9a;F?0#mq=a8pb*qNTDEAp#ZV} zO?w;POX&5$OR;--dq2)>-Un|)8JVSmN-qcdB?9dS18(B?F;Y%=EQh)+ctUlJ-ArjGw#=(vqgZk zDmQ1xvWY!fi#e1@ZaLx<{Dl+#(XTC)w_{Rbm%b@>$tFt(XDsvWf`?>V!0myWMsgew zI$->|jt7a`gf-HhLyxx@?wyM`GSoc~ssF;QKP-}}f%`!xz>8d&>v!TEYf3L*v$hXd z8g+>#c7~Q5h`}$>Uuw-o*&FctZ9XCNdM}7>YUx64zNq9@ap#p229Wlw^;8GPVw(5o z&blUy0@uP+M0*6inJSd_9b3j%x=ICz%+26mM2eiS(mj;d9M{EevY1stNrHm5IpX7j zr?Xs~&0zwQA#&rj>6sUA#XjapnX$J~T(pOvUHCo3E2Hlf(3c!LUMDV|>Bh!I;~RBFPj- zB&;VAw1MWaR5KP`X?a921| zhMxq27jOlaBe`?`4b;YZ8>)S@=g+NKIONhJ5Tg6wfy7}}%|Evmi{3(GMjwMYV?a=# zI9RR{wy&qv8;SK`5I}S{ASJf38^QnNMnNY{*$^)4Wn6XeV4ip5R%dEbx6jvASzCu= z3&G;#CKH#X-=q^O0hbX9VBmAa1^zjZjKn#KNo8zep=>I#e+3Ti3o*Hflp`-?aKbBhuOt%vbmK=GU9 zLW$Mv0$8O{u)1E^Mi@!ArD_`2QO$rBZL`3NP5;nnt&Ts%w8=g#nc0^?)pD?~q$Uil z$1ev%tLB>9KshQ*Z7X0Zu)2nOO`YwjGc`dm90}ivvD;?cvoa=?%hhER*t@Ztq}Za$O=*S zEcXzc{N`BM$U7u$1tRbFgW~l?4H}cjbR6Kjl9GMiQgGLj%qDKLrdjiT#!J*mNOpmxQkL#gU7peHBPDkSEcB z*6@B5)?$U>2bw1lJA+DY$-h^tXwC?Ta%^G_p*LUB9)&}#>|ofuRiED*$J)My@crro zIwUc)Fb%qPxM=7JdUTOc~K)wP$Orb{C&toSj6h#@nuLOO9qdpnK7N&6HS7P z6+FAFWyxa!#&Xj2seA0$s9^9~3JSjwC1Gm~dJWJS%C6HnH{5N6$sI?8b}QOJU{Y1T z5BWL`8j#%rx8Axr7zfk&bB%GBO@a8A$OVJ3VHz383^A9d;IS$1{d0csxINJsH-;-! zb}YgS+Z`C}64uJ!Eg|$+?8+Thd%d^EsXQy@l@>k-_YVJ57}NWT^-wSrlN_VU^(p8L z!jCLtzJqU=lf?{JA=J>VEsOR|vt%CpGwux&L7VJ2_D?-3#Lwr1bEy&O9Hd!eWmcnn z&Ta-En_d|5fT&rdt6{xYM)F+T1SAN|4&AihEUY%5!1?`TJRu!601dKvBdy@S6OTh$ z-20@KW2MidG5nqWRiGi5;@bSGnUvr*x1nv7mP3$~yq58{&*t_xas zTuaRgdDu4P#`s_H0S#H?SQWJPx?DN8Ln=L=`ZmoBMX#VV-)XIU233&~*JkDAfuNN; zf83`TDmaG}e6^VZ^iC#*=g<&J?7e5x2GeD3rGcsJbutFUk|;SmGI>A&hrGE!C>Nkq9f81;|F0LPNIg#iIZS z)wCY!Yk)Z-f0910@Je#Cso590JE)4j`SM5uS(Xr_ZfA6YBvV}^pn<;#Sv~Z z-n02t9}2U&2}L>>quq`_VVM^f0y-VP6=}muz}|6#&SC;#9rD1x-8Bl7`{7RAMP^OY z-pO%bBeL;w1Eo0}Hs`K1vlT07xcatV;7Q!ddtZ>Wv~pLD^`#}cJ6CS8@KO2wT*G0D ziGUVu(AeeROGM5K0QYM!x)LA{NQk8O?@Kl$cHDA!x%4# zw;ni#Pkl;Ba`NaCLtbvn#!XON5bhv%a%V@2%_PrbKCi7CB$ zv;xKaQ8U1!{Jl+7CJe|BIa_%Ur-ZIM)^8T9c>g)=lR)2uywJ2?`JZKtHrjs+;qowJ z&u>d~J|18rQQR#@G?%q`bp&6Lqdl~SM+<6;G~2KDsCVoRMzHGH%logU(lFF?QnAyq z7~kME|B^{;;$rAv$a)*Q?d)1gxS4{wY{}O;iXV(4KNQ}wZ#vA%RM7P;4{^oDm9}#fCbV9e zZ39&fDcLXd0Hl-M1(oYvbjCEo;60~M8>;ESdfUm@^(7SLMfc&9!^;aOOUaxFnN-Llk zYg*xNn;Nu(dX41|my+c&&Cc~c$%m;8Dz!yuIe-VG#Xh55){-87`H5}V+K-w@@b`bCU-kj^gm0Wb*Jo({O~2XBk|hxfBH0{LUpG3Y2aTZw^aqV ztXKpV`sTXrdItN1xZ4i)%av!t3GK$`_op&DLN>oPb1Xtd4GdlxaU3yy8V+pllfQ~G zzU7R)4@M4hy`O}WjbC9Bw@SIuJ$~2~>bp+RI9&hGI_7GR0=d6hjV7H-H6x&uNq^V^ z50=n_I|&;gR(DbR!~L?s98k%Q{x^7|FkQ{R{EeRdr#$bBu8}O$%DL5l0_qwo`d+7A zP~Mrtol+^B%~_EU#C~9=kItZ13?oyS3DoFJC9w zA&^SC3P}GMCMAj^Fbft9rg7CK+RJ?MF=|W3>~I7 zMGxtynkdUXo^uJt?D4e0Ki3v|v|+IkoLaiAoJ)>e2l(b-^R(SXJ+}E^d_<4-)IY!h zUh*y_U~4Z{ugp!af>?w#3Dsdcy8)8T0+6l8n&904Ca0cj(jBos_DMe6LX9Xn|t-E_VW`p zx}!ObY}rP@jzgJXIMRbCSMBQ2lc8Mehe)UFKgQI|Z*uTyYm~xhqSazoQVzo5S9End zeH$?NSX&X@W@Qi=qoa7W7<{9jD| zYuQ2$mt>E41g%QQXq{%F?2X7&h9*s&V*MMQ&) zy#kOmjISiu@W!6=Urfh;#GNvCQAx34Zt}k6;=GJszVIfg5YFM`1VIaF_1;tquUjWY z`s%eNs&bn%>h{Np*t{3LrNP)HZY+h@8uf5a!*{Od}NkF_BC5#{B>^%ak<>2Y?u z4am6LE^Xr6T&LqI6`6y_PBT)c*Wi?5BBby&G?b z|4pUzme7Nlp*D=;to?c{G&$pC%Lmn`!iwIF{wjt9wLo}Dy2ZWP_;QGI026zUN^M+z z849PSh?}dQL0d1$q4;u~LqoCKLQU9a$pG7q7|+<^PjEvua29x7)8e_Ak=*BVR)JwCc zX$v{>;9S@p+Nl72yuoAIAx9=(rNZc_I&^j_+Rv1pc5$B%A;r2A$2f;=YP!@i0a4qV zRYO4XsD(zu|@;dgf81W*`(tc=JH^m6QD-yKG+xQ)6>#*Zlu;tAfbc34O< zouT*ZXK0oCV0Fc~JU1f2W zCnO&_MmdlcQy}}B<90P;GC#doz6To~K@R{J(wJ%-R>n1SXm;}2DdI0Jsi34Ry0;{r>e959nOMkfPCrfdQI6+5bztC?gxzru~n4eQBJ6Yqc) zjpu!yYL%s6Y<-UlwO4rooBB=0!35I@ZL11DF5H(Vv%sM32F z6WVCsEY@Dy4Y7+9jy^OE2FeOqS64u`ShBt>i{IkIMbxkppW`|TiuQJ9U+z)bQFOkpsa?CZ}^TLuRa%GUtYg`2T}WB;l{=+LsCd`>Ek zfh&l#si7|ej6GajpP;fRT8|;1_VBN&*3AZF176wEcn^b#g)n&-d!oWOAi)#o&Hv-0 zgmFmj`f>0M8R!U`kIfRk9~D%W>g%bF0VoNBEI)Zt?pe9+a+ReKpNuUZ|DBa_;G+HG zLwLQbWy=^7doLC=mr9O*JQv{B7ifP=q1d;q%!@O;)mzbS(|99;76Y-Ohaoc>fzgGf z(Bhl}Fe$zQx$fhSQx54Vr0!qRxIT?_;L_Z&R_=Y)MzhkByXEsFm%CEY228Z}`gGvw z+JEr1t7jgzGa`9aouD)o^2moU`~dF0l`~b3hV2vfry3;u_P$qbxcQh$86j_5v6`+N zOY{ej3#`=UK0H0I6aM(*zQyp8;E9X#Fhq(Dc)izNBZf%7bdGBZ(cY68)*?Z*@JmB) zP!I-0beMZVDn|wsvj691P6=|A1g69OsWm>>iv8VaLS+nz<**&)E;XSX{L?HH&_Wm@ zR|qh98Qkk*8L=QLtTzt~Q0{i^eVeCl3{F5U)I&yz@{$HD?bY2d6Zl8}JNgH)hhWXg zTu5PhZ)y~7ku~+RqX|TU7p;bI`8x)l!*9Z#s?)4<^)q=ia(_Q&r4WB#`g~C~IC{kW zL0zVCwOpI_{`$Lm29gxwo_ex1o3$$=xsDF!7Dh2Z4)b5A_^XbtrGVgT**g3}5qC{H17gG;v0o5EMbHAs& z-54)5E3TnhF9~zFti)pPi_5j9l0~l2=AI)EJy5N5-A>dIbRqwDUbkUDiTUOp&JocL zw(C$99B{jpa_`e!R{Z$8jYZrpt$7$)s6u?REWeS2;;{B|_!`rLbU|n*9o&F$YEUXp zO@cmf#P=m0i{8u+Ok0Tgc8Y8p&ckg_vsMnHjt`>MNs+}|-_@06 zsCo^Fw!S~IGr2iOGazaGJS4Bh_*pdSr%bsECXI8O6yC#iV;Bb0B6slT6UixQ#eGTG z?u-OH1>gWSJOZZD_T!UjmJ9$J@xlF0B(|VD-tgA()u9~&)DyURb+7wvKboj8JR%)6 zVXtOTZu~VVWdgXSFuRL=CA;;3GLhgb5iU;^2uf zwW!}XuTkUD$Q&mVxb}1^v-vrRFsIf+wFxak-Ir&U07$WagwJ|Cgg0c`we&A*3gQ3z zW0v2D-BA{mNXvVln*8Xz&?^mh`hGE*1uuMQ?Q{UUnLJ81wQ6RJc$FatDZ@*mOdP*N##29Q??|OM%GF@;^E&MG z@{v~Tv+_d-oHOwUXC42j#$tDFUa-171`ob?H7ug!PPi<*CA(gA#Rm;42|r!0(GF!2 z_i53siFxb$u|`J~D7zAGz#-kf4L&NTp|QN-k$cgL6OlEmm<`R7SOJtcD;+QyV{rN9 zjY<35-EbfGh`Tzetmd+EbtqVJlWd5K^rE+q{M){=Q#Y>SNyYIJb4-jOes% z!P;DDi>T8{L@?QJ_IsgQ_b!aU4pE6i)E6>Tvi&ifOYh$QkEE-Ci=xiob!K##a$T7j z!k&4(db)Y}mbgr2MrpcdzEBWMYImjto2Ni5?*8&DDK%FsT+bKQ^l*I%$1Y_Rgwd$b zP*+)H%oSDyT$gcK*xg}whMBqlGyXq!pSwcbo%y|dU!L#teZEJrtC-ky(F!qKNOD8r z7b#n4n-z!*UAno(yu>4Ygy}X<#g}6s!qjbKRvr{BE%pDxpfa4NA$7+x^yWw{d`CW%|JitJE&HlsD{e!PO^zQ3l_3kI|j1C zfOEtlgT#Kale~z8t(+ZGrMhkpOa4KId|r71tU3@5xprWn!zGhRVR29=l0(oT<_3U} zCPb5QQPn}dbJ@prevXYMKZh4JG#!mUA>orXT~=j&BE5{B15r% z3?C{H2E$m?QWa@*7?A9HEX_+f)*?-e{g9{1@VzvzQy#;LYGULOF%4PQR{QNFuo2+3 zFO*ewpftDuE~x?k&RdDiiOFOZX#k;UKIdQe!KfKZ-&`>RDc)$jQ0Jn`J~Y*PJ?`Ck z4fuC$c>2`280+I`ms+~U`cQ2)#ozl4>!q@O`MGN_6pgd5_PKavG}YLh4A4{yKcle< z?Jejl>{AvA&YMlTD@!1;(sc{CrxHh>nuNn2AEwr2?pUFa#5o4#*-pUpmB2vGK>bL1 z@NY%YJzjvgGNTp_!bd^QYWdUGmxdce&CB@5`kFATxlx+6|3hIosyky$d}Lw&&k@#+ zaTz_s-os{0#TNWnR_XWk;O{TQavH29U;ZXx>cEnr@3LI`)gprNp8VguLG|&oL63aX z4&^8Q8qP*b2xTYrqsMM?yIUNez-Car>f25e!epH2 z`^F+t1rm`zFd@D|CELzFNMUOac_X)ni8LahF|Uq}hbg@_;Nac4jiOc0Hky7)g%&6b zlXvVTS%F_T0K>ZmpAXZ10~#rE-z#~jkp%+?4l6M)QS8HcV0bn0=F{%5*_={Kl-2V* zY7$rqnhqNP*M&Z7>yEdz#(FHj&~yx-_EtyF_(4$-B;Tj@=k;OQ#Tp!gJ*_Ml4@Xw! zqS9gUT28xcVFTq5g0t)ru6rf*H-H`fNK`%ijJ=B*auviD-LD$}^-ykU32Qfbgu6V` za&mZOxpkK~CV!V zp9wZHY|&Yj%v=Z$$M&@OaWa$%N3@a(Vl0NM9Gg>TlGI9&({q)AC4~ZYmrwPa7bda* z*BR5InZOq=MrfDSwY2~k?d{5{(8VOk9#--4skaEuw$R5tSPME z0u6J>na-!;XzOs%9idKTSv;Eb13+Br!-Dp((`0wN3ZURHc-0U!>q?^Pv7V0JpC1e0 z#B+Wo>gJj2>>{Vxs8nAS90TD81#yH+{E5;0yQyNsA%-NI%6i~ zLp()2PMqOBFIpieKXkXbNJuIpjpuVcYD&v}zg>hUi$^?D=N)62XCfCfntTqyABV08 z4<#DY7M{y~PII41YbgDd5*GhM$&kRDZ5*A{}e+z=V{t-n`0 zjhRr;WtkU#!`5c$+>-jJHIra=pZCl#2+N&h$4yk>#ZRea6Sc_4A9$}e%Cn7F-pap# zM~97Z&v_Q07s!!5h=gQ?EEJYOyjM+T2RNGSdX0g*neGLab!+@HF3}zEZt`vVz-7WS zUMGg?;w+PW8+Lwj3^-S%{wsx=ZG#3NH%&Qklxi*{5bln;`pDuy)T z+`WS+Z(|#6p4}jP(qSPvUZBw%11VnZ}>jmXxXL@C}*oYP!-E!?>A^668!di2NoR<9T|f zBPmhr`&P|__Ka|NEfSb$xIcJg2c-*7p4xN_%TL7@nO6J`rZ5o@k-K?A-nG{9I!Dih zB*fzVcDK{MxoOvA7|N44XN_ffWH41J^vi2|5X+NY^``vmxIUo5(B-qprM=FF zrk@QLC-wtZ*$qAHw}4kF)+cnF)9=a{P zhO#n#pahi`(!4tZ?Djs~#kr;c!?R?h98}B-?&`J{Rxu%qFz3)ct7~d!^oVSoH*mL$ zBw3;A*OO)khfa26IJ(laaL`7SS1%t^;2WjIcu=+G1#dvL)>0`b)2P)xi5xDUgS`2e zTHapR>%|qPE|g+FtJGt|1XmZP*Vo1Vo2RwEx`kV1)mGB{8QIq2V8jqk5vV|?0n_L& zQWj5l6NNJpO{S4(I1EFw}h9|QrSI1j-;WzjdMFBomTqyQs ze&I5_tlQK|xlLyZe!?vz3)!2>gWVbnrv7-7lNp6sq9|`wJQh$2uIg}5vhQC)asRsq z$pMcuQN>A-fX5@(cY{tzHZSoAYOz-Jw|CUQpsX&HBuk4d()rER$Hywv0pgWBeO zG9Gt~vHFU2Mj*#UQ~REmoSlN>8*q)Ac9yp%DjwX@XP zDaFv@4%4>1!#AB=!CyentTXx_tq_ciNTj;FeOVu-yV7>CG!wV(d}|rWp_{$2>1=x| zTvVz2so;j33}x&Y&l(|XLx*`ZD7P<$s=-{ax~%iJ`_v?`((aMai@|c~;znE(ixhD* z45dg}GgyBb7*^AL=Y>rM>^QP5?skbL^;M^d^fqV{%nJh|q=?bU>g;$v6OFIrP${o* z9_k-zfB_NA)(K-wO4b$fZws)wW=PMnIEPeY*Rw$UOtg`oYkdNdWb>|HmV^@mZc(u; z2WZfv+IQ%U_1#|S#KSs=k<>$?>z6VhK4?}ODaO#pN3IMW<>+niiS6&lG$F#AhJX95 zSOgPs?(h+ogg7Z*0r~ED{#GD7t*C(Ze{P#YIgDQqZ4Y(?)zxlUlf zvQlgRV&G)mM|zch5ikj5wnGNqZaP0}X7tTm;<^s_hK2 z7)T&Px?n1r7>ZJST%JmLUej^>?c#RCQuodafT&&PO}3C_^qz4BvY%*tt{ z_zn&`b82HR=NhrHfeG+nC)b6He7CLzryN0XergQBXpY1GouVKRB{@jya_C$AZ*OdZ z0)CU~N@P`?B!Awkf|Do6e|u4*oV3f~3SJ<2uwOlc1lf`hF!a8Vwus0rl zSS=B{kkS@V94OBYa0Rloydw7GsGc;(O-o6W%6L7m*ozP$j=6tVLz>S|X@#u$sLL{h zf7!#30HMFt;T#yK3zkEvBqz%z!K%8RG-<&_TDtfs!g+h^_~37cf*=Du+#aP4m!Q+H z!pKKPJN+K@cQW-mea^ToxU9M++w5rT>BGB_d2s3ju!Xp|Z>sOkFF;~w-<_**<0dE{ zo^)-*%8f%;Pk^=IOcprPd6c&`4p$2nL6{#{>Lj6+A~M3xid*wj?b9D-hA=#F3RmP zImwSsDZ|(8bM9-Ij)?ZJW0BLsZgA4dH<0Q!xBQCN4S4B*eq1T%^#CBAZEW+ShMv*C zRuaWkqvW(*B<&poReSZ>Ro)EpmXgZvE2Icx=YF1re`GDffb<#h_Vx_On<0|10% z6%4~Gad50QZ?rGDzwg!|r_jkch5amIVNNVM@hsNeX>yuOm@*C^-EqShKy)j9+pkTr zEU&Bk*CEp-OkLqL{M5)7@kbr#I03Yk!OU6)gV)n244Yj7Wy0*VC6_T%6DnG@(t_3O zVf&pigtnW;Z0kLRb@A(VWe8rhx#43xJ;B&lOYj-xtdjrFe?E83SA@PRmO+$TCV`@> zEu%Ug87bEHesA=M)j}hDY&%)~hR@ZAc`A^(Tu|4GG;WA*tfQx68vt}SJ7;+i%*enc z%S{YLS{nbO4VnbVtlyeNjC|dhERoD2UG1mPx3V@AM_@S`>C{nC&;Fo=RgT=%-@Rdr zpvN5l5rbf-clY25PuEB`NHK zjK&PB|G?PE&YnVZq2x`(nf6C530%T&r1hHi0(e*#mA^Z?0%}DiTYM>wnZr6&>$g`V#D7+L;^ZO3jUyqe z3o!TTq^~XTQC$m#M_kh9?@_2kyzR_F3~Mu~Mc3)W>{fSomHp3yRAc)Ylw+;qxo90O zsyx`FSrpb}^f2gmvX;GDZSh^HHn09n$#TgLpRy1KP`HvSxPDG(x@eYf;t^YJ#5o6J?^0kgQj#P z*EtPyp9Np|&%dk`Q;5Dn^33#U+cEgI9u+rMKdlfYpQ%`S+q4YK=*ahVj4@EgE??T( zJ}b*m9a4L=a1rCH+8WUGrm-HN`2KsZ(cY4O17Qfw_1>A9_$`G&bSgYV&!h~5bkmw64G3Gz3bts7R>vH1?6_C1foWf!DUH{I2`L$4v%@HX^??ey3-g7URIX}HG=u~(!Uu0McYZv?W?M2HDFE_x7 zRA)tXE-&ZIKY^`6ZRw_t6SHO`xlUN(;5WexbfrOBUQp>Vn^{Byl?C$DpS^fZbg+m~ zQe?VbWgkjGX7jGJ*lz``LUfFce*X-(7CXSZS zBMJ7gUkCvgx+$(^VlkQe&zL?KsS4%o!V4`nCSW^fBh4FN3PlMQcNWNLITna=XysCe z@#2*%cD6P2>X^GRMTVTP1QjD#2rRt41squH!~n@9t{;XRP}{))kAlXmr!E4cv(NQX z7bwXey`dfjxn>tyGMKQe2~sY+SU3e$Saq!cja1RR4yku#M4k>*SdIbsxy3Rksl#x! z^kxvk=tu)oIU!kQ_342wodXkQe9d0gG`tV;DCN(2kprGeNlm&%Bb;LGM`nRqP1p?pM2YF%655*hud(BkaD zcXGSf|3LVPT-p7bo0FAdUJg`r{tz98VQ7q;oRIgplGq6e?QbS1`DxYI)8=Mzkgd@f zk4o#&+*@DAUf}}%JYd`P9yU(ioZF}rL{O6+Q_1r@hD9kKj`e|lQ5=)^yNr&uTNuF7 zf(0!Kg!_+qZtX~PMsAD{Milfpp*`tq3}0)5kC(}z`!5irz&ii%^Qj*kjVkw{#Ydi^ zx_}nbZeL3I(SP=N+;Y7J5}jg&-AzZ~b3D`HKIxk8^O|v9u+DZ`N6beFJ!+-7Ur$3$ zsRr$nJoHNzG-3`B?Bww@tEEWASOjqRMaVxc41xF6*v+p%^kFx>?Dg%N98)Y{t|rkq zCTl#$L6L)ocJxy(7eL;5+-Y*7OXHP0>>z7OEiTg9r5@Q9e%9rdaS8s)B1)^AAan00 zSt$JV4t4wqGio40Si9hq6ZKn-1}@<9#akOJEpkJgWKRh&=jHmPZAcC@eO(A+c{-KU z4RmT=SM|M+RJbcWHnY%WsnQT%%eB(2bve6E;(Mxh5Xsl(LpSY?u|8NzMQ!uVDjwS+ zNx~zIDc~=3iUsZ(bolvWt>B@vYD!_TOLX`ul!9EQp9mA?0zXH(tL z6NKT6T(=H-e#LK3ELkc=u-|a=r^VH^6Nq#6r_Xs^tJ|eQY4L_4D3ER_bOo>*3+aQ8 zd;o8Xvz*#H)7Mm2mk|hb<^!S5$v%mWa~ern)KGoN#D=U`wu-A(n=HWrR+c=FffMSe zU;h$mRCQtY>>#IGP;0($Nri@*{&vbXbKx-*Khf5l7=b=zVPx=56*^BizcY@aZVMq& zD^f?l>D+^O6%46-)Y3|G&aSngx~eOEAtfJjzdr1Q@mD)616m^Zj}XeNkyh8WO|&Gu zM<@^DsYop}s)HZ^kZY5JJi3bNUdii=`hBc8zyTdp)Q0!*b9M~`WT59&O`F7{#SDh! z#Q4H3SE~bM_D4Rzhf>ads@*6dCa4J^*9RXr>-Vk^g>LIgj%t@1Q1?Z*WOgax8a+~# zZ{!1#d5OHj=WO?0Lg#?=J1{7!-_38;`nD50D^q4WK0Hr90Kh3A^wcUO` zQ$~zAfOUx81u)R2xu3oGwWLn>$s0XCT(Txb-@7Ja6MCNN#TTf;oox+;vT1ONrAFO;+o7%q`{+X>0h*uz6mk`@7y zk*v4#L9h8onLV4JTxC3!ivV8FzxNyDFMHiatpCh0%Ic_E`{Bq6t7Be}|D{;@2%09y z|F&rdt-0zC-v-4#6<{v){ zDhZUwW&EYAE=0MZaxzGXd8OMUwdWGuw@QTbql@tcY$a^V4b@=)i8{rHw&q8(B(fW? zh=bh};Lg@q*V?*D`U}2gD9YiMj%4R4tNZ%Z-iey$FfZ(vVc>Fh)!y%@z`ZiYSJYUr zok$Tf7a}I|MqG1O+cj-iOgnlJ?yO`knp8`&7T0AXpwcvlK`v=u7Pmc4^xu2wn$ zRGZjFmOsADFr`rXC-hZ=Gfo~wUKaF=QYnG1m~b`!C3Q8~+0JXnxUyt$ah5SYND73L zT%Le{CwH576c=OB#`zW~=Dy=gaLe1vqgn8(jI2AJ<1ny8s;$;Nd3ew!TZACAn(4{+ z1~KCo2~|t2)seGJ=TBM7%v{KVMgn#I7jCoqoUJrx9QPoys+HxR4AG`ro%#VY6dYH6 z^5PC}QA;jCAb7j=0nDt(h-i~2FDmK6jg>xrM(q@2LgWqeSGc>-aomj$*ASDZ?QN3P zv9+ZEGY_Cmp~p9qAs{PR$dnyUzYKa}^g5|NXH{^QowaVRd_&|G?ZN536`Z z9<@_)VkDwW{2|%gbmBH>Sq>l>!htLh2J!GcFEi~tjCd(F)b5aV3zUMap-4anNb)bp zJ?x9FU4_{RZ8 zUPuh1dnM}&S2AlyyZgzQR!Pi8u?UB=xrL;-j$F5btK*R^kV)qndlMU_j9`pr=As5+ z!$ZBr02?9tYWGLTID_$f=HmDhCH>KNv=tc=Jm7b_G-_eX5M?ezJ zUsI5ktV_aXlIIM|ww7Ul7T|7(&WNt+;xW=S>QU2;JguU1{9+-j1O{4|?o@OSu>qXk@k3t{*pxmaDg zr+x*;>fY_sOvPLORoU6(@LtexvehMpxKQ)lqHunIOej7oetSGBSy}(ksVvtSKvM`} z+r(>7YD;oywb_^C+7sugc!~CrzK=sDeWMc-ESdM6(f8Wv9lbbdxLxMwZ|ij0PpG`h6B zS*`x!2e}-1+YpCZO>;7}*pbuRUz-|Oaa>&*cDI$+Z@SE$1&~!Jy^BY>Jt-gU74ot? zQLSDFGsip6llqM>NlT!&1rD&Jetv&D(uL%bC$_RWV`I)W9DmgLUD@{!4K&OvPuQ)H zlw$@7YA@>1Clso!D>>S0_8?;U5ZH2*4|u0-!-cEFrlG{G)z%Q5`=@xBFCHHUC}kDobn zmnQU?5r++n`-0jJ2qc4>#;!B4r>yfU6&eYna8>Z#>L;1O?}tl~wOBpt(VZpG$j9;; z(-lk0wq_6tBC2`i&*^?I>GBplaaXyrzE3XuWvH&jAGn>0eBgOfslx-`2aR%)rEcFC zr93?$v43S~O`lx-6wVmnoTPC7(W|x|{2KKu$P_2H?nUHb)qOo`G?4$ns6jOB2G@Yb z^o1Ak?GF__qvP;G^CJCHju*DABURPmR6gA65km55+>&Qd=0rm)X3MOHt$zS(2(t11 zMtCb-_Tk9>0mO6JNDX02cVnZx9{0w`y7EZdUQ@43=4f7$ z?wL-0+PHB5Fuxq+Sfw)owUWf$-)(Kdav%V2LaHl0sqVj}=5NehSl>L+Is(RPy?=07wxI z?xx2#KsFdg8!8nm%Vm9-!axdC+)@yLP%<=9LfYwhtBUvYxu!5+>OX0P+KZPlun?4# zqdMVx9VUx9JQvYzw;UVJ$<P?DP#9MVHo9vy|PqH=cjNtdlwN0H#YRWAh~R%SZ0$iE+dG!@m{nVIU~ z+b(D-R6+@)NBqMU=whfJm5`acaInHGVfV|3@K&>DOd_fv?3x3J{kx~Db~uy-?!TiN zwERMZa1#}$fM{=-1uiGyqmN^WaabA*U8`&0Qjy#<=n)__;r>1HbEpynr0Jn5>Kxqd zJ1?w3$uztYeTEzu&E^5x5RLA;11hO?7R$lHV5c-1x46302x#CxuYMf!W1aZ-L0jYInzyLFqJhcIECgfm5oWctP|wFHawlV!$ZGIb-Q z6g-Adh?c2#cJ2*G6Hpkte#lD0!tj5GmGE}Fj_IWQ)m80O^Fg=7i@EXGGa!_!hmYwn zdZ~nzFRx@!E7HHL5h1!}Cb(QKzesk@6GVoW>QK0KAbGa$KMp(GE-lcWUk&zK7h?b( zDhyxUyUAf^nEW({qmpj47^t?jy&P;m)%fdN(dL{(o#mU$SmQ4@ty}xiL-8u5+s&_4 zUOJ?Jsgu}9$5U-7wLnLZ`z_a^LwY}(jm^~8M4m>qt~OOI!xVaxe(vfzOoge-N*thr zkOz4&WHbVsbGW<1P;7E{_gBVj>IrZ!FE6O15_#!+Lmm+ND@OqxuHff*L7N84lNXE4 zLjN)Ojd4MhvhS9UL$(*{otSd$*^L4sU?w9fw@Y=OEjS8}Zk2CQp;hN)tL8E!{2`%;Q@0p?p-&IzJF62S7{+{ZAvm}Q* zK1n2zjfoM@u{4EI@^ze?^645f&9hs52ggpC%+)zw&Kcl2wgTN2+pPW z0$8Mb!E;wxOZ2G*$TU}3AvAX^6`acQmc!LzX{U$Ptl;;jR^cuE(FyO?s{Kf|v^sxr zu99o|^-aqPd`T=Cf=I19qS}46^-|E;0&hPq9?+^XCbzuaI@^MExjfA8?eR+2H(Qfe z+LpkFxF^gu2SgR=Y(=an`EC=Hn{7TsW7DCIU231N6g7d<>?nmCI1Dt`Zkux%)evP> z-H)upZofHMud|D{Ux#Hmc=E1KS)~I=8;pMyJgsX4yi*jK&Bri$o9`YLt->}fOm;<* zam(NB^>IUUAc1EA7437;ESCn|rrrhsTn*a`UBX?%KP04(9U;X$8Q3Gze4we73Kchn z#jgP^KtFBPMohOM<>YxQ>1m6o$KY@+rAz84BeY{B=%x3_IOmxVRV=*IZyj}H3i%s_ zK+F*yznY~^2O-z5?*b0PY!gN-y{n_J&s@-lhIIGeT|#c(ux#KD5+=zu45S#!Eq^SF z2Rmgb6rIs)nM}BQ>Hyy;TMzK82tk$@P~J%pBydySvHfBx6_e+rV>KQPI*oDdu8ozx z#=B<{`qtxGxrXocfb+l#7a>wdXv*-$J+PMU>8j=V%B67dd(@-Zm^_$Ye@gnNB{2}X zY_@)*KY@=yNa6VEw_?ps3_NlN!p6)?%EwVKW;O8VUp|TVoaGmJUkY&H;MFTuo7B%> z2#8d7Xm=00)l#=tTmUUD3>HS>8d4X^r329mxa$SVeJr(@AUGNfS1yHkbqPYCuW^;H z#653l#I|s2>#Na#Lh;!#@mcyq;@BOF?L|^7g>}M}L~oo3C)`l+J?JumR# zdKc}?EOV~VBLuK2N;XyTSkCrhHB&V-xSV**ouFj&xmKl`us)*o zneaZO{;SYt*AfVL)j_?myThd=Yc!o?=hl9b^)>Ny(__nD2_~~{2D2{87C1~OT%}s+ z?dr*6;Fs4|X&+6_c1?Nzl8LvF!>6vf{H~7Dd!WMprY zX;coCo#sV^q@J{XqfuZQr0d%GnoU)3!tojlDNk@NFSJ0W4>QN->*EH*AV=lYAt;%l zXo8k}!PvPQZyuJ_ML*yx%gb8~FFbdxg@PcdQh951AYhu~@GSl;ASOamlUA!R8m;C~ zpL$qV3LH#M$m2sIC^#6T=n|@xDWdw2IZtGNw%RpeQV+83hWMrYa+;fgIh4oY@7vfz z8(fUv^C3mP1@ym@Gwn@UD}AUJ4JT2*qN&upwv86LiJ*= zF!&_kVt5@MdK2H(Vj|jMs(u!3K(+M2)2(t}D4^c2&1pbeeD=@qE6qDrO-FNBDXz?@ zo$Bv!*=MN~&enj6?^dGjkuFHM#9+_74#MUDIUOJ0JbWP@ zK-2y@ZY>fK2JuH~R$!rbqmv=x1e~L@%M-7e2N52VcR=I&i?!UrR6bThvMDB~Stk^9 zuoYKl*FrKs5`4u-x>_89=Qw27^9&P$hxdG={<~c(o6gMo5S{$>auq^${<1g7Q7E^i zS3HK3E+74)Jha}#_(SDTUj7uP8zaC_f`lyO-OtTlDadD(e?I5!MlLy6Dz%$_#Zx;h zKm7)vyO$T_@88e^Ok{JU1dvBrXoonDjX-HuDN+*0p6>&Hc3Mrks8bK0ymS^R>0Pb1 zo@>|iVG6nP}y0!f4|!g-^f$K!-9nx$fWP4_)u zxxzM83`VV(J*VgY9?;@kF!E4`U!i`y2MJ553&r5V#I9D-T)nL0>FcUPA!q!qN3(z> zD`_Bb0PMx0-iQrGoC?t0hG~6MK1jmhkq32;G)Cftf)AOz$2UQNB4obK9`H+slRy0y z4GMB94B`|N-6M37^S9gP9QPFK!et><7} zb4#_-(!T-0|0PLWH5jW`?)O%VrBTAJqHj?Rp?>y8EOg|v*T|4vh&Ve7;Hcsx{Nu)rr z#n%ii0Jzr7)|+_)sB=KDy`B?|%BucKujOAzX}NY0oc^2Z9QjaihM3mz)>^ir5=t1} zctk)TN>_}{Q7oweZ)gz0jHrw50Ug*W2BR=a=O4pe&FDvpc{0k$zm%bFLAk4*%W6DU zOAd`ms702_grbj_KC}|r+93GX=a>=ZqLum9F`c{n_zqIPMMEDQ6*_KjG+9NmRb!q0 z;LeDsfSi;d`_~U;50R`fQ~L{O4lc;uJA2y&!%G0RR7d-3{Rr~XNjzB?>?qX)4Sb+( z11K&>RfGPd#R=2tD|cvg-@9##N3eFhN3Om%XBVqiT@1i*JRFc@qP; z&n>mh%Fm8J)(D*YEXa}`0+1rVsLn?vM|x4s&y}$TYzq%Y1{A) z7z^}-dQ@Y14Z!XkM((+yuw8=FY|x4#Qnzr2YUb!3WnKF|%wj?`3b|T0Oio)JpWs{& zi1>PCtT9gOAA$w~QLJi7JDMURs2I)*U zuH$ngTNz-&9)merInjmOi0xFTNffQ$+W-3>v;`BT{s^ye5tNaDjO0Plq@yFO7%;`j zZCDZEco9S`*hck%op8h~X3J_lV9vJNx}Ka?*X^fUmD&}y)xGG7n4q2n6XnG8LMai= zcfZ(p6J5`BPb;`vnxi|Oh7iq8Y*X50)?gt2*;ek;!`^?|;1nBRqyo`f8z9%P0K*iD zId~bqV^WXGavpI$959UugNsc5*vLc%FEW)#y+(~JI)LlxnuJDGU6ytFijV-10vx90 z+DQUCY!L1U`&5^DWArcS+S|`Z&w|vQs+MP~#!J!RE`)-WAg4a&L2n1!wmuN^Nuv7X z!*Ju&WduJbDinydeG!K04x4tNy%6w)iY@tB&*NCG^ggTxN zeWfVc)fUVkIVE`CZRb|0bQ>2CS7OWn2kD=8vx3kTjIi4fZ1n^|VlVQdWB~qMQOhdS zkq?iz!9eA-AnMglar9p>8t7CO#HW3?Ub$Jcc7cySf&fbDrt*2ME^5S(p0vT89B*dn;bF%sfJUW)c*T~F8 z=HYIvDu4fdv(1FM9il;@L@Ia!L{D6gXo`41wa-Dy)>4}QZRHuv-(y8dHvFIsT;!R) z(ncnr9$BiM8H*UJ`Y|r z$t*5YOyIek-PmB%$bmvk9hCR;AuOn}nl(O{qK-r{>Qu-qU+G zus)a>>R=DM|Arz>C3^6$Z_xQYFR5>fKIxW z6UMy{h`ZV=E0`SD-+yO3E+j}K*eUN(A*vASWvy1gJo(otur1k^6KG`&m7Yk>e&t#P8Ryw}VP?QroMr z=X|bGY<~OmwLnFwN*uTzO}9a6nRMZasa) z;b&X+eNLEkQ-dcuT>NMXcC1&z1*JO)zeugiCY2;-?>L-?kl?Q}&!>3WE~r4F&Z-V> z_mAV^B_m?)eAfT??Ml!W5yQYc<~Vw${_mcoEjlI|xM28LC7YgEjAaq{Zy!$ZFv$0i z&P_+ehHJp>lc0-U;*~CLgyk}TF66kdAuErJAx!)+AORXW_W*49U%=ds4yCTt5j!bg ztJdHG+)m&0Df+xHIy4Rld^rBmr zK#8*+EkN9M&pDh6X1_mW*JSzl0g$!e9U&{jT6evU#MDRaOLM$CA7;r1=01`oR6;t^ zH^JXfb}={)hhhMBb<9kFO=oNY-zMYT(Ow7CN;Da$BMRj)O7Yc=F_}ygP>9N|E>m!w z=`{A~Nl`BfmhH_>xB@A&0IWkEQ;1G}_o`2GNndZrI^p_;M@MB2syJu9WTAov2bxw! z!T6#n&S&}A=LFHZ>jgs9cVWA}4*czkQesU`kd`UXAUN?bf+x{dziH(xK&08fB5Bbz zm)A&J98L_d#MA$>R|?D1{gRilSm`ymzCNk2uR9Fs&&8vXc}80T6aB93-M?~ z7>!+ED<2-7a(|wqlvVHo z-)01yQK2ZPyuDE!AY=E~=M+oY-)V^kMML+t+x6zE2BXoBX~{99S}yNghKmwV$8obp zVV9!O|Adg$6K5w8yrxm~p-r{l-1oA@A=CfT3Dx!UuSsF@YyC9cIh#iA0^) zFiTd`&EOU5fKv_m9jc=;qf^QA_FScY?KN{`301(RQbf#!yprLUt@nb90O3{vr_16HhmU-5=^ay!4L) zXi>FJRJVRN-Xr-WuW`%MFXDjKW;Eh>uj9VQI7GNMm&Uf05l6he1UeK*({q1l8N~cu zv1W&2Lmn4GS`m*QbG16Dh214ir3i+tYjIz3Zt7Tv(%#$&lS^P4UXae|wgx#s6ZOjPwGfS1c zCWzn8X<^42*sUcCU?>TYgUzV;qT0|KIHAX(qwK`GEac5^fnl9E%%lgC&$Q89 z%?B@F=Nxj9^-YJqOJU!7ITd!K7GCYiU2G-9DVM`_|2M$(R;{hVNAaYT6R)T>$Tb_? zdjbccV$tMP{&&x}&w_*E8sOx{t65eZ>2%&m!fb&1J}JPrcaT!gP*{lQGu_R|rNDV5 zUppf4?Myr+Q+P@6Cz8*OZX11Sd(5#w4VauP@ zyoUNXvB{HWV{BPM9v<3o|KyZiAo0?1id#(kVu3uwi#ewBdjTzV`J5O@n!-|G4zKOQ z0ZZH2EB43uMi)pRvHSZ1VIO2bO?e3)N>hS*zS46U7(~XCx@(CICe=kUfnPfc z?j&Pl`QDUaPL7=$jit$!DIS+7-qwwbyRkWGu=dY?yZRV{!)tuw>=^)h@XU!!=bZX* zKTEThivH}qNXqdUqTp)N5oYc;%1~bDSlvlAggKX)o z670L#@;ol6zYC)Z+OMEDCA}T{DU(OymlQo}Zgp_N3gDm456$yj*xQP;YMq(P-t>DdN{=t07}pO7E-~FK0mZ7&0LH8WD!D8oarrN~JrjY zv9h)xO!nAkbL!Cl<}h;3N}cAY9~wgeBP^))E%Jix+1?-qTX)sbJxMUj_t(+Hhflf) zSt>*kspQL4LOVKiJ%n~wNz11~E8DHrGj+RCNmicnjwB9}Fs&?T{V~|*UT#KsV8YGr zQ>%w~5fL_274Nl&V7W>C9o+5PV_UWQI4);F?rO%RHTy%7L$1qpq2RHOdPq(C=Ba%4 z|DTZD016X360D`%o^S`*H2X0ZhOS5yKQ|cAV(3qjEa|3j$to(7fXkHU+FT@8lbr2C z8eAzpd*&G4B6JJT^g5b`jiR~3t^dH-K{1BWeAHLCJkcN+|EAH_4d=x{NPd$;aznJ8 zLUa1+ex-F03{rKjWNCDPbvReh`74ttAbHb`Z1zzOW05}ciqcX!c0RR8W)ojaCTFuG z_3&69V~X6NE}*?rp_uK1G;UBlcaY2JcjFV7d7we_w^B8;|DS=D>OZFKV%^a@CeT`> zs{g2#V+0PqD^IR{QNX)BRPyzeYd-u0_hAdl9Z*sLPB?WbLLtk6EQnMTTTb=4?8dGZ z!_?|QuBlqpSy{dD$~#(dw$s0uF@+y_90q;PYvXomV#k$r-P`vN$VaKi25-}~M>{Ok z^9!{)Tf!CV#M^0y)FkMHZ@-b#4<#E!xjrfM}7@0r~C>gTAB?XZv)uN;5KHr0vG+ql4K}xXSoaZI&h8 ztdwc-N&g+T6vv5}8g!LLA-|PPMczYI)_36? zenu{-(J3WuP< z!bHY+JADv9QrkOC7#!^R@9{Mx=j0N6xubGH?JAFS9QgjPTo$64`!DRo()c+9Z>J7` zjLII~Sk#R56pPipD^#;&o@?41wBiTtG4nfvTw?zcHoqj2t}lyKm6MNfF^n~wI^gza zV3v0J@M|-UsWpU7t9nIs&FaaXTD{K4d!-c+M1bm!T(2gesc_O#R}KXA{w(ZutBK`~ z&G?W@)^hse9aHe^Ugv7F8Soc$P;kd0o5K zny>|w-#5N8o)uDYLDnTG#f08hUx@XOuOEZq_LJm-yN?;qKlC!BM~tR(s4G8PuZ zo~lK)T-7zV&)jH>c$|^Gieq>bK0=qIgPBV;bVsyliC{5b+ptQ}f^zPoC_2GqcF-5D z5%>axO^-jhDW|450g$D%N_j1KCmk_dV%YK=6}ONIPHwPViwv%{?!p0W-~bU7UD7W3 z-}i?^$hgY7xizUuR$3~q%xx^Ry8ok+~ zIdprZj`K;q;$nNHa16ey9$6eKa-rCER&{h%5N&) zg%Gj}ZFayqk6i}Df)@qRS25W9!Ff1l(0jWK1SBIG^k2-MjAM7b-~x5wIj@Avw{G+; z7E}=VQ!kbP7zpEa(U}WNvbv*Q)7;#M3uTDi83N9hJ&pafj2%*LiKW0eUa`_6(a`}d z-89GsB0pV$!U@JO-#1!XB7aQzBk1!%4Ain421iYb{DA?wqH{3p%!O7KDqcu)u+yWV z%)9AoUwgP+7!IL$Np(cm<^VLX5dFxB(uzQE4IXI!d_X1u>;)ac$<;SB-g-Jw%SJdQ zweYmb-mz4bDpRGrGn{ ztMg*ODCNYb>UimLKDb~5aF(CYcISBw!sLu$K%97&UW6RYdr*{*2g59C3y6h<`ggYuO8_;SUh#I2`f|-PJgVyMO$5&}VDlWWP9<_k==< zb(DGxcqPUEL$k{MK=3UNtXl77lIzka!|~tcsXJ}FueA&{*+hrm-v!r^cT!$g2FfjD zcG{aa(OozsuQMoZCGv~LLDaFl1(>e>$Ma)S6JU86S$7KOG3e%f8VZt$hv?Crq1x(7 z@K1*OPWLs?ZUJ=Zz3PzuWlENM&odInkro#{l8oj^^kWx=b#?&YxrJct1~%3C{Ew2E zEp*_pQi|SpgabWqK@0-_X^RTGupD`n@ptup6VJ%^K8Uc2*l@D>{)<==#<5u|*8P|F zb|-C`QbKYJ1YyJ$HM=lmI%T1lNTyZytqa0^TBP?4q=RPbOy{M6!LUNz82!*M=sM`N zoii86%ZhWIjV6>vOOCPjMdMVYtFti4VSt8yQS6bHT1zp!j%6Bx))~nsPp&D1lk3mz zN?PfWqw{F(~2YpjYVsxR`InmL?L&i={+f%ExPdSCI z7fsr+_!4>2MZKE6x>g(S0@jNHEoedb>2n-j_-TrsxsdM3fELKWEJ>coNv{xNK!ET(6ZZaB{z;-k;>Ze8 z-_x-At*Tl?1yXhbT4{YAG&X;EI?&{FBTl`Qgj6Jj-^b&7Swk}dP{2(vv1U;%|1I8Y#5AcUC<9tEI) zlp?F3zf{Sp1CRhP@c}q{9OVmpX_za*pG{?Wgj1775G~B?DzOY4U8o*Icp*Qw062c! z^3%tf8MRPzjtAa=qHG-)qt|h;RQBO*GUe8lvJvp_ZdfO|;Q!pY1^w(;<$*IY7)y}q zf%%M=Lf6fj`Q@pG!-yM1<@s!wjd;rT=xA)3K5YjT|M+`knvJqLN(;t&G10H20C>#r zZ4n19lX!D)H+Dfka+Mr};rrKX^C8^w&*D+d_8S?ZzN>{gw@3$_mY%&*%Wr-Cc-@4Y zL#`I&3a%S>UQA9$hY9uIrfX&^L!*T84s>geXZtSNvASfS1CPADMM zVIY@}f^kaL{R$+%QYmd{&Ybr^cl=tXHkvFyad?E$>= z9mEby#cS9TKlY=32)r-Gtch9K|At0!j?W)GU}m729Vm$o!a+iNL**GDYzFNmPOB%^ zM*^MucC7|{qW^w)@(F2$O5BzBurhoeI?1s89k0Gdxw)RSa`g)3%tCa;?ZW32fsM(! zogS&lN(|5<2b~2?*y_Sa|6aoiJVy~S&S?i^0aAO$+G}09U5cTIbpqzRU^!^*_5r3q zit2Ey_jfGypa(s2z%m{qyV)DI++_t`#zbqosSk+TcjO^YmlOG{B$7?dDQAn560u1} zT-ui)N+1QC?^6yTM)4UJH#lxnXC&*#f%9)*?3-8sgCasj!u-E`=0W!wRabO_ngyKz zGdAmc9m{cn@&wLTG1`Joh@VLF*)ANO(!lYiGk?g5>A=sETid8SKTY}-+>WItB@UwlN<%FarcaE>< zdithu5COsJJii0R7<__P(8wi4u5RpCQi-EpY$CQ!*G*`VbosbfX9U$0#25SbgCQj5 zUMG6D|MJF7YY`p0Nqv>&#aW#mOdEpVhCHHbIxrj`TTW<`sZt*|Q7FU=l|V?@$69x6 zoSGP>+$mSan8eUw8-8u176e5?j|`a{(uPq<^4)2UwSS-+P4!av;ukgh-FU3Nc1Cbe z5zJz{2zfl( zJgP;4jmgi`(67YeivPlOtqH&X{@sX`SLeeuTiNDzUK$IXC3Zy;(c}0_^C1vT7V3b* zB*qPAfCz*I|61jF!WieUT7-VLaCku10ni3@wx+L@)S&nLQ`TyJ&sdbbOQN}I!tAv7 zmx><|cUxD1bD9iZr9UVx=>G%}u(u*VqLA+wlxRwRGHOKLpZM}N5n`Nji&&09u zK6yEN1H6n#IONIx8TL=BHmyPbRm!$LxqpE+%hA3Fc89y!u)kqMVi;lxMvaGA>YQ`! zPd?hn%V#00tAlvp&kO3*4UJNiTd~Z7^)j$2*Zz2~Xa#kp_ay_c{p?B+(gRoELqXm2 zJvj~9rA#DxaF$&4!>|?;FT9UTNbuWe=c9cf1e!YYf5aVxbDT3kQei0^9a9!$F$l*Z zIg6TnO{~aJhUDO%bnd%Ux#mM%2;X$gtxL2z@Iv3^Z=P#t4@JPnUgiZBhokpRFh*#` z`PK|wqrB-GES4W{dI%zu>iY+APGKO0x-#0fU5LUPWH3wAm%fUPe#8Hs}NvGUBeBAAmtkr@JIj8F; zIdjW_kIFGyeysB~JFc8XgUSG0OKI_;2x~2WU$Y~?_?AyK6QdSNH)OI#3>jZt_X-<5 z`#YQ+5adnua*l)ZU#1i7`_R;QrTFcyA6Kl${qV;VW-$VTdAXSRm^i>ID-e9KHCJLW zVch#J;^r!;Up*_=IdW=`E7otaBy3Uf9hhVWXMsES^#Hk_jEXOS1|8zLS1`OMk2?1e zYPV94dDU&hSU?FF_JyXfW7zxc!tGg}jVUVv>XX}Tf^RQE*H%4UkLK*o;|l8s!8?-y z<(BVWL^!7WTH+wJ7-WdfYlp%uBm;kc589Y&GXmig&(coQn?*3b&d$TtxgubRpTOc= zt%hdp*BJo}D+_3SJfF3m%V8nr;}rk6Mon)+rrO?&JP6^=fc-cI-GIOLgOY}oSE*9r zAY3L?1V~Sv4s!ATb!|Se>2>j~gCvgtp8Y#MzBM8FeQtW13OkcXqDa{(^ zbD6+z)Iavlm}Edx4Dc97FOhVvM1IQPBWwrCv<})u4AU05!aHx^MS}Ko7|dBy#xVTt>A)>CS`J*z zI3%ujitfafXp)p;V!l>b^Z*DZ7_P&{+ zBouh;%Fnt_*HP*&g6IQ<*bK8YnB6hjq}XMpD;|U~#iz~4vMSg%}i1?cpu8e{lDCsQElpmU*n-OWN7>-yI81vZn5 z)#7=IQ&|TSK9VJdeDbVy6X5x(xa!Dg4HvM>34pj@)X0WDp}-`pIR}f)9gB&vlCm!z z42vwSfqI3u4*S287FD3F{P=<^bGOh8W7;jDSvv9#`*4SJzjk3Eh96GyRQQc3?g`Of zTm172kj4J-g^o5UMUwKGw^B+X!@+dgL&129tE==TwS8tClILGeLb?UJf8IEsmA^#o z91UfTyX@Ia*zEKiyZ@i}+*#+1>S<~97-b6ATYe76AnD9l0po-FxwdOL#NoHF>*5iv zSAl#j>!J!%=zoK}B?U`A!fJ4Y_ph%^_#3M@df)d67`8@f)Lnhi$y%r%w+ z-IDs;|6wizVLW3+74pXCZigPk7V1O)kLi>2lyc6ie%^Pk8cEKV66()V7cgMrsYi$C zQD#^n&0f9KuJIz)zW{Uk&^3H{EUPh@I+3$xqRAyYDX%LOe^<+P`kW59`_SYB#-dB! zsO)z(3|jN>AO|`yWoin(nIjQ4Qx;fMyPPGs33Qi|3M4R-N+ z^eiH(CzAA{#V0~el4}x<=R658$0L?r$sww|(E~1RRP_~Gh30{}br9HITFW*&5D?rN zMmfUfulG(x(H{oWaRYJN+-_%o@Ho)KXwv670)vW!{yXQ3~s9~`(tHC#7X8#CFKlX4wQ7?!|Y_IyOu$<#46)QjWJ_%5c1)JTq(!Q#dJOW? z2{r*)>-aNRjI|W0@S;!@hxUt|nB+0*wVDO(IK7%pP&I@qQj0M(5QAm|+x!*9a2ZVR zL>NiH*3V4BtWZHgC?w)ByrbhZL5JVx4D?Jm8XCAm&{SY$tj-5uJC4_r1}gB#3Qsf( zFG81OP@OWl&u{O;Zq|-HyV(Fge542m{Q=s78N(T|9!%w0x@9+jL#0P(%1i0k{`NpE z;$RrKXLI1cb;*QdyASEZ)2eU)+E&15`y!qm%J%3doJ0aY+?W+Z*uV%kR%H^67vP{Y zRw}4rmHr)I*pl9|^q)*w)>S-Duw&=hk`f<_$Eu4%Vm^J<{y$1f{x|3qik^1`!lKxT z8?Qfu@d1RH*?EGen_#U{&W4thhvhYM4GHuSq&O z&Doo`wfDoD@cgPmYEC}+I3~k}S^xYAY%SmqHxLRB9vL%5ffZ9n8Lx>FM~Ok*EhEbH{U460k4wN;+>dUZ*NNM z3ZJr*O{f!VuaYK@qu+dEa$+3z9nrjNALcBYI6!`;95f8wi2H@>r$RFuivx{1VjHjx z@y_LKxe53er$T-)Cqlg=kCacM2G-ww;%&&)mf|4~8olW1C8Ky5&}eA5*{R6El4+pv z<1|JnuSSrt<_WJ8I~rQCe?D$^KyyG=?H_xcvCBi8+1*F}xC<3H4uVS`kay?sg@A~@ za&pK!=~C7Tw{|SG+Xddx?D_;xdXrf=&M#{i@XT5dVGKXx4Styx6MlB*8TudssxPmc z3B1Kti;bHAy9ez}unom2c;~cI6lSs7bbXd+$w&@8lH`KZ$JxltZ}$MQ0Hz0O5L=a_ zJ*_31L;&;>v@9@PmJhw?6(MA%>D+mClUpXpz}i_-vINS+4b;PhsP69Ny9aI)f(soJ zCgzCJ#BhiUj8>ktz%0J@R37GqXmUC$PELd%f|R>nR_SSn>DEQJ6Wa$%;ZZQD$ktC4 z9V#*%S&H$1#;@-Bv^ZJgjc;RMqA_)sZ<_se;6 z&0;*kT<9H!5#;>Cwi2jU(ahu+lV$*b~z59 zD$XByMnXyn^zV^G6IUuP8at=-S|1EX$O3mBK1SXzmMobo@eTJaXx~ zXu2jBBJO~LvyAQJzntQ6@lxs4Ysf2_4qh9uAF@x!!~wdVRiK&&l%BGc>|z1TQeIUT zepOFY4IRqI6gQCl(Px60?UZ$68H{L7Sq%4;=YK_kmINyQiYa8}JoAcKAfDyFX^N`XeQ z6IW+WuOc&{+{kQX9`q{Mr$1q|XOOJQ>t@WTLh zZOVqRE|7J#&z@r|(Key>?9iY~oPtp0*Vzh!*svKC#i6vGrg^U`49*}KyjyX<9!e|}$pv_I@&4U9;x`!3U?mK$N1l-ZBSx;Z3nfF%`~W7P;@VLP zFk}i8yX3g`4p({jhxe_FS?dKn|1Yr8stR9@;TJ}iwDONEXeD!kj;NfAb=uq>LSNZ* zP5Q~VW`D4PFlw46K=K}Nhq{ibL@YJ=vKFy7mC$@hxPskXYJk+17H zmQ~h4-&mlgszSBc>IEv3NIo(LPqqT?s)~wmkakirPbD~<|KUak*J1>7hnSxe#qr7B{5@kgFj9YWW^L0{j-hO5yt^d^=75pJ>uVAhsmI~tAPr5 z@#)sN^6*gLMyj8)nL@E^y@(U_y5!O&t4!TcseibGMU%PW)tfZ54-!7l^`F#SlW_?J&1GnAvMc}>I6`m~Mgic4+4 zU~@}W;=pp+?$rONJ_AOy*CZy+24KjL!BCaMjJm*#!UWAkQ&rE~aX6MZsq|w|50U8) z+#p-ZKa1*d{cxf8MvKVKEea3kc^Acz#A^!`pmD6Io9%89^u%`w0_j-vE{u27ARoV3 za7>A7Fa7M75Y{s7ZHl8t=gwB$T;)VO&lfp!X5u|QgK5yVRvZ+~aDMm8^K*x?N!dqDQOS~kTPfDVpX{h-NS zN`T8yg*I}GUHFj8txtJ}xCc2bv>4C*7DOA7)v$LGz#!-3!9Tt5>c>JpVw6uLz*zurRZ0Z^<|R#$p?Za!ZHvgqc@!;%+e9NL!ve1O^Aa znrZF;#WeW1tA)LUmGT1?RjSJl=IWz9fk@^g;u-J%u}u{B)6vDuk4^j!%ZfP`m>+NA+ z@&NwLEK#h+oAa>5!@6}n1lfva&r}05Jv)ks>x)m}O@_E%mxTr7+@FhN3qFZxq!j&E zeBXh?<)0bm;p^0dK!%Dw~aqUy&?>`=AcODSOX}Wnm-P*~7fs2NF z-@%4*NQ7|&HFZpPfC5u#5ey8%m>wby6?5eb;>paCk|oZruxueezT0eq+0}3!hK)oW z+G6=E%6{~3@`P7UY(0Bb556+$`2jbA+tBpeeK`1~{28BG7to%*yPY7P!6J50jyt!l zM95f|l;eSczDBNA8S9uvSd`v?WS6FlMy$ zGyE9XSQAO#BCsFB6jBnV=6z?!7;`Q4zdDPA>`0kq-nzsyRvtqEZZ#bB!N53=wKmks zaWM4`SyN4nt)P|%vP_;(|6Oni)~>mUCmw|sorpUNvM#(5Xki@V4LArh?yh}=V6-Wiu=m5 zynaC@nC>O0e$;UL^D(03FgXgZ7EA)arYnMhe4yU>j25UGL>%DNu{j)-;|?C2tw)E?ijIlfs6XH1Unxff6?(n zE@ZANAh^8%LzjUiY!9q3g$97L%IAW1K4G<fv*c|{rp0SH1Bx};UVyZzu}f!;*^eX z4a}%BCasn19pLqMwX!XTSX)ru_rF0GX`DT@aX&QSw=&^K@_ikYt*j-@SxqHV%X$bF zMW$%|qrkzc!!Lc}zfz)4%bkz^;etI+$Ym=;A&W>uoBIh5);Q#Pg2^zBC~{+QY(q)0 zkukMjEAlBqGUO7T2soDK!J&!D@4=K{IjEy~MBqB?N6%PWmJ^mYycl=6pn!K3RSPBj zVSk;%BC8T%X{!lzXn%%k&}t!3qg4>?v4pL8YZ)T4do$Cp!N@*0oRjBN3K;SFAvqz; zbtOKADCyE)IamTu%ijZd0`Moyz4JKI5}pE}*Jg)9Aq7@P7t3{2S~i*xapsK4kQQ`l zgI+(%5N;KT$;GTX`FY_%4ccHwM-u8ubU=sPgnPRe$mQKmY*Ge|U-q@nHif>PM% z2tN=KXJZgk+pKT4Q&kxE*1zO)Y?bs^jFIH6J2#(@1h0Q0xU8HD`sY_(qNZGECAWKH> zyN(hw9H1gm8NDlAY+x9N^MIDinM!3MVH=LF;;9|bF9;|ThBpjvUF|O=@lvDErv*Ez z&LwznOcEk8Ijg3j1B4H6|oXoOa1V~*+ zP$PmY5A|Ccj2M++>8vZsZ$xTFh=h*%d1{&HNG})yhN`(K)O&9c;!w6Lp)!?Jjuf(S z7$-e5DIcX+qzNDz*L2t^C<^cll68NL2NAv$>s$_1W1ai7=c#6@5A?~RNgT4A|Cam4sA>U)RKK%z#uU~|Nh>p!oN#!GR$Z^vw~2H83c@n|4L ziL6bTelYm1;a7cFSLi$Cx+4DKj7mg8Q>wfk9i14j{#nS<6z2!hu@Es@P%EDaaTs*+ zy5g&^N9jUVVNg-GBi(z(*jqcubpvzlhwIsKbuSlkpou~YKtfUPq<@;ioSeui<*iXv zjpV8jvZogp$R{5eR50KM9~Qf!GDmV!=R5v4NPm4z%0v;xA<_72@TDu<96C{9qsU3F z{RLt0L?O*#n}$y~#Vs09y6~f@eiB-2eT?*!iU`iYrzmsIJ((`VV)-gB_y`X7{@nr! zwN;tuum=DA#YW=={aXFuWJDak<;&fqqIbIE;#FqaR7R6X1nop}&Oi!5GlN-7^3H0f&}KrB zzlAj1HNLO=WJ*EHnokX69s;HsD??KhxAMCG8}x3aImA{^YoGwYhfiGFw5$z^%&<7> zd3(m7XXRJcQBD&tzApC2NC!3&RaC~ESRu+ZB3wABV&Bx}LZ75=5N@Yfka{ih905fK zOiqpd_4^Jtfli~!?3C0NnR4WvhVh!Zu*nIZJk0!2gqqqR?55qY(1hI?s&tSLHq>0; z8Sd~dnTevtPYfMGMpP<0DL$YHWs-)9i1d~<7ZfnB{rXO`d@|J0j-(10!TyIkIh%qNoZP0lUt`p1! z)oP^4Cc)99K{yRL1?@9+6zN5+c`!UlA$gafPm5f`-YjFXw2=JLq{Z{%gmFoZMiNcdTXmz%HfeoofJC-SruokPMN`% zQY*3`J7w`iH}p9y1_n@e&590%o?q6|=D)>1Y{ zKunn(RxmLQ%T5P%NyielE4y*P9}=a6#Fulhmtj}Sc{$68mtc0b-N5C)4uwLA#J(g0 z5R1RbyHRLPX~d1&X)C@`-nrNjh$-bAy1@w1Ivas*Fu38g4~=2e#Me#N$;SXqCi|QWCvOc|)b68{Fw9 zs8AB?2t5kwE0bM-8$*FBAzJE^??*0yv+@(ia%`CA4FWvu1gT``WL`v=)fwIkT!6t0 zi1Ft(ZdYFFd#b$VahxsiE10Pf zst22f;eK1WEF6(y;<=j1s!l|*s^$YS-C7rsrj~uhVD(mM`gz`jka@ z>5W6NG&OxfbI(%(?#e}mW;wyuDaH-^7b8$;YHI3&?2}xtD_vvfzDJt-`{r!88?vQP z1qO17KKm1*L5$)2{QfFN3pqo*I~LOo1gYXDtr`-FDIU|Q1@ssyg&IS3mJ2!%skGuD zWGkE|@D)q~+|lz2P&612|NW@%6N?4?&480o`kPe#wT2&Aa4T!9ytCWpPWur!Yx)eDegd^3B zPK=k(?-1pDy4{Z0p`2BiewoHV4|{kP)N?T06+2Y~cgQYqrMK~ASj+{D29mz=v`JxTtAnjyja8!B=8>?oU0@d8$Qy0y`q+0v>&KsI)&Ol#nE@LPp?tz?^Y;{w!X16mO&B|6h(VMf$izvD>4tW1uWRi%8^UPp)AwZ7;Z>Hq z=1=_Yt+*QnSieN;ju_DHRq{vFUN}U~!`F#t>d~zd$$-}rPag^JId(|us=`->{u@!H z6?+3EEDX7`PJWSe7(c*OBAk7WZI=NJYYG~Rfp@lKK&!lHNtZlBjIu{imhsPWF!y7tP+Z}PCcvD zHW;uIxFT_s2N`EQxegXsob<(i@`bflJ!PAxUy`aol=(oyP#-W8&q%=Vbt>>V(jU;X z5EB~uma>}WE(%o#C_$=N2G0Q!pD|!^`g>>JwPN~2D`0pb=IHb&*4^=E@pkxBj?1Ok zi0Qb{Yj|1(|JXb7X+6TyMt9&SCzMIVxM~QNrS;6}5UH>b%a4ePN&`~2NL%yqgaPpy zXM>JjcdkLm{E}*Im1&#UXn@?l;*37E4{j_;Mh83l%r%ybv-u-OIfNpaZW^)34F5C% zdJhT0ZP_2qU7wN+VFEiIVlm9;;g0nvu9P$1A{C3ys}AdTjwK*e>ni%X81bm2_UeWZ z!VN{1=+%dS*5ZRp+B;^duu2JgRLize#Qr}Qc|r7| zF2pOI{aaY41Sqd4QU~^q{5B75k!RmXLBRs=U4piGP@Gs$_je0Nkvo!7X=zPS*iH9c znz{5kmiDgOV_gQ&e%HJmhcO;mF%{? zeME~h#yUK=R1V;M+g}9kLw&yjQg(&jgMMd7X8(awrHHh;{If5yG`T$VU<)6E&9Vos z#WCGlyI_9v-DDId+|4I_NAyi&0ilBie6=tn7c4~`N(u7|*@u_NfW(etI|ovhfyk7O zRZB&p7xEAt51{wMZQzk*!k1$**DymsPA=Ep) zZ^tP|G|>spA1eL|;|@!JZ#zwIO-s;v6twRF1~iD%7OmxwLX;%C-`jzw&_A94R-Jxo z{tJUmnxM<+>Zrm{eTMACae@{TxSX>I=OLSi>zV?`oPM0qr8`h1FA-I*y+K%&yz0i1 z#qb+gRrDToyUMRwXQkI3AoMNNF1`*n~K z#g|#=BYU@kpHfpF=icuVD4NN-xY~?4pgZup<6+$xChT=w-jR5A;1DSB0$&D!MYbtD z!D?6G*g~`G8ds}D_YZ#{ong}rgOyO&@mLzt*>0Ze4qk@d_QEJe5?ZtJS`E1A*h#C7 z5KYyPTB%fsGS0jG9KK&t0{TE~{YOspGOCaJHwH#}Pp^j{7ePDw!`+*dj%8XiOOU6~mOK#87yCK{HpQC~1{!kgD{>C72Ok|euL z8WIMxehIE%Kl~$6c^0F08qEg43|R}4!}IbF0=}>fpPzruYSI`*5RNphQh~G92p|b^ zzgR2Wttk(c>XT>>7`S0wzWBJSOKr`!=rhV+#)D{OmbCVpv|g4AltPWc@62H1bCyRV z;<^auNV?jbRv_0WQ%e(Yh#yOeGgF{hg^u-_(WHc0I)p{k_G`X3cMBp~vVQ>b3@?J1 z2SG@*A_W@+VlM%zMt52~#@^InJFMSNrD=h#%ospTxhTK)yhP4NiwJ%z-r_SUr}xD~ z$_9p?lByAa;cLj#$yyGROLirzJT6EnBqIjKqEhvh)k5&))bZ1{ZY!_aMm<$%uEsSk zfJ$?lts+6ch?Tq1^XrCtS{^^(^=kUF;c1TvJtm%moM1oHyD^VMyxnOJYCZP3{~NTgTruvB-KRwq zC}7QmPjpn(N@HDNQ`2Q6eU_n>+)p959fL%Z~WBt;H;sCN;-SFAB%lxbC(OO7az4 zU7mpB4Y_~$36!W6x)Bl6!LSL)MXPM|a)Ig6*gY7)oi$@Y?o6_@+4#TFO+wgdyG)uO z%nGw?Gv!jI=t6D4cV!E9XgJVg#abmiwAQnr37Y(uhkH%mK$79KuYRo+4O#_hT=ULa zJR7%Pj}p3s({I#EKfy4pLk^^q?Q9SbF>QEYonohG?<`uG$JCx=26__{XDDyp1jm_J z57!jjuRg91wWY|mY;;k5*v*ydU0j$Sv|%00``YHJkoY*;ic@9d?cF{=>vCM{){-%G zkO3+iNQmmD;>1z6Y;=(TzidCD0sYRCp*zFi7mtC%cfDj|!nAyw`PTh7jp>7Cuf9HC zq6R6CEu$I}gIq&$GjXPtqyCwI@fd`}7Nzpe6@bN0QY%d!h5I_DL!sIkFe#~>+L*w# zq4qa-(7uwSsWQ>zk;XO3b&h(j}>AULJ`i5^$tf}{?Ls-Rm(~B z?DRPZK@$@(I!fY0U)2i=+pT zpx|uK38@P`1bWiL0JTl($L{rdXP%M>FeH|<1&}WQwHjkO_S-!eJrC2NZW3HgzjvC& z80xi@PK$b~d30bId?Wy%VCadVOZsmyDkZXoeGMo>&@SI!R}uohfM`4_)8TGjo*3jf z>4W7Y*}!_Op+jZ{%7K~Ojs`R?M&ljmIxa&75U1wUV)D*EL3{NwMwB!g zcl&{k=-FF%Fp(vjD%D0;klg0#b0lCxnsO_4VL-JwfA`Q$n2p-l?G)tK%=G;CZ%`Vn zP);1Tr7*16p4Nl7PcV>=5Y!s|!Xh&YSoHT$2o6Jclp)f=CzyaXTh;!6xsVu#pQGLnX~n~p^*jc9zA~PWFivRR3iliP`|mN}c44Y~!B?Zvr_Mk@xR$7vQo%nx z6QMFQV$}IZP-mk5UY-_v?;5_p3QHZ%BoloK9lBIqC2~Fr*Gbc1ID)9ytIxkNp9K>n zn&(LR99UAmy^mM04oJJZ?r5WVTnLc_yZnDFJ(n-WQM7XMiXOy{LtZ9j2y{mD z2O@=Xog}sGEw&PNQO-D8X2xD)dfk4`6Zyxssj6TIA{s3N0r6`XY#XI%Ty@t%+4s!F z0c;8jFns2wQyblP3ye)^W1=wDC^~ucEYO{Oa^WM1l+dOK`rAe{ixgRB3b&0FieOBn z66cXW{-Yyk&WUI!<8g$CNI1;)M9V5Z&vLpBj{|G!qA}bdS@7FS7wpgo`tND{0Y;q@ z>zZNutnz)I)e1#^NHk5}?$}|E6OrTb%!P-f?rp%|n~t}$V8CJtxF@9Bo4Q+_CHJ+4 zuiT!DI8CwqXdCE-n*_X(@nR+0L-w;PmjTt5Ru@WU-+`fR)*C zp*k7mxVTTgH^KD3LI2Y7*+@wnAd-ge9QP?Z z2UOEOa2X~+l%rIOhe%gMjOxC0xg2P1GsN$yXPI%PepCq9@P+Up6pu>GC%Xi;0Pb|AI|V+2%sy#d zO`}vqpXLE2W;U=lSp9gJ(P;q>oD^9BQgANJ@did)2=}KaL7=hcsDf4jqwzW2; zx6cHc0w-QOv+`n%ptcDi@4>88bk2kA)T-UXSocEqC~DG>0Pt! zhx3$EtifJA3KlrCaH%(1PI4J!<8nCAtZhLHQ7*>&w7Xk@AX3cySy?#p2@`u5Me7{4 z%jZR(qWd_-^WM6C&l(vz%7k%imloEn6k0sz25pT)bt>u4^<7KB?R`?*|66% zz1$Q?_27BY87o^?J33=3Ia5j}$+|O7T9wJ~m)E`v85(G&BzOFoj)J9|{PyjDa=&wL znJS8ml!1f2vk~RCQnKE1`j*0ukcxAcWg=AO`C|P8uTa~$9X(*3tu{ng*fq_r%|&?X zOtN*~+nW^DX~lJFX;BB)h_eYx_DF*tL|YV9&-rR<8J>EuL%fqjJ3f-K&-?@9P^rN= zQ;+3YqCU5RSy0iA9^TD|n}m#NL5x8MIO8N=%pG_WBH^kNJ_l#I1Uoiz^*CpVXIY24v%3lAaq%=gHJO30nX46JynZVbG5o?$KR@ zH^8X^#8cZ`>gaL_N)K3d(Dg;hX$mr z$(Gpd2T!p#c^}HzS77l5eLh*2O{jY>n2lP^#r9hAyP+x%>X?5WLsXag1LAj-n&8Z0 z;{6FMpGq66U#LqR@Mr7bvpEhoxcf-#ZXI$kdgaHD?|owu{9VDQn;ePzmNR-eM7SU!x!4TwU%40ofzo0^mXx zu+_xqI7}xtf#dR4#n~vq{9N1-YZk6B?W z&dcY{0)Ccf_dt>LJwYalmNSagfsWaKiA)w~Lt_1}nm^ZAVn8ERyeX>(sPaF;L?;(w z&X5i-PI}d2QC~2W$=*sHkw4%@G1Iybw?xXu17!$vXh5+&qJJ=W zitY3rJ|s;o@U-bt*du^sZ>qV8`y zg9qSH2$huPkIb{Hpg$=D7Dfj`jUKPa&RcSaO+a^mVPWi*9S;Q!SPh`nY8q-m>E^({ z*MzC)Q{!&x34^BZm{&@-o5DBJ3g%*BHm1GyMuK9M<&;6v%jUVV3d`yq>g}=9sAo$9 z`f{#^_~(==AgrI=AgXIoRQZkDfdRIQu_fw&G*PaWv!OnR0~XjoJADa6OK-9kx)A`6pp3mOyc)2ze z>(Ao9&OV$cxceYFr<$``rprt9g}v%%>RFI9^WIb@g0@{PGC7W~@}N!Lhk$zFp^0!b zQ_xH_@E{CZD_eeZn))zE*)sVRv3D4WEL1hyNI?a5aKB%uScRsvc5)x9dfEaui*sLFIPuEU*h9qRlu}P3zzPN@Y(pl1vCIsrdTLuC!F+&39oAA7 zGy`(r(b`4OKWuC^)mUb;E!*=8R!!nS7;J3`q zMH?{8&60^h2-F;*NQw#P#JS=7VzjFtcj)()MOq;vM^snaLxDkr6%+hD^$G+>B;1$$ z#^N%9xd4kJGY8}k7DD671xmRMamL0eqRh$`%C`15D&wSVN!#kdD|;ZbT&J6@>GoTZ zf9?AlElzTKacEFATZUmqTIABjb~|g@jdchlB5Q|Cp?YdU;j$JuJYam~x5^nr=Q)~u zCJ!K`i6zN?lL-_ad*5`ny{Lw67KL)Se};wD3F!{`DOc;B8&sd|ca#r4eI5LHXkx46 zAuh+qK?<KZ?SmWJg!`=8jdF8}PMyw9CQg=fdsV%cTQ`O$Ufrbm9l>^kPS;|RPy+P^vVf#WeD ze9m`m&BzLD#=g-jzl*ziJnq!G-P>O2ysftGMqIdf(NXh)l`qZqf0Hq`aB)*!(D{(t z?pmE(oSagZ(|zEVUe$>F_t(ddpUu{f{M4~1z3r{i|2&4e(!&c&@}FcXeu-{2+H;nF zJTWif+;!8i9>+~!O~sz+YEd<5j5AjLXZOr=$L2D> zCRJ>Iontn4Os;F+xBBgO`~TZ<{gO*{r*T)O{9Q?Kbe>`8QrD~bO!K4Oi%kyWUaddh zzxLphOYb8BXiKr;1vXjR?fT?<)j!Kt<;cu0X`8KLLTX+Oh4KmuP&c( zEEfF42HfXMOM2mi;=%_sAH0(K4kJC!1o@|qi|_Y0XHETKEkdK@1@fxZ<G*&@#b}4LLqCa8w=pf*o#_ z)Vryye@~sIkvoDMpEzqne{JUj4S%J)p1WA4CS2&AN4QRYSNnEx?|)|vI)7a=@pgB` zGp$QEW`D6{m?$1v`P=9*-roXEHOJn)vTE3wrcI3p`j@W`u-z3^{y7|qCPJC^gX>N- zSe{-e8IPqmy%Z-sJS&!h6R%WyJg4T3ix0lM(>CkrRUB+lMF*Fk33Q?k9pyn-kpERtMSuqhU~-_h`}H=A~&B|U5EFf`9pgJMU-x% zd3xPis|p8|q(7h>(@nQju@b`_ew zR6}+IgnxY4KhEk#u~*o;hX4=*H3X6a?dh(p0&G&X_|t3{soaizMW|!X?U-)<3_b$u zNQ8q~E|y}GCzoxZAa_&vhziJ!Q!!d|jk!>`@KL?NASxL{t|Nc$MpYjU;*~MQ*0MKJ zh#H(-GTr4X2f!Fesk;(IQ4D)?7$;~=;oNnRXtjdRe!{tMoOJ;q zk>&cR=$%-NI_Q?O0@{pqOJmS{>t;!z4{5Sh5YE7k2WL-({9ANmGVV;<#g#w^VXR5R zqIw;)r9iJ0C4yW%CLoqlX%8Ng>o8)OS%tVQ(SYyGA)0_7T-JkHAzayPKmZQs%VPpG z0+aQ11_UaIoB2;I3(J7Vg00`cvMAt7Ii*B2akg8-OCvrm>`tmb!sEL0z;5yj-pi}p z{rIA>o143!zDSirc6K`<(tFyEODo|`#Y(R^ci%L;`b`78PWhC0uazG`DgEMr|9SDI z5i&3w&+@i!F3TJNnh$XBr%46|l0G5AJ+n@R@V5)(4l0^Ms4k52`SBt<`{_{SJ@ z>f%_q`ni*z5cE_zui8LB9*Q#QW=mygXrKETdd2EfVIw^gs`0yJJ8yUj|k+iXY6?s@5t^Gt%NF9+@?|Z`Mte^p$Ia^2{V9s70=z zX5Uo3sz8Xp7zdef9Qp(^Zy~zOY1CsTv9A0i(x^q7iW7O>Xi1S=ak3iuOj&i@-;LI) z%wgC5FW~eb7m~F&hlTW2NR_##NJOLe>8wXI(fO!wc_OStTAjySn@QcitMAB!k6b2_^~5e?1Q0vRh5I{W)E=E z{e@Vlny9XRRu(3MnDZ2>IK+Qy%{{TO6D{$&rP(H4xGK3evVEm2y&Nbn!-bsFcf%dV z$fdlb>_=mF4M_XhqLE*7Hs@fLqLj(?2P_RZ-?*huSWRTmdU&nXI~Pf`!cywO4L~Gd zt{j?E!P;<7EZ=9|(WhZG(p?jfh?lE_fzv-LZ3*n+mNZfH9l~=p63nixe)IHkppRpM zg`dI)TcM%p{e-Q=E@~|df2iWxC>lnYS!8UghtC=k*9V&;S$QIh?{A|LN{INv+XJro z>mmA|au$;R6h60guMfFLz=w&K^qcOrnwi9@Szf^tJZkO^vcIwRqaU~&E<1VQORL?f zAb&|GDGh)?H3#*Y-s)YHwVF*|?XlcN!?`@Dusq^HfEE9{7>&`+qn zGKPB1$aK7bN+v}F$MNMtu<+RKt3@&P@H1osFcGRuXqM}6i;Tac!|>UMtURH~MPBM4 zD4KT&yU@!L=QRuHrXzm2Bnz?!4!^2NG>XHqA&0z*9V45G@=#@t|3nO#*p|mAxRA`) zz40S?6@>Q^Pm9>==TU&Ty9BQa>%o4Wl|nT_*W#!$$>I2VEgl=Bko`AS5S|@;zWiQw zHy5}D-YZRBU^xByNkEVts>~N*p)^-e>{od?6SeXBZ0h`qq;jlE=(T%*QrnoYxoepl ziqtZSb1o*A=0OgLoRf*vKiP038?;H)yM6yEiYox#6CNIg5rj95ZUj-(tJkp&0Et^8 z_`HH{5?7N@oNG`0NKZRxUTV-_{-+f}G%1>`_WHWiYOYz3qWe;6wn^ zR-4_=mz#7G$*1^lWJY zP9!*lFF@f%e&WyhV3wRN!%5c^u>YYY7F>hblr1OIMPF5H3;u_6(3xkyw03i-=ABR- z!RyJa@gsoLLz?_#myPU$ST@qQ3U}%QE!y&N8SK(V8)*l6MNLfy%)`rrV@i#c#}UwW zORwY2K3SFSFz2vuz`J*aVjJCd9^(4&k$;8TQI4j6^@T63L`sRM;Ew;CN`nQ6xd%Ib z63j>SeJt|=SmQ#e{#%ealIqJUE&wCZkM{d-7*I}>hZ;ew5+-~!1MGQn)UEMPD8p{Q zZeqm*66H+>MXNL&6G~hT`s@Kz4lzb!MngZY&7kX@e8%ro#KolNgRX-rv|p79pC~~Z zj9V+GKr4N#8q7!UhY-mrbl#`wU-rHV=hb(z?toFy8x6`*C z`FB?1zn*Kz+Ey5jct1GRzi!^>+Go$bH2KP@qCm^RtIw-9kS26h6mBnis`cBh4+R%f zJSodm{AvPQzxEaT*j;VEQ?I|s?DGl5x0n5NRIIt4%gzt=yq^vosg@7kkoUgum9=Yl zsAlJ;2HVZ5e+cgoXJBXV4L$fyezyKAeQM@j9x53gdDhF)G#5HVX1CF2ipvC?7UfS- zs#{Z=9ZmW=gv@92Ra|!s?b!VXreTzW?++h^{BS$|GIb@yT!9Q(K0 z?t?`>UHqdj3~0Lc)tBav|363QB)Sj(`AlfrrvwbJXgHFdFG4?+WMuW*Lu>dQ>+bg=9%I-;|j$`#CP{Sr8C=S z!Ir9j)9vH5k5os9uTxu`55<6iY@U_x+WCX=FZ$-FIl8CBWn#j2s|u3; zF=f~TrV7*K)XwaiEe zd#w(;p~-%DHO174>>tzMH*T=}Ka#!$uBp2J-yVNOH|6QE(h^-|MrKOh6@-(Sk&^5o zFC+*jHm5?Sv|paE}!q``hLGZj!)i0wy2u<1{Y}+M2;q2o@h3@Ay-ZntJe@GPGF>6S5W&C zJt`9NIj{friojbkDC*UpTj^ghAZlEeVRW`^?}yacm*@|ReWR(yLQui!FW;G@u;LNI zi1SXc6Yw!r5n*Nfu#Jf7S%w;C9#T3SV)APUpdt>9o~;hZZZuA8AaWI0R6 zV>I7^JTmELfgQ~NA>{kg1eu3jq>-9vZXBrk=~LO15@jJhy8gK5xPulvMZ#Sy+QUqA z%xtRA#>+k+)EN3fZnmwBHlBC|p3v9+Wz{~r&}aNH65-hPCpT@(7$XY{B+zD=5>r`? z5}}4{!XmF4{Ga2~8-3?_mEsYE>259VhfP(KSlH$_I$bGENCu>DOcWGaxz?sdCO z-A;ct22zBDZC{tUsN0xaM^x1F8rtghu%Dv=C(FkIX@mOQ<**p|opwaVe<2kTO+=r0 zc!!(m6j^N8qL`~WgoaI!+QTRD+^HF(Ids|yONlgdnc&{BQA}jSSszT+90|7Rkxe3X z2Pw3OB86Fc*yJhvT0(R?@a^v)iju~Ufgd{boai=^C>g`Q7KTo)7L{WfRuVuk->x^H zqZY7;iekniKgMM3m48nH&h0z?5bUJ5$at(Y1AP#P*AolByLcc%Dd0>G#uVlijV#$@-{QG@`RYSsP`&9Jxy zF3A<6^7s`{;z~Ut@*)1~*iKtqM$`gCagVF6(8w%h!!R64TsJuaEhaeqgZxTWgV=_s zthk2vBXx06?vGr)Rlqh(MIYZ#S?pP%cCrx;4%D1QJ*aU&S@Dg^4`$&-f1t~hpQ_bX zdk^ZE7Xt|Na%Op_bvR{}Zh8i#nJksb;5%k+vWo z8RFuRH2m;+R7oecbsrFju}UnY?#*&e;gq9B=WbUNR& z>J0thjxP)YS68Dy_9J+lbmRU$VjG(OfhCv>QGL%+P^W)4Bp~0BCv#2dTYC!=V z7HRZom4<|JmX1_&IZq-)e8o8?mkHL5D2p*boAfwn|8V;6h+S5Llj(#U35|7^iASO^ zIX6Dhuv10{seDx7a_ScVYakK#I$hkx&7b9Vw4{h`$YoMUj(O;A?rkrPMFBJ9ojO2p zWV2YVe+f73pO?}(+ZOr zK#QDgaGr!iTyqg7hmw5)-u&JlWQ4vm)@)RFb2*>D(<#^?x($eNhX`19qI6&w8q30D zXq25jBm7$BQZ@=Iw#@1YH4~;I0;+FbQ;3swY=HV@niJ2#_rFu4FI;Xi(i==1U= zo`T=uZcR?^jkkm`2Aa{W^F;8bIhY};@cM=v#(|JP6g<}@m||}Sw!>L{%xci^n7&^`u7xFi$QoD#?h z+Pc;HdqnwJO^0i4ztzeSu}I3Gn1V`eB0ANN>~;6G<`QZsy;&BSYQn}6oRF&%IQ-ej z1!2d8#R?tuF`CXLs7OacOpHk69L#MRQgr@U3*2~c*UVxv98YK^I@-tFa7mf z+TB_a_P-G7g=H&63a79Vg~K$ zU1y|*%}&jsx+XWF2bvR+n4VY=ocd|gRr>dMW{<>bfHcbYa(quko$RG8o#qj$*8bN^?Z0Xmsz3-GX+6sq zDs}v~mF1RqJ;rKjnAQExGWiQ;?tmzl6tNp!Kz~Y=m~R-{LGUeytz6 zSSnmOiZ?9yYf(O~9foiEU$rCbj*XXp+R#5mH-=AfVKf?hAk*RamJ;`$#7XyU<2SEE z$2Y4)=?gPN`&WwxlAi%jYqFz1M#a^E^Ygv$Naqnl(jF5xIED?s51-&s@#iu_Ii%~( zqTmv(UVTg7M?RPt%mks9#CjsLu}#!>b~Y|<4i3qMQ6EwEpT~qODp+xea!*d@JK_Rr z9O?GApAP!w8*cU3r-LM7BbhI@W*iRQq7BD0klge&r`|Zq|EuXYv1&og_L*DpRa4T; z?k9?eb$jCBVMGtU8dA4e`xoo*&F~$K4cpc>W83DMKhIqujH!Ju2juOa&9bPd1&>v_ z<#QJ1H=elnbkJ+>w|eQ&ci5}K29w6N&%`P8prZ`Eg&EmD0&*B5s``XXvp`XP4)`iU3R@lLK^ zRJ6MGvm3AbUW}6B`nrD3drjo$K$KSB83-VQ`rFm?bWqO=rIfkh7LvYWDm1ntClzDX zKJueG)T%oHi{VkF)&E^RM;;L}UvG42Ky5p1_9aUl+%xV>effi@gG?KE;tuhOYv`}C zAqBm}^_UyP>5l^WdH6mp*&3iHY*y}&<4qj??B|d2{1V##k$fXNj=D7Oru6HzoM(xs zHK4Z+`QHf2ABY^KMv!$z_+P=b_4gAISvOze+1?-(cWDmWEBg6C9o@RtJhL(9>7eV- zeBAgGjJYVv=g-1*zfE-HeXr&>@S+Pkwz`*KEBR0FJ{|P)wnHRme5t1+aUo^%@Mw5{ z-Hx7ew^%D;f6)7q_z!zN%zDOs_8t+H{Uzj$RQx*=v+2gQWqe1Y3z|`|w6Mn?hPsyE zksf6hx!KCMsb7*mBAgAM%|$2u@v2_JR*HZ&>y-KDWu1mS!J-B0{f@XIZqr6St>hP| z3mT6oiOWw1g)A7_`pI4M?RwR+gQ9@s)s3ipKCmc9Wrk=&J{?DG-aFF2{)E~o&+q;7 zJ8gtvk0WoIKXLtg)Rw4O=dMz(Bq^AVQRP)c-|Wz?&vrS}gXLEl$6C3#$$C+|e&>F0B9Lg^Jtr`9xqF_P5Ht59c??XX8ZLk}0{G zq8rIa61ft*@HNV}2A)jvQ?Q~_amG@*p|YA!K7u-@u;OpL6&;H-Kz~wbJgTlnm_4N0 z(-lf!V@QsOlS1>r$$f?Y#Po!^pANcBF=hyXQsPPQ9Kyi5@-l-7N#MzSO zqT2$yc+7zWR8pRvktmTPb3JcjXby{AZ=RMYq`H*zS#2}(I3TGr9(Q1uC?vbKDy^pD zbo&5bW%m_!D~>@snmumTYAK^za}NDTQE!I=$aLc_>t{j=OScgVr}4EH{uA==1*f~0 zCH~*P*FEnZ&{fSUTd2xD`pbcIu~QnE{rZ9Oh-DsjcuQ{cj7#+Jo(s{Vj~h=s!s&#wU5JRL4`5A@;AHIn}d%-u5-WEj;wzQlc#|&A9Ks!A!58r&50E7Y%jm zzHuI7uJ7H;$sRay-~ZZoNc>L4+%SK3l5~Dze|(LrJ7!VMU%sR5`7L1s^n>Ln+wA4{ zM(9(*cBhQWtKVa;l)Wd~?ps$^zGHEs^~-}Dl0be@efLdY$gt~~fJ+qPeRrht!^IiX zTiV1Ue4ov6`ikdRS!wCPRXb|uf5e_9qJm1{M91uVpdFdKqi!ajLD)`gyqNO3a>)tx z>KIl@UbYOeB}hY;A`BSuiepD!R(SJ+EG(&HnEQ*XS20ltX>X6iFTwE ztz|3s7O(Dl?-n5c%PHnWF59R^XX-7xl>w?T;{`>%5fvE0w4O*bJYgOFsl(|*G{`UX zXFCa;-7culaOS?qEPsY9GKjLJQ{?^>Hjl;N!<}Hx|C6VKuL@RaF&sOZ!;io%B`dG1 z@DX5T1m_}L8)Y>w?6}_!$(K7!UV)vPfOE6S=xJGlL=G`fDYk(Ui!a)2yPYcxhyHpw zcT^2jDY$u}ZtNM%nBFrI{b>3cApckqOnFYAs%+D40EsG9q-O_izAj*_y)2)sT>BFo zrj3f@W%(1q8aqxUD>qeVL-s`@Lfgc4-vNThJy1>=_JSJcDVWzxMfLE1M2FJjrS{e5 zpa}&s2x^gb>Z0LlWR!gX)yMLWQA8c27)D;uAC1Pu(or~xQ4X8<@6H!3Dnt`Sx2`(| z>NR)=)gep;5tR;H|qVXJnZjG@2&BG;D zhkgyB1YNb17SLW_^VOW*sY&kn_D+vbvmBI-qb`c}nRCHhqxQD|XsIH8V9(rq9eXQ~ z%*$|q#0}(}NG-rS-(e-yUCcF00qBuQUjm{@n_PW_w%G2i($ICl{JV^*4(;XfJRT>E zJ>!KP=pHz%?h_tOx26+ARxXPT^AEXz?FoXf+t3uCk|BAx9(X^Xqf6K05!wJ=H@F|6 z`|h`YO;2O6|VlFfcSr zcrwr7*dfD>q;LI8!v?uh?A)?+A0M?b(|TpSht1FClWO3xS*D0LNv4lQ0)#O26+#8Gq6AR$!Z39;JB<5k_h+OCGT=QMM zpc-*s?DD0ExB?|LXD-=*P#T2K_(5dEZw|h?P-Spq1q4Iw21B5RZ3KSkB5hN*uAmDI zHpeYODLNEp!;z0lVBUV>HHmEvYRR2*16GH@csn3cMWMM-P3?R-Xe17le$B>7kZ)Gg zu~X(@3sXC4dW!NuJ|t{s2976IWx7TGt+5|7PpBFq#c_b^_&oI@Ad_vrPEF^6CMfjd z;<_Sbgu0|N2md?^Ps^Gr>3UR zzPA~r``vonUu~1Qcz;ViRU!-SHZgONYG99oZv_AhLie}*mze~l%*~ot6B)Y|iajVN z=wlD_Q!uHaxaDF`BcB2`SlZ4uIcBgGgsM}_XpWUYWDqo-0Bk#M%`_>6b@xubq&}0e2>$H+ zw2^ra7!zCkD}Lz?E)j&<9d4N!Qe5n-ubc5BVKw6V(|<=2Vcq=4ot{#h{v_P~9M}T7 zhqu2)osG9230WE$qQ3An7Dm~_J#T)GvRmcjBTxJT?L4I8P;@s~%CIK{r+ZVF4*a>Y zVDO1;=So-sA+DGcg9L6fth8MAqQjfvG`o7Izyg`p2>8zNQooHS8~4j2XYl1cGlc#b zP!HyE~0>U*!spp`Cyr89tMd9 zqiXO3qqr+zHf|3t;T))O_!T)2Zi?*PRSQn(R z;$MTE_IumW>L9KSIBd~Y3(V7y$&Z$q@Cv7O-(FQ9tZ1gVyho~je!qdQ`Y4Q@Q+ofK zWJ!3Ovc=S4j@tBB)okgM!S>|XDYGto?a(ht*jM zM!sRt4u)%(bt`Rem-dZw17{C#1(k-l2RY=S>byO&3fm78S6Q3$2!Yg{s7)82!c?^R zg9+LedOlw0<}tfRt<-kmiP{eTlDqEvz(O6z?|C|CYt*60{5a34_~oCXZjoH$t4s}F zcNIF-=YgVk_`W)|Y=2j`A`nfZ-*)`bnRSw-CO^70Hp3?@y0Yrqt9;oOc<`iH8|Exx z{Z%>LXT~m&)5`rUT&~ixk>LRFd8FV)aDFeqaAVC1|HY$E+RO^P!j4U7k!reTpcAF2 zXDw=XX*c?C0eZ-Sgj}b?h957wPbu7v+p^U_r+|+taV7r48m`9y^gdFA`D9Z$szUL^ z!L12(OX}6IAzKUs?3y%+eQyhKL46fr-k%wBhaz!y zo`Jud{uf`p{EJ=JHDbM+C=?ks%s-JdU73ZanVpauxb9CxLMDIq?7grQ;zNhEkh8>^ zYl94`kbp5`wr-^OyH5|;$7A-rpvKdfdM0F--J5EZxVZ4;3)ghW8T4Rk_UmVQ$L#5e zh|ieq`Zv90!E5o^-_s?wzND)JQzL=8u+k4yAnqFX$r6s@`}c z;*-DJ8_|3>=E+~iYcD+@!WJq$kIH@fo;$KCwDr()`B5o|4IA3yv!;Z+w(!g=3ZGiU zjT?&y(N{8m;(@Se-$Yo&56iB8{bEPq89hdx#!r_gc;731bg0QZQF$UFRbrFSPm-P+ zeJ~)EpX2iQvxzQ_s3@sko=g_H>5i)V+eU9>XTopFi1}3GS$vtqH@XyPcuH(r`VgZn zJkv3b7+!=P;>g>SQS4$p?9cr$@~`Z?{NQ53Hv?eXQPDzdX<&Lj+F|CkN=sC2XERkE z{le$DS;0O7M2v}!4FpwVK(M|skKd@HgV%$(Lk5{7(wXz9_8nGgf{!vumcH` zm-GszOK_mqPPpAJs?bx>G%Ap)66?FEbKC#f0NDo-Rt+nv%Q8Ok2Lt9@p?PP`6a#)k z>AER~xJ#?Xv$oCrTl|QRMeWfIx~P`GJzMt~1f3_3Ka1`S$Ip?+sG{gjpfo}vGyKpE zuXzR19gY}7HgtESuOTIIns`y!y)8BUTqGi)^Rn3Eg=r&_bXX3@P?22fc=QomLVWBLh3j&( zr^gKH(;_(@kUp6;*OH z7}G@0al6w%>cl?D#g`=YWT?bOF6yZu7@bFl>(M$`x?IW5=j7=Vy{(?{b$mMCK*qxR!Ru({>C=_IJ#R%XvL2(NexU}b9MFzQB|8bT zsFc2IiIOO^;(EMJ}>U*GCaRI$@F{@s{ly4dic_l0Ez zw2Z<^4U}QsKC=7N4>FXbXZ(%J@ID(I-meJk;Pt3(>=7w6bYz6*(I$v-@O94{8=SqB zZ~`Vw(u9-d(gEX+Ig)m%$m$D&-0r(bwH2{P)#|$k%#6l%XAeVP+L?{#t?#%MIjD1o zMtC_y(qKbBEGIGB`K~Ux?N_)LH2zZg8DN%E32#%%^lXj0=0DH)l$3Fd-@t3BMr2!q zJsOKSgC2TmeO{TZovmAn6zRI@*;xtca@?kRY}Z zPP<7sfVY&WfP|J0Xb&KOy!$zJL%Yf}0+=OiJY>)-Xu{wg8;2UCohoTfEf)||r2K09 z|F#)al5X}l)^#9~LiJV;&0SM&i=2QHoEN z4~>**OZFPOX)`Dj&vI$P#h279Q;MD!vb&E&kNM(#$H z2YKCmRVBl}vmHF)dPuAET?SFgYJ@EYcP*HLE1lTJN}2w7bnrsF(h08Do55SAM{k6I zsKi!(zB7FuCqwFRHQvS3cv(Yt-iG3NIr^7AI~02+#*Ev{ob-C2=;~(EF9^Cu+=>6ApJBTC$pZs!;OZI0Re{JiH&o2a0{Kh?79)|3BiOTr(Zf)*= zi_fODP7wd<=swaYerDT=$`_>9*71}7Oz#Wqi1K!ZZ7z3K5W zf&*SNAr2a*J3nv2`-{rANFN+OK94y+)uFB3m-I%f_}xo2>#tAcGw6%UI4+8x9OztH z(fMZ1u9R=XsXwkox;Ib{9(4WE8om*Ebbr*_DXXZHU#G^oPK;YjjnAK|O^dnSYmv>~ z`U{8zOBcBpjJL=$c1(Uc=wayg?3ex3jhCJ`UtD?SEBmOT#Xw?lV{Qk(ZJ1PPv)+ zcHnNy=dJ}*`?~*p@Aj%+EKjTaqdWQ3NqzeDSg|8R!+n=?<(17lw{F!uxFdfv%hdNa zd`76z3Si1qs1FO7!bUuZ(0)@mEh{*@tI)gga(aj}x`>6c` zkpF{hdzej!URT#DdL|P`=>^@coZicvlmnw?7#eh4n8AQh__w*SJcH`+8g7%k#v&jg zJ^j&c-cc-c({R-PPC0K^NYwsOC;Ss~;Xf)KHbGoh$v$K53p1Ed)jm|=$J9lIF3j@V zgK!cOl`4^C)&QYKGcon+0Bdwt^S=uZ!J>XTXn7-rE(vMe*XaRGnS0BDc>twcKsNqV zL&e*9G3y~ol0U82h>AOe?&IfC926MfjE5P87F5Y0N*Sz)ZP0X}b9ouN0MO%-)S+_{ z5ZnNSwvwpP=DR%+QYuE``xmtb`BtK}`4>6gU{tk@MTKAZFwDthF-o!Pu3{gpY&9~c zQ-$RCVV1*YfQ7lCqk^xE7iG}p;Tg_hXaLv{P0AFHC~~)5b*SX1F{9RPWNQkcS8Cy- z7ZBy)vZniqSXsNK>~spuj^Q$O-Hru3ZA_+#S~*SZGefomWPzT@<4!|2Hv_q57kuPk zRYn%b``N)RG<2W~YV)~;9HIQ5Rh1We!`v{JSSmamZmplEKY|BinCyGRXeCJ+r()_+ zz)j%eL3^%|0`u~mlv4K00+JZUOv*0;Hx{;!tKP=aw;V2`y6(+HhJs$%j}V`vlFa5K zCRTZMtDH2(a#`>%*atFKfLTCXkUoO?Z5x1Cjtp(?P|1A2R^w1xK$|Y)B)BeN^$x_YW zvu_r4eI@#Ie~R;A-Sgl6dPvmq?TD>pd)b%c`*ypn>&LC=iFtVR1?iOuSz0iJESlg; zVQ*giLHo|Vk!r^Oy1ay59o?y*r0%ybhs+VrJJ3iyOrw|tDP!}8JRS7F_X2feYW(k+ z?69P8=D;iL;{Gnm6=L2|#`>3*46MBS+Wb>fbq;l7i(?C1Qo1{1i6 zZTpmCCv3CzQ&;MF^24qxQ3J{h2X~olP?Tp;>Vi*T%j2ZLL8qtFyOaY_L4Fbc9GVW^ z%Bm+{&~MEC##TCGg#VP-w&n77wIAyn>5UULSxW0zS7=~Z5XWVlEoWq~`;PU#dZO2z z@^sLeMOog<_Z`e4Ofokrsfi*y%WK)TG^Ozdd4K;z579T)mrSg6_>z(*!j;K}K~CX` z&Ur70{I2oopi6V~)3{qBEwNN77FAFykUkwyNw!eV$O&B9f~e`=tGD0p`7qKhxgw=< z7hQ1J7uSAztGeU#&1|lfQ*>%O%KOWK&(v~%X)&U!dDve=9 z4BKE(-%BGC<^^mRC;lAH*h>VdD#q*so->k4=EH&l>ihSmbIcYlP*s| z8?Y4N$<}k<=;;EbN`68UA}`?QA}thVFj#o8L1OunlfJNhy%p{Ztwoi=VMs*m+k9KS z5Z!<^17^!#p9`L}-)3!APE_`pi~TQQNfK35i{&9WZ=hTYLP>gtTi_RRw~;%{MvO@G zp)q_Up{^k(4H2{c%!nPCnO-y8_5?#+ry> zx8ZkNkWt6<;Yw^aVP4zdaG27ETmb&jNhq+060pd6_b6zc8liT~SGWky#bYs0+0Q1`JoP%#&Zx(ezZcOf|-4*r=?}{bc5LTwX3(Jgx-wV zTFFsp^F`9iF#iMJfC?LN& zTN9%t)&h4zp430qPbl5Y>bB+~SE&8=9kjvNj4nROe&h z?vxFEe{lIs2Bh|)Tk)G@?qRduAMCOl-BSN|N4s00S0ZE6W=J8ZxQ0kS*}36qRy ze-1x>(NB@<-mobeSdO|iDMmn*-lGJSgD_<#GDEXo-iL3co#mIhSFt|c2 zth^4^zrkr0R)0zPI=1E)wuS)~JMzRdMBYYBI*J>_bk}DHowEm+y9UOL8ZMo(7Qkey zUr?wkV_Ss@C26U$w7O2WWSZgL@LKV|a@0BYOb%+V4J>;F8bbL}AhA_!u&weeJ0cq@ zk0|suO40N~ksH}i7dFn*UR|0T3LT{sh&R0nBNqZ+S#s7QfT%@?rIzGtR(n9X0J017kH_bDwL@JD2VH7d&KGXP$@xW%#8J`Cz zPfds{GE)Ct94}2UL-^>W)42T%I^zBcp0*qdSGbyr&72fzj^!v|10L0i{WcpP%JN?w z2UX1#*lI_+P7u=6`{Inu6Kw)*xJ_AFF;TkJ`8<}t$RO+9*<9>j_M}>N152uv7Mt&7 z!NG-Km4uu&`aPPJ!o{NvaOD+zis;%0klC2Yz0 zr-7P;6%d@cZ^53H#O8{?mLnUex~V7r?G0R7MUP5Ep#I zp?@sO=_&GRT6@=Pk|*BzdcvQ}*6h!z+P*6@-pujEmY$T}Z??0gykZtHarM*D?W`q;{n7V}z5sCGsFShPMh1Mei%{ZH{{7bIH+)@-9xtfg} zj$IDyKC_xc^_Z}QM>A~<#KmGA?))MrJDXPTGfl!&@cT~Jz(wza?Gbs$Skk z2o~$ncbcqz5oGpy%|F1N42N@I+9IcHwF%^&X@~gS?XW!Ne6~A{s9$UN{w!BtIxITNRQ0r8b+|X62SgLHC6!FF$Oq zH<>j^1Z>PAjGQ^?b4rD$s*URVj3e};OMIim1=4R|+N5!}2uB?2#Jx(CS?yAaxUo(E zBKr&d4F2=?W*3u*t+uEuvPR;z_@vpFaL9qep!FwIRtsh8pM!)TRO7b@m0ONwYdjVs zg;}?R^|sNup4)SoTuYlm@IXzScq}SaXXbkN2_)#fA=&)m2$rre%gy@=J+3!68HUQZ z;G+^-AEmn0PEXthCgV!#pB=wE5eIG$EwYNRJ!1KPlk$d~Whx%?hf=Ss+i`kNY~-SJ ze#BH6QD(h;x>z&+ZcgW4D>$Y~?0?PpvhIywKhP6f@3MwesKAvVP5Ho|DtkKUkA$S9 z%M1FibnaNMVWX|a!PW;Mz14S1-`C&mmmg@AF3XTz8<0Z4M^1EY8-MbWoC){N4jTN% z2s^8g+ID0X7VBP^<6WA5w8vn-UA!Ph)6K|(@0~85?v&}4Gn1Olds3qK$_L`%o67ze zAKK-XbdR6mJa>@HK`R6*PjuYylXMTtD60AVJpO$m|kHE6G1wYsE3L$|!JLs5Y|}_=3$Iq^ zgKmrW`%tB&jqVz+KMIGcz5L$KJLa?0=$V&8HSEw5%4oi02SP{n|3x6L7mJ;|@=+u# z4qAAUeLtQK*dKm4w>r4k6|2Q?I#`3hlC)~n8Y zM#Fc|jQ!CxlDOS zVfSacj~n}NG{h4S3WuOe&mUZ+@^_j`_H*G7NTmAAC&(rygUhx*nk4iSM&p<*_CTl& z&w3E^mi!Hnd1Nz@G-_@95L`$-|3W{#nM23Bool{I=tZUR-8O9pr`qF2fK7G6}&-%o39MASg@OGx5DMaft67n9tF6PDz2dA z#}lY}&Rp0#JGjq+<+eN0kcT#4^!qi)1Ha{f=5=W+NH@TTArUJJt0BW`gia}6+&iDA z!n%EsX^R}d{hmVx+3@8YAP``Pu9GegkKRp~D^P1!gD46G1BytKg5DFJ!ATmarH=`r zijeQO8f=TJv+<@IJfW5fI=2Y-{E4`m#~?nO8)w2Y$;j|+cc|i4-|j5E!N6|kl?&+N zlT92X<9sWS5wymy6U&KUE31E}j135=i^}`pR6jBD&%8IwZrAy3SJH}s0+r4FEoqa) z7DE-6G%Ix7E&Uu-G7cxVYFnRw!oSd~!T|c6I0yEV5&F8NaB3wb^5T|w696aB+PZXD zmM>govbGUWx(a4Ddfpl=FkV=2?V|`;aB>|&j;p!M2*q=&_az2E9@*1DC?yPln?yB| z28^+6UIpaVc}~R6-Y95Afd_c#1C7&ars1)N#wyVxC&fz(6)r2E|8L?0buS0UPu=@p z15ZU+U|fC=mM&0YG`aiCfE)zl6L#XSjt%jWdKKs@UT|=D=(>%CZVF^Wqz4x{*$=&( z+;NW#6C1nvxj$H~24cBz7hsJ{sFvn9xaDC+@dOHEsdvN(_woMDsx)JXGHgQaWkd@l z(%&0>MFvms)#X(IeBniwtvZA5<{pqp-@|cnGL8#hjh~(*FD(FS-yJrGu$ks+5;y^0)pGj?deImE_UMV z6vpCbu(oQP+s_4f%D4h431a-UPRzy>7G7LRk!YvlNT@IDq!|7XN7uXmSx;^w#UBe_ zK}~EU%fV4HC@^K7oN8iechb&Srjs=3yqk`Ka`Ddca7(3khRoGONSu9q&RVLM%BRGAyq-H_m zEs8FjMhTd=V1pxBi);fANfs?93rUz@XhmAF7_Wi4=zhJdU!;JE$wdtZD1`-;=y;IE z@OS8_0dc2J4(f_5R5gC<-ql0V}ivA zMIGX%I8xSZ?{?lxJ2c-mV!nDTNJ5Fsnc}c*vnNS-&86^}kg;H_$4dGOOIFaOJ^|qK1ewAA)lG)Y{Pqz4WwbvAEJoU#KeBZs_N;Pb*`{p%N#GPx7P19WoesLbO zRF=AK*Qfs{%#yjTFzCKWHOd41WIp z8RVM?P{kAe6(902rmSn5b^k++oOWb7lE0Ds`veZe^kw6wHD$j_J%5E{z6>9;D~3;A z`JcM8+Y{O5K>4Hf#ncNG)AfF_XJ|$@wE?+TEFYOPWXBt=-y^|645o_of$L zy8C5uTURk3(-yEczP#sU?YLW##M zgJ8Po`1^M-Qf?A24k{NJ(IDTC-zauF?$2boi1l!5X5~ph4&;O-v&Fo|bSmwY|7X6lDFhooYdw(M+x_VqgAL85)FP}tB z!hwzF-d^v^wdqgm5M6t%(Kv?BF{?*QK@hb4Ih-9TKZsmkr@W$Yv0C!cS$|MxMKeZ5 z&O0+bR$dlK6}Jyr1hh3>woT&8mk;Kq@PzO+3rL_J`AU(W-=OngK8*cBQuzU^OLM%Q z0Da%LHXLpELp(R|8VJ+ON-4$s#mheDQU$MI<>P}J_`!C5ZZ*<`G42pP$X}i>m2VI{ z1mhnfM4%fMmWub9l4QihQ%fPX8D=}}h=ta2-8n0t2k9C$nA0x5v=9#@lA{^7lqVut zwZ*%Q){TUbZ3 z&k#C{KKMh}9;9*`{lmBk$QE+!{+E#RBEP-+%YcC&%tZ+h#k#EfxqgiD%?(YZR6HgV zD355uH%6K-n@Ny*E87c7=U_+)(ds=zqho_?KHwo@XB`R`vaAGhKV6pUl5bEVCK++7 zeDw@o3vuk4AP<~o(%jj>BuKOQN`q6?h*9?FLue$0g;g^_Uno_C((03+FRcR+m-jF^ zr)h*0BOihRn9{|M$`l(68Vv75bOT%cf~Rv77cM{A&umS~_sfqMX-dnLm{2^8>0`fl zV2heGFR_e`>WAS)(&{-xuyYn0rS++}9G36Mc_J!qM+b*pILd3FJx)45T#4wDB+&{ISm+VpY*04qa13#&ahD5rL+}>akpy*cw^w9?rUT#!>XG@b!x*T;fKa zUaYr~M&|LTnff&pFv|m8gkADDmE=wmd0KXl`)0%4uaX`X4ei<&y1I2_W76kew{g)6 z&MhvQ^}*gp)?06?MxF?*xS4jg_ke%-n_n)?kNSm-ZH81${QC5{`m&<0d)w}{ zj-xUk6cnAOo;3lYPyfPvcTSOTcj99OJ8))K*vi@K?63YleM|J=$)bw2Q4K*4-y2$R zTGzg+Fjq5e)(5*hnFYIJuB~TE7B1g0~nwe~s`Ffj%-??9p za|lzwpEFg+t~|aVFeAEE`;JdifSW9vV*e6AB38h-a8abXq5lnqq#LgJ3hYrE$KP2>EaZ0)!|2!t! z68OEkH4(^>hlEpLCQ%C%K7jFX0)ySK`SP82BWb<5JBGBWDO;bYSlGleg!^iezaQ18 zn$Of>uS}DYs6R)dAB(-~kupl@XQkXYxw6nq^|pOYtBoo*+QrEm`y7Z_k=8^tsqYJD z+aatctk^k>s?`k+2n6n|3M0x3KHQ&x)IO2X+{JgV?)MC^v)Gx|t?SSTwfdjDDKjfQOwWiQHV}eFJ$mkVFlu&E zB2pFMb*n{K&jPwJwl>t!>RQaBWNk^+4}Qwfqx;Bk$Z?KWfW%x1Y#*%3XDlQMbPqctd68u#B)VzfZjREuEu_=QhW`fMhMw_!{u`;xlr z6oCtN@eSP?3fWVcQS-%O#_EN;p5&DaO+l6~5N7>QWTCzjv^@Un!`aA04N+wPY~WH7I(g)K=1dq(myozX9SSnTo1hnpSepuLHd z1kg~41UVuysqb%2q>VTlL&_^fO5h$4r;_h*#Byqn9h8ro}>0tC1+8n>iIY85r24*CxG#{*rl}j7YmtJXE${jQ(>E- zYlZ=juaA3Q&@qDj{2yg3XL9(u=Tg-EPWn3>qGC>pY~=?k`G91_eq>}G>VqV^1O{1G zD6d}aw%>IaZ=_>=3Qf2!9Ct9h_RvO)6BqttRb}0CO7wF1@Bi@H)g3s6@xWrp%)g2v z5$nKc`5+2~A)jQLOXb?U*gvZ0g*^S8W9Ftdt8LFISPNu~%f}bMZ_%D_<73Dt zQ0C`BpuSvZ%-R;h{XQ_NQ!#P!x5bfbQ+}Sb-2KJ{^^9S^eRH4eT)E;Vd#1oizTak^ zS}gmet@BDo$I&wzK%q_6qjAY6Cq0rpdg!+P+56S-fv)1+e6{zl=y7=u%hMcV?9{i58YjFuZ=?OK zu}=r}KjwxM42=1C$`{eBc3_fhTm^Z)M*j_~TfFvO%3XeqqmMm1%aXfu&zPF?y-C}K znfI-cE4j3O%a_?>^|NMO^Q>_+BJm5@Zts<*V!5)!*3>zRwD6f|iLK0K!H@)`^Kh8q zcN1F|o;$1`>;o)8QbI3Xhg66+ZBaV0p_k>ymV0xpCV>1%i)vxMJVhE%I*D5|x%Y*p zW#6buJD*_faZ{5BWrx-0vik3Ns_1TYcXk)jKkVDP0%Y-qmOw6XNJQLW&$85w@EjgT zD=BA~8m0w)u`m$MfKs=R$3%eZLn&j~JLrYuXPB@{(``n42rN@fUQqzH4--BX8Sm+q z*xVz10r_YiI9ZQc?9#OQ3f&BW{p-hv@zO4yHfYy{i#;Z>*sAE`4-N2j{|9+75Ct9P zx={pbuOSeo$>TV>RPEl(1nd3@K)pw`kn`XoH;Q}P`$RMC#A$LbbvRB$i%e+aM#`<|Vk z;Wa%Xtd(Y{BHYg|Pyul=8^r)pq%(*O@Wp=3^X&4b?b$Da}Rh}Yc_vY(?*XE zvZ)}XD6)$?BlHHF z-QYp;i=AcY$-iXtMpEjl!5Yfo8gL7ot?>msWua=t6u!dH(2zfhzGlIhExAXDvn8Ns zcvjF2s_q^8b#u*I;l~fbD{9H{>GzA)gl;d`tuf46KJ?&!qC2+sly12c=lh`YL9#XX zZai7o_4+m-NXp?Q*q73eU%UJHMaRw@WiPQWuY$?DO!{Tdj%}MEZfaIv)jt3S$8L5x z-4iCbC#M`zag|=r8=_yNuexS`s9B@jV{*hN=d1Vq*qzSc76MyljDPv)zrqEDT5-?# zlan{idoo{qr-CzjGNsVT@fa=Lr_q!YanuU_dv(Jx1&CcnD>ty4`E0`2%H@T{`E6xL{jTEb5;f#q z72{7gNni(Lp9z0V2Kj(ib?mZjRU)BqaMQoR1EwXV1Tip=f3s935*`Q$5EX)YZ7!(nDl?$(4Y(W{DJ1cX>hxMG1MMPP5<4@Ab1VFJ#*^rq>j)}^Tt5Q`iZ8vy+Goz-I**#fGoFS#=RtrzJ>WL{a-n@cGpGO zm7th2XZ)+s#qP!XAsaXO(5m@-59`_hNw5D$(zk#`QMT{f&#$N~`T8u+upKNjQ!+Ib zgvm@P5jKw)2$Pz53JC#`h21Gl$>VxR@dTq1u7_YXg;ih~4Rux2RTfxfg%tspWn32a z0K2m@)BoQ7SJ%~5A~Wy2@AE##`?(+NtGc?=@RzR?Rc9e2_m4`Z83zd3-d=|GW(t2p z7b7$K#@kq~C7+HfX|G@;hX+}kdPWG;V)TDIx2doCz1p^8y&C?rCaT{2?i{f%q-iKc zwV^S6P6$WVRoeF=n})`2JSA^#X}S77Xu9|p*iO`QWa0wMMko}ipJnmb^k4ABHxETB z%obH^IEUnnTK8;)84J%bTRee$XwOxC3-yt|^^L5*3NC;oXwcf-%QW|o1|H`_siSq7 z*goX&D|9HICU}MC`y8wbw7l5Uv$xHy7e`i#bbYfJ`U8oh;|q(7hL=+L2lK>Io0(g05x8}G3O;~DpUey|xUFX$1z|x`TYJ|U$ zRlrSDTfZ7-GvMoI6*`Sw8ucBLa+}od6%Tjg>P_ZoMc#~{vNX3@lsFzsIe7hniTP%W znqk^vz2KwE#9;#*%|^YuSUwpaJ_TM;)&i2VbJ-{;Wf%2QiFp%7%+XU$bmmVG^~sD& zEZ@#yyjdxIs>^RM(=1MFY@2tL+EuX`DD+-RitYtJxwq2DR*7oL6P6B7NWoIbh&cC2 zri($0KJg<|y+%{J1YyWi20BW45CqK%oucZIKT>W=_c*}MqndCq-r-2hcqZft`{~{yIlr& zjslaL2-}`&(1svId2UTHczhv42w6sdJ$!WKxBnYqt&DuRU~1r@b74>VTXxCj-=5X) z@VYt5^|cGj6EsOw(b|ZGJ<%F5A=WGV^veycLw0?c(y`-DV&X`g!S%(<1G-8=X6A2y zfPT!L0nZ+Uu`G8Yd%fg0aZ#|U3nd@)mn8OHD$9f$N<~puJvy%>hw9=_4N{rC)|2ML zBZP1v6yMaQiz)F-`5#tGJA%}N+s=-m^4*OY)QZ(FeZ8u4NlvmcOX<`VE}u7G%kiQg zXM~PQKiVR>vCz~xc0z}=`PV}0Kzr|46_MVef4PDBv))Gb9bDo}eg)ygqQ{CUeVZ!E zD!$%x-*aJb_4Ml6kbMaOi@wrZYR13eGLxDE$>scys@9DFq zdSl1>$Pp)*tqIjxj_Z+R9(d{%&V2f*a>odSM)Krjpv^xX6Ue3vr(3Lv3t~RiuPA-@ zO{!|vu*}rcM2DC+=k_OIj#-H@a}$^Y=0k@@Dl3){O~$b|Qqkb`tpk0r@NmmXlt{r{+5VY6Ec0l=BmgATU6{#+M4>=n(A_;yEk_H3U%Jpz2DQl4_!L% z#9N`BZOnCbs8(*Bl~At1m9JVe^rxJvmv!>J&dO>r=)VZN4Q`$i7UZbiHD(Z!T9C@m zuA-eDU!bUImL|dRdQ8LD17=jT&|i{GJfZZLDS4^)ZZNHORj!}rLAIstdEfk>Q#kNSJVP4>f*m-|Z6%xi zz8UE>(?uEZlYXYIl!**co8jeC5ARQgR{~!SD#O^wK9nYl=OlED*-{|>+cZ|M!ebQw z=jNFZ(AwAMn_HPbbQr#c_OXDNDvjR-vG0q*_m&D%_c6I^sDyG^KT)m?U5_fTEToM> z>Zw(dffiim1$nngslxnsejh$%lknphDmsZtu9z&y1D+B$4r4q|U44N`k00igQ~}9{ z|Dbh_V+1sB+v6~wsO?6F<*Qk^q)Ct9cJQF+pke?FVY&6XV>Y+GC?pyn0|UQX)`NBB z=ZVeW+Q2h36L>!=@AYIypkKfEHW5+;IDyV4C1Yfe8_WG1Zv^e&wZ*VV+Hr1yh(j8H zU^&(j&u{92tzy5t>|Z^CdSX^G z{I~2Xa!#tjyUT1jOf>tbc>147{0NDT>Da;bW; zJr9X~7?hY$o?RGl&<6v+*ib^yXechHA}>V5F9rgNOML4@Lg` zy;BT^Lg?>TqL^1pB+_-zzR`UrU%~Yukvd7t1?m@nbQ4zG*lBns0T4p3(hh?{<-E@& zxh=h~_nHTzoj*jyZ0J6X4sW zIc-@Sl8h+#ywtE=%mO5|&0lb!5-Ohn2p82gwnQx*XGEzFV@-NU4bP)q$Gwe7M(PT7gkuU=j=|MhuUYIsWrQecpe?PSUR2(&u$ zvaJM!LtUkJT=Ew_^oe<^l7#gRt9)W@M20sWNup`vAr1zKST+WFOF{pHlDn`n#Hy^q zm%kuE>I7IgMeFTQG16gWwCIl;+lSu zmn8}D8fxZnng4QU%@ZrBZNUvmXp&?ej{-QF`g=1HPq#V6|1BhUf-q}PFusk)YzanP zi)4by;XT~2o++{p7Vp%lpMP$-tttQgi?2ogozjS}?+y8?=dNt+XP-jFc0H(sHfUTzRWHr&4R!qn2xy}M5IJb0^HS6zAQ zcz9Tz&iLLoZuX=g%fqaXE~s|IHWh`1rN^qCyPr2ux<;C2foqrPoHs_@rh|?;Qj2qJx)WG6zhgN zAj@OV2XC9Bd3uCbr~X;usd~ch@%7fGInB1uU{!J-<|kFTx!B9ol^Yc5?ve4Y_LR(8 zyO8RAy;dwaubX;gh-CB3lcrhbUw>a%sftc+VFD6|*L4qt(CzwdCm;=m9_)qE+t<@ml5GX?N*nr$o6;4F6fZ z4ZtNH`PZ*3M!z%bM0wk*7?#0LHzc#)k8H^|=dkt$CD0|)kfLIysdx-M8wM{Zf-^7k9hAdp*zSnwF2g6vSJvd*rAa%~!p?l;@z5AGg zQZ}+)H$EmbdUB;cO6GQyGFv|&auGSXpRCxWF~);pPWGzEC>xF@Df#i=qkQYha4OK8zPm-PuMt*#< zjqi5z(eRt7v;9Pg9D%zS*g4GT?_v%%7YEkl^1(EK(NIgd2U@-g>K~D>g$aUIt=~nr zA*Jw(uyUwKat?yOZ~% z{`u|bK<%3$J*OkP`z*cK{|W{ft#+hLc{XPgqtO|jZ7G_$*qIpf$+I;zH?3O+yfv@6 zV9dp`zbf+*n7%u;p3^6$UHbMBNq*}3;f;nXF;s<*F5UoFVRN?l-mXs@WJ^xXzgDUI zY6fpw7f+2m{^&LJf5j;`hN4r5ZR;g&T8=!u-kh8}v*a7;%*%UB68p=w1MC;&FAw+r zujNkU!|KzgdeTRj3%v`}P3HFsmwy7U>@RKE`;AFze%Rpy%v;anC2MNdHuq`{haDCF z=bhZwKEw&KjRvm$ z$E#22{xL*G(W*uT`&jo%&r`YTJ;RWeLfM>qj%`f;<&g_|RD+4AS$a9uyyN{X*NWP! zPu?m|x867G>ZnO}4_fFPWo?_i7tTS-d5>ag`SHY^WOMDW!U($XPxHRZ^oRr2V%u3n z>)tVcra)Wh86yl}9JCW{T>A&W9Rcv8XQu1DHXHnTS79cQ!I1ro|y#hla{t( zZahk?ulFsfqz)R`_DqqWLGbuz_gNk@6`cFtGSo7^!8wH5LFb+}<3YD|%74#R2= z9IzpbJ~ITg{qP^y)R}O(y`+o6=!8;MNV<<94YcaAnHQ9B8c9htKsCV>UccBoDS6AOjx$sa)Q{qSyl+CNiFvgMK zK>gYFejFNP9bc|sJ*h|CEe1?OAH%`;lgHe3n%+zqP(B8; z+8<1`E@R%rcq;LTt5%_g?)io5TyUwZv?QT7_P_D!#dkk?x5Z#dcJke4<95D$dEwci z-(09)H^=&*lsUU{{?b<0cEw?!42^BQ!;36C)4~$|9<^MXa%0TW5i1C1P4sV>B0K4v zEpgz;t$+O)vFA+p|7&_)%Tl(~d*?4-*s9tLs(nKX+lv z<8@PS(Y8SA?mjaD9@-^E*`4og?;c-PwWK97y7h5e@7P5u_O3T*zQYr;ExI>qhPh7N zVRb3c3r>t>fi-EQ?r8IPS2m!l5I?V%J{umH#%^?uPj^1jQM!i zr5cs=$wuj2Qj^6X>d(yeD87Yr6#bJzVst;OH}B4;cM-GYir<<3LItYYeVgR;;)@v)=zOt7Uw1MT%yFiq^;JKc6mc|-6Nwx@11{#fde$PYYv`wO75OE=^_ZY3t3HCCkBUZCCT`qD za7iWsQu=ZxYceYpv?_*X2e>kpcbE(YY5abWLB8}C4 z!SHUS^;TC$mTU!RJog#(m{u`alp~FQ_H{g6EQ@uRZppTzAd&3u7#SW)?eT+Gjn$Wu zkX=Anzy7o+g>d7K#L>o+=8O~<#vX|M|LOB=r12N?UV@G}r>+!Bnz5|U6{0Xcp!jUkSO0M1?ani0x%Km$mZh@jBA8z@Qu2m~Rs z*yo<-JznYfgdpNV6lK608sjyn$E{}#j4RixcsD=QL`YR|n>F)X1JOzc0HA*bl4^%F zpSkHr0jv=|aRS3;wR-yP2At1=@TL}5`z7pw+cVJ$;B)y_KW{=cY_ur(0#RNO(JV%_ zB{R~|X#-BmIBr*pU6gZk;I`qx9YO%4g1;zMT)RiSSFx_@%IoyY{uZRkIE4q)~!e~D? z7a(OTF`!hEG7U4KVil}%c`%;8L^`CFBs~g^qJbB%EnWL z&RCzuZ6ZJMW|u3znr`=IiP%xPaAiL(xzoszhlV`qK~)&u&;Afp8FHJzEr!s%3p`0r zcB4R_rO+(EE151LylfB544LdSVc{4}aurD!=u=jD2J zkem-_iq%++(J#Ul5f%H6BHrc%|#)|5NzMRIj*DSvBwv~pXLRjcH z3VGn!FfC?5@nr$8G)OG;tg{Nz*by?8p)q~xSoc13L4T|Bh;MNUWYe94GR*QZC{k_> zk3{kh5*Mch0nIDD-XtNL8F_wEveQhcUHmFHqKpvcSO_7dtGVZ4PW1Zp>Q1RxIFpLw zfR#NxlveijF?%+!x8l#=; z0@ljFPkG&Vc95$Fh2UG^4Ba9sE^=~n{gHjZy|2}V$X^-fpADsxsGDQ)-Ql6OTG9xJ zmio><#)=DBJ5I0m7+XBpl8v~RjMYF9G1s;~r*8R~Z-{w%UKn(YaM~ZpWNRL7fLO@2 z5vm$BB5LlTw3;&~=2}&czalYHZ1sWn+D9z6CC(flar>u93sUCf&FC5Bb1*Ba(+8ZajiV+lS3TObXB+e7URU_)v{7>w7QSq7&HAU$ zXKqCi=6tmN_x3C&k7-n(yKonO-_X#J;EU*m*E5t;8#V6aO5dP;b8F`XCmzp~d^fNo z9qj+ef=RpD7gc<(7`|W;7qhy$?S1dTviXG-?>V=zR7iRE$FHwh)K}8bK#Kth&JaVvffZBcOilcV z3jW}afBIaXLfmB>{EgE!O`j-lkCHdMMd|#pLXj{!aO^D^p0`yl!4%{v2&Ww%E@XkH zmK%dgeTY2jnSEDn9%?GCQn;s}OZX9Q?-M3-i@Cc&NCvxkfjv4eo=O3@j{FYNnM78$c`jO<0-+@*HZ3Z{He+)HkweD(^-h(APVNdy<9YnryX3sSb+=@}{D32=urU&`XBYi9A%6Qj-tW z%_;g)#qi$aYD48Xc=rR3yopxr_Or&c^}b4M=UsZ1lYdC<^P8lb6K%&1K@~H?+Hjv! zDmG#w00tCfo88>wc{&%)WS*N#d$Tf1syEh!czyyVgTD2)UWG3vEG3`t6-B1C`Sh{p zkOWdHYK+z>?m>pAc?dtdu51fMuWiI6@*cl=k1%75y1#eg30f%xzXx9Q0<5Cis_3hr zEgVPfi3IaWwO&)G0}Vx*SdnKFBOz9kTTTXkB39T?*cbv?9cMx%B07*nCk^rXi;hA3 z2SWjfIf{pG^jZb5k|9PF66=^TRFOTz3>UeT$sN%&7}c93uQ ziXGHPA%Y^q42t|g;L(obf917-ULiDvl^Os~uAH7=vsfD%B4}f(8%;#vK5=pZXIHx$ z6`=vme*c*v$EDh=`Eb+jcbkXw;D zm?|~pG~?Vm3Mu@W%cnD=Wx@APpYiAwr7da?!*U`7rQF><(yLQxf~dch`!TOCuw$T^ zK`~%eEinym@G&atZ$Oz!yk7a$B!$4JkxpVoiIG|6dK0OLY@BLzXpVoDabj3;43pK}OQ>6ZGSEFc=CZ;_gc_ST>5|Dh z=l~TQmZKOpXRrsdZI;SvL+xz8A(M7<@^Q$k7%j}_@D|xNRZ40eliOzV%(WX~zN#^$ z607H5m~0a_fO1HZ7wf^0Yop3~iQivIQtI}v^->Eg{=HF|Zlm9kYv{)T#>?#5xI%5@ zelbcA5Y_wQ?FdayRocrtA-vmZfLC2Em(?1XuXTycJ>>dL_@FJKhJO*;K>b@kdv&Ui zghpY@{a7o)U&Y21aB#$*QVkQ<;4pq$!% zZ27>j^PJ*n4dcS!XV3Y6&Ns1(v7ZIe_>=1{FXs*%lPj%qRhql5;1Zi>@4$W6 zen=S+gNvBfQBG|(yA7=$#H8{>wJHERwVZf+Dmrl)BCCx*N2f z56^P@>P_w}s8`a^pQv){NT(+qEe45XNWQ-z$4DQv`~5JZaUVOwEgnRiMC6?# zt$s*_5~FeW3EV2ji?BuN82TU$R_Juy)37O}LbIKC8Kyk|SZM{MQN&*2f9Y@QVR0)Jn{#n%acU{rTqPg#xmS|ZT- za|Kh}BfxNP#CDzq7yO=6_#flhDUlDLb5Iy-Jln%61y zF$mDKGpb)nlb-Ysm8A1ZJ`R%3MSsKQ9)j(pTEA!GgsdSN<40c6L0Vub9Pd4vhrhR` zlWZ%^U;ga}2j(4GeqcI~A3;aVo~<_h#2u0iyIs6frR*-EN}S6}*ZfBI2CLy02-&}OJ*2n*6@s2f{Y{D=A-->aIwr#^sO5lf z@t8gHPoEzxglpn8KcP$4KYc#IMZB_en{?G9uzcxnP#HG`Iopt{ZF5#0Fs6I+qSe>+1Ewo4 zUO$n^k7z7RR@`Gf9P^Dr6kQ=KF<{Y~bT znW5y0JDuyIJ`iWIiQRldk|J1fq{lokJ7f}9S8EGX^gI|Ic%vz^Kk)*)&Alq+-q(cE z^o>08^vTM_dyi0I#FeXUllN;r#uzo5X96>+H*DA^{1;tvUG(Y^&{;jb>wVOaqFPzn zNXabMs_uo;Vw>+Q3mkRhkBKJRv`iHE3r6NXZNaTmJjUycp0nQTw*jH21=L zu3Wd*kgdsLtI-RyvlrRy)d z+Q;nQsw*Xe_g6=}d(&z^G?!}54buph{t(+76L$3*H0GQmu}qQd{NY98^^jNNcU&K1 zv&`<7HHj2Pue>Cz8(m#=<53XNj23xn;}H_%Y;jb=u7hm{HQgUpQCro5=180OdFmi~ z@PNVR9t`Hb&Pd;tBW{@fhQ9f2tKm|2%J6LF*?_U@oTtO6*7NY&qRi7z42g8sw_lv~ zPoM4HB4+f_otA6*Hyd}%2rt=4H7M+zX} zJiiqlKdX;*I=*BDQi`DiODQ^0+@w6kYd_SuOGQd?om$9(nYkmtU==`0qMQ@yX69@a zWvN~y!(tsOH0h43^Y$E0T}RlD>}*kKCN@Te-$Qya@RKvV zYHWIMbkrGZ>B)6}FKN>b=J%HY%K?vWZQyTBALQ7hR-`Mv_LV<#X_|3>gwv;^cBCGr z-n3#nf+o=7yr0Me+Sh^;Hp}0aydUB$7b|TW6r;?69#2iti1*a{rk<0hJbQ&W#E*WU z(k(iuHh(wjp6^o3H;M75OHOaPeZ1yk?wOcswL|=>Uiox?E?-(xybM9x=}X(Pv-n#Q zIL`eWvQxL@cK`I&yPV_p_*mQe<5rV%yjXqMvs%?r7X%)VU<%OdNy zj@eRua)dn66T5hWe$;_3b+q^I5KHG><|^^tqyxtI$;?bncAZKr{H42JRf6TRw72Me zJ=v3LkH>L88cpgByH&)4aJ7b?B6;LdwvjTYOWdu}i3lI)TPbi)GNu6NNLemFrMX9Y zVd-WwT?tY#@}!!%8F758D7}uk$=2k&+ka($+10UPNyYC-(u5^l?g{>J>#lre=kkcL zw^}Zoop<{aN6qb+Ft4e5`Jc=iLY=duJV|lmOY?vq1Nf{}n$+R2#nc*s2BZGnhW<1QE6 zaIgp94q0qW@36R4!eXOu+}g9@R5^7!Ua|1;WtGVmk#Q_b1qVz#;i)RI4nfTXJ{%px2*xl{Yvgo9T z^m8b`MxVLy%;(wiW+yzn{EB$02Or*X2Eq5IyFlz3C_YklOy2IojOReM>uu_{(80}1 zYZoayulBK+r0dPhRq*o)p(G4oZ3UE z+<$eB^y;Nnw?1+52_y}?pP)2MeKj2vnF8=~i^Vsyk?M&f#aBRLku0PS%Wuq*fk2wI z)_|~uF;4S>Q)zz%k~*P4KUyPsiHFE|Y(o^MCYes}{|ARn-KKPUNrz9Ih7to6O}tZC zk;S3G-g+M>Fk6{m$~-H5Rwc-7EYb zhAoLpHOW;}MGO^axLoKWLmtujpwQ)U; zVUSUOMaG>ob*>%bmJsT^#S|Y2F;dRg@JnD0V+@ zjQim%Zz~4jT-x)n^%^PWjFl1s*@Imzy11pg#XoHZh=kn7;Dq;ytYRZYJd=q*lwQVH+C7w2Mi{$* z(N60hjvo7yRA0Mwo&Ybwd5%#DX#&y`O0R|UwP=a4<}Q&`{e-g@wGt__244~`FB6HK zQaAV{cJmdLsQx63ITkFGCkYXo&<82C6z5fcu_!M8l^RO4rT>b1viE*W7_^0y-?LPf3Jg4M>9pU z8lifIapyxCBoBM0=!4KL;T>w-vSjP7ou`X3z7C^IrMzr+FcpMIc^9GoF(qN#ot7T! zB`!={uZddiv))HOgGxA9xisIySxgX1Vt?A7Ylp7y^^(0fTPopCq!~dI#h#D{LQwfl z@rj>$el#A?mKbW~R3YZw44ad4ic7~#r`J{x;u*3|OT<15^$Ruq49#|49Q%m*CJz5N zo32xF5Wa+$_4g^X9kUQl7cZdw#GI)N=?*P+gY7L8%DXcr-@4FJN8*DFJbu}c_>a}3Qy2p-CJSk)=XAC zk<^tXi2os5O!4;6G+7;8`Q-|{VGqlt9F9x#UG(RD%KBmxJjs{& za_vhJCn&eW#Q7!gMM&fEg&H~+yb||+L(?XTu~wVWItL1{o@w1w+-NhoBDMvgo7zZM z^AS$INLbAjt)J~-#b6QyF#ij*h!k0+h3kmW<#0fwsz?Y;y1$PH{VNsNKH5ncz25g# zu&`Uqp!E8ukJF>Lbg~@#MULI*1XzzgY3iuBg{$fP>g z;@Xk*Wr0BgxXW>3g{0ZoEiz+5_kn$YY-658!6hKn+HhpdPnw@eu}0A2y+1s#+6stg z3?gTPXBivs85tD4XQ^m4kSDL%f%^F!Xi7~#LAEw;_pMaJvRKlSu@ew*v~ zeQ#D;JhPWd`D116k={|aV@s>uQ_iY`SFZQ|_sI4e!xbGNVT#(6pov(sdtSi+NnHl6TsvF(D5!$al5OwWJAf+V1XeP3%5c+=snY z{SN<2#36Rk+^2WmWVYv=4xCs$A=exfYU@4Gv>^8Ry-%5}VvJ_3Q{Ojhx^r_zUJ)NG zI@l7CHhzZp!Uy+=Cf>*Weko_v+2o$WfQDHqn!CDO)%w)x7q)Gz&%HaL$Cbgqerlrp z1Ij%#Z%5uI|LbThrz*bEGZWhly6;wF+Xv0cN}4;y{wP9>oO-H$i>uJEfhorv%?Wi6 z#MW&swQmxBXA8P$@$x}+L}a>STwR(w&Tfd_>Ifi@-O_ooGOn=p`7X1%I*HKpo4Ewe zH9-HX+`5$f^S5!F(rJ&pc(U@bEIsOE9;N=gRsOCEHCSyJIW5BULxj8TRIu|J)YTP6 zSkzPK-qufcpIN(-=bkg_51PlwjSeZF>s=kvvxRQr?og&X@BPzf1=L~rH|IAb&AT=) zD!~#|DbgqZ?nx&sk4ud+MKDk?C23cCONRY7{Po9u%>+yI_0DnMkq9r&WrXY;FOSwA z`aG^dTP@Qy$Qy4lxrx%WpEB$GbJS&=kr7HPyl;V=!Zn?Ck?Q(BG~4(%WXZR%lZTRc zC@5dn7l~y}dzpkU;DaeaQSp|fA#=szzc>EV=ThxIeePzLa}TM7*C;*g*K5rD5Pn2{ za8SB-G;V_Ji0gmBzcVF{i(t-NK3&tjN}QFLzmY2)DgFXq^yjY?G~I~w)ru|qiZ3id zfsLlrz2Lb&EjHX9=-oNeI>Ov6WG+&lUdmYRRIYCDl8MZ_75QOZe~`{W%J$s}w`g_l zkC7@(>zaUThdz$@IF0lyn@j#qnl;DQjJ-j4*SR`dxN_X3Pmj|7oBHt~Q%d@zpm#4E zTw&^M4j5UqZ0yIkmX)lkHLXr%#Mvjvp2U!~i*)r-_A)IJCtJS%r_aC%zv>@dZ2V$r zXy%Qk#!N}m|87RAr?K0fp1pDDMQZu4MGMaIv;IrU*2%MmeSF}8=giE}f0cLed)tlt z>;2a{pBAe>yuNd1;cn5j+5SG+`9yOdFZ>(M7rW=Tmc`KNja{|v$$zTnk|R4qDnnG$ z{~9uJaAWP!GqU&J{HM<($K`9QgGU%kvUg6OSC;=7+b8*>mpIea((yKjOESy*I5GLq zvU%LSPtyl9O`5aG{p(z1bLxH7uT|fOK_8wh>*U-SiZc7-Yl!dFB+Fk?hjCPnTa27h zQR%Lvjq%$Ey_f6hTnQl8Bz|(aC}|VqrUXjg=1+Cc8r0HeEoSO9wiI|mPs09xMN1Qh z%8S|)9)JdiY$W^bHcmz*inYueeqPeLi?5+f;ucceXA;RS0ZbJ)eHBG(bAe|+hBE+G z+QrQQ5MYgfoC6Zy{FhuyJ8^{r$V17f(PLJ8qF#_sq#V-Gh}JkX1MMQF#{$fA7{+H| zaG4z(Zn*OI$+bix^^Pd(zExmP$n~zFI{qfRsG{41;xe z(}F}I7oOeJ7U%z=m5eLCNunt{*WZRRwj$#hjg2%&NAL6_9qX<`N#rbs+HzSB6Gb5) zhBsVFcNn!?a__^%0=kg%kN%)Uf&FqOdk*z#Kv?)bfT*WEk2t6&3xi7?e)KKElUzN? z-jA8AZ}Viy(#7fdqd``oPwsdQes_|pK6iPzJS!!ig73dNu7}rBVTvQ$8bgz@g7nP* zzDcXNtYr;K_8C*8%?ikE?)54{UH|o0gmhkAi6ox^y3c`reKlRU2{MKbEY*Zn!ngJ$ zqL>~nsl!3)=TJIMCT<#BD3TG3(RxhwsK*LUPV$&i=^ z+4}a80-PZ7QX<-fB!Phrj9Vhn=;;Ue6X6&&42KMXAx=5snN3$SuZuMDU!e437f@nUC)+S}t|b?7Hh zfejzCqcQ5p4sQNajPW#%UOO{T~^Mi=P2^Mn5U~x;O|xkp_0`bG`ABKcKK|OH6?K!+bwbEHk%x z@v*Ga)iYIr2C9h8To*d^wu=(3gK7TNW;S+&3zUk2sp|_+r?E8*j2=sNUVW7EZnjA)E{@@ix9Z2@i`AX|xGK zN*qLCaGZbR`8P=E7@|n7=&cR(hscwAZcfNX^Ln}R4x$|l+g{Z zFrqtL5a~R^uZI$+;o#bYv@cLHS1i)2$&-@{)|zuw-)ZE*l?+C34 zbGEj2e4S|7>b@FjU#G%h+bO&)2dy zG_9uq1jOWenz)QR;M&C6%_j+cNno`Dgqz10aCM8N;ZQ*WY1uK)A2?e*XXEcv5qVTm znD~Djur3UQi%Q(YGg#G2hWrgSlS&<4#wp&kqei}d5HG3A#7TStO{_u=FTQ3ccAdK) zCg|;Gpu4{qetH6^1Ao8BD{!rM=eiA+hlI4-1(^zmtjCfEwOQ0|#zNy5LOjXkb%7x1 znnbeI(+DBb5bVbboK~@HGI19V$FMbuYz^jvb*1YlwI%WZgX9Fod?%_Q;Yf&xSPD^y zohbCTW(J(Xm}m!IDcf$%r__x1YC)G z^dFoCC*Ywjiu|8W^Pjb7yk0^tYwllxYtTn}bKSQnBU z@v;OeF4+-INHK0heo8D$vx1`i5@g0Zj{0~RZM8)q$_hOv>tu+8|8QV+GoI?TW0sqh z{kI3Vna<@uqwD|n%blFqkCW`+77^-*Q!uTxQ-nGbG5F(I$gN~-v{xMZSXyQFD&Awg z&vr3g)RT}aVKQ%`7*$PqesZ@Et-ZSB)l@w&;rKRs7#F9$w4&>v%78zDLR78V8Wpt40IEt%!6FmEw9fO1cF<$cF`BR$wz>1QYl zzhIlEDXygJ>7OA`ZmV~zCmnB(IhxKQn^xwvWxdpkub}lvS;6YLYrMFKAk}ZPkj}j0mD)Ok4fov8Pm)Wn&r$*jnf+RjUbbaLBS{e3GaY!On2d!EUjoJS=@~5KqOX$7+#JfcQ{MvHt z*d~wgPoLC5ZcNE~ElVEg6&0Hdg{#a=GPvR;&?H@1TcIssS@q`bYl1Kd=oNEaK(fOQ z(9U!|A1tsJdwdtoKOu!s&U33S$)`x}V>ucsXK+Cm8ZcH5g%{%&@M_07>>!-i9lp7> z#9ct%)H5Y|j8lbJfU04&q-)_3ip=>O$A!vlN1+3Mj`%29dBf*bcsQ)<&w7`?dDz9(ZrjlG&Wt73y={F8#IZ}h) z0!}H&%EqVvA|?a~-^%g$h%Z*~S)fdBZ|E%r_RxgP%cNfKk0WtEaK2N;-|1Y{8gSv+ zOEz&2l2Gb9Zqi7qRnNj5P@%vhwr=7y``tFx!5r_3h&<*NFMP_V^}G)AqO?de(iTy{ z6QJ!?pMtg^49J*3DQ3E@LaGn*9*0>yL`b!LfYNCO0SKX<053?k z*==hR(7XM&3~W{y8>0dcsDD$!1WB?7pMI8gKI{+M_6B5grFhW?xP|aMA=~Ia$yU-K zNLkViV_v8D!!@qz;ddm{ehFKNb$nP1&>;Zi&JCH_y&0}+HE*S z3&~WQR~|YC>~7f@of2Y5-Vc1Ys@rA)>kSb~b}7iwvJmTA0x-|!oV2OS+ZZHz zC1X-XzJV`_`A&3&>r>S^!pCK%w zEwH4;SB-l(PN3Ay+d$3a#E$$CT@LyMFjRhGwwk;d_WM-KN|>qc2g&E~*Y#aYbKCv3 zS>h0Qo%+>8At+EGTpKA;$%pcN|2;)wYrA|@29!bETR7oVyZ;NpG#&K$5X_7#&rEkX z*>h#-Akk{R%$kFUz#qG9ktCAX&_Z1jNI_pc=Nv{m-B%$Q`~CQ_`*so?w~=G z2dJghd>0juPpT~6LU$1%>>bc?mEp%U>>7=fdm!tMPZp=qo!$PkbC+R&J9Iw(C(e5p zOo*^(wr{w^Y1Z7I4`(Ii4h)*o+iT_-S;7T?+*p0Hq2RMP7dmx5_a@Z;1-5IiI<5#l+YW+A_ChnS5# zxbn6V(`m;f*Aiz*bv4PB-a@~RO2r-~3w%ASs5lVlQT)sOUiAv=pNaAYm@)FeDcWln zG6(uPg*e>nJ`fqs2Y!WGzvFCFxtG9cy+S=3i5&uJ&*ySYpsx5wX5bngppE-|#m9|k zO;mZUk;xrmsfqcnl*@o`RU5MbPg3G8yTH;Of$520WfZ~{-JilJmYoC6dND)J@z2LeEB47Z+&Unq)(lZ%dXa5h#P2{Tx@I z+21-|^n5rq75VB5u69s`LMxlO0P^o9+UQ-C!c;qLyF|2#=?_ON%(CN-4}n=X^A#>o z;&^!vt0!mmwF9k~{BU-QaxE4d@jKIu)2FJ$jmB;t4Qsqn*286G$%$KqCx6QV6+|e! zNpU(QL3TMN;!uHR=U4T5%JqpW(*-=7ntT`NJy)hurz6QjV*(dskW%4pn~H|a17F##)CDMVuDn8 zbte@if9Yy9%wT3;f}oHE@De>Ky$UkNE=Wj(w`k##fbMx~I;p%;tBRU-16$}m*2Iu# zG!x}B&ko8lhOUtPC)ZbOPqOOx~$7wsC0Q@r?| zE+}jl-Kr>PIt#8EW_~O##2Slcj|3B4aD^PpVCkuZH{#+MR0t|Nt|3c?f)i_N@Tc+( zovzWvj50S-Y44o*kT4F$0$aSby>E&B&OYn?6$lO}$v=I*wG&W1uKJ!pR+LoVHu`?^ z+hNi{&@$4GSI^TmQ${6R%Y(5?Sq0g#$grpu zU1iJ_76e?Eaaq{ift_Jy`aQ?*<57(IjU#DWvlTXa@ zRrb@@Jj1r$D`7Fo{PCFgx0eJxC)YFD4$1yck8l}nK_U75&ZW$;y!s1Q3j37iGi^67 zsp$A#n?pa;Uu|mm!uIc(Zedl%`QwCZ%V zet*KW&HQ$-VD06B+TVl%zx_eBug^_?f*U^8#{3g-Q5K-N|MLg0{E4n!q^A@v`cqGP z^za0=wli~buz+&TRo||K6LDVu(s79zt?F35!}QY{o#g5raY^#*D4JhpQ*(-&`PSbS ziWT2&+mp7YS}Qns{MgQ1$0x%b#hN9vWq2(g>OVj1;Ex7kGtAo(`mn2d(pyvJli+#T zxc6guZ@w%~;~(dKrz%=o>`Ks=+LTCG2cP(P%-^GbiWUMP3m#otadmwOinpH@WsTJx zF9VQx?X$>`tp6R@^ec|n4h?{{SLg82q;*zR`<3@lVK4c4jJiwpo_;xf+8K0KV58SU z>;Pe2*MF$}YcxCR0wk%GeMsFqE86{^rm4Ymw08ST_C){F@6+Ov@f+u?=KAjZd5niT zTY6*p@L%&!JmziGKfOPA?SYxS;f*~NGkoFCAH{NCzUH;8C&P>GjQ?wN&3`KU8*K*{ z{Z?PyWH-0c$#I{4l(9|v^l!h)&3v`IWn3oLGwXxX<#qFlR{Zj9_UT>nV@sTSoikB% z3RvMxN0sO#&jio)kA>$V@{@YTz-ueSh93k)doHr6|Gg=jEnjY%@mV%$a2)-vcJKfF z5`A4;_cwfUb$Q1xf9cs>mHom~7pEMmF*QVcJ0c^>05oELNQofwq$M$pY4h#w@FOYkE-VvO<|KyL?;AQk7Ra zPbI36_XVD5K!rD1nAQTX0?UxrP+Ez3p3 zg#UXQj*#*}m)zafs9ui@tvy(}u7cO-i$zhv&98>SrHTtS_?6)GvpptX0Jaq&XSEU& z{Pd6AoKKO;#j7i-DE8Pda~L~*UH{{J+y;sH8%jZS(xZ~BizJ^F5+mafA(PqYHG47B zD1s|H-Z!}sxAQZe?b9{{dZ($DrUs($wUlV{$3`_!4Jo{+2n)dQ9t{kBGo9oeR||RR zB9fByPDJ@^OI61)>iJr#%kh>Yu(LU(v5AO>5QXZWS*SexF>X4F>FYA) z83os9R?Dw%tEzJR54!Me$cHwEz+DB~AONZ)OW^LAYA;`f1(W|RTpXOnzETR{% z@{lxQz;~Ol4EHMS?y;R*fwaz`{l?Z4zBUsIMs;oQgt5Y`QRhRGP$*8L@^RI3)F*Ia zv3qV2TluJ-_Fei2q^fQc9)Ix4hWnYSk6>ol+AMq);983942JvqkKfZHuNSg#D;L*W zm68Cr#F=QLxNzC(%v(0T(vR0N1PagWJ`VRVKAxCJg#rQ__umhw#+ED`9pmLgn1bG) z6%>M8_sD&S{;c^^aKnQu;&)gqkmW(&`K zSsas29*2;KLup~B&B*wua|kyTbvTs*K6U&a-1S_&((S36=5eX1PcmCy#YawYPcH~< z%j}8kd~eSzXhm=a&+UDnwW%IpWY;!jm!mz+S@N#~LG1eG;!P_$3MYT_n4@*(o@e3aWze(9FEM$h3Ml=(Gk*UQ?5{?TFG zJCqQh6E6`Tjr9R~Y61Y^iJUbfB|&A>`%I|cF>hF{MD7x!>b5G!{sJF;lzBzE2Xdn7 z_hTag`4g=1JEtowypKj$bWzn8DN$_&s@M2>#A7(rscCbT<2e7PHhjbEL)<9?D2mA2 zDvi4MGQNYWYSc?aWiz_D`}N3Jr|!X7Ah^9}DRO9l1eFi)rQN(sed-i01u@a3r5}+@&l6=dUrk<=#0uTLuW;CKR=sSdvw+Gv= z*h^=7Y++?B;>67zmyNutM59u3sBV}EOT+34*duH5)sAg^D2%cZAUbxQb&%k^BRf!Bpt9hCv$*Ly6sBn=!hj-}SMw zy8a$X4636VrCfA$WWlbE2hdh%M3&zTry^3>_y(bTfh=c2sDbuOy>0?$BlN?PY43vJ ziIKbWU%~x^EzJ_lY{>R?Ua*o|a+R>>mSGhJ298Y_LMJ)3V;DAc|I`tf8#|oweVF+W z$;lP0A7e3=Fp%@S#sSkHmQlUr7njn+p;kDPRO7Cq3|_oP@b8h}O5`ltfro%-aiavSyUjR&9iJ z*y~rc$$X{Dx322-;_xQqv(gd1gEZ%F8j%&QHFj~P6Eh@qXm3`o@gnHTSM{ooSG`90 z7U&iWb6^>4V}m334#^{}%CS=_I`145x2$y$#yrM{D{x#Tg0do!tSqaK9{;cw_c9T)jOfGmEA^cKkf4Ychz z9y^8@Se59(uM~J}%NMW{++cM%xGJenC=m;#a^F(R_57=LLOs7Gfo_kASWJ$_{e#C& z8@vGm#9JAzxtweMDkvPOP&dh-#h~JNRviParOShD`SV89lqDUbAFNj{1PAm+3;&75 zi@d_xkL_PjHRd5BO_|RQI%bX5>y3{|YOOFZdd5MbtkpmCgQ=Y_hYvc!*z^>)1iW=J z${QZy_Fr6fek0UoJ}k?)i(vWFi;~Xob~S?{idE+ns6$aFHUMKh56Vz~$j{YEFuzoP zcLEuEf4?RB=P`fA$Wai&^R9{b)KP$&6QQe>Jx2X>F2n;`lp4FukxA0M!Dh8_<%0+D zt~Y=)V?uOGv#t-LC_=5MS44T zK2k3mSW`5zi?6){9`NTeJ&~61Pev{6^yMbPSsO3DMY*zgmprR%!+1~&OD72=znN{N zp2tFvMZn}cejanLn&sfF4VaekWmh$14j^>o(YRIO12j&Ht?O&cpkocFFdOf7+49Ceo}MM8sCPSn;g_X zgORe)$tR#Cz~7{bpD*3&D%f zUiC=yUP;~9Y%_THD)}2zA>m-FX*FrgaqK@ETfLs=@EQ!?wd|d!6i)JHv4$E&oq@S9Px4h$7 zzBPemy(e>V2V2DW1hx*ZK|gNU5D_(7JoQ45bcDI9Q~OljmHgm5c7U+Lt745d3!vMp zB3$n}J~a8-E*Q_{Qb2!@xTGUjdmtoL8b4t_p!F(p#FjLkGO2mq2moe<>5w*$ zgODPAsgm6p9x*RYPqcTw9v6dd?(>!|>f3|4dg>bd{Sc7jeqwaJ(N!R*$wLYsE@MpQ)A<#Iqg*S7P@;jyb*{v+OGkm?eAP^?Uu5F zJ$jKj#lV-w2}cGSUQ+=={X4@%}E$_DMtgse8?1mGw3+-inl zFEy(p!&&%+eGh}(2{gA^0UZoa8?Nf0TzzL#Rd^eccb_!csI!;0j6zzGK8#eif+C5B7^Y%GyFeW_ zrdBPVZRCA<^Ko2Dab@)zWYVk+E0Dr_OHl)D=xi73jB^q_3sPk@1)WOQcIo+BRS-rM zqsj6HtjbB7pPMRw(Bt9g=W+Yx8}YzeF@D+eh?e!PQv`ojVj(Ue#0TJPVCXMmx7UO! z#(`v%G#_UBTHI*HR6n)3Ra5f`6gCvWDu&wDk?-(JZaXXHH}SQ_CY5qun^_9`V#)GW z3?WLfP$qLMRUDZ3Sk^w+veHlWChD+BsP^~aLmwePt?E&wu9qPZ?ZP;O8gKcmbU%)B z*9^*X+Amio8aJSI;1BBoFCy&dpQbJ}aJDm-tr*>fcIL3G6hqH}X>fi6$!qA(DCH!h zg5K_Y+|%kWLOViSugj>~qZH$r&YijLLdy!o7S~m@PNq7;&X}CZ^79PuejPA3XSRlG z7vhu12vF9jbfJN1wb`X+1>dQx+RrPRLf9YZT%(xlR6J5RY5%~taWYbhz~^El+lPqm za3-Pg@{f+&amxc_=@sF3czFXC(T2|{2= zQ*)MTXKz><7}I9cAZk}iV&WATqg?}20S3A}{`eu#DCA!uGl+flZhg5arn>X~QdxADW311og1)y4=EeeMOjW!3r$w zVuuwir~Dx5R(_$B3`d;U5wkQr!tA#*m{!T!|25@=T~+vd$m78KI6*gEN=18NIYer` z6%Ajw{<3W8LT?~;Yj^zWCrB2la#%?En`#zRSt|d_jpaQaH5GU_;*}d<3{k5R!-N?riv?@$uMb3zCg9I4ED+3&wZ` zW{zIPw;sZmw&G4YAQO{b+7C0UDMV3R+aGG1^NOL9rK_K zQV2anTLregq5A`}E+d|kX z8?R?4+T4Gv(J63i(3_c$%M$)R%N4jpqcoz);od+xI!zK(u+6(1B!`0w9RDK-?UihUqzH z{QvbysK2bK{YkH4E%?Qy2!UGU@D*n~m*juE6~rTHFbsFkg(EG6eJnp83v(TT0WBo} zgM(PV?yI3-AQ+$OzxoEUL%JD8tyJ;`R{dl&q<$H?xGdmSf6wU?_7)z%Ac=#2F@lie z201q?B07X0-h3n|GzI`tFq|R7L3QXkR%nfmz6-hUu`St@WG0c{mZ%MA3c>)xztdR( zEsf;4Od}SgY7j~4p3&w|AU0ZIBok6GIJ`$)ZzYJ+Cr!>e*~8JcP*hopC3_%!zmxyg zHgXe*SomsO0dT4PuUWi+?*TP~fCtHIyhD^F!X+IIx_vE$CpB~^ zhnT3p|$7fJ=U&0$nOYy081y599xFp)s$7K^AH2zwuTiN%q-8!TS{r!iTY?G@KAnlG#`Yn;-1) zZ<{`%B2^RHsM-ctl>a&fb`NSuXAZH*9sZ3Mc zm?>QD=R4{*t>fEySLpHz<9Rh4@rP9GO0fMPN>^&e)#kwg@+0AnP|ue#B_5V;>Eo7s zDPXPD#tP>;9c$hVu5FA0PEny18EHv|gg($LZ_<=2WJ6SNxayfv<}W&}k(!CRs|V0Y ztCEN&)ti~<&_xKz z(v|CyI<|E{ua|zZEF7YGI<7XMaPYhZ1_RmMav-?MIK2$-Oq*AJKA8nQka{=E?@yq>m!^}u&0K3Dj)?Gv zIS>6Pt%dceFBplmW~0Ai^Bz%8>rpJKpar-^d)gT(irZyFCno1GWbjMP(xC5MBVNsL z%!9jZb$5reA(%kvMt7-jSbxA2PUVB@Nw>y02=_H;k`_fLf?x}_v=cl@mImk?|7d+9 z{={>3yf)FsU0XmlaiN1MoxR)`Ya(*7Zt9qw}@@k+x{Y|&ldcyS}e zb;i$xpJOlacVatiEyB*|O|v`EGo-!gSEPXAJ@p*H8!Azp1HcLd`%hvI7~9B1WWgzQfxZNaGA^z5&Z{LaKVMzSTp z66w91JAj#1zH6P4lGX*S!WE~uW+Z$VP9RPJjB4Hx;rA4%I@L>l!=QH_fyb?IL4CG| z1D@==KD~_47sz(zV>_gS{yy&~9hsl1r#_1=CT<5BS`kHV_W7~Rx5X_afG&=})eA;L zp=B)PhU`$i=e5E$ByXPn3~EduF?t#ZNz456{tzc!e$EVg~?NdxAqBHvd3Rbd<()a(KcLTt3Cf^aD2gB6Aaib?bZWFzcjrJ)G=`jdta z8Z?ijh5~sFCBo1|$|)#ziaNGb4hKNCS+QsUCkEy$&j8x6 zV)$U~!%8F!!j;qozt5^g7~uW$Z{wr^AX+-7HFrS z3_s&Yu9V+IaT&)p^NR5iEM+7x+(qzCCTZlxL*I@>ceLCJV7d3r|i4vAS+S2uR zOO*n}FnoUEY>^n@DhhQ+5b6KuC{K@$ojY4UOOyhSu7V{#Qu&1lp*W{q!| zq???AN3MyVw#sdUlJ(8J3xsAK`4(LLVuwRRRgo=PpJWXw(k#JDq@seK@9^g7m_m{^qxRfuCVUG?JAdhYOlbnXVV%TUcD z1_cW1&+4ESW_Jj*3)3~8SOMK^Lp+|dm0ibbE?aZ_%%lrQFU!k{ffF344JfgEAm6`e z^ysbr0Dn-O_p&TAz@_GmKywa-1US)fIN+vp@@DB?ZJw0BKm(dFHagn)9xJFrXw034 zWyA>Jz68HC+`8uAeLdN>xPJPpE8xXRjtA-BTR?tg)hu#AMH1{4q$I`YMNCD>u=+lc^i=QyOlrZtkFpRL7li{ z$yfh3{6;hmw6M20H3S?8kJheQ1mh(3Xrxw}5Zpai(H|R1V2H*BR(l3{Yj@ve%9kQ5 zWXVU>twUd6WaB3hiIAQW>~+kp1}@y995ZZ0$Q=gKQ6rb4FS4qEv6rSAfQQ6?TZ7pN!`hC8PsU`} zSv|jJaKK?V2`5bLdkHHw9D|6XNdN2s#FsE&OG8PURwB!H2_SR}{)2Uy^na5D&c5dW zO1Se6-jcZsVk`|eEht3db7n_IE)yV^bzdgSiyty>r7HA;q&MAZe65goR#NBUht68d zZyO!Tu>6#VMX~q0;H9rYwoK7sWodoqUN|}3)H@FFFlA|4{sT}P3LO%ld{FRAui;J1 zBe~mdCBIcoRQ`Uj3-bsb+xuz*h@koLf4AsOsUy6L<0ZN;Y18Q`SPG4ivm5iETUnYqs{U2rRaiB-F~{jKj`cFT_)L_zKMu^V6W*&G1{o6(}0i@?|xO0 z1dpuF_Zh2iH=ck?D%G0+pzH`%=^d1kSf#JQs77rYV}Px&gXh$2aT`Uqnm$`egyoRX zXGoR)QAkF95xmr_sCW28L1pa=+!9jOoD`e;8Uv6a?p7jVz;-SxihjGF$IQx@laTtM zT5}WEw()-hbE4h=i@t@a!YJGg%MD0(rConrY!40wtNEp!$&g=-Z%aLvHW%aMM~s5F z*EqzGCB=`5|As3;A#p;k80G8qMx&|sgj}TZIb<-{&cB1!)`ac_?ZUexwb^akSUTUF zq_Eg4L&2e0euJ;gL%;t4IGiO7`UBwuQUAfjNI1;aEJC?TOVOCzwHPb2#(^~TPldA= zZ2vQr=qG#06fuB~?0W1AA$b*wL#*!5oJAcD) z=)rF?iSp@&cr2*gG&kxGVh-&Z1+UBf1i>gCg^DP-uY!FU5DhlF>?)vcw zSUSfwdkE)(?((X4od{~U`+^C!w2K8RM(@ZVKN6!(o_ijDpKW5iiA%4Ht zhEjvr3oS~;kX*mHM}N$1Wr7HKscwxyl^za?6a7)?K6Q@Nl4R~DU-D94U+8j143mwH zuL$erx;4uUou^tjc?%|cT!{(+*|UgSUUsp#%Nu;0gVpwI&&7Lrh1vhx4D4aSw|(cr z9+nRc^$5q>o|@~+;$ap&IkR=1Zs|?ug{AX~eW4FZP@0%-*K@u6j=Wpoey*{X;z7%s z@>)!FSk1GKt>)ad#x{Yvnf<3p6`}~kV4}C5-<-$@it*K88h!MDAdVM%YR|egBuGUW4D0xP=Abn-U>&y1zYS$4&H=( zGeeNc7RSlZ*jbI1-A&#I)#XGMum+?ZOJ`zfU0rItr6-%~;5xM2?_cq>;;HotLb>tv z?T3aVVi>gIZRqE0$L(|^KeXUW6ta0@0Nm80%xfM{8XPbAsYDHc4CH+)LN-v!R?8&s zE(3TL;Gu59QHx-c6;)5(bD_2(XJ0^yCig8pPiH4dPKjKaNxsDMpE?y1Od-F!M_ZMu zL`O>E=gW44E*fzHYwcTv0NMdgjm)w#^tA`hWvo;~m+`*XT5}6VV4`i$Bbxo#?zmPk z1Wa*(uXhzJT?%ItB$Lsmwejyh*fp`B-fn=DZf(`&l2IN(Iv6L|__j)w)H(V|7d(Uc z+bN6(%#bG<-ZPSPZr%00l1x6PvGb%cs_50_MWXf;(U^`qpELx4POpH?B7E;uYy8Jd zW{%YFxB+REj|F{$z=pSfuQxePPAbJh6hN{8HQHYZls>@8>4yqrjWWgc`@MKYd1u`c zxO{Kj;!1UB(+^K_7m(6Q2gn)06C~nE;PiSqUi{EYhG@TDivT}>9;zpz=Xw!Ap#FSz zIU2;G6J3STn9O8t((MJuhDDaF&gb{nlXrL^61Ce4VyJp((@Y)QIzE%+qTR&}8>Je_ zHSJHeq7`54{YG04qj=MMO7z7r#;6s?P3~I0%j^P#M2CVG5%mGFzjR+f(K7U=WfTW~ z5QeJ3NalRb))MMpUY@&{>S7KRh>8=**3^(qK$UwO#BmcW&s6y)_3em=t_<|41nNeN zR`J_g6?sZVk#5pC|F)|Ai_o%93%w@N5li@`L@E)~^$@%2b-e3FT^gxDWO4N+@&Yp% z(S|$ul8Pvc`$K@{_0*8^UJ$ZU>0$QIwCaz58FF56ToMj^%pbOZ$;i@Fe!OIqRCBW^DWe3<^)Ggfl!(D+81F+Slq1+sP6{O6B^= z9&r&0U|R8wioRs7V}@38p9;xmCa7r=tYt%H5lfIAn@z!`kPLaG#+6?&@s0gm?CttBa_s(!!MLRi0 zs;=3KATcZ#lPo|rx$w9_!9k(ing0x0_tBAH5}F=IYxV$lmC8o$End^o5(tkH^%t(89l+davct0@%X-+V)@V>^LdU4*1;N+`=Ur!oeZ+czP*h zX>J#o`z9Ai9!V*?+@gRjhaUrtT_)wiNE|^oCD#~@rC~8Qf}v$Gxr|ow&N2$@nK^5; zZ0pXj%BN>jJv-aZhk4W?QvmH2Bm-P4Uvv6IS_=#p`d%9@p4jXS&_n!3Bmz7>!M>hpK!+OgfS zz%89m7#*AA{qFB+B<32}<}Yp3?(@?YSK*A#UJXM|7(_zRj@~kF84ds;Qlrz#;s8^W zXL`wY!Y**um`Wj~>b;)N+Tofqah!X)eR9vxuzCdXV{q^*x!B);BS?-51`Kv+gX2r| z4P5A~&|R$qi5UGfIt-wm`|uuCPi{(t-BPbLpBM70$Xn4Pm<3PtaHid>RD(d_9TVz3LEnqSk4Os7y$EJE7X`c5RyGC=4pE`SbNW82FDpdrlL&1*)KIM#H`T z`}wtp18>e*srJBb9AyV?=q>M)Y6dq%3yB zL9Q;}2>*NX_t2WgRq}*M_z^@C^YZ&M!nUOrI78-Lh;Y^^e4o#rZ|q%Qroi-XREOL0 zIwnxYFRa%Wn-IHp7Yq|*MXBPtLkb!)eRMwiVOCRP0?T(&Y$9!qc{kmP62uZ1RIw!o zcqK3XpNRSIR?U~zt8VooM_6j< zJOqxHP#QF+?}qjuBG1#qaq_4MqEl7mvs(z~ceK257VumZ+w+4-=nxK^Ze$?xU8{Q2 z|K#I5azxUPbGFt4B#*l7r?Bc}Lje&b0U}C~H%x+R>K~5ZM{zb=bHYdMH_;S2Y(!PmuCcIb$&$kHT^Rx_ox0`#&^hR^G6#NXvDL^^9!G4hG;Az1!VCRKq(aw3@6 zU7dG~I-BR3tSu)HNS@KXlU;%fxdpI{20ZI+R0;tVpO>^{LZ_#}Zy!uNMW3P$gH)hF8&3 z&JiT3B|*}6;G>ABTV=&)E{@`0+Gv3*RC3*&51Cd#&6_d}Qh+@ggnJq2ld&$!EPKGqxcia>o+)-%YpM4UC{ ze}B0~S#T-&fI80*c4Lr`#kLyE>|c<{D{@Y7@JrZ5TdU$}ea*t-GNJpmjezS(?v)nl zrvO~V6GSmmnVj?nqfa)EdQ>A8{%GOh?wy9;mPr1-YfhMN?o^6P3dI9$h`q{7@v`6K zr4gRGRJd2tN;9+$6CS`|>pJ)vw9F-G8(NRzxP8kJ z(XD1!#Ws2ni&2^uV!cynKJ%9^)guAu?$PKGwDkjNa-2)W)R$#cTkXNxBW8eq2klaH zlC*8NGc=9SMFEfWE}|w=K95Q>a=JiJP8>u)&=(uW&_~1dAB)1`of9cm^yU8vC-(eu z-3#pZK%s{I$EMhOLA4F{;=o2pK?uhHy`#{?3jZ;9(g zbf^91_f42Y=4(&C=jlmCLvsH#Tvh+Ka%=oLuKzo&nYuO;p13{SxvgWPp;T?{WaMrE%OXTi-+@yaG5eGq*2E|fCS@G% zxKd7x^y8Cqp_~%NU@bJw!n?#X>Rc=i>wiFqF-<4hdw38Ny$?x9g+2=TuT~ug_A_OMgFLRSH3@-WkUi7WL?Ps`QjfRIBUas{Hcr5)OKSP+ z&gLPc|J8Z}E;X1n^gHk_WK}^y=A*j=PdA1(gR10Y^m_S9)ydVsCu*5aKoxZzci?S= zochV(>qis#eEz#pZNnw}ms!B}-P*R@e-_fxrB}U+Y&az74`vvogD|pT41_~RuP<-? z79aO6UIK4vqgKJnD{2L5Nim13=M>xWkm4xv zkx*n2nqntPVF#&QNI_-Lx9Pt{CGvJoP&mZ9gGctQREi^dQPcneiL1*b1cg@Ndy0kU zWs;LaDB>Y`QA%=3LF?j{sorhVu?b~7Zw{xZ6yC^}sZo@%l$EjS2(W@~R=N)3qLB74 z0lDv6$;O>_3K6+(P8iES^7y=r zE2B>TrL7_mwVfy;YGqHRgh%>4P}7PS?4~lLIzue_OXA@`G;*L`AjwByFiNGRdbZS` z0`v1=WTBx}L%~nsoNZ$KzWIh9rQ(5j^}5zU-4hcAObDjYa#dep zl<391Uv&04^%Eum3ogOVX~k@p@;dqi@XpcG4tbLL4j(i&e=OIJXA<)ZlKvNyR`hZq z0SbVdF@UPNuN-6r!&bsE)WCP4@WfLu(ti5Vh+0432*!O}Uu08a(*H**uy<|rjUQmsm5q4*ikv`2|+w5qnB+7AKJS- zhM6if+H&~=jJAabo>x>?SHyK&zj`IQ|ZhX?`@F@Nq@R9tV+8gQFY(7 zxbH;6J8Dx36ziTBM;T(YtV4~Gk&zFP-l*4IaJw)s%|_QpgC&_ceSEcf%yeVH@Qg#mhXZ>UnSC z;cFaZ3=Z4eKl-7*Vpt*R%|kt(_X$QJWqhcnF)!gy1U%B!5<9$BlIk6Ga7U+X|JHZ?TPhF-I**ecmlKAds9{x?e zH^9s*Ifgp~i=g)Bg$PL~ZgQ3UDULpAdm8vPnmQZ*1o58Afk@~gZ*tkJe*M341?7BM z*;Ib}(_It1o#^dQUaZnAX%Ieo4{mXjhCuapFd6R$%YifgoupDn!@%HccbKH;k0k3~ zwEl=Y6i{wtl2>fK3AN;2qXmVjs4-*Nihh@25tD^(QEt4a1C_}piZ(EB+YKsAyF0WM zHWUPwGn$4(adsxn0YzVhU*J@eHCfd71!7~~=MU_J{59rUza}ngEC-WQsWDZX1`I%O zx$^a#b>=u3BZ{TH6N6AN;BTA#C5zLCET}&~_=P?=hMy3`Vw5NZngl!8x`X(Ei z2OBcwT#Z&n^6euN*xei&|HkY{w0O8Au|A&zJ1Im^`D}Ek9VhE(Z!!V^4e-T`g_IeoWAIcs z`MwQ0oM;@~Tsy2~N?}{_zp~hn8WQBCqO7ydYndF|4byPCq4*@)khYz|ezKSFxctdn z1ml}(_$3FcQo-q9;eDJj5SueDCX<}pqM6u#YoXHjF^>Vb=wuOfE}o_HixU$*()pW4 zJR7KmInUE9)Kfw$IV&f`Q2ZVzhw%^;pVlBD-OQ;Ld;_@i(5Z;sX)_Eg4=f!kFKy(x zR(;%63LpYR012R|nf*f()eLOS`@4Dyr&$h%iT2Kz$woJ0TnJD)-bK| zolOj$Pg%KMgGJnjbp7JS;aD(k!d#QRaO5T|an_y(TjZ|2$l)6m{}B!=kpfCi$$gKV z((@c&1jTH~wniT~4HNLBx$&r0nz~-~dMokJk0F0dsI#9$yU@0dJI;Z9SxWJH%B*pBPi3LFB^P2D4;m~8xzH(`-F$1Tp*bI>Db z19KJ&Y&sG8^z2kLu22|Y8?_}nCE$HEfO6t34 z!NCGe_)7Og`s8r&R1O?TYT{Eqp$~L;$5{ zM?Ulo<&H&sa@WJ@5!@i#cR{Or0HD)G{;sK36oA})&LOK3XdOIntMztA`}F+%#*l&Y zm?YxYEpv@BXz)=_-mM0UYo%e_)$Ld_@KxN7Xr8q-UW8EJhMIT_x=vWKyyZ(izLALt zdnlU2&`u0aqLY@-8#&g*bGEp?zRFo>hEp9`XA+P=vwJ6s2s?KyQbrpgSiM^}M2z0W zl1Ws0xt`TA=lW3tpb?{qXB-(sSody-htKBor(qNtKj+=9Qjeq;+SkotMV)-*l13al ztkGX0f>DS%GZFUGlEphiFWV42G=^V;B9B*S{q~7Czp3&05Z$+U4!o)^w(5EiU1q6q z1g&&)Eb)7k9hO87tkIZql6N*Gj*+dANOHoP2C=Sb<* z5Pnb))YYR8^O(Uyl$VvW4O|P<0p)J<|HE79GqkfuvyYSymx92kyci9^mWBp||1vxj&D&_PLL0bvD;5Z?%e2!Y*C3t$ET87!57i z1>5#le%?a=VVXgyRkqaws=@j+-2soM=vp{vJq>@}WxhpD5ICiKgS}8dfqYr`S*q{Z zKD?jGSZb@d1FQNRzu{{E%W9))uyB4Q>RFFFxB-?*xG{Cf?<~YXXHxBqUC#i5 zMxpS&{U+LYPm@ae8&@9QI0gPv`mKT(;y>A!)->mSU87nDFJ}go09aDf4_0~Eb4-)o zG-nv%?zTR8d$`atyZvSf`KToc72Z}o3o}E0pYMo$18%FooAnJrxZiW@xrifEgaadn zLL?`oNF#|J=V0Ooif-tzuK?faJNH_sR5W{X;-XdV>ls=pAihsdP4;%g)iYFRFw2^U z1Nf4Dhc`do>+Nn^FRb_F`}mkeT$RXP$FzS928tP z8ojeSE=Erf$uqaDfZ(BhjyKhs z)A8=QZDFT6LJLyc3kj8B>E^IL%c18+LkHlw>8VLM(2HjD{p%xqYNVb-+aqfZvX>?D+`2T4@kM`n8)+jrZm-xtKsHQFo8h z%E}6u+_07jwFX!vfV~rUb4IvJaG@3->hPXcdQ0oR%I#bY@QSA8)|&Xm4}zuhn574HVg*{ zb~_?&QF}9ez`OqxW*~iB{d7!4>%o8I!Yjx4>yJVeRtm7Ln4aOLa35qc2KQ}Xy_{M0<$?aqb0#Rz*I0aIBu@vUY*ed$z zC}${HgYy!~_At8_i?r#;>XB`Um-7lW80Yopl`RCVt8P;z{{?x1uLb=zS{fIhxbhX) zz3|otYm(9SPLkDO=JpKZQjX3%?gZP24Euj00bsiBtFP!Vlqm4-gs~1n;xOe>uQpAz zokG5W3v8&M_Fz@abYYFm7V&s0V3!J@)UB=I=dew0il{e>44R88mw5q;L^Mi&y_=1XN{ zIhH%5tu>TequhefWWvG<^>jmKNw^wfZvM6J1=P8Lp`ttDj9!1)p?-apG(%vk_;#nb z?qf&rZ;6Shd9mG>=R{dQ6*3*Tz76q*bb`A`20PjI-SPV@-jkugwvK6d)Tq8NphO8a z44unI9t|HA8j|^$^Itq^jyOX#SJsA0EcqIHR z5#En9P^4aMo3~tvp+{i+HE^38=-kYoqGv`tb4-v2B&*dQ{E{6R5 zLDU_eaY?ML=If3QCUh9QM}5d+&S4U>J6qIjqUV~)b=}Jl=YgAST>Il#)xb+99QVj0 zlVOSlFps9*K(wADn<)|X)MmcP4s@?ivutD7UPUA63BHbZ7iN{_zUf0)(E%lb>E2?= zREYBw^Z=YL(z;E5g>-O|5WiMw*U)&)74zw{FHTjYvz6(o!Qi01D@h!rEgo@bR|QMk~dS;|vT4CcGN3j(McOZH+h zam{HIvhcL^4F^d+-FN*Vq-?MmR@A=e!;SisfK`kw-0~ciN)M_U^&57lQDyADY13%s z7W{1TQyL@zO^K&<@^r4-D0z<4ER6T0FFqW87K+zBn$r!GW$hDoN9uZUllr+pwVkJ- zql<_Cb5-(tAkzFm8pf6dzbWKh1?E@G*WbmXiFEh1UY$pK!07p4=(@=)@~!8reH!sK znf5SfyszIoJW&k+C$p}Gr>aG4x-}Z)IPS=PK+P?(X;Zb$x(7C(aY#`5pD0sS%J#i5 zL+h&EMd*X=cE%RNR1V-y4F~nMWN6Rpr*WOT6vA?Xq)i_&n)ga4g3fgWdParX0FB&g zeUw2C02uSw)hf6p;u4yGJ9&Q|!&fJ6m?(tC;I+C3#vx{BPInm?nb2txtfCDgA*2;9 z)w%9nr-)){Y#do0@t_EmX$Qc7Z@6Z}{Zg{uo&~+iEwhh9+0xFeC|U$oL0{aU@%3}t zS-*-fW1772-w?OPx^6_O7IJuUuy-ijk{rcsrk8*@flA*E*z`~+7D|j@kB)Ky*lT0L zgt#Qw+M5aG!@;WjZ?bX_x$ZqCdttOd>WH(HeX|f9G~)Z!HY^e<0paFPEwb+g09|~I zwsEr!z_(_Z_xU`gGJcD|1mG!1_pvQPI`9VTXXznTLji$?SUppVP8*+`|#Y^CSlL%)59J((g|BMhrJkocvLA(gC4``e2dpvsaZ-Awjz5x ze8G)DkEF?eZxB@Z@9D=0?UG2$M8|>{WZCfgeeA8(7U?||*^5ZtMhL)$g+|}%pNo+V zb5v-@*+)T-6?At#K{&a$#I2E?8g;a?132Q$gy>6>e*m^|jIPp3ph$(K7C`hq>7EhX z0u%#eB=DBBl7sWrimzsBW&LF#o?6z)hLgnrR9pQ%+8=#2bD zX_y!+i9;K}H+KDHGB`s+fP-_|d6HoHkz2N`w#9UpFOQ6$hvI>a#fFBZ0m|CUa_*Dp z=FeWYzfdb3^)Bd(2V*){SUQnvb=$&F$1`Sh>kR*rZ^fUv*nNr}&p8+We5RFym84e7 z<<+O&iGzPp9S$!xhV{HFUq?}ar{knHg4a&rLX1G3}{LKiPCO{?p z+x}%QE5(lXk((wL=8o!5UIq8oWUa}OJvnMP5KcU}F6inojB=+LgBj3Z`Uc;vDkT7k zK^2i`=4DLK{a;lOUGEQ*{02lPW2~*fgv;ZW@}k83{8Utr@#sd2&fb7G9Wg z_gED_o!3xXOc&AZIP6?Hba`eHsFWO8hMp4O-FI~W8^gENRc8<*_?AU$D9m@n;-;>@ zPh~}U*ra>sL|zI8K_dI}m?z%PtLLvhh1g>nY~Y4b{{JI&SFn8H#MeJkR4nrXOb^XU zg}dIr!m ze*NvhFM5=f${SJ|g2%jh`1iOP(3>(~dg<^YP*-iOW843MIYQW)-TX|7Zh1_O4_HoB zD|Wn`{QZ?!=$?0)|8IA!#kjwp$9&^#8Hgku`nx$BfhpD_&|NxHd(NT^UA4a&PhM0T zpgaNpOMG{O92|Ir4JUkkVgC?r3yZ-fN+BC-ZEt4y%5I$sU2vjJL3`8EWW%@Dz&GsP z#Jb0-BP|pgUM2u%Y>lNh573ty()VvENc{gKy$yU5RoXVL4{Bc*A-fN*h*+YJugkhF zL>63-(vHX~yP`x^1-G>wS^O^_rHw58uxXPc@?cj{f}#|GW>B^S#Wtw4!IpHyf3?m-V{27su3}HEC8#x}w}bqnDXIBqo`7TO z_rYu#}PMPqtm7=eiZTovENicJB(C5m6V z(1yJe#O|&gvTm~Vi`>%p5o=?#gXst2-T4z)p15cg@D=3|ItLbYP#RM%&L9KnwHTK7 zD;LOc-l_L%{2_bQdq~5=;>>mYNpn1e@rhXW^H#V(oE(1X=QQ0$B?ISk-vPUGT6X}x z)#Yr`6VNLt^D`pG&9#SyHLR$h)<=DzWq-rkhH*q=cglu%{$fG%n(^pEOSj1B6WA*1 zMP1}vv>Stjp}0~vg5(uXsv$?SD8pXepd@~((HQuZ+rlmDdC$2wAu8rbJjmCZh5l%( z_)vk{%~!vt-=sP-0U*OtEpdeFspN!~2I|fqo1~OTus1@$S8s+^x3u+{JG+Q}%~?Com9V^-92UyvW|%helNcDC)U74ULnpX(Tv6e&>m^cBRy(L|ev} zM?nJ-8PnUNicx(JC?W0fPa*nww&=uQit^RgXV3P!U(Kp#mFxUzeYCsZ$5zYd=!)y} z;6e!I_7RUXR>EtOX?}H-N5@zrf4PBxg*qhHAwa}UisZ1vb9ij@<*kFs;5Fu{4f=0k zcrXn-0~Xx}J$@8(U1tqa$G-rak~Ed^!_awI01ooJv%RcmDLlu_Yx;aKcE1ff|1|)^ zpUre+XOoHDyFBHR=##_y^4isWo>^vCr6|%)QZRCEJj9-5=6)R6MuJXq>hy{Ou!jg~ zTKz3(MC|y+l?dlhJ?pP1R<$@8P%IRD9BJKX2t-(Z_(7{Auq|rtLl|s@XktEK4*z60 z>$2xz7y+Ac4pnzWBS=X!wT$0^%L4^?`H`#d;PBy#t(lRN2a7>0N6XJ6qwqPGP@bhe zP0ty6t(I>GcBXkei~^!MPhBJRcpcojZRp3 z>`Q2dZI$#nm_iS-r*b$EI~o%}JnveR+|Pn%;Og@3+!&m=Sr8o-M~~9_Tg;&<9BEs{ z4y91f>|2K5HIbWE6QHxgBT*qz$lgU=h&O-HLZMpb##3 zs^(j8TGP>Vp^WEFn4s)DnP0+{IgMEnHQLSSOM8N0D+NAraO0!2W^WbWsC01gey2a7L}yxdNoQ?({ibO<|dSm`1S~D=D38My$t3h zr;~2Cm&+QNs8?>&vYCL!#qX%aH>95mrp`3VBH=d{o4JrT9?{++7>lBpjK@4pV3?$r zsk7@VsCj4id8eC{_a8MzvGnVIY?~L88T3chO^(_=;GWJR`6sAU)bCT?`2V@%&#TYU z#_K>amVR+|esSv{L=G>!86LPBR%?sJnj)5fdW~3Z(pkdaIWSvHd>zrCeseLi$oVlZ z;;YZN!8tGD>qqw^I6RTp1oRh5N$8uoQREfMF4fhv4F{TT{UkzX-bXT!Fs$~(m*>SVw9F8hz&2Lk~Y(dw2vTL6lK-cfjK1nXqu&2lX zB6hX1HA*##u@Un}S2zWjLw)Tf#5ERGySa;2$WkgPbrNg5 zVt;=KF+GbJPvCY&Yhw22LntN}_?w^4AgO<3l`BcKtr$F7LHWJGH|% zqyQWZ5KAaCt0NYU`???}wuSKMk8OSgr*I}~m8SlJnOct5d(SV}$qAR#f%;T60X2NV?(3UT&w#7C9_NaKeL$330H?xd@HPIG8j3c2>}w*gQ|8w+@0XBVme6ZU_W zxR16f9=s`Nl@7(m3dgV~rWwDV5>S9ey*AGS_ysC(e`XGWp#dfdYUm4Wd^@5n0Jzdy z&Nz5eKe$P5d=fRdw$<14n{Fa*|0|0oQfOPW6FH17j)vjHLRi+{u#CC3&NJbJ?;z0s6+K>Xl1-YUqp z4^A3~U;|bF$Wn_mJc+@P!Cp%n(Ry2aS2^53fHIGlAb_wW#GE6L3EulPU?^jGbn0O; zDM%nBT# zG*%U$EWyX~FG5O~ptIuNB5qat0pWgQZQ6v^zSU7IlL>0OStoxrN3aifU}%Muaa}&b=EKi;1J;YoJ$f zaP2;YfMNH~^9dsG!a?t$XO!i`f zH=nP>{Gzdo`E7CC>1TpV*VPn3K3NCfzL2cwZu>G-NelGF&i4WQ{uLaCOw4os&kb+t zk9fR_b1wBiCR*B!LRdD0k{#BKoM|+#KcGz41DN{uo;DC>?~f z#cwx_8$qE^B%>ScfteiT=ntNf)!w%IWqu6mE)Q43pC#2iENWs0H`m04BC^-iZ{UE0!-35 zBd>(UPbu1cCF15bY4h-y_hz5W;-!c;sb?Atb!2#s8PABSmDKG%!Z!pHzT{Zr7Eg^A z=#D;fjTOzOQ6oL(M^nV2+P11g4B zFO8Pt!lv#T9at+CA;e3WUE7b*9NmPRdYS+o8ugvR;=LDWR{7+e+F=w-PxUH0;KSm! z;(xcG=PztoQuQ@mZH_1*G~mgmC@t9ZE=Q~d4qE#;6mc%ZtF^_R0eTrwXO;&OdSzK3 z03YyY9*+JvQ+HrP02&ayzB_3_YqAx1J5g=)FV>yT{BeRSXv8rIaszUx7p?7zaR(`HfzkG!TEJVRPNQnW6@V-~koiCf z(y(fI$K{!?Y*0q!94?Z5P*nLk=+oEfdm)wI6H3C)D?s)~fKD(C1P?orSB9s#pTcn5 zD3Lbo!m;!Jo#o8o3U&>K8ZBJ+7;yP(%qagLUyAR_2eYFp`Jf(SAhQ_@m*nrA?_4na zf4=M0(#8Ax`&--9^mX%a6&-@M-n9?;`ATr^tQofK4z3;{F8mU=Ce~I9)vyXfMU#U8N6z6do_QpM^`LnAt zD`@`F(c5Do%zL`%fCMoNU#@sVZutN35$i3fn<(jY?>Aj}^~`KY_9-*Q<+WH)9=Q?F z%40lx_7B|skN^gIvjwylE}4$1nXTs*5BO|{Rh9YArKPN@I*CvkW(ob%}) zPb&AWmxEF6#bq`m+A-Vl!e|1cyODNzvqi%gPtco|6GQ?DlcmiQ4awIwm#0Q`RHYvK zxtcT%_#RFkYvKFPmf#9Lbxxw}L!lvjyEi5!v{wxhjk_#`##jWv_Q92eu0*#{X7w5* zV^vMb0(891#17loz!$eLEFw#cEdA-7ED9`eZy!DfX5os_0bn`rypvWfL;T2TQ|+&Z zy|PV67=>%YOn;CChZY0K*quG-&*zi|S0eG(jT)qVTAMbqxN8i`;u$0HZql7w^*_u) ztn%u=MNkwG_ANoZG=D=h_5|M#W{nuH6rmXO4pb*KKWad^B)@?k%ie^V5)iG|S8uDt zSCjU~(OvKR0j95exAXN9)Ihz~;ZM@_QQcGa@zZw*7m3?$e^yR|Wyf$5T9$TB<%YFKH2%zQu{mt# z&Q(666u+w$xWj-IKT&=?H_cCv;5)2Zf&`_04@_f{shNXa>baI#iXx0ZXHmIhu??TK zw$)7|oxAa;KC^(j=)GUTJ;!hv)+ zp*8=;;dji^nn`XxGs761`r^Z=^RCM3)!f+#A)rfiCp!$q#dfxB#8)3wiOO%cs+3!a zoUlU(_04g^X%ygrS_1%SRG3uy-bLHG{3cNqY|=t!c_>aB^M=4a;b|al0=7P=hP?LJ zS2pQ%i9WOD65ypkKMHfY0XEa-Dix-4ln*VMt-3tWl2TelUWMU$Lr(EE>|Y)-)z^7tfzo>wio~d1T-?zcgJ1H)1B;Oz^3iUW~3@-o-TVZ<(S7C$IYxt{~8wy&=fB zdQ#6}xA3MPNGErJVi^6FFH@^DF1nk!3@z|vxOAeMuWK!j5B+9?csF_~0=-X0HQt22 zs|QuMi5?dlM>jlrQFc78j926*u!{-1YJ<@97pl zjLzPKLS{B*V`k`hHC^pNklH$U{bu-XPO%yY1h8CNBuo~FUYsp}d^wryZCoLHK3q=y zPF&gUseDbpT6r#nVczMM9b-;1+%@?WwhgQVspqa!_+vSnoql^M__N1T@)Y^qOv43> z#V2wd;r63lKf)=MS7A;gINr(Et-^%tYqm>R5%3$jlOB-voq&5@@Ub%0|&owS^Fw56qS%1ih zaT{g>ypOW$e)vOeh4F!`LOhm82gHYPY?W`HgJ#+c_UF&c!t*aT*|FF61dC@;ho2AT zg0PtHpe+|?h@l9nL13+@$?TDDC$4o)LjpnIFXjA1*sIO9LkJ`|+rZ*p?I30b&^WnF zmORajFPU^7XR{@eWBMBOi1Y1F05FXDc!}eWx6wQ0UeRMq2)mJgZPoc-CPWY|R_dL9 z$WS0avSZ_J3w&)+xO5jr1gJ63GA760$^#X+g^4S;X5O>eS;#NV4kj7zI&d{0F}hMG zJN4F;Tp||M-j+egYLQ-w=|%nhzN>BVfOIC~DO&Kpy~^!=hZtq0W~{kyZq)s1uh|tJ zJ&BtHH{?FUbLyELjSV@uo#=;i$x$I#S)J#{8(Hb9MWHVl3FqgR5TOfR1JY4NiK&{( ztwg2z)<-KrIdP?zF%7(Y)S@L$TxOXU4+LsHpf+`d5jRoullf)FwF;hxl!FxHhiaw|{VmD;5j`)Y zwf3kAobS`KoO_)h$w>q~PgE;_$5QLCwbXe;Z6`(}n0YSJ9oB@V3e+c9JsWNPGV4DAt{h{y0>PLlOEK19@ zU4VuINzr)-Hd;i!Yu${wJ}Ctzyab< zB~yShV1AF*j>XZJknV@(r@Qtgw3G}pHm4-Xi+vWxx)h|8KW@B^wiB+;;V{eIoqJ3p zX?PZx%xX~izvs1Qq% z&AntmPdc)1hUxLzBKiZ=eqPS7cD^d5}X9c6WGc`G_Ia;_DRb!7V9`d6>Z`+T6v4KS^ z*6|Z5*reYNcjnXdNjNr@+$S+Ei2Q|!phov&2k!A$iu4qEDABrz&8q=?|L zN`^+eZ^RtLaI<`Z2>2`!z}Do`=0~6fa%wZ?7-q&g0A5F>oRoj3+!BMotm*TTxQydu z+U%;#LmU=S8}^S8`E%%UP5mnl0tEeQJ*XCEu$Hs4!+6vVMZcjZ88f^+a@>xmVz5}; z7nL@YZ=_ZrZXl{l0Q!T0AB6vHt&u~)qF){xi2#`Cy#XNFkf`=< zM%5rf*^bQC^r!$&C2@loxyLAH>!sM6gpW;)qflVE&dk6N_9sd+gy<4ArV{pjsgVC3 zr>#1KcqTU-@v-fS9LRMLc)FG9c-%is$#`?Ny75#1g^vH+Fj+?!)BfGBjXElmS9DMt z0~XxTGLrf$a@U=EVjnSeFm@WN?g}G zKCei<#ZK)^q)g`%MaWWEIxIaTc$zQLuYlh-pHOpp)B9v!~w%%;anF6$g&6^1C zv)&oi0#7BVbMG>ziYN*cA={7P0+NKQJ-UQ9098FUL_kQ&2QkXx1rL6dr$Tlb_88aP zfE&`vN~DF56d03DDRU>v$`g=Tf)&748Yw$(`-HcgxOzU^m9UDPR#3v3Ei1Heq)b+66o^vOl_8!#QYCVVx+s{{nk zlm+K7{RtEfi4gxZf7$Tg@KSSes&@|iy~vz&-kJgJZQsf*1x=THdkxo)A&nEf{iyk` z7+Z4>SPFUT$bM>u=pi+cbKD3z6h(cLS{cKA%0+{=dBu-pNr$+vg%4nIULbW2DOMnd zCR-CAoTuAYyD)tet`+fETN1Qo?w7!EmdTl-7=|7T4a+yHP9k`uiyYGbv|!N}m`3Zo z6YYeF-}H1P3$*iU{=OA1i>vHc)Ao zAP{X{uRojrwO%oU^n5Sk{&^Q}jM0r!h_|-+#`h!Z)_P@;kp_O>P)j2w*znfBPYP+S zQv^5yK>df3h|rb`Fit7kv1clDVgYIrEgULDC3mZ86a|kM2?s1ZXO`kNdHj=UV~Cnz zPjAdaflnH%SbMk_Vfz%y_B^UVNEh125cCHlih1~IxEY6w9|W-peLj_ zUOhPhf)v9m+A6AxCfiWLFdV=^sdFoSe&=c=K~Z9!_*V z>pItW?@C&6hQX9}{{w`D*Y`KTBaDdb&?Ilw%W1+r=_~`ACdwzqkG)x{QZW@81bq!5 zZEQc(O2K1jyOW0CS-Qnu=vdUNl~VNRJ-iy(j9O;aY%N_HxJqv8&|1lB&bypBesyff z;xqSRvt$*)03%V8GF}aPdVsKwd1-4#&)X%*D_A`%NU7?}{3&di{1qf<-pR@A8~iJ4 zqo^P0j`_E`?IVJQ_kPSRMbLl}>RqFSL-@gEIvLA>`?n(W`Q0*5ETq6+mZ4|!Pt%^u zql2l9)bZO;B%(N(e~~2!YZh(7aDzt%rJvx(tZir+os1mfz|2@dPHR^);lAIZDx=!N zv8V?C2W&yjwL!540IV@&Gk#IV0!O*;0wu!b&G#X8n}jS3(*E=D?#XhY&qz7$T8$VA zq3-~5W)0>909b*EK!PCybf>Z|YdRLZ*S;aO;dBNJ=NP#d7G2- zCI%Ppge7dFE5kV5eswGpBQ7Nc>i-jBO=_(y0)$OtHyYNI`2Y;HOnp&eA~bjxG#dyE z6%ZF?8QxEgqiK9$YOT&5{xGRqLk|X&EAVX`dYi!@bLi4+H$EjpLo=RSCfMpGLjD%L zC`Fbm9=j!$NR>%yY0Nqd=6tfVcC+_#3sy8S*o)h63|;9X$iHAfcne~LS~5oSoy#*)rEzG^dw+x&p+(l+{l24XJwM*b&b?~Bw;Usl za6?Wr(r{}n({KWCzb4E;C`=w4m-;^$2zC$8T#lt;c<^#l3XB5Vf_zTEYu0T~vOB@4ztw6_@lX4Gvxvd-XNcPrQ!~ViqIo)Qc^)HjO!hUb(MY%JG{g9B7Cr z2{j&Tegm!L^efeM2HG`L+ym-ql1Kl(+JN^VEZXmF%xT?C^5;y3X(|9nsagmt#Dzb* zko-`#K)Bk#$u%(3Zto3YSeb+TjzM+VCl`OL&wwJG!qgOV5NlR_<}-{+HnJE!+vyMo zxWqFvT+z4jFNsjcdp<22j=FO{>J6KD=mk?<7MLmE5Mh>6&K~3=yKG-SrDA#@@)F_7qWW(o8w&*1`vnt(f2l@3<&mO4 z2l-ix&x#x1cln&hR`aQ4fJXFxamlbH*UUPBqg?@k27HJ6fInogpYcEmVka+ZpD-Ao zTRxezvBKiBf0#E4~koxIZ#L0a_!95rI(&d>Em< zFRk*f??@j(@SO-RMCBCADV@Z@nbtn}`8z0+;Gc&kA?gOuaqQ&ev_40f2t*SZI6f$j z$k~1-xNZ*a&1n9yYCVsdYP|XKB$?@RE}-vwbsTWHd~STdax0iJ2*;jSrZ~;pIN=po zmFNVWsJ-64TTH2QYBUwa$uc=Dl$pio#MSTa`uy35%_6a({G8_nw5=__20~C5=0kW? zJ0+mwP3kM;i^Zg-UkZ4Ap`Tm>UHFP%p9{A~l&ZkX8&e4K(7pg&UhZHfR@cZX$$ugu z;%g!Ps?SFL9+{q=*F~hmagwjl+5~*CnYHhjYkHioH*uC`F%mwE3Fz4A53g?+TwK#{ z#IZnX1#=30k_G|)#3ZYY(xxGX6Pq}=N45VYQxcqlS50A{maPRHTrf4CYVAR}(()x<0Payw6LC)cy z@i4I00qwK7a3zmzo~JsUoWTu{KN;sn3i2Mre$Lhqq+n0gG`8)^=4CCru+|oAi)F^!D)yGFxK(E zFpzX`!YrNr2jP?eiFSL2SH;P& z_{JXR>*ffkzMUWLFIr)Rx+MuD`xq!N@AL=L1II z_TQCj&z>wdUcVP@azuW|+{u++ZoGN5ZbR;7`!{gp$QkC_8W~I{i?59bULYC&sqHUt zyyP*-{b8N%ENquEkI>cv7yrXb=BbF8O~BV47!TRMF}tOB{LxGBp_!n0TlO{Z-9YA{ zbE*vxJeYG_oT1>&|kzvnyN2;n(GK0@VnVN4t6*lHT^kZRw;GKvQ{wMe|))y_8c>Tf?6EM@6p} zS?&8=ov?*|n?gUbC8GU)?ZlbIh9Ky+zyoC0V1IXe%qK_s<}w`bu`UdE!^#6i%GKdQ z17{eY!l9KAFxojWTZ>ngln=leIIWp{9ltgmu)k}}M`nGk%tp{8aF)3oy@2Gdku`NG zy-82ByPGZ7#)I#o)W*h-@{v0!dkUO*>;?WZf5K3Qv<#!g`lHF@<Yqt z`F1;5aT|h#_K~qM`Lszz)`LEVN_0-zaU2aKy=L7>cF{C-uZrWq@<2g?L1$__2VHNd zFP>#`x{h^oW!yu^MMNMe(^KUz?&C%whenm%HJwzhorCYKOE9|35k=bE`( z_IQ`Nx1EAs|59tMjY4#K&<^()FXNUCW#TRxA?w@E#(g#vvl9=tt4QklCe71~TiQ!+ z2Y8d90keF&CmOIx(X;SP4pLvMADEDIQ~Jbo&GjrN7zh}X)PB&3Sa)Y5pLt?J7(U;& zu8b5lP!boakq=*=9I)_-L4AWl=M?!VJ1oA#-y;=o9SM82*_}Obr|QMl`Sxd(3Omq4 zA8aX(`B66DN3P8r>h4W~ZH&&@!}mf-0j^>b)UcZVHlnFxPy;)nONx=nzyoqF`+`jz z=c#M1cvF$b@JoZC+bOUjEPn5eQoTwQ=?$RUW`d2GesT!o(^ppUnP}vwJrRrtAVS#+ z)C0PMEKiprEYh>CSE`i|c1%6oPk7CzW3TQ_vch+R(c+fBO$aW{qSGZ@XtSLaz;<)6 zOlz^PPZRgQz9GM~Ry|NPtQ`$yB1$JNS~m0E!lcsRW+QbZ+IP_CCI$ z#^fh?MPB*nhfL({)x!uP?Qg+9xMtzx)Qni_O=F%fIBjgJ4d>3noUqR*P1vI_7R@+t z6l`iu&ssIU4l_%unxw0U0y2y{aR#X=FaD6{8WL5dM88P_qzhmQdPJ$9Ia~cZMGPn` z95Ol4s%nGypkfl!9pZ21hEXvI1_;K_*4_i#im zW&&7HKSu&^%wUdQK*y0B!n_hqF}ej5QwClT+g-#w3cMrSklMPal4t+2C*7Ev064_ zm>dGGu3gUBG+Ci%ZKV}hnAv#*b9tz5JpNyC{_Dlwc=|``_pga-^PTS6n^VqdEadI- zM0J%9`iSW~q#6z;^ZjuiF$@-Z8(M!Eb3Drd4*`3cy!3m}omLGd&dx_95YrdWL4n`Y z7W#p?T#_DZq-C+QtVii>vijuHmZ-7tS5P%1hot^XY+ylY&SpW~2-YtLxlA8RB4BPW z7GG=Op-@?DxpbL+qx6W84s&^5+ zg6+$mZ<$WMx`vB0H}?&K@ivO<#Kx1zq95F?PuAx1@`Y_(8XLI}>3PQ2(dHrZM}jL;Q*m;TMEV$fta9n3o4jBwmSox&K%XoY^^%J@OEA>83uLR% z3Mwf$Z^&8SjBImKkcACIuiAjgza6{MPA1a84gb*uRy%7b4pi6B9oHy&FI%>u8=i+F z_8eYBfGm3+r~3Mhfh4nZe!5JG;jchHmu>Bm@!qQ|7j5ZCVI)XuMQnx zF0&EzhM`pp#>KONnxPjuCcz?Ql8<6mZx{TX;YGZ+-{aW>4QE=lBLHF!EwT7a7wO?m zN13HvB|h1AY9c&eg??41TQEYry~Xq%B4%8YkCBjnf}BcfvoN$P$oJh<662FT-SK!( zVGIEHexw3P?!7iF-5EO=^FT%~p`dW`E@xKhbxLvY#Z?+;Kv`iKnaP|&|Amp$K?{x{ zjeLE*N6YZ+<0I2_a)wOAsOF?jdM;KV6Pweo-a=H(!PKNs-$u%&?+#=dS@rPhuvy;- zI$Y)*CeWU^S!bk}mOWXMBkqd6)g#v@OyfKBocxp07-5mJGq;7!5#Q~+b>JsWgLzWf z3#0Hpl+>)gcD?fMtW}ovcPjt$n$#n19Lk-SSU!YcAQ z`^+N?obThl3!(lWi|-hOnC3T5oDWAyDx+-QT|~gxKYbi4#c6$^eP0(oNRMh{<{L;E zc?!1<4e;itOD@iZhR{i^IlI-WCewk{&i0TsT1wxWyD^B#=TS`wTvhWB+Y}YPm}_?u zua>=~%Y8H=9AGT4g7gTMd;*!e0>33hr{H0>z(D0P#g=k1!#CS@u&&Ge4_NL~@^yxJ z3L~>D5>m8_kZa!=vM!wcbAmPdE9w}ik$tv+n)n=TFpY&x+-qH;bs6e<#ekZj$pAyq zOorjhm*vBQU6oFP(B*gLr+F`0K{pk19`rxXz3_s~&^AUB+v3yk{mRS|s#+Lko!^y3 z3T6kZ04D21Eujp^`2l#X(A+|>xHSp;D~GQ(j{?9!eUs@~z8X4sK&rSu0+hG74C}x?0$K zu89+RF(qSAU@ekU9L`uBazR?bDth-h!<3*xTYh#a?$}_*ceJ+o+EiZEq3B<!`d-^+E1uRM9$jB!1;*m^=Zlv z-wbu3(Up72GUzpZDXbZQDE-b&`noB2SsyOa?T&UI_UU-K(Wr3rG~yn(V2S3{f!Y`y z@0Zv*NM_0+pD#mAB@>GmvJ3rUl4oaF~8J(>=V@NbLY^E)CqnP>iTykBkR(f6kxnUWS z5txz&#(-vC2-a`Lb}`$vSGCHJ(ar&y{soNyalxPCZ0jA2?wEDb9C4f@;s_r>BzRm=(rc-b%Y9FUU*Y*Z|Sf8B=Iproveh z$iCcFmgX&~Oi+_9q_3D5%753f^zdi|8c3a%($S zB&@qGC1o(+hp>-J>2jaE5;1*E(*MgnJm*O{m_?|UVFdK{(QrSMN1isC*@A1t1e#18 zpdn1XgcVyJ`Yy5n{tnE;XIUXB?5~lPH<6mwCfpP}>sag*1#hYY9I|p)h%=LYUb$&= z+bWm^iMV|0%l2D${^U(0wd`VKZvYY4I7Wg8?B%2C<%wrt^OjJ^i}j@#R@}BtTRctV z1fOym`2g>C&KsfThr8FK7@e8w4WF<4JA~CM4N2FYMCqU{hU{XF2tGf1uXGK6XRXqb ziD6t;EobwlV>*++*J}6=mVk0sK0=|MWBfB9VNPJ&!!to)nr^q_ALp+?bmZv+3!O28eidSb z;DWL~lFNA88o4D%sH$OaGJS1IphpbD>74igqU)c!Kh8fw>%mZ03@T8K){@ z5=7PHn0X}mDK`3o^WSg@I0?{m(deqgZsjiEqGKd)fXU%HslVjf%vezTnfduQ99JBs z@SV|xRw6%D=G+UEbs+i}_${;WYcCj0%6WtFj&BmW33X)e+s^z4qB`&ZiAxV-bAC>6 zF}*tT9W1%cD*W)U&is3d{%Rofb~###(b7jk!d18_;9h5j+xVb22fD+Y3tu9SAUSaS zESJi`U)bTBg0>TOq6QykhlBf*=}vf=IHY{ML)y36>xmC!)6Jd~f`8J<9fZQ9{DtOi z8j|U<^LCVR4ncypqhCWi;v>h3?J$>=+qt2`l|n*4rETfg!34GaE95Awo^=H-Xbt}V zT51}){R_I?uOqe{)gH2|_H!sTfCo9N91e0WG7x)-tM@EcK>gXIUe95-G#d6f)NV`N z%UNwmMEg?9bih2chn$s!eZ$|feu~BfkyZ%KAxq$oleU{Nr2Kq_@?AjD_=&$I9X>!E zuGN4MOpPA=5H%-w#?hy#`|&cLsLwnO12tg$m+6SIsvL`mKJW?S^lk%-dF9)LyY{ejV&Qiv1kP!@RjWa4%NSHQ7K(Kn_nuqkAt9qg??b>N6isq{rf7 zUlzjnUhrh*!|hGW(=ph%C~Vta+KaM^s-2^`YmpZ)p$Lhdzng7H7p`N=~2>fxX-J;4z^!OPtI9U@w=mnP73Y|F@xjNcRe<__O8OWH^LhPppKC?y)mo z%t`*Km=Qp874N#`I_jih$RPJ*LGFwq1FGh&oE|=M z5uIAEw!WD|KT{4!l)-2t=WddVl+BAx>7?)AYTgDx-!Pb}EbAH7 z>U|CH8H}%i#Orw|>AD~ zg6Jsm)79&kYljr@a2;Z(<+Qn4Zo($4SjkKza2FOrwogwhmvr`vkXm_18uu2>J{foj zebp#RJ<*KX2_U9CaBgsji_roJ-!@zQtB6)6UpIUqG=$1vHorux%9FhvJ7`lYAG-F} zW{e3jNyD>agOt%>Tp*xr^$?WD$%omDL5GR?aupg0L@#zglLHd{;1DbZNP*vucfy=e6)VAlP&KTk{62? z3&T^4&KFbvlBJ#LPE<|+oT>VDwPrjS|2rtKQIh|?f(pnx)0HF>*)*tqzF3Zf4W9a$ z`WL!Cq^k7i%QhAEoz1gb_MpKo4g`-yz8tG_5A3^RAD9`qb(4uFMqPlD&k0udD&bS2- zz_b{|Z0X%BIvboVMP3-b8iQ6;ue@x(?Z!aviu54B5wpPclq$2a++zzyuVvr}n1#yu zF(@s_(t^!u=XVuKS6-3!M&v!F&DXEK^1xc%u7dOqRf78Y3aScGDeTFCNC%B7aJBF# z4l!h%LB9WHwK8U$clHAnxO2q&bcVjxmbzmwaqbN=j@mhT_+tp%CY?!42B8nE?vJ++ z4@nF?!1_2MC9h{yApjW~JYS3|3$B$m%WA-Ueu8D5;Ga+0il_UmRm3_H4b8#z98%WY zWz#L+h>@|s&4xNt=n>-!pl({I+lrctS}y(rBNYPjM>0~C!WndYR5-e-Q16<=Eam&0 z3~jjC0*W$+ddbm>{uC`aFgKhHji3bLb^R!#IIgg6R30Mb`nt1S8A{;tU+VM{eMNs$ z*OP|x-ai0zfB!bFngn|3?bhFQ&lJt9u~2e5A`RLf~J!no&uDGBvL@l_z|l%hOH^vqg^fv z;bnF{Knjpe2*pgH0>D;j&p#I@V$|`8(@8!>{i02uqy3RKCNDlEqiLfOUr4A9$28{h ztxz+E$nx-)&=hX^zlm>2&AORTAC|0JxEY+)8sslep?|`BBCf4|8VX;Xd}u}=Sm3z+ zeYF%uSnW;RUV`vN>?n$QUhC3U_mLqSK}%4*z6C`KOiw!ndO_UukWzXLKB9(( zT}j(X7h+dnH}R;qEU7%CVc4Z@z!&d{dd0*St34p9^7f)O0k+~U=Z#~KCCp-6=s=<- z;``4HpKjw}FV`)(#+%*k!+75l5v{LG%UHh=-C+)0lP?k^2=Y{FpC7-vtYQtLO7T;^;rWaHts@91e(64$3xn@ z+WZ%jvA16#XI`CShjAcnAHe~&(em?*1=YhI9bQMd>65*g~bPTwq>}4)2kJhI?FuXk4Y{}+> zz~5oB(CTwPLZ5?aRv41cRop@*GN*zC=V<{eoXSP1b=1#azW!UNIWX5hAR@wdke+@Z>jXCZ%X!MEmJcd4deWo}Ziy;5b#m8WCW?UJWLK}oeOvk(HS6p7n)Ze;fE4SXZ{j++ zkp!bE^x!=77NI;4)9)o;^F>wssoD5D7Sjba_8ycYTFHf^S^I+o;7BIVCNPEe^xb0r zfdM2*3anrZTnGomP&D4;?YP=FeP{0N&3d?m^~x8^Ud<+42m^G1zfkTU8z<6*dgc zped-S>Dr(9F143a)(WjZgG%BL3E@m ze?{tiGEV5W!6r9aK+8Jlzw)~r;4M=I4X{HVZp84zzy1t6!PW$=yRa?y2{$3nd3u`P zDAD$xHA8~i*33jnUFn6rld|U{xK=V)X$9&{&0~{c-RS3P<+F$o1v>3`eC?p_WM1LH zQiksjDoz+aX!7#O2HIL*b23UdigMqoP|~RFnXKDk?c8Eb&$(?uytPn_8#;eX<9|^6|sh%ooN42h#v1*_1oN zNoWoItHya{@70-{XC*NQlwQb(H;`)^68oc#&CcfE01M;O%#Q{Eh8a=cD#&kT(Ffn= z>%oMtrb*gp@7+$Wj%mR_3dC;5HVs>owAkd zk5Z<=vCal(xWts-NWD$HJR4}padVz1UM)mYdiNqxEo0x|8d@gc+v~_2*=eJ556P3G z@mS-QgpxM`dwN{XY#F&Pti8n)aKb*MV%tQLxUKiVBZfda$ZgMwFc1AtCy*tb?11df-PWAR2f!1u5EZnO{uqNkC`Tzl8z{ z;E+%vr(kd3Mq{Cj^iMJaM{ctXfUzmZ|7ujC_H%m0AUNc@3LzXFmu82UYGqpZ%Z^$^ z+{g*VO_rs5a0&0kRec+G;HM9+Q{0O>oAtTZAYzQwN7ZW|p zX3Gp3*Ws4c5sOri)`RDMt*?z=^D_sgK=wrp_i{Y&^RmX)Jy-&BgZ1tjxAz?0+Gn7p z@-PogUdSB`9{x7N8W=VkRNa{Cmw+HnP~Uu)qQ|nDtRq6HCwXKd{4>hWnTowgrAPOB zKjynqx_D0^@&%2)o#9I;U~1LHy`3K*q>~4-b8yti{9iE10}M(4hL$r0RIRMzxKVV` zGNK0o`h@|w04F|YD}sKgBj+Z3troV!?))>ouhonpt}!LNXugW>*$M;AI+P9g1VXX~bxFub8f^q&v3?rfAP8ka7m(U{r= zXjnq@nXQTM_9q6TMA9~UmK5RT1?>bEJR=ak(0)C~s-{~X`;oNe^+)vL2bdnEJoq?uWL{xd5w z4Z&#-U0m?Jx;B!EA$#v}x)J4?U)$q1VnJdxP)&m?v2Vt$S+-GeVBZnyNXrmR+4}r{ z;&G+w0W9nXM%7Wh?7E$jeti}-|2)>`;3V{KC-JL$LxNg}vcsw6;WHwq-AJqnt;PH# zD{w(_lwialnAtwUQ38_uwvKC3z=Fc;fBno8zH_%+9}6fVK>u zC0VusC&esv@7f>pX>+^i%c>f2S-)zv-Ria_S(&rAKFJ7xoK?BlOsfDS&8!7~T z=Wajrmfp?IXfB%s_wktt7b%0bm<-SDL+EqXORi&#*n`+WzVdhm-ep<8*%k0x+VIEI zZ0tO6jzh;<#skqpZy1RIQ7nZcF9-Be2mc_+zuOcIup`s-=DizEX7a!GT(Lxv)B0Ll zyjl{qgew%i7y>SCt14Y&OdTTWh5{+XbKMS-Yv~UG*KX!|6Y<0~OF^}va%p8+{*Awx zu-odY`1;BH`&OeI-y@HKjTm3wl=8N(EK6t$(iK&oWx5~$Oz#R|gnIE$S1mz5+8O>U z5;_Q>=7P$yQY2IKs?CBB+PCp-;zAaI`NpO@&93BTTMKN&I4F|{g33dx>}0DI3nDSg z0A`8(X{Lh-?wbcGT!jQaZc)`ml8(+^+JMx3|I*oYxylsEOwZ`u>_G zYuN$AJwz>6dV((pL7MtzJ()h1R9qQM#9MclMS9wj;N`Pubx6Tb zAH(DLfd{BQJ6qVhN@LoTWf)H5-QEJ>XD+{G8izKB7-c@lbj(2Eu_8kZ$)JI^JN+YJ zBR5$Iwh8XSMJIBNSqrvh;W^6592XR@;OY8%X&R$I?YEFv18zt#M;V=d`&uLnO42y5 z44>%h>6>Cc@JMVoX23*KrWkD=?*{0pmYf>h|2RH%>`gd(BC>chL1!W*q^%(5Rzdn>1Op!*b+H-5;az3@viJ-$4Yy;vxhuxeQ zgxMu+K+FHPG3=e4wNY!v$+hiMJBUz(oB-KHj{itlS0DVnnPRV+4rxdxH|1V`8ogM^ zRYZe{-h|eA1eUXv2ze$<1H{rQFO^+~&ll9T)mD5$7&q4`c5bq@Sgk_)h|#s5BGs24 zFvgOD48#gU`Sqmo2K;mxgs?^~-cz;N2+Z!C>-77-y2g02*JynH9DPBxD6{UaHbc^I zxN_7ILVP<8HfZL*bh8x=)N?X1m@1l*rGVW~8mAC|JpZxo7zan9*Bprs!T(BSm42B% zk2iaBP`q+7=oeY*1gt*v!y!jk6Mp<&1Xo9~yKI5Pp#)}ChiK-_$c7lSjM{v}g2i1U z(h@b7c;<^2xirNVWKmmS6#l z_sVa80`FIr#W9b;fnlLY*zm&z{DZd`_G_c09TbKXl~_@DL@Cj}HOw>mN=d2g;3L$w zl#+*l+t#z_{)IXd^Tv^DgDCYQ^*w%slw**~t(c_b?G-gsV*eTOLEu`ovAf{k6)gSf z%@&|BE1~&2JZe&eBRvcIVEOi&)eYpv#ehY_j%=}|%+EGb)J z%DcEC@(4)0&urD+(kw_v8`UNE`)-QXTD=1CAs3DR`9<8hg>XZYs{Y#+Y^L-m9-0AW zjy7x-do(*w8&Q4%x?wQUn3p1q^VTc_iRz_QdpB(3+vhm38KxSszi`HMnqgg`mo^RI z2;pwoX+BKS67LUX$ioTp7s#uQ1^N5XwwTB(((e&{ay%UDoBBx(zmpdtedB#{!y)z3 zGXxsug|lO64T}H>3x<08YApI)7aF_I7Xdw%Jg~fVR#pnaroQC!*d+C_)l;ZvpZ+_r zo*AA}TMjRPIOE`lNr`iQkX4q3-&XamPIC31Cwf9&axRth<{W`~h9~z~TOl@Rc>WrG z`Rp==Z4G z)BME{#e0IDR9c@UdJ+d{Wz^fA(2DQy;f8G9hUPzXt6kmMTo@h}o?dL@RgnFB7(-c? zTIJ)YGljG{hw~1IyVETs@137r8aKL6u5Q)SMYJ$T?`G>!29pjKM|@W56BrlXPKJ?| zj{B?eW#6p+82XU?^%%OOf%5BB%#>t{0D?(%XPHQKswTxUBTJ6}so=2P;@2`vJNf$g+SaB^{Av*%cvz3NED` zk+Y{@ZDW_Vk+jJxvd~plf+Cc!cEFwz6x-lR8)#@p>1vUpfd)EAXopftNQX3Ol4&!O znel%Q=YL)6wNRSOJMa6v&*%NzkCM8i0NBvVRDK{k;08axwn$GRUL&Hsf(0Zhq3qOo zQp>edX&5=VcomFVvhYohh=ziGOr&FUU8MU~e`7l$DU}?%wi-$E2;lM4f7pkExSI@+ zR)`u)o1bkdylmC#J<3!2kc~`|nwd*$S)l}{WF54I1UB-78!#w9M;@FAtfY zG)9Cx(6t)`ODU2&Z*&S*Vyap;5xH5v5J`4I%CGZg!Jm@>hh-I~jY1dCCYM@)<(@B# zfRKDd%WSj8zeWF;VuNwzu4n$gCcdkAQ-wC zaA5s@f8#`wSEV(NtWFd8e}%QxW52gKi1S62%v)s;TdSvg_}UcUrAo7-#4!OE{LR*I z2@FA-(Z8Gx^0GRMpFI~|(BK@F?(F&Gl_D}9eB)3wXPiu#m!_*E$LN3=zJ?ox>i(Tj zKj7l6mA|;k6CN7chyk;naR+q-gG`vH0gPw%*^?Mu%Ct%R-h2=Gq!`!hxP%#T6-JiB z< zyN7fjM#_Wp@&Mh{fXAAt)6av}4aV3I?{s=e6^Qr5ABH1Wp?`>QepU^Oj@agnVLv3V z9(3k~vGE;42>9Qes?>C&zyd&(`@4)po;ix(sJG^d{(_*CtJpF)QTOb3?I&HlKLUas zjPfvIWo4 z?u;bKt{rXK9=`0V(=5bN%!l`@8+X`0VLOH#WM%=38lrdkU0uczHlkm4vHoT=@pX7B zs>+egG8^0L4Pd7wZGcaQMk?5G%$qJJ3>7Z>Q`BaBj0QR_gJNj!x8T{{7gTDHm+(u= zF<38691+K|4PF3Eilz`a`;_lU`FMDyt%EJ22_?v?_5MB{zJp&FAmc8P)mpuhvTd!u zIUKS#Jksu#G$z>Nr01$-@dX|c9)L1(yVL%Z@D(;RA6e*fh5fb?q4)DB3d9p=)jjwk zRv#ZXqBN7ccCTM{B2^zHy>0#oR@ydJVS!M&?B9=T18QKluRj>~oButlMkQ3g5A0+P z`tpfb=4rO~gk)W*efR)KxY4|vR&)dK(?T5Cc?v?*?|A{|eRFwIN`MIrSKKrw?2^(X zAWqqOibnT@WuR+8e-NL6g?kssgCy1Ujvfr>u|cQnK?|0V=IVF*E{Ei>r7CpI&EN=xZ!pCIz)y>s z$G;7>H*d)TY<`fs^G~bxk`7T>LUsW=#iAd?@s11;G@K>QmP|@d$+`78s>mocXzw52D}?zEZPO!y)!nXk5Ci4LeWmHQam|?%AthPW~d* zgsIO+Eky@S=H=2C9z+_&3dYue-uYk%kq;4Ek~66O>ibL7Z$a75k?d{5lh`y9e!o)bfb8F}s; zEoUsSnr;%ae}bU~EK-4+J>O2RqQ6IReNCzlW1-l2G-9iIsux|BqMry$w?aWvW;YtB zXvI(^UNKP(?+ikkAyeWlCt48F9iun5&(}MZzHufgPP~?v%es;H$_JoVE4~Ds?-t{^ zZ2clO*EaHnS}tb9!)RG-h%E`hxWz04^2oR1i@3%!&J5|pg8fV8n zkTF_K|7NI9kkM8thL(yE!!BGy;6Q*HLa~~(FQx7wds^HL)#a#NOjS~t$u?;l)2kBt zF^qKQ|2mS0jUqn58Q-FgW4M9>%s^Eg=r={R!5B%X+x=4u*n5Y4II; zFUkOtAgN!jS^}_Dhd7w!Y)fDvrZ4#S%CX~CKDk|n{_oy!h)@9g!$!Gnq|%Zkq1WBT z$WW9j^R!xEO*K|X9-Q=%2ah`kC47C$5L&5gF`gmc4Ohodb>j)ZsW1v{yjf5>TbZtp zgN6>AgS=72FnOdj_d2L9WOiPeTefekDJ1J4?x&?KG{2DUXIP&l2t^=t9mhs9Br=Vp>Hu)h=mW+&&-S-jZ&S`m9 zF!zfG{#oWaD z?(aZKiM?0tPi#QWgq1Ra9$fF)0xUo!dy`UM+rd{R)ami5n3v;jxEi@R(MdIydc&X2sDiq|HrS0x2G){C4 zANR7xScaie`l{A*K9|%dY>vY$#0&Wv$Vi9m$!)*b5ZHvodh)`^jaPW?0j=7`KJf#_e}3V1lR+4QZQZyD{2f&cDh+^_7;;uu_ue z$lF{4kfZjt<3ZAwcSCxN& zY02vs(jZLCW!8hy%Psn4XDjm88+tMo5k;uV#N~dI@qTfVFIe;w6~b z<3vRWypb|yYIk|iEOQW4idff*mJ`^qVv?RM4%5!w4kz z76o}WhTl{35{^uCDy}y@49$(5F#&l~d>itv+A5lVhiiyeV9Bk~QRMUu9f8d4dL9t+ zH+?i@u2&klUk(nnqdR6(t( z_nlAVPY~j3EVVNXkw|2o#AZjSV4@aQ4j!)mWHU%k-ntB7VL|qdD3id8iQ^g;C9p zkAsI01%FR5F&8hB%OiKm;DHImQuY=pt?WPgPK}1}^*C8M753Xt0QF-rVrI_;O4fcH zb%d(wTP(T+@<+oQj2E;G%pmG31}ApoF)7dyOEo?0&50xseLs0hI~Y$Gc9``Rv18Ma z0gawi=Ww*pQBoM?rAj^Yt*Z1 zU42KM7?Hwi3EOweI1rIT@B%)5z+}>u4)}*Kgha`HBQMuPx#Rvr2U=1=|5Qbrzpjhv zO^zfSbr>cdw&b=5E^8EBLA})$z9tow#yvhyS!x zC5OH-RZ4fVKPuB(aIAbkdo-ueRBn4)YoWeRyFPEnm&;4RGG*m1)UY76S~ao_>2yf4 z&bA^9PICcYqP_M&5P8?zMPjWnrO`Nbt1R#q8aunzUB-rp^>t zsiBtw%Ef`%h(PDzE4WPiNqtz)HtjUr+ugf8p+@Aw*z4ocIOdJN*+f(#koX+2kDy1+`w8Pd@D(!&%E1eIPr=94Xy%ZD_CeGK1~OuBoKvUU^9{hO2BWeL zzi(hcroXTbnKmiZ^iGi+eAE!fiPtvFJ9~SaIS|A=*4W$^adpQ;iR>J#L^kfFNE}TA;8Jw1oS~tH$uMg*zwsxsxW{&JR!gA-=q>2OB#=ul%-trNZ z=j@*G$}H`4%lyXswMqkmun!iCO}ziNxnA7; zyT~hhS`vUuE=_I9!S_l(%Miarcd7;xV+oaokvJ%}#Aaz5mlWEGyG@+PV%)4wk^5GA zYZf_Ze@l4+QS)RQ;yt)a^3O8zm?~*>EL2l$&I`D4Grqh+SJEJyiJojJAJ$52Gzh&~ zW@qGBFnDUmw?fjk5e~Y#!3COlz+bow8~`T1q;%q^vp{_+bH(GM!~CNuT@!|0)^aC# z?dSOD4d{4bFtdiDI9pA{0AmS?2?7Ll&NQ5krLBks@R83ynBeF9Ti}P5!_#*mBnjxK)9cWyT#t>hx z;_O4W7(e5%4mQD0RJzKqtY^zfTN)!urJOf(B0?#BTn zVp>(lS<29co3Q0j_mw^{VkXs1*$InEs;b1bVU4B)^S{@qwwps5uD~}{-Rf!%7cOi2 zAez8M&-E=7CPb|B*$8LpfYDeEu|mjjEisnAuuf)T)I6%bG1XjZL1!z#IW-5;4{C_4 zx^cL(t~&jeY(Dx>^O$qpluLc(%^>R5KGgnhmMBdMJ8`?Uj-`d6`};B-rxep-^I3li zhzI!^E?J5_KTC74)kbs$tENSDDN=RaTfsi$TSlt#u=|`F2`wS2R`7Z^_!1PT+~~Mf zp87Nwjc3Mh)UN}P6tZK#^GO(`R1P}q0@YSF01E;rxulMv)La<|-*EpeDw*kJecFHQ z(@y6zQF*^1Zx|ZJJT2$KN>b$}?dnm z{JlGpKtbM7rFl|cqw7=N1+5?}jb+B&IJ`GmIfyjr%Pfb6N+zpY$0 z0C7N>zkh$>O(b6kJx|bCr65TppYX-1n@n?(uyD*x zBC}P=jb=Ar#7E0Fl?@oU4>hl2`~xQ91^)gB**#6E)*QKQc>%=99Z_+#KL%%dCiYG) zux7r8hd3;+VLtJ# zA=yvhEOui`_MVnjyCWhLZ~dId5CBCkht=E`gOido)@G|{;*TY`n^OUVSDXvwPIy4R zqZFpqHRUaw1+igFK>Jh7V7H_+mj<1* z4OcAj*PLj9oI?rEQt>+!D(1h1Te(z{3yXSQL-5D4H>X6}ol!wvp=3t{RvN=r74-Pr zW^=Om)KgmPm7}+iYb!>RCHa^;Ulci{q4v>!(xo~G2b%lF;nX*Kz&zg)_bWG?xSmA3 zV5i)RKv~rGPal?SvXzY7IHCu9s`dD$o{>lkJJzFo^MH~X##?;gJXZyZ!9t^+iS#0& zU*NyUEPD%1@er@v*abhE>mPZjAE7>qWd4a>CFpWUkb(Jn!iGL1vKBB>yxF~2k9q#I zGBq6FK6(f}NVIkDhoK^4ja&pst@wp?40;`ClHZcAvyOj{gf!O_+-_F#p=m-Zm|r zmLQePzC))=86auzWL&91H!9obM*-$2w>er zpjUib;1Y$d?%803y;g?oHSc=eh=j1#G%!)FP&~?iO~LiWy}2M&)Z^#)hMSX^;3KeC zkCyh;8=T$AX?7u=L3?Gcv5mS3iYZooophnrcx!@2m15l(|EytC1#Qg=)Q{PQ%>XmF z4;B5&pODD{a|G#h^wL*`8d&S?DUmjXam<8^Q@{EmBq=I@)#>-Hlvd~BNVWZH^LHh~{BV9-J`UL317Tr?-CF?vYGc z#orlyb=V9cc0hOe(R6$$AIEIu0tuJDAMIC;MP#+(Sfk#dmQd5OKLVg%K)=1#ti3<> zr;bc;3V{Q*i1$P7)a*y#K67KFU26AduD98*g5UD5lB5~3tnA+W1P~mOfnHt1XTPI; z=DEsSY4%pWqM4j-q_y&4v9y(;WTgd4$~0Yi%P(fA32}^|Ck2r&7BTt-R0rAHGttSEr;8N&y zcY&VHUou4KI8=g$m(Q|rQh0M8sWYIGk^HM==^`Yb+~&M@Mz{aUP-#Jv!t4USKaswv z;@tlwFR3#wr3uD;ESzDt01|Awnl?I#z25;VNO^}q1s6gOWo-QXC^@UlTq29jlI&Pp zBv{a(t^8Z7z{{E7kL|~R>I#SyT0=mU#G6r(?*9%!R(m83&TFQAQDm`Q=sXrdTQ{hL z6@=rq!$07|*)4XP?Ip;uRmos(Jd6ejWJM3kBZ?`*;LlKG2r4z>9W?Xg6i8J23z!*| z5Tqf1JTS}$srU2^sueyXG;0>l7P~OTUYm@dQ3W1gkQ;vv3jSTW>#&xGkiom`}5ltrA%hkJQ`o=0sUCy~);iG~zXLdl(vXu(;@x4gVP!Dm@<9GTLO)qTDpY$<7(waV*?O=~E#&!@KJX)sC z)8QV-Y6!uQ2fLr6gENkMTPP5FUd4A^#-ONo0K*Ln*K~gq>})z`PFvB#2&r&$x19-s z7gTv%nS(zE2DOHX5GU12b|QT!vQ%uQfIS19`whGeUFlv+)R!nP0bou!%k!@hpR+pLk3%O8TK)stNf9nZ{% z;DLzlXY*R1SL%s-W`P?Dyfl7tUnJ}^XrInj2%4WU)sYQ)kq~G}$Hw9#RW9KiE$WF+I-P0y@=x%d#3fnfy1z z!cKtXUOVZTP*-j=jUlOHo#25)=WelzLGatGi9N1;xD02W z7#@!c3n4l?xA->Io~VTxJB~NVdZUH9KBipDY>%$PJJS;$Er1x zs@o4E&X^kLJd@91o*mlQdR1g)>Omw~X<_|za_tYON{`6)tf7mJW(VxS#Ja`~oJhO*%XpU)U3y@%t4c4p8UgNbddYZeo}=1iLW@UzW=r<764f!JXg`j6 zN!RswLgRRJ$kqF1jbUu{Vx41m|8Q@q$J-hV?1~32< z&bFbZJb~E}yS|0Q1u3RJO9;ppXin_c?0?6Pz+)9E@L;{8m(KspL@i^w&LEvm#r@Q7 z16S=uh2-5553&{WU{AJ1+Wq)VNW_B0;)sKEZBeq}>Pfd}*fmQWSdAZQ>&3{Y%Duc) z#tm`_kMjGV{GL@z0P)#i*wKvOueI8E{1leP#3k()4a|Ol(;l&*S5?v`y&HkI6?743 zDogYeI!fwW*TM`sUl5XdC4SKK#4y`0DTy!OeQFFAVa>Vr0-<3*88hAgT#6Ewy`!;o z8+|#wMkhHK(%?nsJ&t`NRHzbtmH?x^F~k0Q%GDeC#+3BUR&95c;!Hd5rUh-(f8%bT zl$FMQQWrzN0a)=g%(99Zkj+GEOXHkY-bmvTzGI}5nI6A<`~U`S#lhyM8Jr@C-!X8E zozN#|flC#;{=Ol~-!!40LbkVz&StTt&b89el`wCPH}Ty0`Rr7k*yyAe$uf;OdvPRP zVd+JhWAg{$5T|pCuRC0uYlDY|&Ps8lqJH3Uzpv+M+zH|SZs)voq-ReUF9RM6g6-H9|c?9S)<@d?A;eavz<#C3H_1fB(Moxo9^!*1DLow-b7qbvu6*pbPbvi za)NG`okn4bz!a`bn-s)=M-=thaz_iwmT*eS##1kpqfV`hn{CE2d?s`}A6eQUI;L8& ztTv}5M7|6UJQ6|qqF)qV)TND%XTlFgH^v=p5`T8+WxQ;^zhg0S3iY@nN@GGvj3?%{ zNi5hWHsHRw2~$i~12C8SN+e#h#p%kV&erPt(1zSnFjVLT@h`Zja5BM{2?AF{ArE6y zkr7%Ao1B4T!HtqX0WTJITJO$NXX6i60(v|yA%y<8UvTkoM!o`jA`MK=+PS4*Uk2fD zsL~=V;r-FpJ>#iurgHI!-b3e}vA@#Y+h2ex+p~kn9;LC%Wyi-=A~;5|#|Y2CMJzEz zrp3?yrFGJN}TQiTd5NUqwGnWE&VhC{uzU*cmz`6d*$L5^q|`y_xsT!MQB~yQF-O2#|Qpf8JzOP2|`c?PFk}5yj}hQe6s5w3gA9&?dc+;koua7qU-5R~-eW zJE-mS!a`Qhl`M=yY@Z$$M4xRQc5j=KHJo0N!j^X47*syzFzlEBqo9k74pjYFi2{UP~7+^bYcuc~ z6yExnYj$D3`s-l`1r2!7>0vmUQPoy1=g$T|oy9L>lp*>^e9`gNUQ~w=vcin%@c|fy zeA**&I)KSPj`}M!???EypU7&eEL5U1Zf+WzhIJVU?8+tN_yqq_D^fvS`|V!|zJ%~C zn&eN}+3OT)^Vcdo@PeDuy#|_&hr~YT>$$T<4;-vgJDRNEevtz|H+%w^hijSo35$Uz zNeh=4P_}k&f%U=p)F9I91r`Z7N1VW+B8aUa>I2sOcv=3vh%>_SmtGIQ)mbI z8Gdr}1Rr|{8Nz88orq(a9}Hoz(tgUNEo;*nRTFjoe*jCyUVGfVpvyWYG@fplTEyU+ zW}KUag!cS0wHRq-sBMyY4$1ifDR8t%+rsv>12sGHUU!pnI)Yea&2@5+iSxg{*p0L) z?wzj#1N7$ERCH}iK@OU0v1H>D;3A%&qd||JYG-e~B?J`hWg2-y@nn4g$#r93558hF zE@Q^BGgT7U=kU2(gq|}}qJ1_4X@(BKq}`Y-ucNXy0|(N|Fy&;`1HaZ$FvyU@gQbK8 zITrK9VbwHRZ{GC5^e}qXFt8Q}6V$_`Fc_FK==L3pmdduqq;eV_sNgwreAQX=wPbEi=@52G6DXH=dR9XCyzgCYH#z0e=L4d2zdE*(|@)m7R1U_?yEw>~~D= z=g!ai#=-cVwC|t!nQ;p3t8if^f%Bs3+T84(+7N8wH^(q}jO3)b0Qu-W=)ju zkA-nvpi9n9Z()0@1h@HjzTQh#9FvVQR`s#BT8A7IE<$-eN=5w5pRG!HA&1&N%-e!) zGM;??ZTsS709FcLM&2uz%3$eoDuHuPZh9X9cF;}YjBgr&0^vk{QPF`y*}^Bnmu5LT zYEXkTEa0zx)T-6coTD$q$HH#u{%`f93H-Co0P;JSX=!;3XP+$|zb4yK2yG^7m#` zsYG*sjBGaGxxD&U*mPS7+1nT(N#fH+b#|L<){*en6Kpwl=sbI6e>_wwNr|89=B}#m zy=rJK$Lhlolvc><*X4whdR}{p63+45zFa*x&$Yr-EuGH6pg}ocSyiAk(e5#o3L`d1 zws5InZbGZ+cCdYm!FwcqbXpGp2D%@a1g}Vu$-x!uGAOLrzpmv%AcXh>^BrqI-*{5_ zWRuEs0Dd*_@G|SEaZMAwA*Z9KwX*B|X2HXt;rJRl3?*v1EmZt_AjPCUC2?qu2C4MQ zqV7HWF4?pbtXn7w06hUg+?y}i=Q*{{eeu~PS|dn19eTaRdfgK!@hvMB_4kvHN@RD6 zJpW(tIcQVMPkq4CLBkvBFiFTFxQp1mB^rj-wrzx%6}6)H-Y(n7m+7UNr>V924?ZEp zI56E|37|vy*Ffr8GBBIbbgZdR3|ErTTVe0Tj?s17f-YAP<-0({PcYL~(#X+z1hVwD z+Kni{3`y8G(ItZ>5@C)Aj!d}cn*)a)R;hMpuya3FAPl{VNO~Um^L6>oT-7X|p(ABtOUn-7g@HUX-O0x4*m}vuD7;1ZHxS0$}XAtNKm&anz`}gd<+GM^CPn zw}7dz6~j@l0}&7~hvfS9NLV!rmdSGo1(2omqIRMzwG+@N2iw*5g|--+HIE|6ZVma_ z-rGim;IHbh2**q+aiI`bpuUnF*2v|{UhVmBM_?BLs1Q+ZXnuIRUpb-J$e*VmfhpUs z>PgGwe@xf(spkJXBT~c%Jr`EQwU)V(Q-<;#udbhnDilUV=|}Ivs3>pchlD%ATF-Ug zo7P~$lsoiE31IW{C}SJJl=h`Avv6m-LQ9%j>FE5%R9h7QyJAA$DWJhnJq!VI2PZRw zMH)zJyuS|%-$_)*J3ClB&`0kiU;2@B2pom{fRilV{$M27AA{eO7Rl)F4Jm~q8(=~X z;zMBgHe*^)#|v;*dfD&BkQpZR6ns3)tz4<3Fsu(eMdZ5U9;QP;QHzO#S_o2HC2dCm zfY3+UtV9L|k~N^%ERNW&)q^R`GJPTCgU-fAc2?m=gI;Xu>8gef-}zY#-Ss{UtZTg83SvVW9KjP zsEcHuhFjJA9)hsB*NpI8m!M%9Qv*XBFFv$7p;DPteQActigACK-*W@GBE20uk96M7 zd=jbcrdTFWi#rf-$6$X8ivvFBwDW7!tYM@zP2X<}FM(#+G7^b7{t&QWut@S%pI%>N zd;OlG4VtMmp*2udxy1cF?f{|M1C;MQD_}0j(o9BNxU@pOSJV@Yw{3p54K4+!-u2%$7kz@0af&tH9!QocQ*!oY)E@X&pm=LE3+;2>Hjs=0;ErY z3$OfQ5;)!Z38{974{$HzzMW6xD{l257X7sQkq%A1Y;4+*2yL` zaI4h6ii|}K`8MQy4nC}z5gRtEG%a|{d+*4E;+QCy?qb^B9KW6txYtMBgmN<>=VySk z%%O>(i>H#KS+jm06W3pCHp?JVVwYP}9`v&@;7#-zV)q)hxn)pkr4`{LLKBMKr;+J~ z6wJSf>RGE5i7JxIUUz>9rbGvO(*RRB9^ilo9wgqGiiSF}dfOdGMR|T83Jdp-S`TC^ z0|(NQmVcKM(d2y*V}*q}bus)x|I%h#zz4z5SgxlUjW5Q2wd8_>;oKcdiyo(3O&QRO z{y?3X4?GJ*j^^&^-G%cUl3(VDkPo$RZLW~-4)Rg)!WtFBO+$a~#s|0$D6U^1Z1g86 z#sxAlT#=5N$jcXy7pJ)Bcx;F-;d1G7575dp|Ae-?;WH@Gob%5!bUbNGIr6qc2xn~8 zODs!P?m?1k8W%izBb@$T5o60!y&QtTNG@6F!tTc$m)!cFCjqJUjfV| zXL}9rhTW%_*K1e~DC*5>Sxlrm$5U?Uds}LPn~JAevhAazF-fDgp4O>OVHWNN*( z8xG%|ZhdEESl4Op$9zz5rg@h%Ll=Xwt2ww#fPwaI{hs)OW{`hgn4@{@PbzbiXFdSJ z)7QIbI6g2Tp`B*02R?2+j7-fc=?=g>l`mX1naEi7`s9s~WbtOj`Mml#E-#qh$}(FW z$2@%_=^xa9%-1KGzId6i7C~Wu@1Q?~snrCRHQLp4pd=+~EsJ~>+;3okn^?iLF#eel>7PZfc&Dtv9gTnP&eNEI69Nn!wDmEvkkb6eTaJX#m*35D&=p=T3 z{(qtbhEDmWc*cjg6nUGmdbt^Rlrz=%2-nZkp*5@B=XfU_^Sky38R%{j??Ph{V9S&2 z?ePKD<$BXMNo(!KxY}cE>s1_sVUPAKW*dQsUfW=G)B@FRd#wt23HmX`yZssxQ>)2b;X8=D2|cIu5NXEZg&-A+Bwd9BYcrT3XeOX?J<(ZatET zobp1YnCoOvUhQH?RfFeV7)MZ~bR!jCQC_Ar8(T(H>Ob|=)$=d#L4h-<6+`@f2hmlf zSobdQR!v&->j#=~Ts~)9Sj_8(kw_)R>d!?3>JQ3Oi2fc|?1drAw8~XdBAnlkSfbYI zS?=p&z=*!Mh^a}jGuhAvH-h1YGhm6%UMz_&B)Dbr)deU~Is2U;qJX=XbOU7stlIJ_ zG&Z#hv4=G9NJ87BmfycTSpx5HbX3}+orr-2q9g+?Hk$n|GpoYT$$J3t(3<$0kLZ?o z7jF2$*PMcTfTc`7>B)U#%EqLIrg3ui)0n_Vx;WuzPt8h<>Mq54hQilic>6D{U>T9` z8FpwKckBz@@7>UD?zDZ~uV z!Cz80c;K$moG7PzdAI+csgz^ecKiUvj#p@|&K(#k$7~R7alaoU1y8W`DNkkGG2J5%F2Wwhxjc}IxtQfrnrR#5 zqq}r6{IBAFP&gl28}6&&QJ9#olh|C(SVWRpJ-jit&|^>QM@C&7Am5EZ=l&Gi4TA|R zfppytx`D4;cBK7Xbo=pEjW5H=^B2>-id_0D#o7L#3bd-$oDuV5Q!8H!evaMHPM5YP zTyQW_z-Uckrh{!zFaZxunCLOb7sREg+y``)57J$~gma4n>!0ZHkFSBr-G6-g2 za8ibZ(u)v5axjnQT+b4EvG%7ovs>Zm=JCPK_ooL)%)p3&U?6^F-a5bXJ|8^Xm-*>w zs7u63H*u4%J1ArPQzzh%>g3gHkT8|GW02!*OA$!izVGVR9e#hdxWag!3-c_XWzz?!g8r}4{}g3K?%v0 zq_&i-9BU8>h+s0AHRFEwd+Mx#J7OQtL*A64bUBB71xlNI-sMh%u6r7Ivh?M+zS8!Z zYkI~+zUW}l=a;)`{}-ID&%e{2&6n1>;YL6GsAGx~XO0$=!g8ZfNL_dQ$C^G^K}4N` z?EJ=Qgd4yeL96!a*8L$BED2K$+|aO|YoWIeudcvk-RUt=$&P&Wb~f)b%>$deFmNvj zPy`vqYz)sWYVF;nv=ALCVx=)+>jf6NCr4(z-))1^fag>6Q3OiX^enn3Fb=dr@7+I| zz$|VPGHP`s`L{;h>WQP74h50+JS|t(c54A>0ruts&u~$NGNayi*N-tKA8xEy*Q}?4 zB2pe}Ubc~36bZ@<(BgYxY_f5}PMVzCE)QSDOSx{Q2mMea8(Ki-_!d<~mYvdGLgnYW zj3K#%u0C<`@J0}%2+7n%9Z!eW5iMi+MvU3jf1xw~0+q^b?sU?OSm5w(m-A{I|8Uq6cxHQ_R8s5S1#i{fba6Nh zkI5rk!5BOBe5r5Q76Wa5-O&Q?i0wVCb23|KJ$98(4Wz~3+;-jiut4^>dvqkMNBkGv zcEq+WsjXMZBSB` zoEro0(}GHh)KKFx9wam)6-epIZXl<6wS^lKkH|LIEz=iw?FLlH+t~~_0$=Ek$T$(V zSsR<`wrv9YN2(D)=Uy)h7U%1w+A9bLY3_!Bh$Fdy4(`yyhDzE&rHt{e8a&fHaCMVo zfjS*RK-b<6X!(mfa73zo40t^8G&*_@Sq&sZ?r2H{xXjTLjJm!c(HkE7^rRz?erq2h z@$OAXWY5O%a2o2u@Ua+cb}XSU&gk<+TQIK}I&x%%D6+Js!ykE8yL{mQP+gi%;ca@*uayl-;C zJ=xuqN`lIJ$m)rjXV3&Hf>1O4Cawk*#MixSY)^Fdygh>Sp@mdE1O6^dKBu-)f}f7F z*Ng+ckCoEFxmL3aB$0yrGb`^wT;J8#ujm~D7iRH_I#XdEh41X9LU)WwgE2RIXcj+2 zVY*l6cJRvhEbZ>4&xw~26SPU`um%GPIa{Y%@ou?)2JsQg+?s-za>&=m2Y!ON0)Vef z0N^DQx{ZMLp!}1kP|pDbSX4~J-5Gfmt5z-X#0Z*!ray^;9)H(85T2cn%zy}Ki`hzQ zxxybuWm3lEy$%*b46sOe2fu)+0!uW^)i(Al<<2Ti)gL;5-YcH~(W;9f5<2p*=B221 z`ojObCEMV!CJvdh^K#{qJKG+<`_MKv{t2sO2#rkWR@NqpDRRrowmo_^e10j0(B{bg z^K+01ZReJo%FFPH4$l9c5t*7sBvjzGUKADUub?gXptC|-JZDBv4xx)_6hwI058&%E z%9mF@TssKel_Au(gDfIBwwp`i=iiS48`xm{3U00YH%aXP{6Cp590QUHmG~|!CsQCJ zMFy@n3E$-7{1C5bFR^2*um$yo>l7>B`6H4HUwk&5^s!4fBC*_(eO{YA0VJ zG5aYw$M^HHy`rcAc3 zUM15PX0yOF?luY+sp@7ZDS#7`hJI-?L_kbrpAuaTrUBD4in<_}|2x^@)-jRwFM9e^ zN;p5A2z1-fL@z)b{RtHvF|A}T@)2Gc;Suy6L;QgrIB=^S``vrquLM79=>ypeMtUO9 z%_wltGaUsW!FeqoUD&G0QS%WT+!jrM>*%JEhN^y^Td7x&-6#je!%NQjl=`L=i0zP< z-Qaf}y{0~;VqDemEtjmAsPB6gD)w>*MP=Q`_=h41jNG{8M6>FLleWu1P$%!hUD12k zCd}50FALNSNuW|U!)S8;E5XDKXGfIn7)))Ed7P6u{y7r-n3c5RhislpeEsQQYXr`E zy5lbj6s+jt+1qSJT>1V0$=$DgHjxDnt(lJgq83@60v8DFm5gZxH>Z$s84CgbRM)3k z454^SDnpyVa~9?W<*5M#4-Q)Ubgp&+3eJlxU0yD7jc4bsQ`9W5;QbOxDHmb=t%>l6 zV)1~RK0mi446of$v*k9*XW9vxni-IJwgbg7XZ)Z&3p19XN9v97Fo!(JBDL)PxNHSm zZLwKaJmP?%3KwT|FmRah>+m>g>!gMN`SU9jhFpLAKtQpj)?t_VXb!4C8F=H{=m^dC z8_*ve2?^#XAC(3G*RkBn;*NvCfoXU~8B4~VZq_!VV7-ig>wptXKcZr@KdwV8XyX+1 z*&aLf5P(+O2KgZNv*sg+RfbB;pnse^%SY3MYap(Hria)LNa_r&ER(4yH~3-(zh~XK zp0}|U!CbZX0Ccp`uK=vaKsn@9+ea6nvj*j~(^S!+YN@z0%>764yInZEc$2ZPR=_+3Q0_+Kg8aPzhTM(9d{@nwBPp{QV!p z&W$&f8;Ygn(i@_P4Ih1T8phu=D*x7lRRWm8ijwto7<)D z4Cp}NUCKQpD&5f^h(3!qKm*2mtB^)O0uJ;H3cH-Z0hiR@o)E*>PD8hyfJLCx@+<3T z>^9ROzcd0KaQtqxPpdL}We~Q2ihQ()E-++t;aLp)1~&TUN?-q$u#mKZ3bPJFd{Omr zQ2k{vKi~_}7_Id!UsqMHibSwBWP!<94-f6>c1tX~=7b#-tF4y7j3rokLXo|j=Fjyc zow(8iAM=n={{PU}Imh8J2BmSf7g-C}f4qrs(3{ju)H{+HnrGd!Qi;I(wMS8dWR!_J zLYkR_One6c)<|a>1~zv$WgzUKwARacIb~24_F+_Yb_2M(Q3DXsAFET#A}U$tA1N99 zanw1!%3g_#WcH7v`gnbOWDChyx@8dbYe*N_$@giVTkAD+<~T+JD6Rt+uu<>;%$*0Y zuPwL}ze6rmNjMJ7z@QXx6G2Xp?!{K*#KK9V`O7t^{u*e_LwCN<8U%W}X@Typ{3aAS zv=27X9~UQ`u<5o+2)3SIsf%`tkjA-of(a zaeuj^O!>PG%Qwtu#@IG_N41F<-Sz2%DGcI1l1fvucvt^bEw6S26%Kef^;x<`B5mSp zOXQ0($z9aV>n?Ro%Tr%x7UIxX(?jWwbmV8}fqb0vZw}ysnc!w_M%?nh6E~@_$KL3g z6e`^%!{T?;*AcZa9*?J!T;g6fyebn5!x(V#vsIcqkVs?*_`7@Z#=DNLAbtv&z5Ey4 z+Lco|bUkYm>3vL_LW~^Kxn07@(ehuiNYBiPdv=}@e8As5XY}N?U>Jy7+TJgLs$cE< zA{55oko3^wd!xRen?R7Rr>j>5N|6o!sT}C=;<=m%XT} zhb;ZK9t)yTI1Bco{$=>?9kO`sNy3RqF|&pbx~X8a7Td7}iCU6}SmJi=LFAWfU1A6| z!(y_V^_c}_mldml6!`S6KP|2B>;3}c?udISn|_$g(3q;miH;hZi8Qo~?q@{;W3&s2 zwh!%axpY)Iw=|3|4%n&3zNaYs=u$EFUamU7ndGdWZp+CJ^xL!TMN=XjoS<);93s`a z(lS4zS~YeQGPTnDKB3E*%&b7EHAlWPgJ8Wr=WUbimXr2I7XYDXiA&=WB0jz$qB|Oo|6||)j3q|)>tUF%M+5}KX&*ybJa6&6KM`eaP*Wa zh-fz)N+CGQp^^ZO{aK^kzwS((hAbGTr7K&?h@13tkKSS|UJkgPz^h>^>aP6GeYa;p zzrihYyj9nL%%FH{6-Larc}R^~UJL?uT9lEpT~j??bouZSZ=)-O_=Ql9v#L9WCX{;{ z<2WEdZ+*#0$mL`}5-Ww1tFn}u}D)k>qq^S zr=|;_!GS4ekdVA}>wSYVw}?69LF+BrM^E)3aDog~)fu)0Dqw?Z@pYDw*YO0?OsM&n zaDBluQ<4cK5|u=Kwe2R8jcmm``Tf3=s1A}`E9NE`al8*A1QHYMTGf+YkRsp;)t6{|Cv|o@igoOVgEK(t1K9>R2Zu6)M@0}geTr+zL^9KTawSsY zy`LqtmV3K3JIV;ck_4}1^tSF_PYFv=P1_9m4OrgzNa#B%Nsts;0MX8vY$YFD$%y-f zMbLBTNr6Sy7_)a#@=$ksuQQtXj;abt*w>l(&)uC&--Sv{aPjWTvLijlDo^EO0600uE3SgV^T=I*pJob(?w=Kuny3L@$KeOfTT`-WY_anUg143SCpxF><{O{Tt zQ3$tN;y~##%jamsX>Pj(L73`vb3IJ3MQ8NSFbYwYuiL6?*BPg@kGwKjsV>CixZyzq zoM%k^F0^NDLfHuN0k0T`+AmMQvb8+mu+2k?=Y9wq0ONs7^yhBKzwo4<*YSZIp{6JK zeTHpbOT`;c%DJ=+nUX-hzR* z{i@|k5$Z<)WxbL`^44iyvbyZb(sqDeWZ;MmW??Ax4)3fQKo;}JcJB_h<}IBtxKlgb zbPe8u+1sW5*PThHu(;l^hW(%i_@iZf(VnY#@;mto9(v4bf`o zz;FLQTtcs$h>s#N{Mun*Sp<**)mF5MX1NX|(3_!ny$EAbj)h?p7L;n(6CKAFx=T)-vfwg%nWx_gTJ(3Q8=g(4xwT&rWC^GxgTjHRKk(Z6F&CK zOI}vX?qtI|#uP;PH))Ezk-<&mFunjjjJx$l(^UixAnWlRGW5zNCb-W@gUff8=K6GC z&|ySUNNludjdW$Vd6*(}50JbGyvFsc(_H!=AmYJ0i5Z>A2`Z zl7v(PFMPA|Cr=OK3d~>En(-iRUbDkch4h2q6OXg!9b0&+_dRNACt}14q(*aKB*G@x z%Sq+hN4URcAu*0c!m|OnVO-Y-XX)_)^?p{Qev5nuSA$zy4oP(C?G^W!QE?~M#J9@) ztv(u15rf6GY;5K{DEjXnvfzNY{?_JqnSUcKj0-+xyXIiJ(4XUya)|IR6h%=^xxM%j zwkihpoOGaJ>$8`2-LFCHK^#LNbGA@<`!YASv-oFO4e1U`=v56V zL#yZP8rcfe1Z0k#u9am7(VPwC8u*ZYP%}8m@expI&VGNh#}ZoeybLuaqWr_7jy1l5^?4+!62N&K1=ES$r9AJr}UmxP4;5V#ymG4!Vx?E*@z$J#jlNuXspz} z%rt9px0(|_J}eOs%HDotBz0}$_YO7~tpiO_6qudT1SH)c_)hMFE5lLfM1SLDh&U+S z4bgj5n{t|U9dfmTrB8M2L!1fpXc5Km!NAK69hXo^jBCtlszc6OfYuI!;5aZQ(gE`t z@WaT~FToJ4EHq|`7Pg^@T;4W#y%c&dc)QpSP_|i!pIYhgO4y6lHk8Er0$9H6sD2zH zCCD$SUc@Fg`JX;X`-^VBK4rR9i{(ODgzqRoKHST?`}_)JJX4#a_B88;?hwfhclCf4 z_dp9mC_vUMXxZB0-lehAQ2M@a1P`tR>H-%vb-Ggb`ZpIs8N5BET${w|c_OLCtgyXo z{X%S81AA+VqXki9__^V*O2xQkt!pjGOq1OpHhr8Au`#i7oAQv>FS*-~ZVF!{^v9_N z5H)gaZ^8wCthoe}n;N)O<3RHj$S%_!Lc{(06lNy+`cK+)mJRM)Z_Or<>FQ7``l@qj z^D+ECx06(L<5e!KNhO9M*-Y2_S;VYmh(D0F4IV(1+o*+FdGU_7+8frRO+avDFMzVJ zN@-X>wi|*ge{NQqaD)CttlhvDxvIa0Lx8NTt4O=@iH>n=IE?N7lKXU`H};f?n#Aum zbg|sA+Y?K!LXB&`py@Wb%%GB}9a{n3=M3O#BK_Cy1LL%z14ZFHw)04*q>Q6gBSE|Hsn%2R2dP|Km8`(kV#a?}0MK5}i|Yj79|o zDeZ~ObqX|ArnuJjM08kc8yNjz)8<|(LKT$YRKkGfP*#GnHaI9L{dHo8fmI0-Xpm5j z5<;3DY1;f~a@V`_`#3(|fA)j6$=&Pq{QZ19A5WAmM?A1eq1bK2!9rc1Q%ooe6Z%_# zZQ!8R0&f>2W|wW~@~7C-3R=IcFff zznIUV5QM(dNFtIXD;BR;*F#tb@$?n@xgHWFXXNf400EUd-v4VYq5(m=c0kSG|Ero! zLh8*VfcGsCeq`~SL_~&j?C-ULDa7Y)g}g2xD@gAbaEmBY#-&?V&>!Jvl@rMdwF`^A z=HPWdPT=GUkCd2y9v6V`CQD|pM4oX0(CGENluvA(TzW{k@RHiOFfpY%006?)vz?fB z9mpAz6tA2U`OQL=?N>=tMm7_1Nqp-V2I)ZI=R0`DgqkC<*}Ct3J{77|$Q?6>dxGM+eZgpUL% zTK+$SlhQB&}yD)iw^ZeeTWnp3h|zgjlDM;02l=P zo3l_kKckp$g;@8r-DO~c3AKSzDjXi8aAFDAHg3e@<4UM{nqUBN-y6j!6GR>57(@qf^y{a6V;$Q&$%)6cpu!Xc2P*yB)pM{5dGq|i3n4g+(ry(y*0|gZWG2z%`Gh+lc@!(I;^f zl*i}s4e;XV06Nv42pAzUBeD2iToIbd?f? z0o$j}iDWzOz2AQ60kc6A!rl-4Ph^`Pf=T2IR#?$-g;hACMthIrW4!!1K!}_4T2Mm- zs2mt(h12Oks0Y1b|?62UO4c`=ZD&*M}YA4Y>tTsdU46z@k*WeszR?b?2|GojP{MCBPo7M7L z5HRJzpK1W4_(q(FiC2d7_J6Dr8d+>?fkcW6E!r}2%Col`DKw}lYf%O0#S{0XYO-(d zMAUtnj(O~{QT31e6uiP9TINPUDvfwzQ=J$^3*)>NIJ!ZH*&%PnCgfPCY_?RtUr=kl zTR?1aINtF{q|O3>P$-3!m*!Q)gBH}Y(VwH5to~m0St$*js#q&xEY*;jbpRpL`vn-s z#8(x)*C$zEM}Hpo8(UjC+=U>Wrk29Zc%P65WGY=~+-MXGoa8Y+d@9YpE=BZtmoA;e z8I!2o;R1ma=3kBmWmM3{&XI1j^7I!Pl-@B2ga~0#Buj6a{s#BYBfNcZ>}J?4Z!9(~ z2mg)%g5!Ehkm3dPa*kIa&Fx!QdtSC8%A4L&-z9cUqgpyzW~Zu@*&w8;3dZoTn9=>C z6II47@Vf5&XV5uchcg@vAJ2eLvX?fhg_T<3TYt$R2CIYeS2=25PDHp?g83{yk-}(X zy|#|rJC~uXHjBKi8o$aVVpC^u=m&g!iN!i*md;@xN0Srnuh^tv^t*Jyj6-Ny9N{*2 zhGFd{kJWW>4)$6mK&B%|rF)Zm?S?_`G&)a1CK&F$tk&6bc8{WcH{)BYpLfbsfZvb5 zh!$SI6EXt5W7W>bkYsR8Y0z(nXA#2&IR__RLB!*cVsE@i+r}pA{I0kks97Nu*~bo# zr6pocTOWY$Cj9xgtegSbeN3hFzvnif_YF_pa&sE33vW7d_R@YY3UTA-D26E4!z;@52-4LR7=Qa(Tp>+fy zs<;M2w`}_qzVtH4Rzkiwe`2XZS(j={f>NdAMZm!S$ZGa)(u0&G#ddT4CFEWP*`*Pj z5$+i*2!e4+2&VpB)R_jh%3F`AruC_-BNcY- zIu8&8SmKdKXMhX01z?iY#P(?7Df9_3Yx50+C@7mdVetU*8S2~+8S4t?6sUz0cbhRX zpw{LSkA!LBh;uvl$RZi}H66`4%sGTwQ)PT6$VT^IF^w_wsbb$N0xXn(|~}d0B+;& zripC%ZlV?BO|^v9JePUABM^#4`D@d;bd~e_n(j~W`A~3gf@#Ptm(9d2#7~(YQu@3X zxf6&gP;7EXM^$Xw(`na^mZEJ#XRR)VeC%rsO_}s37NDEc=ZOtXN99h{DMs~>M$Gqb z@Xf2Fw;lK9{A&7ch>2?_vPy}^-m$Jlzh|EG0J5RGx}B?#gsGofg1JzGw78P}j9BH=@}-;I zH1@BL{pbui*e6x)<|zJg)3j=I89+b`KeI8rLUu-Z#vQEP2qP_Y!aC&t4Hk30Y^Ek3 z?g~c~y|6ZdDeZyj_?eqSbN0i0khEoC)FCy`cj8fka|tF~{RTkGF=m(suMUQab_(MH zyg!$QaZ)>H+C$z*R5tzPASi)hn+@LHk2=D9k6nH=I+R6hoL+D&n|pAzR~~sMH$mDZ z@#e!NMy-svb{7Xs0#?n^7=CpmBvvov|CAiXX9TA@NOwdgmopD6!ZCQbTIm*BACOhb zlV7P_%+4)_9yk2)|E*WG{J;@wG^4Kbc>so+>^X}4<2VRx>c&W5r*0ey%|mQkA1x=7(++>Z8_Xertcbtp1asEzia3I-$RRV)(Wh;!0}Od9QC7!uYO^Br)EhPfQxnmc6FNEh&Jbv61BpQ?JEFN%$#g)gg zh|B14#yf`o2VvpMqw+)5O4{Ct2$S11c75DsGj(EA&dMjza7^vGj9N?0MAanueZ0KD zLwkEX9z*ITpn+&2${WKWuzTy8v#R#?#KJN1#YDu6#Vkf-z6=i#yo%$J#VuVprkE^l zEtCm5Teb4zX17$!+`GFHsvp;#t+azjV^~Ya(`E zal_%;c%__I$e9B$GRkA;O?5EZh0Htc_YFe=+%0(*)FWa4OB5+QgXE;FE$+9tETfo?3t3p%m&k%2O_G|>E)rI#UHT=rx|@G%-*78d-Z6L z6N45nb@fL?90izlE(xUy4bP7wyi=ct;g0*XGv+i`loSW%5nq#ZJTPW8tn zMwg2no|1ffJ#v8Axxtbxt?T>>NbZF~wK<%6m za;uXd1m*V^!sTqZ(D&Rwvg~a&6A_?G+-D03t)Hdd6$e{4wu3oD`9bfHE`eMz z^wsI5((2}H6T{Js(`1LwLB5}joeZ_5wSX@0GIoLQK~oA}YpvCPlM{)WCG&|nB7mVd zl9EUYRd6b^o;Da3;SE!b&Vk9ihqeIs|FOk|Ut#~t0>~tAOVWWy9|mspx*zvK+o}43 zOb!p_nHhMU3#Fu6Sg_YC5321Ia<=(d1+7A1(NC_t1^!T6M!EqQICTK`t&Qin?QvaD zRv%Mp3cY)I`O+8vMqmMQ$kxj>IL(do07vu`xfJG(h)TbIR0yjxHk<*?j}MEA(17n| zszgS&jiaN)uCw&#vb@!q*-$R=eKryijIe;X$#jor2sWP>o&Iu-VlxH9y%7W+7BhXyJ!w_Ns zn4RN@j%XpOUs!CaAv6|5q`wHTiO=XBo&@8Y-4+j_Ol}ty-nzdUM|c2}v>&jbwCUVL zHB#HvT{Xbkp$SripE+jV?m|9ES)+b?*ISKzPe95(DQD~Lc0M_wMygIqBd)2VYFAQP zv!VgN*CV|el;_)hon4WbPyO{SVmLDz#ZI!xeY~6u4KeKgy* z{SjbPbi2rbG&Br{2h~3nU8+yB!`TSSy#_jTfhY146aZ4??bkEk(zY8}_K&&?a*9-N zL)M*cyUrbeuK)Uk?n8Cmaop!VDEoPxABn*uP#RkDeP5)*m@K^m zPXO?gRwf``c@7xe#aY=HnM5KmwxzweOu^txF#IfYe~Mx6x1XSU&;~1@41)S= zYGx9%bWH=9xwr-j422mbCd`^DC8)ADAdeorGAj5uQEt70;GoDFP*+BUt}j;G(Vk`P zTmcH&gMGc-5odoYd~mhHDdrrGB%KOFd;ieUGUoMj^5gwBcxO2{wV3w?xkVt-gdspP z%MW6`-4*dhBtPshb+c2>$Xi*I@>pmmM6B$n=!DVp#!Js5212=*T$ZpP`dno+*3voNu~Hhl+b=(nysx5&|nYwvGAco7Gk*J&|!dwaLU z!+{p=z(h%9Yen&vPk8MTVrQ&&jF?3y>WiSr8#u%1lEE77Y|~&1OUgvEf8elOTM`hY ziV~G9j$a1-4Ss4BoC7+qALW|*gg>TM&_QKZjsAog)p~<)c4=I2%@Q#GsGV(*9G}cV6deS!>kZX6y~NI z+0yj5UzZ0pbvmDA=pa@pc=J^b@K@}WW733_Qc^Y6xllXU|8ZIkkA(u>Na%F=jj($p zWN_y3z3mgFaI&)tdkxj*Zjbl$=w5Yt*-KeWXD6Aqk29Su>Z4erBXySlfmjocOVcIo z=2y%YKyc#)ij!+DF_ob`x6`_=PC1_!+kIP}%d&&iflB z1wE{*C3B3?ZRC0ukpc-G?VG`Q9w!{$h`5~l0w=@0FsN@w*EAqqNBsWfeX_&`o=w8H zAOenObS^OaLQ2sa^B|A5x1{B2rw%VS?s23vLeGKg5149K!RRI8fO_IN`}C~@(0TwN zOJFyH^0m(}RwAZZ@$@&1sz>hJT}!~b4errmIJ<;%6`WjLnGhUUPzz~yHO`8tFKXd! zG_>~MMPzE0m^T)vzR@F?oDIh{8%o}4OMyd*~~2hV_T#k=`wE2^}4Y^zN<;XrLXq4O8b>RH0OaxF?rL zW1|Xnc~74urZNrOvspM2uk~V52X@XrpX2JCI1{8hS-N_$#BMEJqs#33kJcbS3^>&p zDOVUXSF{n)Zx9jDq!ZdN>w41W68bZ=pp#SXizn{(C*1wVr-O_T`zj09%C%BmQuGbo zrPT(UC~#D#yF&&$fPA`P48^Kl1!!}sZ%NFK>+Nb0Y)hd6T5THyhwNaL^0zX69(RfY znI5V?s z4Nh^??+l8|<$1hx0jcBdNQooUc^!*q%gzD_j~-4#bSSizE2y>Sic_Jb+;gE&*So7Z z$5KpNXFLS8H6Ts63O8+C=WDB7n=4+~3I)QD)k=gJK|3g$H3zdaXm8PZ9sN**bWcw) zh`WYDZ0I6Zzb4>>xhChJeh{#P7T^ywhrz6WhEF*A(6F7g(V7sHvTM4{mzL zfjByg=1!@01bqnWvvXH&ru4$eH+5%t> zvdmCjbAKL}3xnA+gjIC{NSqS4@g7<2K-XxN;PFU;;JkLfQpnXBLxXRx(s|G*t|DKZX;g5Qu)6+EsRfC47eI26c-DpIsl;h*d@Xw`Gl0i~Uy$Kbv}J^DEXYvvm; z>AufGP{YZSl{cxG5WNod@=S<3rM!7#rwzRkx4lm{{1{va0E$6-l%fsAoe$N874tDP zKRI{8TLc|J+szPtgA=q+^3X)oeEK)!bmnFGW!5nAgN~py0SbhTjyN~DhZBGM0C5|y zQu^Tluaz+!|EU6Q(w_J+Ef{Z9<|&1z=SCxk5*cjB16g62H#k&(Q{)kHOj&Hl-b`Ta zv%lm<6dV~kn!Bd|YM4-$MWjk`kJ9L0jy5C}$TvM&NV zJb~o>huA(vF$B}wdi3|#yx_*}Ib!gf*$ZdrjUA;oac5+mV@KF^;qMxJ#j|g(R_LA0 zJ#Z)H9&D5z>SZ#|jU%8<{lY7GIeB{Ms-6yPg>Zy-!t8IN0iAjmIcn44$kj~EXH#~q zTMZ#eE8i(H_JkM9?)rbyOo&V^eBKMm@B|KOhq1)WSAUi&f#4~4%Gbexf+$6 zMUk%QE>c7tNT&r3$9dCF*;EdiOG`%q+eh0P!H0pzXi5g_m4~zPd!@cYi4gl92o8M0 zFQ?1NQAw)sUqH5A1z45#H~M?rDF$tBZ&!(_M*C_{1PNdq4I4<^-L(ykcnQS?1giyBFh=!ZT}Gl5@Q04$?y+Lt?{?sAn?Gt&N<*Nu zy^FSp=$T*)KNwPeuNTtKRQ9~{LAtCbRWcz>3|#>+$(vO z;n8p9(JsVRNS0|pH(+<=4=em2b}_~h=^n}HmKJmF6iKx1I}ARB)c6a$H{pwfZ_F#;zjLF5#i^TOa{;^5=w08u(+qb4We=lV+^kiMQY^`#uvebYFOuV ze*{IAZdkS+LvNo;$yD%f&$+p4xMo;UWMZ*P{IGtNQBWtIud2z&&SCv*6U8Cny+3;7 zTT~5a&laT#LpE&VLofnwZV>WSKq!-gjy>&`X3d|+;tS7}gnTel|HPuynUeAR%Oj}@ zNinB8r+$V8#x}A9tY|ItF!(?St5slIGTy{pS$phQP9^KIxeR^qG#-|9d*dz*T6bB^ zXfvipv1S;3uKw;Ee68p@@}SR7qgH2J^5P|8>5mRPU`EN$4gI2?j^aOy$)h+bY?{5c ztE<6`Bp|!1^|(HDm!7rn85_X&HK;@Hv`ch(-}LjFM+riH4PU^t z!?O#LjS^aE?!+t)Y|ikw^=`ipD4vbF%pO@*=`Rk>D)WsLRgK|2Vfh$H?1+$yXQMy* z;NLtnDwDgKY0##0yx~9E=zx&)*#~D7C}VJ7Pr74?QIz(nJOE;A<+d8}c8*tS)LSYi zB|{OB`E$kC;iqn}euK|fLN#lo5t(cg*OWEk62l?Duy;B@odT5~*{j|RzRk*lvgo9b z!%8+Ti~8s;Qjnf^M7VZmP>|4d>$UwiLdVW$p%dd!US0~M6WR(}A6oMn*Q3thfhd7} zTDhLLXliO}Ga{q`Z=V0lWY}YDm!fFINSyK(u4LV_ke<&m%ci41C$<`#jg&hiJdFb= z-afb)=516S4_LT4`w9P4Jg!B)$?Ri*iErNm?c?xUmO&q8Kj*4P(#*mq4tc-5wmoFvTiu!f~+Hm&IW-qVw@MpSP}6g z;^Ke;%Zt0A6w^%%BJ}Ml^paqy)*Bcu=#ks$)6i_x%lj@}2@0-$)REbZIb1L6H7BQZ7a4PzVt>Y{G}U_{G!YoD^ts}&f3?}_^8Z;?@DO=vGVz$~(L%l@qh z7MfQWQEq!dsuyBHC<-^44#|h~3;7P97jnowNBY>y@;5pXOxDKL)uGL#o)((AM!?aN zqJpW3tPqmYLB=E`#yI+zkg9~wAJB{80ZJ)iKBeszE(VT-&h<@0Q3740dyGMh% z{3XyRy-OOn6)J`W8+R&Xk~z2kg|;{@@a+s3+cJg@1TbgWIw~_85}_rCK~WWIK=jqc z+AnqIVEmj84r3o;NiyBJgwbW%$mS{V#nd}S;*^<_x#Pb|gX<2G~b@;ozq7d@<(H1e%qTnWOwVz7dIYr%Q}r#xX+omO^ZcY2=- zMqLn5PgDaUaHvbSnlu3IZRKoG+pp}>s^N~Qq#)sYI=QKV!vh~4xP%gqVn!OcMB_uq zY)ebn!Gun)TklKwB{&O9=S1K==~UN!V^jY+2XjV#h#B}?i%@UJm-*$Xg~36QFh zZ{!7=fh(bbmZKK-{M4-d;55 z)w_;KY5{Bxy)(#rFV-p)+mAtjD|cw=meswe1|{Y}=woM{EVtdJ!WXs0mRW}^mi}$dxXpw0Gh7CJ{)a6G{ z4zP2N5ODOXMM!}*DkdoGB#8k83)7Ptg-XXZJpyt^YV}YyCJ|tD9nRYeDsb*E8A-QW z3i-|qAmwL^`*IN_TDW2e70&x(BqOgMIZ|7;k3W+KRx<4jo>prk${Tm!Gabnbp)D-N zS+TW8Z~(U!OUIUDFlPPBjYARVhw_k9p#I=|+6a-NxBCy>=%2aJ@CM=@u}<(b$RYti zV+tmqxCeSG1#S`Z5X00>$U^;ChW&B^uZww~rtAfFFfZC0-ie^HfE#pjQGak zFv1G?e6`E-1SCPK%ErobkHlTgcswq=;&wVgZ3B83G~~h;=b~9gs?^VANoPE74J&{b`NFL2?$ULKSJYu-DxfGOgv zSWG;UYtVKT)qu>?^4!b}lS<*RsWVorz_41cW!hFOIo0cppinaT0h6V?p$)r#K_Cyt zAvsqmOR0q)v|}H=Y0NL1AA~ZY==>^9)L`v-u1~})E1k*pf;Vz!z0HcHI1sA;AKPH{ z%JHw@_DO+nct*r6k+-ko#6wct9iQLGOGn^Po_~IfL+Q-xZ><=OV1sHX<>Aa_b~-eR z6!xJrQe0T3)B%LWdtj2CPS4yDhV|x0JP`8!?&_2-=8b2h1aO+Q(Lin%g7zeciUW4Q zQ~4=o$2SX~_erJb24eq&QhoLog`!;{wf2k;_uQz|9V=CsE<@1q71*A2^(lz@LwGgL z+{wI(N_Y^ci+dN2C}|pcWZ0+b_8}7wlzza{#&Y%qQ#AR(PUOU-aLd&rph;>UoR_mh z3uKII7K~yO8-`RKCnIbZT|X@AS&HOD&XF z&JHV;zZyFe0lLx9 z20AuvZ%jf=y?*KDwrbArd|DDgVmAQN&Y22Ri>3^U560i7?V~X5!*0YLb&gJzwY;i! z&W(xaGK(@*eDTKsE^mXkhfduW6JS5HhYm9}ei>=)(vNcw;AddMxM+awm~cTitWN1vZQmKqwr#t2x%+%&rbNaG7_j4>3N;4}R#zCbb#$N?c14}GWVZ1Er z5y-yCOL-SIX>!*a91f{Va4nZ9PvELTO+%2H6BIaK*H0!{4Y=Fe?WxY~^|nz|(KrDUw3zwmx7%61w_4 zY#Y!()#X{VBp6va=Zm16O(9W9?BiJhfY_0r)NE9&Z3YKEBl;!5@&xip`bj2ZHfHX2 zd~fS}D~aUpTPt`*%sI82VDEVkK;y1vf{K3cR?IULs=5=@Wn_o#6EIUs+;5Ib%egYO z_zm#9akP8SKXiaasTIK5VQ%ML7{&I&;ek6LB4g{N<)|~@Ft|$I*4F`B)Z=^wX`~Ye z1oAw@bmI``35F$AQ-HnZgTq+pC8rPesr`^nIg-qLzkDbgf93u4-eI+4?4r32687Lk zB5`gnwdp}VP)mK*u@SA>fN|%q3!@RYM^>o2=KWNW(N-ATw_Rl~&0B|#gan`XEGxX= zlej&9$@%I+iE1K6@6DuC2Mo16b@y^E&L?{POSHJ<-GMol*k<}M#VD#zX;#+#eK}#d zqsKIgDAci_!{fhR;_;Mba%e?Sr{;u&4>i|lkbIR&bz)k=kqAV6Mc>WALw3ineFiTI z>ltrViAjtVR5uAMh9kgDaklJbOXQ=N+v5GNv68$dvy8az+HY;UDsx z1qc{=ViPNPOsl2Jind*heWK;V!}4*;!+~L_u3jQV9ZhAw#J)nEVxldVk!OMOyIY-} zIKPY!LMG+?_;f%zgy>l^Ox%+42WW*gkGM^{e2%{(kU?d*1CDKjhwQirkB7A37YEMO zz$!k1-Up)l|C_fC4A?=>R7?i$VRRn#@FZ1tb%xo@(XXc>0Mt}{O?w>-MDZW!HcOZ# z(X7A{={3+%bjFd%EL_DooV^xStg4O`B-2wf8WvQlZSNZv-iTb9kgrM{alMN9EoQ?r zqkiF-24(oyoZ}f4@^;qi{+`N7^6*}USc)J5(AlRV8iD`r;%B4Vo!y2L{y(hoz?o3Ms2?=06;DRZddbwz|y-y%v(;Q|m@m8${93JrWUTZSml&??I1WHNgqh2l3<;w>>6AqqNt55gM&G z>``A<<~KSp{t^5sEzz7*+s~KRsIRa9E3W|Uavcn38k$~(U;m`D+dVVbphkA>ljQCZ zwT)`?-C8)1E-KmSsne(h+0Ba?R!{G^2tmZ4(5U<+BK4b9U3Jl8)8ZXn1!n#X?SkfL z0oa-qV<5HaSE_X8g<5;=e|goMrJBv;S%T!i8j4~#0`sX#jY|x9gh*~EMlQGB4Gni=APYP} zbt7nhK&4h(2Tz&Adz=IRQ1^m_!U`~j}M zGFge&wjE=8a4`{lmJ~ml}O0zbNxwSA79_MhxzbyKUvXhpSH#7ybDEjT?_;ZA@H-$H|sE3w0zSlImeMBr<2_GWW z0vRPHJzvb=182aZqyBo{sHM^BjQ>eg}6Byu?xT6YStlPehi;Ekz5F?_AgQ zUNViUEkk#zEKFYScePa-$E!+)`;FbsghP0x&w{8+Ywc@$^+^A>J`L>kjd$p&37B}J zSY4h?Ye#O1#s}vCo15-WRnADqmltxMM^Z^7qt?=jnTYCiH@-cGqkCdg@qhC0G2f&M z=kN~uvT|IQe86`k?#hx;Kq-ve*2Z)KDu7i;Kaa~hk5hng!9-wsmX=;e_*c@fo|Qk3 zcS`J6j{uX=xRDREwzr}WfLwBFC4`nbalq^aw;Q4FC2kMqDv#rDv0*@}JBdzQ$_P>b z8xk#7i~fG48jDQkM$eNih!P7oPuF~UeX)xLO`>AvJw>(Saeso-&Mq5ISsg$+IH|@g ztqAJ)jkyfPmsN)>!=vsuUrUF(2OCDHUGC_%%L~Si_rba^2XhV(h|?Ni)6yko1xC1o z2ahJ)hJb~phY=!`k^Z*$k4O%xrzLoY-&u<8p2yQUo4PEOfKGO;tb$;`Hw0&B+ktKY z7R8h(*?Np3thqDf3T(}Sjg{c1>l3^b3iT0s7?JpseOgWcRu2PMfdD?BS>v|VvL-Ky zFHy`sQx+-vdEE5RP$)O%YexE$cQ&Jst3?&9^O#>JWzGdkiFia1)kXO8qPFVmcc$UT z8>ce}+Ql?^de|eC=66eDyQ|QWE&jB)$F2FS@V?J6b)Y5uZnSva0}sMyrb?^Ki%~)W zj~y_9Oh)!Yao~XPyoPAHK|}u^kS3U6=ZMIGLFpg4fvPv9cWQbJ`1!jf-1WRD_&f5 zJ(D<$z&t@1iNR??XwCBZ@}MOi_b~Y~19V7gc<$h5~cXhavC|JuzOx z9-V`Y;2w5j)26C(?|%&lNjmUdTA~pZ*XLRgAxmVP4Q4AFOcv%ZeR3~foj4E9#sBGp z0N}40F%&GN-I&nu^*o8_U!E_hQ^zWJ?Vl!Nr4Q$j$3ed@arHr0Xh{*#r*0A{T3DuH z_9%$@@<=LQsrC)4J5Q5yU8*3RomU&&4cRWwA~_Gj>^S!z?-q`{KVRTSWR8yg0DIO@ zovsg6fDK|&kYYtysm&)n5+6C3gpiE)4#^c4U&beljD|rs0($f8g+Grwxy9>VqPdq% zXh*tH6Z|ZjG#asXG(t_Uf$8jhhsB^i^C{#%aS&2lywV0Cd=no7*Ns!c-A(?_Pd;oR z*LfFR#LNivM!2#?-HDAk4LK{DWJk<5}I(=0&l2LHl&;j~$GL=u3zVj9L)-oo>|tUfmC8nn zrQS_lPHL5oX)UwxvJh1FlC*vV#*Nsar7G? zt($ZV*NdkvAE|(8lGL z#l}A0aK;nLE%JJ8HAkVO;pov_Mq4B^v&J0=pJ&)c$WgIXt4%wIRovs|mWM+S7hS#q z)^_i}49>e(@EA@V!;5m_=;$7;d~~w(;CQt*==6+8BfImp{BQ*(cY6r+LwvAnWC=rh z@E%^aI4eJi-ifC)Jg7UP+>F16Am`hkPEFvdWnEzw4i%DWaHN98Hx+rR7U@OKNCmvl72)+n!cMBwsALE5p9yVv)%cd$k})5Rh3^c;nC zC~nB2pl~|K0E{qd;MS`Y)uTn*E)WdfgzHpS=@5WQFiY5R1e(ckbm|OF(%j3x=i4ukDT8Kk*VNYWDFKC|5K4u$$8bfzZ{qH=3B~6Ho?O!Lq?t&u^r6aF!HV z>GtfbH|~sqtoPT2_MXxLfJb&k&KjPey4d9D48&Xfv(+p5O6(ztSrra)fq?p|c=9KY z(8`!=fBe3^(Lp|Isom^$4}~1oE8V9opI81ot_xZFDbidLGe!{FiE;UK!IDy(F;{=&ff#o9 z{1fz_+Q}zas`c?M-wVRJ^!|HhhK^BJ&x~$UU&rDKjO#>u#Nzf6qo*gZ??2Rqs{8J9 z(@U=tb!LcfF&t@>d3cT6mGUj4FHqJIwM%LLoWJn6x%q!9P?Vf6lT)R>-)Un1%|?y;j&wQWPP!p^PuYuSD^?p*<7=_wQ0ErUE{Ln)$6<$A@2j6ZbRC9C zpPGeLw3RzHRV}_Z^wIGZ;;*O^``>E(sht!PYKLOkiAWwYe{srREFFKde4gg);`0ux zEi=9*v&jpALF!eW=CogspYgtUsJzju4EVUQe;{)VAE$dClC_D^%LDq??{9`I3-Rkq zl+V|Yz`xa{PspHPzjENhnV+7~cN?ECdZNwK? zg62!)qYtiHqg1E_6VV&O50Ba?L*o6K5E{WRtk3PJjd+Yjrab}cpK*2V-r&WYb7}JE zd$lzmL?Wlm1EbptV)w_;3B4y^jdDjJ32XTy&?NWwGt~*56lI7$2x)t3taGRC_uR*! zt5StCXg|4S)Mpe^@9Crg?i_dGR7vf#TO;^X6 zo4qP?k5u!eXdWV&58e2tghm%pf9OlHQ3#Y(b@j>8*L=y_@zyQuGpqa=ZHmFOJ3oA{ z+~am2P#AykZ#|{d(ZtxOV4T~r`~JmpiLLuB^zOmg7kYWbydvJEBB6e_rOgxy;4%Pg z1PzS`I%>O_N*OV7qm*jSa{e$DdJ9f2sALwNZ*<_VN>m+Y)CYZNy^V#}41Ift-W# zfba9Xo1nGoi(mcm2s?asEUQh_IJtJ^hYEkax75vlS^jnPFq zSl9GAf)nt*e2_}Qgh!84?QzuD(tUgIF!qZeNs(*KZ(aFlAutSHsqd#GjqXKcV6Ky3 zjMdW%-38~rZdm#Nm0g&GrR76F?cni0S(5MtxQm+$D*^xdg8$oGEG5jKCR6UV9|>44$uY1wA8A0AeG{eb zRSizV8H-+Udxj7iZ;1L{SD01R>2&PFn8czm(&&{UM&aP>*&JC|V=DXS%h1lD^?^ zbo$3JGi5-*&i=B8V^pHm`?ipR3Xt+`YoM%MRC+A@d>$!xa#?nktQ=!l>NS zXY06Tfv|8GC<542{0Ob0#@qyAzVzVN#l(Y}%Oi6_Vr5+JVz=1=G$r2WP(Tre(p63i zGEHy+5kk*GKxTD<91w*kdy60$e!ZMIQk{{S2o>!k^`F(o|~2ZR|h=x?Xjp)e`&L(_LN?A6UCm3R~Uo^xCt zJ52tWCa5N+E2wd+7E#Ub!LcSpvHBOx1~du*RVwU}6SItiebhK?H#VFl3!g{ONIk;n z^qkq))P_h67ccB&c2&r8<3NWQxj@$yFh!bb{b=puTXC(A5Fl|E%_Fw8>74lM(MBza zpdSh0c8ZW7?Mwshwtu2Pv$SFzbrsg)A;=dJ?N&Yzh{mV1Ue6}( z)Xpga*RNEf9IDp_KADvw{Wa z6Dg?KI+I-qdBgP>_k$|b*$;`_7VZNXLu?sMyD_)HKSIUk4W2#&d3fz zZ$|aU*!pq|s6OH@prE%1c47D0Zb^hy@_S|e6}Dfg@Lg;B*xizF$CKnpUj4v_(`9rNL|s>ae(= zi@o=6W~}j$D(nOY$%5#A3M?w2ggI{7yr zCFL-ho7a}mTRfg0!_w_woK=bL+e2zcypMcrhq|g=F$!7LUm3^vVu}uq%D)FL36qRpy+d_!2|Dmus5QMXvq{;ywd* zw|^^<;-y|sIqwZY#eqy-g2nHsFx0AdzfhtSl>}OvQm7~?#of+Ype04bAKkPkKH;#l z&tuR>#q#d+IPm&-GAOxQ9A#~yMlBkaN|pY@5+1PTg6 zqN=;M&}l6sg>~<_y-4JQpd3xFMns80L~vB#E$!AFtD#ML5FK8~Ygd3XB2;~EOLZOx0Qzr$j@btpuKJ3u zw;g?po>fSr>Vceu*eRx=*^jI3rWyblwQxlriZ}9}5rs_NJ`vMbEY`x@?C!sa4~=am z-X+BFJq=$}P>guxTEul)=Z;BLb4Q~-DYVZY3angj=^n;w+4zt2Ko?8GdE9>LH~4D| z)7!*-+&@o-eTI;@nOYtWL+TxWWUCXMoTF%KC#@;>L{>%H^e|RvMxFhGSv8DNa`vG? z{q_^`6G#!M|5`jo*K^tu27D?e(p9d$SOyNq@po~HQ*OnNfj;UNzS4mmY+^xMk`IDgs<-et4Qod5Ek{y`bKy&Qxs}5np)jNX& z3V_E5&Y}R68osHi9()7nS1HDar;L?xVLD3iw2nk1I}g6GG_*+5s1-v7BR z?1?JGkvWIsVqJ>|@zN`(r8}oa>2f&3DmeDxY zSSU)3J}2*!E|wZ@RYLdC|5pj1!kb#J-2L}3Kg2n9 z;Y4Qs>Y-zQOmp;6hG!2)00HL+@x1i#c%NAmE_E>g3Mjxq-6NUUwx`B zIdj?i1F*wCkLzH_2?;2YHMI8<*HjAzcUfBr1k1I+q|S}|B-lFY!~#7WPKOKN4hstB z`WTk898nu?PQg@q^~r&0@iMV!=!v_0(X zutY2-?b?UOG!!(_x!+^>&%kBH?8c`6eRXiPWbRZO}#^ z4Fc$q-+8t1qZ7+d;?06vDG7i`2bO6WKhB}`h92!Hp}FlUY1Gvx9LtcFSYo^ceVPm= zX%&O`>ZfrhV4wJhOw9Z?cZ^lW(uXl!OQC$c8Yefi3m)f0PI$IbV-(J>dUkWo>oeN7 z_9k5k-SX!z6dwN9*abz#eu}HlFULL*flJ&`}xl1yJbq?C5{jFL;}Dt+bkIG>s_GnF>u;%-)Oud$R; z%Z`La<@i_Y5+a(x{3B0?zfl)jo;u)l3|oZM^Dq34JQ_LDW7O-PylQDs1(ga&zxwE@ z{Bx^ZSF&I~Yt1^RH7b@eopoH(Eu-rO@H$NbulWL|6)~E8izg=H4hQ@9KdtJ&3E@4|2hnd#ZdSj*OyPBiG5O;J^MjWb1I#g}r_zlvTc7!ml8zl424P>fyZ{{U`t0XcqjJ8VV6Eqm0iz2B z)gi1dt%(H4cJ)Z;JjDtaBgwnL6BZvGFz|ub1qQ{k{j4MC!q*G_&2)~{r|Q&nH}Ixi z5Q-P4Wotix=J&+*!4~G1AtNZ>+nPkr14&`7L!+=I+e#5MVJp7Bo&Ox`!-Cu|`C}5ne_QYTxNG$yHIaH3jC538!mwaN7VeF%08-9c_3n+CP-CxID zDKL=Ch?Al^z;k{1g&6&FA8hBa^d-go8Nm9KnO|Gz#=X3wym_Z&#tezKG2MVo;-1sB z$B3h_!lq=)x?EY@91pFSZ(o4+^#I2X*ZbM7rOuD?J0(_+jQtId*&&%K_QMu+t(cV zYW}11jGvi)9>>2{d#km0#^1tr6j#1}_Cwj~M#%Wo(cVvVzyGZ?RK^v%qDtw!_rqz) zM#o7ir*q-vKQB}x?Lp~__BFAQBlGLq%imVuX7>j&&>4yDkZXxcLRNN-q%@Mm*P zzvNoVMG^bZ({P{Jzhk~$-qir*G%9PT*C+Q$os^-&GM1Nu-!%Sre!VyK#%O}t6&*_y zAXTovzNZayIBNTc^OCu0;YrWeuE606EY7u*F0Y;`GP-jcescXg-XdjcdiK

(`px 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�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 RY}szk%?lz-=YIL={{f+UtRMgY diff --git a/src/assets.rs b/src/assets.rs index 55f3fb77201..bd282eb352f 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -299,23 +299,6 @@ pub fn collect(dirs: &[String], programs: &BTreeSet<&str>) -> Vec<(String, Vec) -> Vec<(String, Vec = config.programs.keys().map(String::as_str).collect(); root_files.extend(assets::collect(&config.assets, &programs)); } + if config.programs.contains_key(crate::wallpaper::READER) { + root_files.push((crate::wallpaper::PATH.to_string(), crate::wallpaper::rgb())); + } // Extra files (test binaries, shared libs) for (name, data) in extra_files { diff --git a/src/flags.rs b/src/flags.rs index d9173d79433..20445c0fa8a 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -66,7 +66,6 @@ declare_flags!(pub CARGO_RUN = { pub BOOT_CONFIG = "--boot-config", Next; pub ARCH = "--arch", Next; pub REGEN_FONT = "--regen-font", None; - pub REGEN_WALLPAPER = "--regen-wallpaper", None; pub REGEN_SOUNDFONT = "--regen-soundfont", Next; /// Mint the owner's image-signing key where `signing::owner_key_path` /// says, refusing to replace one. diff --git a/src/licence.rs b/src/licence.rs index 6bfe3e1e1fd..4fe48462c25 100644 --- a/src/licence.rs +++ b/src/licence.rs @@ -467,12 +467,6 @@ pub const COMMITTED_FILES: &[(&str, &str, &str, Terms)] = &[ "NOTICE", Terms::Spdx("LicenseRef-GeneralUser-GS-2.0"), ), - ( - "assets/wallpaper.jpg", - "b6f0c89bf966cfb458333b280614f0c7723615e42e340b9d43a760a64fe05976", - "ours: `cargo run -- --regen-wallpaper` writes it from src/wallpaper.rs", - Terms::Spdx("MIT OR Apache-2.0"), - ), ( "doom.jpg", "ae22f71dc732580bd4f789937c9fe564969029413fc2092f27bdae8d1ceaf8e3", diff --git a/src/main.rs b/src/main.rs index fb9ccd2ed8a..d44de033d5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -189,11 +189,6 @@ fn main() { return; } - if asked(&flags::REGEN_WALLPAPER) { - toyos_build::wallpaper::regen(&root); - return; - } - if let Some(bank) = CARGO_RUN.value(&args, &flags::REGEN_SOUNDFONT) { toyos_build::soundfont::regen(&root, Path::new(bank)); return; diff --git a/src/wallpaper.rs b/src/wallpaper.rs index 90cba2a336f..c1eeda1ac69 100644 --- a/src/wallpaper.rs +++ b/src/wallpaper.rs @@ -1,27 +1,17 @@ -//! The desktop background, written down as a description instead of fetched. -//! -//! `assets/wallpaper.jpg` used to be a file of unknown origin — an aggregator -//! upload naming no author and no copyright holder, under a "wallpaper use -//! only" restriction nobody on that page had the standing to grant. What -//! replaces it is the output of [`draw`], so provenance is answered by source -//! anyone can re-run rather than by a paragraph in `NOTICE`. +//! The desktop background, drawn by the build: what the compositor reads as +//! `/system/share/wallpaper.rgb` is [`draw`]'s output, byte for byte, so its +//! provenance is source anyone can re-run and no file stands between the two. //! //! The picture is a lit horizon: a night sky, a glow behind it, and three -//! ridges receding into haze. It is nothing but the constants below — change -//! one, run `cargo run -- --regen-wallpaper`, and the committed artifact moves -//! with it. +//! ridges receding into haze. It is nothing but the constants below. //! //! All compositing is in **linear light**, converted to sRGB once per pixel at //! the end. Mixing two colours in sRGB mixes two numbers that were never linear //! to begin with, which is what sends a naive gradient grey through its middle. -use std::path::Path; - -use image::codecs::jpeg::JpegEncoder; -use image::ExtendedColorType; - -/// Where the artifact lives, relative to the repository root. -pub const WALLPAPER_PATH: &str = "assets/wallpaper.jpg"; +/// Where ROOT carries the wallpaper, and the one program that opens it. +pub const PATH: &str = "share/wallpaper.rgb"; +pub const READER: &str = "compositor"; /// Drawn at the panel this project targets, the T14's 1920x1080. The /// compositor scales whatever it is handed, so this is the size at which it @@ -29,20 +19,6 @@ pub const WALLPAPER_PATH: &str = "assets/wallpaper.jpg"; pub const WIDTH: u32 = 1920; pub const HEIGHT: u32 = 1080; -/// **The quantization table is why this is up here and not at the usual 90.** -/// libjpeg's scaling leaves every entry of both tables at 1 by 99, and `image`'s -/// encoder never subsamples chroma (`h: 1, v: 1` on all three components), so -/// the round trip is the DCT's own rounding and nothing else. Anywhere below -/// that the DC coefficient alone is quantized in steps of two or three levels, -/// which lays an 8x8 staircase across exactly the smooth field this picture is -/// made of — and the same quantizer crushes the dither that was there to stop -/// one. `the_wallpaper_neither_bands_nor_blocks` is that stated as a bound. -/// -/// Not 100, which is the same file size to within 0.2% and worse on every other -/// measure. Both readings come from a sweep of the encoder across the quality -/// range at this picture's own dimensions. -pub const QUALITY: u8 = 99; - /// The sky, top to horizon, as sRGB. /// /// Both nearly black on purpose. The glow is what the eye sees; a sky bright @@ -184,7 +160,7 @@ const VIGNETTE_OUT: f32 = 1.25; /// This is dither and not decoration. Eight bits a channel over a field this /// smooth puts a contour every few dozen rows; a triangular perturbation of /// this size turns the contour into noise the eye integrates away, and it is -/// what lets `the_wallpaper_neither_bands_nor_blocks` hold. +/// what lets `the_wallpaper_does_not_band` hold. const GRAIN: f32 = 1.6; fn srgb_to_linear(c: u8) -> f32 { @@ -353,25 +329,17 @@ pub fn draw(width: u32, height: u32) -> Vec { out } -/// [`draw`] at [`WIDTH`]x[`HEIGHT`], JPEG-encoded at [`QUALITY`]. -pub fn encoded() -> Vec { - let rgb = draw(WIDTH, HEIGHT); - let mut jpeg = Vec::new(); - JpegEncoder::new_with_quality(&mut jpeg, QUALITY) - .encode(&rgb, WIDTH, HEIGHT, ExtendedColorType::Rgb8) - .expect("encode the wallpaper"); - jpeg +/// The file ROOT carries at [`PATH`]: the width and the height as +/// little-endian `u32`s, then [`draw`]'s RGB triples at that size, unencoded — +/// a lossy codec here would throw away the dither first. +pub fn rgb() -> Vec { + let mut file = Vec::with_capacity(8 + WIDTH as usize * HEIGHT as usize * 3); + file.extend(WIDTH.to_le_bytes()); + file.extend(HEIGHT.to_le_bytes()); + file.extend(draw(WIDTH, HEIGHT)); + file } -/// Rewrite `assets/wallpaper.jpg` from the constants in this file. -pub fn regen(root: &Path) { - let jpeg = encoded(); - let path = root.join(WALLPAPER_PATH); - std::fs::write(&path, &jpeg).unwrap_or_else(|e| panic!("write {}: {e}", path.display())); - println!("wrote {} ({} bytes)", path.display(), jpeg.len()); -} - - #[cfg(test)] mod tests { use super::*; @@ -386,15 +354,6 @@ mod tests { /// almost four times it. const MAX_FLAT_RUN: usize = 40; - /// How much more a pixel may differ from the one above it across an 8x8 - /// block boundary than inside one. - /// - /// JPEG's characteristic artifact *is* this ratio going up — the blocks are - /// quantized independently, so what a person sees as blocking is a step - /// that appears only where two of them meet. A picture with none of it - /// sits at 1.0, and the value this bound separates from is a doubling. - const MAX_BLOCKING: f64 = 1.25; - fn longest_column_run(rgb: &[u8], width: usize, height: usize, channel: usize) -> usize { let mut worst = 0; for x in 0..width { @@ -409,71 +368,21 @@ mod tests { worst } - fn blocking(rgb: &[u8], width: usize, height: usize) -> f64 { - let (mut across, mut across_n) = (0.0f64, 0u64); - let (mut within, mut within_n) = (0.0f64, 0u64); - for y in 1..height { - for x in 0..width { - for c in 0..3 { - let step = (rgb[(y * width + x) * 3 + c] as i32 - - rgb[((y - 1) * width + x) * 3 + c] as i32) - .abs() as f64; - if y % 8 == 0 { - across += step; - across_n += 1; - } else { - within += step; - within_n += 1; - } - } - } - } - (across / across_n as f64) / (within / within_n as f64) - } - - /// What ships is the decoded JPEG, so the decoded JPEG is what is measured. - /// - /// Asking either question of [`draw`]'s own output would pass at an encoder - /// setting that undoes both: the dither is the highest-frequency thing in - /// the picture and therefore the first thing a quantizer throws away, and - /// the staircase it was holding off comes back as blocking. Between the two - /// they pin the encoder as well as the drawing — nothing here can be - /// weakened without one of them saying so. + /// The file that ships, read the way the compositor reads it, does not band. #[test] - fn the_wallpaper_neither_bands_nor_blocks() { - let decoded = image::load_from_memory_with_format(&encoded(), image::ImageFormat::Jpeg) - .expect("decode what we just encoded") - .to_rgb8(); - let (w, h) = (decoded.width() as usize, decoded.height() as usize); + fn the_wallpaper_does_not_band() { + let file = rgb(); + let (head, pixels) = file.split_at(8); + let w = u32::from_le_bytes(head[..4].try_into().unwrap()) as usize; + let h = u32::from_le_bytes(head[4..].try_into().unwrap()) as usize; + assert_eq!(pixels.len(), w * h * 3, "a {w}x{h} wallpaper of {} bytes", pixels.len()); for (channel, name) in ["red", "green", "blue"].iter().enumerate() { - let run = longest_column_run(decoded.as_raw(), w, h, channel); + let run = longest_column_run(pixels, w, h, channel); assert!( run <= MAX_FLAT_RUN, "{run} rows of one {name} value down a column, over a bound of \ {MAX_FLAT_RUN}: this wallpaper bands" ); } - let blocking = blocking(decoded.as_raw(), w, h); - assert!( - blocking <= MAX_BLOCKING, - "steps across the 8x8 block boundaries are {blocking:.2}x the steps inside them, \ - over a bound of {MAX_BLOCKING}: QUALITY = {QUALITY} is not enough for a field \ - this smooth" - ); - } - - /// The committed file is [`draw`]'s output and not a picture somebody put - /// there — the property this whole module exists to establish, and the - /// answer to the licence question that replacing it was about. - #[test] - fn the_committed_wallpaper_is_the_one_this_file_describes() { - let root = Path::new(env!("CARGO_MANIFEST_DIR")); - let on_disk = std::fs::read(root.join(WALLPAPER_PATH)).expect("read the wallpaper"); - assert!( - on_disk == encoded(), - "{WALLPAPER_PATH} is {} bytes and is not what this file draws — run \ - `cargo run -- --regen-wallpaper`", - on_disk.len() - ); } } From f71697bf64b94c8db3d8ee93c2c407c10351b8bc Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 17:58:16 +0200 Subject: [PATCH 03/22] os-release's commit, time and dirty flag are read with `git`, and gitoxide leaves the build The owner's ruling on the dependency audit, "Drop gix, use git", over the host-tools issue's earlier refusal of `git` reads in gitoxide's favour. gitoxide sheds no host tool while `git` stays for worktrees and submodules, and the build already runs `git` at every other site; for these two reads it held 84 of the root Cargo.lock's packages (694 to 610). `release` now asks `git log -1 --no-show-signature --format='%H %ct' HEAD` for the commit and its committer time, and `git --no-optional-locks status --porcelain --untracked-files=normal --ignore-submodules=all` for whether the tree is that commit's: untracked files count whatever `status.showUntrackedFiles` says, ignored ones and the fork's submodule do not, and the status reads without rewriting the index another `git` in the checkout may hold. `a_tree_records_its_commit_its_commit_time_and_whether_it_is_dirty` is unchanged and green; with `--untracked-files=normal` removed it reds (Clean where Dirty), and with `%at` for `%ct` it reds (1000000000 for 1791089159). The issue's row now admits these reads, with `log` among them, on that ruling. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.lock | 1308 ++--------------- Cargo.toml | 3 - ...d-runs-host-tools-outside-rust-and-qemu.md | 2 +- src/build.rs | 48 +- 4 files changed, 120 insertions(+), 1241 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 150f17d9bea..cf0fe79ccb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,15 +185,6 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" -[[package]] -name = "arc-swap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" -dependencies = [ - "rustversion", -] - [[package]] name = "argon2" version = "0.5.3" @@ -391,17 +382,6 @@ dependencies = [ "uefi-services", ] -[[package]] -name = "bstr" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" -dependencies = [ - "memchr", - "regex-automata", - "serde_core", -] - [[package]] name = "bumpalo" version = "3.20.2" @@ -589,15 +569,6 @@ dependencies = [ "inout 0.2.2", ] -[[package]] -name = "clru" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197fd99cb113a8d5d9b6376f3aa817f32c1078f2343b714fff7d2ca44fdf67d5" -dependencies = [ - "hashbrown 0.16.1", -] - [[package]] name = "cmov" version = "0.5.3" @@ -702,12 +673,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core_detect" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" - [[package]] name = "coreaudio-rs" version = "0.14.2" @@ -801,15 +766,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.23" @@ -955,20 +911,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "dashmap" -version = "6.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - [[package]] name = "dasp_sample" version = "0.11.0" @@ -1169,12 +1111,6 @@ name = "dpi" version = "0.1.1" source = "git+https://github.com/ToyOSOrg/winit?branch=toyos-0.30.13#f58e1f3bca784d97056fe47475c2dca8c6386816" -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - [[package]] name = "ecdsa" version = "0.16.9" @@ -1307,20 +1243,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "encoding_rs" -version = "0.8.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679" -dependencies = [ - "cfg-if", - "core_detect", - "multiversion_no_op", - "rustversion", - "scopeguard", - "simdutf8", -] - [[package]] name = "enum_dispatch" version = "0.3.13" @@ -1367,18 +1289,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "faster-hex" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04839bdf9d8c10f66806fad16b852fc72aab80873aebc3cb69d85b4fa41543ed" -dependencies = [ - "autocfg", - "defmt 0.3.100", - "heapless", - "serde", -] - [[package]] name = "fastrand" version = "2.5.0" @@ -1501,24 +1411,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - [[package]] name = "fontdue" version = "0.9.3" @@ -1568,984 +1466,175 @@ dependencies = [ "futures-io", "futures-sink", "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-executor" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-macro" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", -] - -[[package]] -name = "generator" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" -dependencies = [ - "cc", - "cfg-if", - "libc", - "log", - "rustversion", - "windows-link", - "windows-result", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "generic-array" -version = "1.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542" -dependencies = [ - "generic-array 0.14.7", - "rustversion", - "typenum", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "git+https://github.com/ToyOSOrg/getrandom?branch=toyos-0.2-sdk-0.12#2092d1ccd2833f00559ed27850c576ab37fe9347" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "toyos-abi", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "git+https://github.com/ToyOSOrg/getrandom?branch=toyos-0.3-sdk-0.12#67c17e0a7cd6d29e8ce231073746970cbd7dade7" -dependencies = [ - "cfg-if", - "libc", - "r-efi 5.3.0", - "toyos-abi", - "wasip2", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "git+https://github.com/ToyOSOrg/getrandom?branch=toyos-0.4#f0286c8b3f0cd6d9fa9124ee837fa404e66313a7" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "rand_core 0.10.0", - "toyos-abi", - "wasip2", - "wasip3", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval 0.6.2", -] - -[[package]] -name = "ghash" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" -dependencies = [ - "polyval 0.7.1", -] - -[[package]] -name = "gix" -version = "0.88.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d6dd6028308ad2f2662207506e396b97f9ec899f74bd537c0775248c774f21" -dependencies = [ - "gix-actor", - "gix-attributes", - "gix-command", - "gix-commitgraph", - "gix-config", - "gix-date", - "gix-diff", - "gix-dir", - "gix-discover", - "gix-error", - "gix-features", - "gix-filter", - "gix-fs", - "gix-glob", - "gix-hash", - "gix-hashtable", - "gix-ignore", - "gix-index", - "gix-lock", - "gix-note", - "gix-object", - "gix-odb", - "gix-pack", - "gix-path", - "gix-pathspec", - "gix-protocol", - "gix-quote", - "gix-ref", - "gix-refspec", - "gix-revision", - "gix-revwalk", - "gix-sec", - "gix-shallow", - "gix-status", - "gix-submodule", - "gix-tempfile", - "gix-trace", - "gix-traverse", - "gix-url", - "gix-utils", - "gix-validate", - "gix-worktree", - "gix-worktree-stream", - "gix-zlib", - "nonempty", - "smallvec", -] - -[[package]] -name = "gix-actor" -version = "0.43.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e046e9a929e8e1f40f9a34f736408c4c079f9cf004429f3e718d270e847be96" -dependencies = [ - "bstr", - "gix-date", - "gix-error", -] - -[[package]] -name = "gix-attributes" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d57bcf18768dc259868e335fae99a9063174178b78b00348603f0791cd780a" -dependencies = [ - "bstr", - "gix-error", - "gix-features", - "gix-glob", - "gix-path", - "gix-quote", - "gix-trace", - "smallvec", - "unicode-bom", -] - -[[package]] -name = "gix-bitmap" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9d28a8333a322df5c4fdc7b86a9928965e50794523c0edff57d1fbf2a520cf" -dependencies = [ - "gix-error", -] - -[[package]] -name = "gix-chunk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25303d07ce2b8f98aab48ce4251317d785a3208b7ed65698928e4a2f31889936" -dependencies = [ - "gix-error", -] - -[[package]] -name = "gix-command" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3c2e61f97adc08764060e9becb0c819d8f2ba27896434710e039ae57b1d2a7" -dependencies = [ - "bstr", - "gix-error", - "gix-path", - "gix-quote", - "gix-trace", -] - -[[package]] -name = "gix-commitgraph" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0462cbffd5828447f376559d397d9b29f1979dac3d980b5212b17fa174b174eb" -dependencies = [ - "bstr", - "gix-chunk", - "gix-error", - "gix-hash", - "memmap2", - "nonempty", -] - -[[package]] -name = "gix-config" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2cb454dce2f1895cf9def1df8b0a6bbc579d86d8313bdf60f1ab429d52df12" -dependencies = [ - "bstr", - "gix-config-value", - "gix-error", - "gix-features", - "gix-glob", - "gix-path", - "gix-ref", - "gix-sec", - "gix-utils", - "smallvec", - "unicode-bom", -] - -[[package]] -name = "gix-config-value" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1894e816c774650b5157d965853b50d7e8f7137ea74055a6bac2f2ec051cf997" -dependencies = [ - "bitflags 2.11.0", - "bstr", - "gix-error", - "gix-path", - "libc", -] - -[[package]] -name = "gix-date" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb8beceb16a77fb222923592864b94beb4ad4c2b175a7055c2cac6815ee0370a" -dependencies = [ - "bstr", - "gix-error", - "itoa", - "jiff", -] - -[[package]] -name = "gix-diff" -version = "0.68.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "939aee7bbc9f233de858839e865c82886e0baceb8f1fe792ea1703fa895f09e1" -dependencies = [ - "bstr", - "gix-attributes", - "gix-command", - "gix-error", - "gix-filter", - "gix-fs", - "gix-hash", - "gix-imara-diff", - "gix-index", - "gix-object", - "gix-path", - "gix-pathspec", - "gix-tempfile", - "gix-trace", - "gix-traverse", - "gix-worktree", -] - -[[package]] -name = "gix-dir" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e41d125c2c6f981aad27299a6233a7ace3413289c1e2994f57e5bab1c34847" -dependencies = [ - "bstr", - "gix-discover", - "gix-error", - "gix-fs", - "gix-ignore", - "gix-index", - "gix-object", - "gix-path", - "gix-pathspec", - "gix-trace", - "gix-utils", - "gix-worktree", -] - -[[package]] -name = "gix-discover" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4476ba055ec5fbb05f59dd98380b596428da060beac5f9dccd7374302ad1fbfb" -dependencies = [ - "bstr", - "dunce", - "gix-error", - "gix-fs", - "gix-path", - "gix-ref", - "gix-sec", -] - -[[package]] -name = "gix-error" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4a5c4cd326ddfe7f046ad9eed05461c59af6ea98b681648bac73954317addd" -dependencies = [ - "bstr", -] - -[[package]] -name = "gix-features" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb3a430dbc02d6c5e30a9f92083459593495ea22a476e837d248b22d800eed80" -dependencies = [ - "bytes", - "crc32fast", - "crossbeam-channel", - "gix-path", - "gix-trace", - "gix-utils", - "libc", - "once_cell", - "parking_lot", - "prodash", - "walkdir", -] - -[[package]] -name = "gix-filter" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f31a39e2c9b04843709d1f72b2c39c98dc0ee591e2f67d21302dbfbd06d2956" -dependencies = [ - "bstr", - "encoding_rs", - "gix-attributes", - "gix-command", - "gix-error", - "gix-hash", - "gix-object", - "gix-packetline", - "gix-path", - "gix-quote", - "gix-trace", - "gix-utils", - "smallvec", -] - -[[package]] -name = "gix-fs" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0105ab1cef4542d092c27766d2daf1548fcbad7e460dc2208642c120bb19b3ad" -dependencies = [ - "bstr", - "gix-error", - "gix-features", - "gix-path", - "gix-utils", -] - -[[package]] -name = "gix-glob" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bba50803dea16646cafb9a2d67e95b8cdf5b21c7e8c45bcd18f38bafe02fb81f" -dependencies = [ - "bitflags 2.11.0", - "bstr", - "gix-features", - "gix-path", - "gix-utils", -] - -[[package]] -name = "gix-hash" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a22b6febaaee8546eb0c9dd21ecdd93aca269a6cb3897e1250f0f60933c0174" -dependencies = [ - "faster-hex", - "gix-error", - "gix-features", - "sha1dc", -] - -[[package]] -name = "gix-hashtable" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55bff2f32f6f5a95bdd43e5e5e01b0656250cffbc48eda19db0afa3d73adf2f" -dependencies = [ - "gix-hash", - "hashbrown 0.17.1", - "parking_lot", -] - -[[package]] -name = "gix-ignore" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bfd910e271ecd1a20e4df4009a0d9d844a0c51ee5444aaa3fadd1b1b077930b" -dependencies = [ - "bstr", - "gix-glob", - "gix-path", - "gix-trace", - "unicode-bom", -] - -[[package]] -name = "gix-imara-diff" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305657ad44356151d73c145f567c25b24fdf2466bfb3e90727e1d5461a4e9748" -dependencies = [ - "bstr", - "hashbrown 0.16.1", -] - -[[package]] -name = "gix-index" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfd5b484b5b4e218a5ac114f0982949f9bd7582ff67986665a0cf85895332433" -dependencies = [ - "bitflags 2.11.0", - "bstr", - "filetime", - "fnv", - "gix-bitmap", - "gix-error", - "gix-features", - "gix-fs", - "gix-hash", - "gix-lock", - "gix-object", - "gix-traverse", - "gix-utils", - "gix-validate", - "hashbrown 0.17.1", - "itoa", - "libc", - "memmap2", - "rustix 1.1.5", - "smallvec", -] - -[[package]] -name = "gix-lock" -version = "25.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd5ddfd0cc476fef744ac544783b96a9ff5d49f8de541e6e9d6d6002aa90720" -dependencies = [ - "gix-error", - "gix-tempfile", - "gix-utils", -] - -[[package]] -name = "gix-macros" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11f5429ca73cc3758c9f53af56a9fba100a8701c5b4bc30e29b8b0b15288991" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "gix-note" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6879cc9e5a9a0429e40b05970af6c8dad8734098a3142fec23e32eeb567580" -dependencies = [ - "gix-error", - "gix-hash", - "gix-object", -] - -[[package]] -name = "gix-object" -version = "0.65.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a72909eeeed845721a143ef3dbeb4d6cd5df79c839fe7eefc138cb4f982eba3e" -dependencies = [ - "bstr", - "gix-actor", - "gix-command", - "gix-date", - "gix-error", - "gix-features", - "gix-hash", - "gix-hashtable", - "gix-path", - "gix-tempfile", - "gix-utils", - "gix-validate", - "itoa", - "smallvec", -] - -[[package]] -name = "gix-odb" -version = "0.85.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5794b85ff563a290ea18867fa1f0a5b0b84709f2f34dddbb3614556fbe88c629" -dependencies = [ - "arc-swap", - "gix-error", - "gix-features", - "gix-fs", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-pack", - "gix-path", - "gix-quote", - "gix-zlib", - "memmap2", - "parking_lot", - "tempfile", -] - -[[package]] -name = "gix-pack" -version = "0.75.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0451a48faef8e0e7a8f6d903c8329c7d18a793b3030907ca841f889dc695d1df" -dependencies = [ - "clru", - "gix-chunk", - "gix-error", - "gix-features", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-path", - "gix-zlib", - "memmap2", - "smallvec", -] - -[[package]] -name = "gix-packetline" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ba540112a3fcc6388eb2aa4dc4837040478c285a35178cd9a44b07345cd6636" -dependencies = [ - "bstr", - "faster-hex", - "gix-error", - "gix-trace", -] - -[[package]] -name = "gix-path" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd051ac60c5dbce2228daabf25b6a76408ac732d416c678cfa0a4914d13f60b8" -dependencies = [ - "bstr", - "gix-error", - "gix-trace", - "gix-validate", -] - -[[package]] -name = "gix-pathspec" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee883ab64bad641bf31ff338044edd7aa010605f19e866d98c9164e635c38b1" -dependencies = [ - "bitflags 2.11.0", - "bstr", - "gix-attributes", - "gix-config-value", - "gix-error", - "gix-glob", - "gix-path", -] - -[[package]] -name = "gix-protocol" -version = "0.66.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331ac489c461790b6b692afb322085c42041c6ff7621c30ac3dbb00b12e05e89" -dependencies = [ - "bstr", - "gix-date", - "gix-error", - "gix-features", - "gix-hash", - "gix-macros", - "gix-ref", - "gix-shallow", - "gix-transport", - "gix-utils", - "nonempty", -] - -[[package]] -name = "gix-quote" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b040cfa7af50f131bfa34119cceee804c3cc40c766daaba8e0c8149340aea7" -dependencies = [ - "bstr", - "gix-error", - "gix-utils", -] - -[[package]] -name = "gix-ref" -version = "0.68.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c90ceeec67de03b737c30b1b69116ca56fec803edde022f3d25181f0f597083d" -dependencies = [ - "gix-actor", - "gix-error", - "gix-features", - "gix-fs", - "gix-hash", - "gix-lock", - "gix-object", - "gix-path", - "gix-tempfile", - "gix-utils", - "gix-validate", - "memmap2", -] - -[[package]] -name = "gix-refspec" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4caa89a034a055c0578150092d3edb2f1c3f74cca86b883263a28caa26c5812" -dependencies = [ - "bstr", - "gix-error", - "gix-hash", - "gix-validate", - "smallvec", + "futures-util", ] [[package]] -name = "gix-revision" -version = "0.50.0" +name = "futures-channel" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8438d38e197fa3ea7bb297302db1701879a64a343f23a3d150a602a609a8751" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ - "bstr", - "gix-commitgraph", - "gix-date", - "gix-error", - "gix-hash", - "gix-object", - "gix-revwalk", - "nonempty", + "futures-core", + "futures-sink", ] [[package]] -name = "gix-revwalk" -version = "0.36.0" +name = "futures-core" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fa6d913e7cf8c6407d3954f9794b4b148c2113c672c34b63c59ea654a1e060e" -dependencies = [ - "gix-commitgraph", - "gix-date", - "gix-error", - "gix-hash", - "gix-hashtable", - "gix-object", - "smallvec", -] +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] -name = "gix-sec" -version = "0.15.0" +name = "futures-executor" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d8eb983a830ba586b61f7005deaf44609e1a4186cbf13a0e8668154ca910461" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ - "bitflags 2.11.0", - "gix-path", - "libc", - "windows-sys 0.61.2", + "futures-core", + "futures-task", + "futures-util", ] [[package]] -name = "gix-shallow" -version = "0.14.0" +name = "futures-io" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119bae1301715df40e8fd136deeff4fe8a3be4cfc001ed5e72bad7b47ebbc090" -dependencies = [ - "bstr", - "gix-error", - "gix-hash", - "gix-lock", - "nonempty", -] +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] -name = "gix-status" -version = "0.35.0" +name = "futures-macro" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb7e035b6d9dce932f6b6c8d33d29b31b46e05da544bf810e324bf61aaa5b84" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ - "bstr", - "filetime", - "gix-diff", - "gix-dir", - "gix-error", - "gix-features", - "gix-filter", - "gix-fs", - "gix-hash", - "gix-index", - "gix-object", - "gix-path", - "gix-pathspec", - "gix-worktree", - "hashbrown 0.16.1", - "portable-atomic", - "windows-sys 0.61.2", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "gix-submodule" -version = "0.35.0" +name = "futures-sink" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b498192e5f89453fbd728263d52088aeec634a390e732f1da6d0a491c552091" -dependencies = [ - "bstr", - "gix-config", - "gix-error", - "gix-path", - "gix-pathspec", - "gix-refspec", - "gix-url", -] +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] -name = "gix-tempfile" -version = "25.0.0" +name = "futures-task" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dd7dd8df3345933caddd6ce67821c9eec17192564f1011cf0bd0b8cb0d07ffb" -dependencies = [ - "dashmap", - "gix-fs", - "libc", - "parking_lot", - "tempfile", - "windows-sys 0.61.2", -] +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] -name = "gix-trace" -version = "0.2.0" +name = "futures-util" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df45b2cf6052d9e52681130c17d67505b023e8933ad974f94a2be0b0d24f636a" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] [[package]] -name = "gix-transport" -version = "0.60.0" +name = "generator" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d2beb7b0387bbf4d7c13763c6e168f9957319aa811f09349dc59601be3b2951" +checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" dependencies = [ - "bstr", - "gix-command", - "gix-error", - "gix-features", - "gix-packetline", - "gix-path", - "gix-quote", - "gix-sec", - "gix-url", + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link", + "windows-result", ] [[package]] -name = "gix-traverse" -version = "0.62.0" +name = "generic-array" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4864934e4efd92082ecc37107bce0c389b58d82888db634817f9c711efb7ed" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "bitflags 2.11.0", - "gix-commitgraph", - "gix-date", - "gix-error", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-revwalk", - "smallvec", + "typenum", + "version_check", + "zeroize", ] [[package]] -name = "gix-url" -version = "0.39.0" +name = "generic-array" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f30fe2a228d7de5f9d582463d9b724debcb870162d9fbe908cd5d76ccdecf0d" +checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542" dependencies = [ - "bstr", - "gix-error", - "gix-path", - "gix-utils", - "percent-encoding", + "generic-array 0.14.7", + "rustversion", + "typenum", ] [[package]] -name = "gix-utils" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70525766f53426ca4cd2ea4d58b0b31488dfedb416b3254e2efdd9dc184cc880" +name = "getrandom" +version = "0.2.17" +source = "git+https://github.com/ToyOSOrg/getrandom?branch=toyos-0.2-sdk-0.12#2092d1ccd2833f00559ed27850c576ab37fe9347" dependencies = [ - "bstr", - "fastrand", - "getrandom 0.4.2", - "unicode-normalization", + "cfg-if", + "js-sys", + "libc", + "toyos-abi", + "wasi", + "wasm-bindgen", ] [[package]] -name = "gix-validate" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30574f81fc41b2ca3582ece2bdf8696bdfe9c170aa7e8bcafb81199c86b1ceea" +name = "getrandom" +version = "0.3.4" +source = "git+https://github.com/ToyOSOrg/getrandom?branch=toyos-0.3-sdk-0.12#67c17e0a7cd6d29e8ce231073746970cbd7dade7" dependencies = [ - "bstr", - "gix-error", + "cfg-if", + "libc", + "r-efi 5.3.0", + "toyos-abi", + "wasip2", ] [[package]] -name = "gix-worktree" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04fa19b9b3961aafb3b9e60005b9bcef0100f8b211f46ab5269a6ac896073780" +name = "getrandom" +version = "0.4.2" +source = "git+https://github.com/ToyOSOrg/getrandom?branch=toyos-0.4#f0286c8b3f0cd6d9fa9124ee837fa404e66313a7" dependencies = [ - "bstr", - "gix-attributes", - "gix-error", - "gix-fs", - "gix-glob", - "gix-hash", - "gix-ignore", - "gix-index", - "gix-object", - "gix-path", - "gix-validate", + "cfg-if", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.0", + "toyos-abi", + "wasip2", + "wasip3", ] [[package]] -name = "gix-worktree-stream" -version = "0.37.0" +name = "ghash" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2021e1609beae0edbeefa76ac641be0571b725afacb77ac5b12f33b436e0d3d9" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "gix-attributes", - "gix-error", - "gix-features", - "gix-filter", - "gix-fs", - "gix-hash", - "gix-object", - "gix-path", - "gix-traverse", - "parking_lot", + "opaque-debug", + "polyval 0.6.2", ] [[package]] -name = "gix-zlib" -version = "0.2.0" +name = "ghash" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44a1a9c82ec5b712082566cbef8f5782472a0d3973132911e5a83380a5298fe2" +checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" dependencies = [ - "gix-error", - "zlib-rs", + "polyval 0.7.1", ] [[package]] @@ -2580,12 +1669,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashbrown" version = "0.15.5" @@ -2594,7 +1677,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.1.5", + "foldhash", ] [[package]] @@ -2602,22 +1685,6 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.2.0", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.2.0", -] [[package]] name = "heapless" @@ -2845,60 +1912,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" -[[package]] -name = "jiff" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" -dependencies = [ - "defmt 1.1.1", - "jiff-core", - "jiff-static", - "jiff-tzdb-platform", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", - "windows-link", -] - -[[package]] -name = "jiff-core" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" -dependencies = [ - "defmt 1.1.1", - "log", -] - -[[package]] -name = "jiff-static" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" -dependencies = [ - "jiff-core", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "jiff-tzdb" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" - -[[package]] -name = "jiff-tzdb-platform" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" -dependencies = [ - "jiff-tzdb", -] - [[package]] name = "jni" version = "0.21.1" @@ -3138,15 +2151,6 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" -[[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.29" @@ -3292,12 +2296,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "multiversion_no_op" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" - [[package]] name = "ndk" version = "0.9.0" @@ -3356,12 +2354,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nonempty" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9737e026353e5cd0736f98eddae28665118eb6f6600902a7f50db585621fecb6" - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -3906,29 +2898,6 @@ dependencies = [ "toyos-window", ] -[[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", -] - -[[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 = "password-hash" version = "0.5.0" @@ -4187,21 +3156,6 @@ dependencies = [ "universal-hash 0.6.1", ] -[[package]] -name = "portable-atomic" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" - -[[package]] -name = "portable-atomic-util" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" -dependencies = [ - "portable-atomic", -] - [[package]] name = "ppv-lite86" version = "0.2.21" @@ -4284,15 +3238,6 @@ dependencies = [ name = "proctest" version = "0.1.0" -[[package]] -name = "prodash" -version = "31.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962200e2d7d551451297d9fdce85138374019ada198e30ea9ede38034e27604c" -dependencies = [ - "parking_lot", -] - [[package]] name = "ptr_meta" version = "0.2.0" @@ -4879,12 +3824,6 @@ 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 = "scrypt" version = "0.12.0-rc.10" @@ -5015,12 +3954,6 @@ dependencies = [ "digest 0.11.1", ] -[[package]] -name = "sha1dc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fdf1713fb0547b120571e5f7b37dc2650dc03d2abf46a18928f54372000947f" - [[package]] name = "sha2" version = "0.10.9" @@ -5440,19 +4373,6 @@ dependencies = [ "xattr", ] -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.3.4", - "once_cell", - "rustix 1.1.5", - "windows-sys 0.61.2", -] - [[package]] name = "terminal" version = "0.1.0" @@ -5546,12 +4466,6 @@ dependencies = [ "strict-num", ] -[[package]] -name = "tinyvec" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" - [[package]] name = "tokio" version = "1.51.1" @@ -5722,7 +4636,6 @@ dependencies = [ "flate2", "fontdue", "getrandom 0.3.4", - "gix", "gpt", "kernel", "libc", @@ -6239,27 +5152,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab14ea9660d240e7865ce9d54ecdbd1cd9fa5802ae6f4512f093c7907e921533" -[[package]] -name = "unicode-bom" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" - [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-normalization" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.12.0" diff --git a/Cargo.toml b/Cargo.toml index 6f22bf5d2ab..092563c5179 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -214,9 +214,6 @@ flate2 = { version = "1", default-features = false, features = ["rust_backend"] # takes (`issues/the-internet-clients-work-unchanged.md`), whose C # and assembly the host's `cc` compiles. ureq = { version = "3", default-features = false, features = ["rustls"] } -# The commit an image is built from, its time and whether the tree is that -# commit's, where `git` is a host's C tool (`src/build.rs`'s `release`). -gix = { version = "0.88", default-features = false, features = ["status", "sha1"] } [dev-dependencies] # `USER_TOP`, so the harness judges a held `rsp` against the bound the kernel diff --git a/issues/the-build-runs-host-tools-outside-rust-and-qemu.md b/issues/the-build-runs-host-tools-outside-rust-and-qemu.md index d45c5a44edf..6fb48fedbf0 100644 --- a/issues/the-build-runs-host-tools-outside-rust-and-qemu.md +++ b/issues/the-build-runs-host-tools-outside-rust-and-qemu.md @@ -18,7 +18,7 @@ arrives and is not one. M4 and M5 are stages of `issues/toyos-builds-itself.md`. | CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key; `src/libcxx.rs`, for the C++ runtime in every sysroot build | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest | | `sh` running LLVM's `config.guess`, and the POSIX tools and `cc` it runs | LLVM's CMake, whenever this host builds an LLVM, and the C++ runtime's, in every sysroot build, ask it the host's triple, unconditionally (`get_host_triple` in `rust/src/llvm-project/llvm/cmake/modules/GetHostTriple.cmake`, which runs `sh` by name) | refused: a Rust tool does the shell's part, brush 0.4.0: on the development host (macOS, arm64) `config.guess` printed `/bin/sh`'s triple under it, `arm64-apple-darwin27.0.0`, exit 0 each. The script runs `sed`, `uname`, `mktemp`, `grep`, `rm`, `rmdir` and `cc` there under either shell, and that `cc` is the `cc` rows'. Five of the other six are refused, uutils' doing each: under brush with sed 0.2.0, grep 0.2.0 and coreutils 0.12.0's `mktemp`, `rm` and `rmdir`, and nothing else on `PATH` but the host's `uname` and `cc`, it printed that triple, exit 0. `uname` is admitted: coreutils 0.12.0's answers `-p` with `unknown` where macOS's answers `arm`, and `config.guess` reads that as PowerPC, `powerpc-apple-darwin27.0.0`, exit 0 | CMake finds brush as its `sh`, uutils' `sed`, `grep`, `mktemp`, `rm` and `rmdir`, and a Rust `uname` that answers `-p` as the host's does; or M5 runs it in the guest | | `git` for worktrees, submodules, checkouts, fixtures and rustc's bootstrap | adds worktrees (`src/sysroot.rs`); updates submodules (`src/lib.rs`, `src/sysroot.rs`); fetches the fork from the primary's and checks it out (`src/sysroot.rs`); makes the tests' fixture repositories; runs inside rustc's bootstrap | admitted: no Rust tool does the job, gitoxide 0.85 adds, removes and prunes no worktree, updates no submodule, stages, resets and pushes nothing, checks out only a fresh clone and fetches a local path by spawning `git`; a fixture must be what `git` makes, and bootstrap runs `git` itself | M4 runs it in the guest | -| `git` for reads, a config write, a commit's paths written out, and clones and fetches over HTTPS | `rev-parse`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `config --blob`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `config --global --add safe.directory` in CI's containers; `checkout -- ` through an index of its own, which writes the C++ runtime's sources out of the LLVM commit into the stored LLVM (`src/llvm.rs`); every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, adds a value to a config file and writes it (gix-config 0.58's `File::section_mut_or_create_new`, `SectionMut::push`, `File::write_to`), walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names; and gitoxide's CLI 0.59 (gix 0.88) wrote the runtimes' sources of LLVM `849da7d6` into an empty directory, each path's tree through `gix rev parse`, `gix index from-tree` and `gix free index checkout-exclusive`, exit 0 each: the 18759 files `git` writes there, byte for byte and mode for mode | those are gitoxide's | +| `git` for reads, a config write, a commit's paths written out, and clones and fetches over HTTPS | `rev-parse`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `config --blob`, `status`, `log`, `diff`, `ls-remote` and `grep`, in the build system and its tests, the commit, its time and whether the tree is that commit's among them (`src/build.rs`'s `release`); `config --global --add safe.directory` in CI's containers; `checkout -- ` through an index of its own, which writes the C++ runtime's sources out of the LLVM commit into the stored LLVM (`src/llvm.rs`); every workflow's checkout | admitted: the owner's ruling on the dependency audit (2026-10-09), "Drop gix, use git", over this row's earlier refusal in gitoxide's favour: gitoxide is no tool the build sheds while `git` stays for the row above, and for these reads it held 84 of the root `Cargo.lock`'s packages | M4 runs it in the guest | | `cc`, `c++` and `ar` on a Linux host, `build-essential` in CI's containers | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap); `cc` compiles ring's C and assembly in every build of the build system itself, whose HTTP agent is rustls on ring (`src/release.rs`); `ar` archives what `cc::Build` compiles, ring's included | admitted: no Rust tool compiles C or C++, or takes rustc's host link; ring is the one TLS provider the tree takes (owner, 2026-10-02), over a provider in Rust alone | M5: no host in the loop | | the toolchain's own `clang`, `llvm-ar`, `rust-lld` and `llvm-config`, built from `ToyOSOrg/llvm-project` | rustc links every guest binary with `rust-lld`; `clang` compiles the C corpus (`tests/common/compile.rs`) and, with `llvm-ar`, doomgeneric through `cc::Build` (`src/clang.rs`); rustc's bootstrap asks `llvm-config` how to link LLVM | admitted: our fork's C++, which ToyOS can one day build and run; no Rust tool compiles C, `cc::Build` archives with an `ar`, bootstrap reads LLVM through `llvm-config`, and `CLAUDE.md` links everything with `rust-lld` | M5: no host in the loop | | `ovmf-generic`, `qemu-efi-aarch64` | the x86-64 and AArch64 UEFI firmware of CI's guest containers (`src/firmware.rs`), packaged by Debian apart from QEMU | admitted: QEMU's own firmware, and no Rust firmware does its job | the instrument's QEMU carries its own firmware | diff --git a/src/build.rs b/src/build.rs index ad366bea1f8..39631e12e95 100644 --- a/src/build.rs +++ b/src/build.rs @@ -664,43 +664,27 @@ fn render_manifest(config: &SystemConfig) -> Vec { /// Which build `root`'s tree makes for `arch` against the sysroot whose key /// for it is `toolchain`, as `/system/etc/os-release` records it, read with -/// gitoxide (`issues/the-build-runs-host-tools-outside-rust-and-qemu.md`, -/// row 21). Untracked files are dirty whatever `status.showUntrackedFiles` +/// `git`. Untracked files are dirty whatever `status.showUntrackedFiles` /// says; submodules are not read, because the fork's state is the toolchain /// key's. fn release(root: &Path, toolchain: &crate::keystore::Key, arch: Arch) -> toyos_osrelease::Release { - let repo = gix::open(root).unwrap_or_else(|e| panic!("{} is no git checkout: {e}", root.display())); - let head = repo.head_commit().unwrap_or_else(|e| panic!("{}'s HEAD names no commit: {e}", root.display())); - let commit = toyos_osrelease::Hex::parse(&head.id.to_string()).expect("a SHA-1 commit is forty hex digits"); - let time = head.time().unwrap_or_else(|e| panic!("commit {} names no committer time: {e}", head.id)); - let committed = u64::try_from(time.seconds) - .unwrap_or_else(|_| panic!("commit {} was committed before 1970: {}", head.id, time.seconds)); - // Set whole: the platform `status` makes has no walk at all for a - // checkout configured to show no untracked files. - let walk = repo - .dirwalk_options() - .unwrap_or_else(|e| panic!("the status of {}: {e}", root.display())) - .emit_untracked(gix::dir::walk::EmissionMode::CollapseDirectory); - let changes = repo - .status(gix::progress::Discard) - .and_then(|status| { - status - .index_worktree_options_mut(|options| options.dirwalk_options = Some(walk)) - .index_worktree_submodules(None) - .into_iter(None) - }) - .unwrap_or_else(|e| panic!("the status of {}: {e}", root.display())); - // An index entry whose stat alone moved, and an ignored file the walk - // passed, summarise to nothing. - let dirty = changes.map(|item| item.unwrap_or_else(|e| panic!("the status of {}: {e}", root.display()))).any( - |item| match item { - gix::status::Item::IndexWorktree(change) => change.summary().is_some(), - gix::status::Item::TreeIndex(_) => true, - }, + let head = crate::sysroot::git_out(root, &["log", "-1", "--no-show-signature", "--format=%H %ct", "HEAD"]); + let (id, time) = head + .trim() + .split_once(' ') + .unwrap_or_else(|| panic!("{}'s HEAD names no commit and time: {head:?}", root.display())); + let commit = toyos_osrelease::Hex::parse(id).expect("a SHA-1 commit is forty hex digits"); + let committed: u64 = + time.parse().unwrap_or_else(|_| panic!("commit {id} was not committed after 1970: {time}")); + // `--no-optional-locks`, because a status otherwise rewrites the index it + // refreshes, under the lock a concurrent `git` in this checkout takes. + let status = crate::sysroot::git_bytes( + root, + &["--no-optional-locks", "status", "--porcelain", "--untracked-files=normal", "--ignore-submodules=all"], ); toyos_osrelease::Release { commit, - tree: if dirty { toyos_osrelease::Tree::Dirty } else { toyos_osrelease::Tree::Clean }, + tree: if status.is_empty() { toyos_osrelease::Tree::Clean } else { toyos_osrelease::Tree::Dirty }, toolchain: toyos_osrelease::Hex::parse(toolchain.as_str()).expect("a key is sixteen hex digits"), arch: match arch { Arch::X86_64 => toyos_osrelease::Arch::X86_64, @@ -2108,7 +2092,7 @@ mod tests { .status() .unwrap(); assert!(committed.success()); - // The ref as `git` wrote it, for an oracle that is not gitoxide. + // The ref as `git` wrote it, read off the file rather than asked of `git`. let head = fs::read_to_string(work.join(".git/refs/heads/wt")).unwrap(); let key = crate::keystore::Key::parse("0123456789abcdef").unwrap(); From 0e05e6a1f82ac445bd6dd54e1c01da7aaec5c874 Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 18:02:02 +0200 Subject: [PATCH 04/22] The build formats its FAT32 volumes itself, and `fatfs` is only the oracle it is judged by `src/fatformat.rs` writes the empty volume every FAT partition of an image starts as: the boot sector and its backup, FSInfo, both FATs and the root directory with the label. Its geometry is fatgen103's with the choices the `fatfs` crate made, so every volume keeps its layout: 512-byte sectors, eight reserved sectors, 512-byte clusters to 260 MiB and 4 KiB to 8 GiB, and the FAT sized for the clusters left once both FATs are paid for. One difference, on purpose: no BIOS boot code. `fatfs` wrote 129 bytes of real-mode "not a bootable disk" stub after the BPB of both boot sectors; the jump fatgen103 requires stays, the 420 bytes after it are zero. Here and not in `toyos-fat32`, which is the kernel's driver and whose header refuses a format path ("no code here that could write a BPB"); the build is the one program that formats. `fatfs` moves to the build's dev-dependencies, as the differential oracle: `differs_from_the_fatfs_format_only_in_the_bios_stub` formats six sizes, across both cluster-size edges, with both and finds every byte equal outside the two boot-code ranges. Mutated, it reds on each of: the FAT sized without its two reserved entries (1052 bytes at 260 MiB + 4 KiB), the end-of-FAT entries left free (432 bytes at 34 MiB), and sectors-per-track 0x3f for 0x20 (2 bytes). `an_empty_volume_mounts_free_and_checks_clean` mounts each with `toyos-fat32` and runs `toyos-fat32-check` once the free count is recorded. `fatfs` stays in the root Cargo.lock as the oracle of this module and of `toyos-fat32`'s own host suite. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.toml | 3 +- src/fatformat.rs | 203 +++++++++++++++++++++++++++++++++++++++++++++++ src/image.rs | 36 +++------ src/lib.rs | 1 + 4 files changed, 217 insertions(+), 26 deletions(-) create mode 100644 src/fatformat.rs diff --git a/Cargo.toml b/Cargo.toml index 092563c5179..466b23fbba1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -155,7 +155,6 @@ license = "MIT OR Apache-2.0" default-run = "toyos-build" [dependencies] -fatfs = "0.3.6" fontdue = "0.9" gpt = "3.1.0" libc = "0.2" @@ -216,6 +215,8 @@ flate2 = { version = "1", default-features = false, features = ["rust_backend"] ureq = { version = "3", default-features = false, features = ["rustls"] } [dev-dependencies] +# The FAT implementation `src/fatformat.rs` is judged against, byte for byte. +fatfs = "0.3.6" # `USER_TOP`, so the harness judges a held `rsp` against the bound the kernel # checks every user pointer against and not against a second copy of it. toyos-userbound = { path = "toyos-userbound" } diff --git a/src/fatformat.rs b/src/fatformat.rs new file mode 100644 index 00000000000..f22e415e95f --- /dev/null +++ b/src/fatformat.rs @@ -0,0 +1,203 @@ +//! An empty FAT32 volume, the one the build lays every FAT partition down as +//! before `toyos-fat32` writes its files: a boot sector and its backup, an +//! FSInfo sector, two FATs and a root directory holding the volume label. +//! +//! Here and not in `toyos-fat32`, which is the kernel's driver and has no +//! format path by design. The geometry is fatgen103's with the choices of the +//! `fatfs` crate this replaced, so every volume is laid out as before: +//! 512-byte sectors, eight reserved sectors, the cluster size by volume size, +//! and the FAT sized for the clusters left once the FATs are paid for. +//! `differs_from_the_fatfs_format_only_in_the_bios_stub` holds that, against +//! `fatfs` itself. +//! +//! The boot sector carries no BIOS boot code: the jump fatgen103 requires is +//! there, and the 420 bytes after the BPB are zero. + +const SECTOR: usize = 512; +const RESERVED_SECTORS: u32 = 8; +const FATS: u32 = 2; +const FSINFO_SECTOR: usize = 1; +const BACKUP_BOOT_SECTOR: usize = 6; +const ROOT_CLUSTER: u32 = 2; +/// A fixed disk, which is what every FAT32 volume is. +const MEDIA: u8 = 0xF8; +/// The largest cluster number FAT32 can name, less the two reserved entries. +const MAX_FAT32_CLUSTERS: u32 = 0x0FFF_FFF4; +const END_OF_CHAIN: u32 = 0x0FFF_FFFF; +const ATTR_VOLUME_ID: u8 = 0x08; + +/// An empty FAT32 volume of `bytes` under `label`. +pub(crate) fn format(bytes: usize, label: [u8; 11]) -> Vec { + assert_eq!(bytes % SECTOR, 0, "a {bytes}-byte volume is not whole {SECTOR}-byte sectors"); + let total = u32::try_from(bytes / SECTOR) + .unwrap_or_else(|_| panic!("a {bytes}-byte volume has more sectors than FAT32 counts")); + let per_cluster = sectors_per_cluster(bytes as u64); + let per_fat = sectors_per_fat(total, per_cluster); + let first_data = RESERVED_SECTORS + FATS * per_fat; + let clusters = (total - first_data) / per_cluster; + assert!( + (toyos_fat32::MIN_FAT32_CLUSTERS..=MAX_FAT32_CLUSTERS).contains(&clusters), + "a {bytes}-byte volume has {clusters} clusters, which is no FAT32" + ); + + let mut volume = vec![0u8; bytes]; + let boot = boot_sector(total, per_cluster, per_fat, label); + volume[..SECTOR].copy_from_slice(&boot); + let backup = BACKUP_BOOT_SECTOR * SECTOR; + volume[backup..backup + SECTOR].copy_from_slice(&boot); + + let fsinfo = &mut volume[FSINFO_SECTOR * SECTOR..][..SECTOR]; + put(fsinfo, 0, &0x4161_5252u32.to_le_bytes()); + put(fsinfo, 484, &0x6141_7272u32.to_le_bytes()); + // Free count and next free: "unknown", which `toyos-fat32` counts and records. + put(fsinfo, 488, &u32::MAX.to_le_bytes()); + put(fsinfo, 492, &u32::MAX.to_le_bytes()); + put(fsinfo, 508, &0xAA55_0000u32.to_le_bytes()); + + let entries = per_fat as usize * SECTOR / 4; + for copy in 0..FATS { + let at = (RESERVED_SECTORS + copy * per_fat) as usize * SECTOR; + let fat = &mut volume[at..at + per_fat as usize * SECTOR]; + let mut set = |cluster: usize, value: u32| put(fat, cluster * 4, &value.to_le_bytes()); + set(0, 0x0FFF_FF00 | u32::from(MEDIA)); + set(1, u32::MAX); + set(ROOT_CLUSTER as usize, END_OF_CHAIN); + // The entries past the last cluster that the FAT's last sector still holds. + for cluster in clusters as usize + 2..entries { + set(cluster, END_OF_CHAIN); + } + } + + let root = first_data as usize * SECTOR; + put(&mut volume[root..], 0, &label); + volume[root + 11] = ATTR_VOLUME_ID; + volume +} + +/// 512 bytes up to 260 MiB, 4 KiB up to 8 GiB, and past that 1 KiB a 2 GiB +/// of the size rounded up to a power of two, at most 32 KiB. +fn sectors_per_cluster(bytes: u64) -> u32 { + const MIB: u64 = 1024 * 1024; + let cluster = if bytes <= 260 * MIB { + 512 + } else if bytes <= 8 * 1024 * MIB { + 4096 + } else { + (bytes.next_power_of_two() / (2 * 1024 * MIB) * 1024).clamp(512, 32 * 1024) + }; + (cluster / SECTOR as u64) as u32 +} + +/// The smallest FAT whose entries cover every cluster the volume has left +/// once the reserved sectors and both FATs are taken out, the two reserved +/// entries included. +fn sectors_per_fat(total: u32, per_cluster: u32) -> u32 { + let rest = u64::from(total - RESERVED_SECTORS) + 2 * u64::from(per_cluster); + let per = u64::from(per_cluster * SECTOR as u32 * 8 / 32 + FATS); + rest.div_ceil(per) as u32 +} + +fn boot_sector(total: u32, per_cluster: u32, per_fat: u32, label: [u8; 11]) -> [u8; SECTOR] { + let mut s = [0u8; SECTOR]; + put(&mut s, 0, &[0xEB, 0x58, 0x90]); + put(&mut s, 3, b"MSWIN4.1"); + put(&mut s, 11, &(SECTOR as u16).to_le_bytes()); + s[13] = per_cluster as u8; + put(&mut s, 14, &(RESERVED_SECTORS as u16).to_le_bytes()); + s[16] = FATS as u8; + // The FAT12/16 root entry count and 16-bit sizes stay zero on FAT32. + if total < 0x1_0000 { + put(&mut s, 19, &(total as u16).to_le_bytes()); + } + s[21] = MEDIA; + // Sectors per track and heads: no reader of a FAT32 volume uses either. + put(&mut s, 24, &0x20u16.to_le_bytes()); + put(&mut s, 26, &0x40u16.to_le_bytes()); + if total >= 0x1_0000 { + put(&mut s, 32, &total.to_le_bytes()); + } + put(&mut s, 36, &per_fat.to_le_bytes()); + put(&mut s, 44, &ROOT_CLUSTER.to_le_bytes()); + put(&mut s, 48, &(FSINFO_SECTOR as u16).to_le_bytes()); + put(&mut s, 50, &(BACKUP_BOOT_SECTOR as u16).to_le_bytes()); + s[64] = 0x80; + s[66] = 0x29; + put(&mut s, 67, &0x1234_5678u32.to_le_bytes()); + put(&mut s, 71, &label); + put(&mut s, 82, b"FAT32 "); + put(&mut s, 510, &[0x55, 0xAA]); + s +} + +fn put(into: &mut [u8], at: usize, bytes: &[u8]) { + into[at..at + bytes.len()].copy_from_slice(bytes); +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Cursor; + + /// Where a FAT32 boot sector's boot code lies, after the BPB. + const BOOT_CODE: std::ops::Range = 90..510; + + /// Every size the build formats at, and the cluster sizes' edges. + const SIZES: [usize; 6] = [ + 34 << 20, + (34 << 20) + 4096, + 100 << 20, + 260 << 20, + (260 << 20) + 4096, + 300 << 20, + ]; + + fn fatfs_format(bytes: usize, label: [u8; 11]) -> Vec { + let mut volume = vec![0u8; bytes]; + fatfs::format_volume( + Cursor::new(&mut volume), + fatfs::FormatVolumeOptions::new().fat_type(fatfs::FatType::Fat32).volume_label(label), + ) + .expect("fatfs formats the volume"); + volume + } + + /// **The differential oracle**: `fatfs`, a third party's FAT + /// implementation sharing no code with this one, formats the same size + /// under the same label into the same bytes, but for the BIOS boot code + /// it writes into both copies of the boot sector and this module does not. + #[test] + fn differs_from_the_fatfs_format_only_in_the_bios_stub() { + for bytes in SIZES { + let ours = format(bytes, *b"TOYOS-SLOT "); + let theirs = fatfs_format(bytes, *b"TOYOS-SLOT "); + let mut masked = theirs.clone(); + for sector in [0, BACKUP_BOOT_SECTOR] { + let code = sector * SECTOR + BOOT_CODE.start..sector * SECTOR + BOOT_CODE.end; + assert!(ours[code.clone()].iter().all(|b| *b == 0), "{bytes}: boot code in sector {sector}"); + assert!(theirs[code.clone()].iter().any(|b| *b != 0), "{bytes}: fatfs wrote no boot code in sector {sector}"); + masked[code].fill(0); + } + let differing = (0..bytes).filter(|&at| ours[at] != masked[at]).count(); + assert!(differing == 0, "{bytes}: {differing} bytes differ from fatfs's"); + } + } + + /// `toyos-fat32` mounts the volume as empty, with every cluster but the + /// root's free, and once it has recorded that count, as the build has it + /// do, `toyos-fat32-check` finds nothing wrong with it. + #[test] + fn an_empty_volume_mounts_free_and_checks_clean() { + for bytes in SIZES { + let mut volume = format(bytes, *b"TOYOS-LOG "); + let mut fs = toyos_fat32::Fat32::mount(crate::image::VolumeIo(&mut volume)).expect("it mounts"); + assert!(fs.walk("", 8).expect("it walks").is_empty(), "{bytes}: an empty volume lists files"); + let geometry = *fs.geometry(); + let cluster = u64::from(geometry.bytes_per_cluster()); + assert_eq!(fs.free_bytes().expect("it counts"), (u64::from(geometry.cluster_count) - 1) * cluster, "{bytes}"); + fs.sync().expect("it records the count"); + drop(fs); + let complaints = toyos_fat32_check::check(&volume); + assert!(complaints.is_empty(), "{bytes}:\n{}", toyos_fat32_check::describe(&complaints)); + } + } +} diff --git a/src/image.rs b/src/image.rs index 7b28e9ad0fa..03bfb765293 100644 --- a/src/image.rs +++ b/src/image.rs @@ -456,8 +456,8 @@ const PARTITION_ALIGN: usize = 1024 * 1024; /// The smallest volume there is a FAT32 for. /// -/// FAT32 *is* the format with at least 65,525 clusters, and `fatfs` gives a -/// volume this size 512-byte clusters — so the data area alone is 33.5 MiB +/// FAT32 *is* the format with at least 65,525 clusters, and [`crate::fatformat`] +/// gives a volume this size 512-byte clusters — so the data area alone is 33.5 MiB /// before the two FATs and the reserved sectors. Measured at exactly this size: /// the format succeeds and `fsck_msdos` reports 68,551 free clusters. const FAT32_MIN_BYTES: usize = 34 * 1024 * 1024; @@ -466,7 +466,7 @@ const FAT32_MIN_BYTES: usize = 34 * 1024 * 1024; /// /// The `64/63` beside this at the one call site is headroom for the two FAT /// copies, which cost a byte of table per 64 bytes of volume at the 512-byte -/// clusters `fatfs` gives a small one — the worst case, so a volume whose +/// clusters [`crate::fatformat`] gives a small one — the worst case, so a volume whose /// clusters are larger is over-provisioned rather than under. A flat slack /// leaves a guest whatever the rounding did, and an fsync that fails while the /// host-side volume reports megabytes free is the symptom of getting it wrong. @@ -479,7 +479,7 @@ fn align_up(n: usize, to: usize) -> usize { /// A FAT volume label: eleven bytes of space-padded OEM text. /// /// Without one every host calls the volume `NO NAME`, which is what the ESP -/// showed as. `format_volume` writes it into both places the format keeps it, +/// showed as. The format writes it into both places the format keeps it, /// the BPB field and a `VOLUME_ID` entry in the root directory, and the mount /// on macOS is named from it — measured, `/Volumes/TOYOS-LOG`. fn fat_label(text: &str) -> [u8; 11] { @@ -495,15 +495,7 @@ fn fat_label(text: &str) -> [u8; 11] { /// An empty FAT32 volume of `bytes`, under `label`. fn format_fat32(bytes: usize, label: &str) -> Vec { - let mut volume = vec![0u8; bytes]; - fatfs::format_volume( - Cursor::new(&mut volume), - fatfs::FormatVolumeOptions::new() - .fat_type(fatfs::FatType::Fat32) - .volume_label(fat_label(label)), - ) - .unwrap_or_else(|e| panic!("failed to format the {label} volume: {e}")); - volume + crate::fatformat::format(bytes, fat_label(label)) } /// The volume being built, as [`toyos_fat32`] sees it. @@ -512,7 +504,7 @@ fn format_fat32(bytes: usize, label: &str) -> Vec { /// volume is a `Vec` in this process. The kernel's adapter is where the /// read-modify-write against 4 KiB device blocks lives, and `toyos-fat32`'s own /// host suite is where that shape is exercised. -struct VolumeIo<'a>(&'a mut [u8]); +pub(crate) struct VolumeIo<'a>(pub(crate) &'a mut [u8]); impl VolumeIo<'_> { fn range(&self, offset: u64, len: usize) -> Result, IoError> { @@ -563,17 +555,11 @@ fn build_time() -> FatTime { /// Write `files` onto a formatted volume, creating the directories they name, /// and leave the free-cluster count recorded. /// -/// Written with **our** FAT32 driver rather than with the crate that formatted -/// the volume: `fatfs`'s `create_dir` writes a long-name entry ahead of each -/// `.` and `..`, which the format requires to be a subdirectory's first two -/// entries, and gives `..` the root's cluster number where the format requires -/// zero — neither reachable through that crate's API. `toyos-fat32` is also the -/// driver the kernel appends `kernel.log` with and the one its own host suite -/// runs the volume checker against, so "the image we build is clean" is a claim -/// about the writer that is judged. `fatfs` keeps the format call, where an -/// empty volume has no subdirectory for either bug to live in. +/// Written with `toyos-fat32`, the driver the kernel appends `kernel.log` with +/// and the one its own host suite runs the volume checker against, so "the image +/// we build is clean" is a claim about the writer that is judged. /// -/// `format_volume` leaves FSInfo's free-cluster field 0xFFFFFFFF, which FAT32 +/// The format leaves FSInfo's free-cluster field 0xFFFFFFFF, which FAT32 /// defines as "unknown" and every host reports free space from; `free_bytes` /// counts the FAT when the volume arrived without a hint and `sync` writes it. fn populate(volume: &mut [u8], label: &str, files: &[(&str, &[u8])]) { @@ -1365,7 +1351,7 @@ mod tests { /// readers that did not write it: `toyos-gpt` finds the partition by type /// where the `gpt` crate placed it, `bcachefs`'s mount-and-read path lists /// what its format-and-write path put there, and `toyos-fat32` reads the - /// boot parameter off the ESP that `fatfs` formatted. + /// boot parameter off the ESP. /// /// Every name, size, content hash and symlink target against the list /// handed to [`create_root_image`] — a listing that merely parsed would diff --git a/src/lib.rs b/src/lib.rs index 45229856279..7a2adcff8bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod cicache; pub mod clang; pub mod clippy; pub mod compiler; +pub mod fatformat; pub mod firmware; #[cfg(test)] pub mod gitfixture; From 1c87ae6770f340c87383c5afb220af83b7fd6ae7 Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 18:02:17 +0200 Subject: [PATCH 05/22] soundserver takes rubato without its FFT resampler soundserver builds only `SincFixedOut`, which never reaches rubato's `fft_resampler` feature: that default feature compiles `synchro.rs` (`FftFixedIn`/`FftFixedInOut`/`FftFixedOut`) and swaps the `FftNum` bound on `Sample` from realfft's to a local trait of the same bounds. Turning the default off removes rustfft, realfft, num-complex, strength_reduce, transpose and primal-check from the lockfile and the image's build. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.lock | 59 --------------------------------- userland/soundserver/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75516233810..873a78b6f76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3418,15 +3418,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-derive" version = "0.4.2" @@ -4251,15 +4242,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "primal-check" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08" -dependencies = [ - "num-integer", -] - [[package]] name = "primefield" version = "0.14.0-rc.8" @@ -4460,15 +4442,6 @@ name = "raw-window-handle" version = "0.6.2" source = "git+https://github.com/ToyOSOrg/raw-window-handle?branch=toyos-0.6.2#2a5d102bdbd5dc987b653a7ffff5bedbbbfc53b3" -[[package]] -name = "realfft" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f821338fddb99d089116342c46e9f1fbf3828dba077674613e734e01d6ea8677" -dependencies = [ - "rustfft", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -4625,10 +4598,8 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5258099699851cfd0082aeb645feb9c084d9a5e1f1b8d5372086b989fc5e56a1" dependencies = [ - "num-complex", "num-integer", "num-traits", - "realfft", ] [[package]] @@ -4762,20 +4733,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "rustfft" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89" -dependencies = [ - "num-complex", - "num-integer", - "num-traits", - "primal-check", - "strength_reduce", - "transpose", -] - [[package]] name = "rustix" version = "0.38.44" @@ -5369,12 +5326,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "strength_reduce" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" - [[package]] name = "strict-num" version = "0.1.1" @@ -6191,16 +6142,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "transpose" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" -dependencies = [ - "num-integer", - "strength_reduce", -] - [[package]] name = "ttf-parser" version = "0.21.1" diff --git a/userland/soundserver/Cargo.toml b/userland/soundserver/Cargo.toml index 13fc21e9b8c..6efd86a2c12 100644 --- a/userland/soundserver/Cargo.toml +++ b/userland/soundserver/Cargo.toml @@ -10,7 +10,7 @@ toyos = { path = "../../toyos" } toyos-hda = { path = "../../toyos-hda" } toyos-mixer = { path = "mixer" } toyos-inspect = { path = "../../toyos-inspect" } -rubato = "0.16" +rubato = { version = "0.16", default-features = false } [package.metadata.toyos.host] exempt.owns = "ToyOS's audio devices, claimed from the kernel" From 2849a830783814a7c1e35991475c0e3d618c03af Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 18:09:00 +0200 Subject: [PATCH 06/22] The build writes its partition tables itself, and the `gpt` crate is only the oracle it is judged by `src/gptwrite.rs` makes the table every disk the build writes carries: the protective MBR, the primary header and its 128-entry array at the front, the backup array and header at the back, in 512-byte blocks, with `toyos-gpt`'s CRC-32 and GUIDs. `src/image.rs` places the partitions as the `gpt` crate did, each on the first 1 MiB boundary after the last, so every image keeps its layout byte for byte; its GUIDs are `toyos_gpt::Guid`s from here on, the on-disk bytes, with no text spelling between the build and the parser. Here and not in `toyos-gpt`, which is the loader's and the kernel's parser; the build is the one program that writes a table. `install` reads the partition names the parser does not off the image's own entry array. `gpt` moves to the build's dev-dependencies, as the differential oracle: `the_gpt_crate_writes_the_same_table` lays an install's six partitions with both, on a disk the alignment rounds and one it does not, and finds every byte of both disks equal. `toyos_gpt_reads_it_from_either_copy` reads every partition back through the loader's parser, from the primary and, torn, from the backup. The install test now holds the names an install carries over. Mutated, they red on each of: the header CRC over the whole block, the protective MBR's starting CHS 0x01, the backup header naming the array one block early, and `name_of` reading no name. `toyos-gpt`'s `TOYOS_*_TEXT` constants, and the test holding them to the bytes, existed for the `gpt` crate's text-typed API and go with it. `gpt` stays in the root Cargo.lock as the oracle of this module and of `toyos-gpt`'s own `tests/oracle.rs`. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.toml | 3 +- src/gptwrite.rs | 218 +++++++++++++++++++++++++++++++ src/image.rs | 295 ++++++++++++++++-------------------------- src/lib.rs | 1 + src/metal.rs | 58 ++++----- toyos-gpt/src/guid.rs | 26 ---- 6 files changed, 353 insertions(+), 248 deletions(-) create mode 100644 src/gptwrite.rs diff --git a/Cargo.toml b/Cargo.toml index 466b23fbba1..e2786e099a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -156,7 +156,6 @@ default-run = "toyos-build" [dependencies] fontdue = "0.9" -gpt = "3.1.0" libc = "0.2" toml = "0.8" uuid = { version = "1", features = ["v4"] } @@ -217,6 +216,8 @@ ureq = { version = "3", default-features = false, features = ["rustls"] } [dev-dependencies] # The FAT implementation `src/fatformat.rs` is judged against, byte for byte. fatfs = "0.3.6" +# The GPT writer `src/gptwrite.rs` is judged against, byte for byte. +gpt = "3.1.0" # `USER_TOP`, so the harness judges a held `rsp` against the bound the kernel # checks every user pointer against and not against a second copy of it. toyos-userbound = { path = "toyos-userbound" } diff --git a/src/gptwrite.rs b/src/gptwrite.rs new file mode 100644 index 00000000000..8294a8af2e0 --- /dev/null +++ b/src/gptwrite.rs @@ -0,0 +1,218 @@ +//! The partition table the build writes onto every disk it makes: a +//! protective MBR, the primary GPT header and its entry array at the front, +//! and the backup array and header at the back, in 512-byte logical blocks +//! with the 128 entries of 128 bytes UEFI §5.3 requires room for. +//! +//! Here and not in `toyos-gpt`, which is the parser the kernel and the loader +//! read the table with; the build is the one program that writes one. +//! `toyos-gpt`'s CRC-32 and GUIDs are shared, because they are the format's +//! own and the parser is what proves them. `the_gpt_crate_writes_the_same_table` +//! holds every byte against the `gpt` crate this replaced. + +use toyos_gpt::Guid; + +const LBA: u64 = crate::image::LBA as u64; +const ENTRIES: u64 = 128; +const ENTRY_BYTES: u64 = 128; +const ARRAY_LBAS: u64 = ENTRIES * ENTRY_BYTES / LBA; +/// The MBR, the header and the array before it. +const FIRST_USABLE: u64 = 2 + ARRAY_LBAS; +const HEADER_BYTES: usize = 92; +/// A name is at most 36 UTF-16 code units. +const NAME_UNITS: usize = 36; + +/// One partition: its type, its own GUID, its first and last block, and its name. +pub(crate) struct Entry<'a> { + pub kind: Guid, + pub unique: Guid, + pub first_lba: u64, + pub last_lba: u64, + pub name: &'a str, +} + +/// A table's two halves: `primary` goes at byte 0 of the disk and `backup` +/// ends at its last byte. +pub(crate) struct Table { + pub primary: Vec, + pub backup: Vec, +} + +/// The last block a partition on a disk of `lbas` blocks may use. +fn last_usable(lbas: u64) -> u64 { + lbas - 2 - ARRAY_LBAS +} + +/// The table of a disk of `lbas` blocks named `disk`, carrying `entries` in +/// their order. +pub(crate) fn table(lbas: u64, disk: Guid, entries: &[Entry<'_>]) -> Table { + assert!(entries.len() as u64 <= ENTRIES, "{} partitions in a table of {ENTRIES}", entries.len()); + let last_usable = last_usable(lbas); + let mut array = vec![0u8; (ENTRIES * ENTRY_BYTES) as usize]; + for (entry, slot) in entries.iter().zip(array.chunks_mut(ENTRY_BYTES as usize)) { + assert!( + FIRST_USABLE <= entry.first_lba && entry.first_lba <= entry.last_lba && entry.last_lba <= last_usable, + "partition {:?} at blocks {}..={} is not inside {FIRST_USABLE}..={last_usable}", + entry.name, + entry.first_lba, + entry.last_lba + ); + let name: Vec = entry.name.encode_utf16().collect(); + assert!(name.len() <= NAME_UNITS, "the partition name {:?} is over {NAME_UNITS} UTF-16 units", entry.name); + slot[..16].copy_from_slice(&entry.kind.0); + slot[16..32].copy_from_slice(&entry.unique.0); + slot[32..40].copy_from_slice(&entry.first_lba.to_le_bytes()); + slot[40..48].copy_from_slice(&entry.last_lba.to_le_bytes()); + for (unit, at) in name.iter().zip((56..).step_by(2)) { + slot[at..at + 2].copy_from_slice(&unit.to_le_bytes()); + } + } + let array_crc = toyos_gpt::crc32(&array); + let header = |at: u64, other: u64, array_at: u64| { + let mut block = vec![0u8; LBA as usize]; + block[..8].copy_from_slice(b"EFI PART"); + block[8..12].copy_from_slice(&0x0001_0000u32.to_le_bytes()); + block[12..16].copy_from_slice(&(HEADER_BYTES as u32).to_le_bytes()); + block[24..32].copy_from_slice(&at.to_le_bytes()); + block[32..40].copy_from_slice(&other.to_le_bytes()); + block[40..48].copy_from_slice(&FIRST_USABLE.to_le_bytes()); + block[48..56].copy_from_slice(&last_usable.to_le_bytes()); + block[56..72].copy_from_slice(&disk.0); + block[72..80].copy_from_slice(&array_at.to_le_bytes()); + block[80..84].copy_from_slice(&(ENTRIES as u32).to_le_bytes()); + block[84..88].copy_from_slice(&(ENTRY_BYTES as u32).to_le_bytes()); + block[88..92].copy_from_slice(&array_crc.to_le_bytes()); + let crc = toyos_gpt::crc32(&block[..HEADER_BYTES]); + block[16..20].copy_from_slice(&crc.to_le_bytes()); + block + }; + + let mut primary = protective_mbr(lbas); + primary.extend(header(1, lbas - 1, 2)); + primary.extend(&array); + let mut backup = array; + backup.extend(header(lbas - 1, 1, last_usable + 1)); + Table { primary, backup } +} + +/// LBA 0: one partition of type 0xEE over the whole disk but its first +/// block, or as much of it as 32 bits count, at the CHS UEFI §5.2.3 gives it. +fn protective_mbr(lbas: u64) -> Vec { + let mut block = vec![0u8; LBA as usize]; + block[446..454].copy_from_slice(&[0x00, 0x00, 0x02, 0x00, 0xEE, 0xFF, 0xFF, 0xFF]); + block[454..458].copy_from_slice(&1u32.to_le_bytes()); + block[458..462].copy_from_slice(&u32::try_from(lbas - 1).unwrap_or(u32::MAX).to_le_bytes()); + block[510..512].copy_from_slice(&[0x55, 0xAA]); + block +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::image::ImageSectors; + use std::collections::BTreeMap; + use std::io::{Cursor, Read, Seek, SeekFrom}; + + const ALIGN: u64 = 2048; + + /// The partitions of a boot image with the DATA an install puts first, + /// one of them a length the 1 MiB alignment does not round. + const ROWS: [(&str, Guid, u64); 6] = [ + ("ToyOS data", Guid::TOYOS_DATA, 3 << 20), + ("ESP", Guid::EFI_SYSTEM, 34 << 20), + ("ToyOS slots", Guid::TOYOS_SLOTS, 1 << 20), + ("ToyOS log", Guid::MICROSOFT_BASIC, 34 << 20), + ("ToyOS slot A", Guid::TOYOS_BOOT, (40 << 20) + 4096), + ("ToyOS root A", Guid::TOYOS_ROOT, 7 << 20), + ]; + + /// `ROWS` under `uniques`, each on the first 1 MiB boundary after the last. + fn entries(uniques: &[Guid]) -> Vec> { + let mut at = ALIGN; + ROWS.iter() + .zip(uniques) + .map(|((name, kind, len), unique)| { + let first = at; + at = (first + len / LBA).next_multiple_of(ALIGN); + Entry { kind: *kind, unique: *unique, first_lba: first, last_lba: first + len / LBA - 1, name } + }) + .collect() + } + + fn disk_of(total: u64, table: &Table) -> Vec { + let mut disk = vec![0u8; total as usize]; + disk[..table.primary.len()].copy_from_slice(&table.primary); + let back = disk.len() - table.backup.len(); + disk[back..].copy_from_slice(&table.backup); + disk + } + + /// The `gpt` crate's table for `ROWS`, laid as `src/image.rs` laid it with + /// that crate, on a disk of `total` bytes: its bytes, its disk GUID and + /// the unique GUIDs it drew. + fn theirs(total: u64) -> (Vec, Guid, Vec) { + let mut bytes = vec![0u8; total as usize]; + let mut cursor = Cursor::new(&mut bytes); + gpt::mbr::ProtectiveMBR::with_lb_size(u32::try_from(total / LBA - 1).unwrap_or(u32::MAX)) + .overwrite_lba0(&mut cursor) + .expect("the protective MBR"); + let mut disk = gpt::GptConfig::default() + .initialized(false) + .writable(true) + .logical_block_size(gpt::disk::LogicalBlockSize::Lb512) + .create_from_device(Box::new(cursor), None) + .expect("a table"); + disk.update_partitions(BTreeMap::new()).expect("an empty table"); + for (name, kind, len) in ROWS { + let kind = gpt::partition_types::Type { + guid: kind.to_string().leak(), + os: gpt::partition_types::OperatingSystem::None, + }; + disk.add_partition(name, len, kind, 0, Some(ALIGN)).expect("a partition"); + } + let mut device = disk.write().expect("the table"); + let mut out = vec![0u8; total as usize]; + device.seek(SeekFrom::Start(0)).and_then(|_| device.read_exact(&mut out)).expect("read back"); + let guid = |at: usize| Guid(out[at..at + 16].try_into().unwrap()); + let disk_guid = guid(LBA as usize + 56); + let uniques = (0..ROWS.len()).map(|i| guid(2 * LBA as usize + i * ENTRY_BYTES as usize + 16)).collect(); + (out, disk_guid, uniques) + } + + /// **The differential oracle**: the `gpt` crate, a third party's GPT + /// writer sharing no code with this one, lays the same partitions on the + /// same disk under the same GUIDs into the same bytes, every one of them, + /// on a disk the alignment rounds and on one it does not. + #[test] + fn the_gpt_crate_writes_the_same_table() { + for total in [128u64 << 20, (160 << 20) + 3 * 4096] { + let (theirs, disk, uniques) = theirs(total); + let ours = disk_of(total, &table(total / LBA, disk, &entries(&uniques))); + let differing = (0..total as usize).filter(|&i| ours[i] != theirs[i]).count(); + assert_eq!(differing, 0, "{total}: {differing} bytes differ from the gpt crate's"); + } + } + + /// `toyos-gpt`, the parser the loader and the kernel read with, finds + /// every partition at its blocks under its type, from the primary and, + /// with the primary torn, from the backup. + #[test] + fn toyos_gpt_reads_it_from_either_copy() { + let total: u64 = 128 << 20; + let uniques: Vec = ROWS.iter().map(|_| Guid(uuid::Uuid::new_v4().to_bytes_le())).collect(); + let entries = entries(&uniques); + let disk = disk_of(total, &table(total / LBA, Guid(uuid::Uuid::new_v4().to_bytes_le()), &entries)); + let mut torn = disk.clone(); + torn[LBA as usize + 30] ^= 1; + for image in [&disk, &torn] { + for entry in &entries { + let found = toyos_gpt::locate(&mut ImageSectors(image), entry.unique).expect("the partition").partition(); + assert_eq!( + (found.type_guid(), found.first_lba(), found.lba_count().get()), + (entry.kind, entry.first_lba, entry.last_lba - entry.first_lba + 1), + "{}", + entry.name + ); + } + } + } +} diff --git a/src/image.rs b/src/image.rs index 03bfb765293..0573d27eb32 100644 --- a/src/image.rs +++ b/src/image.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::io::{Cursor, Read, Seek, SeekFrom, Write}; use std::num::NonZeroU64; use std::path::Path; @@ -8,6 +7,7 @@ use bcachefs::{BlockBuf, BlockIO, BlockNum, Formatted, FsUuid, Superblock, VecBl use crate::arch::Arch; use sha2::{Digest, Sha256}; use toyos_fat32::{BlockAccess, Fat32, FatTime, IoError}; +use toyos_gpt::Guid; /// The image that goes on the ROOT partition, named by a UUID **derived, never /// drawn**: two builds of one tree have to agree on the name the kernel @@ -237,18 +237,16 @@ pub fn create_boot_image( // kernel. The kernel is given the partition by name; nothing anywhere goes // looking for one by type or by format. Every slot partition is named the // same way, by the slot table. - let guid = uuid::Uuid::new_v4; - let (log_guid, esp_guid, table_guid) = (guid(), guid(), guid()); - let a = (guid(), guid()); - let b = second.map(|room| (guid(), guid(), room)); - let raw = |g: uuid::Uuid| g.to_bytes_le(); + let (log_guid, esp_guid, table_guid) = (new_guid(), new_guid(), new_guid()); + let a = (new_guid(), new_guid()); + let b = second.map(|room| (new_guid(), new_guid(), room)); let s = sections(kernel_bytes, root_bytes, params, signing); // Room for a kernel twice this one's size beside it, so an update can // write a new kernel into a slot's volume before the old one is gone. let slot_bytes = round_up_sectors(((kernel_bytes.len() * 2 + ESP_FREE_BYTES) * 64 / 63).max(FAT32_MIN_BYTES)); let a_boot = create_slot_volume(Some(&s), slot_bytes); - let slot = |(boot, root): (uuid::Uuid, uuid::Uuid), version| toyos_update::slots::Slot { boot: raw(boot), root: raw(root), version }; + let slot = |(boot, root): (Guid, Guid), version| toyos_update::slots::Slot { boot: boot.0, root: root.0, version }; let table = toyos_update::slots::Table { sequence: 1, marked: toyos_update::slots::Which::A, @@ -258,21 +256,21 @@ pub fn create_boot_image( table_volume[..toyos_update::slots::BLOCK].copy_from_slice(&table.encode()); let mut parts = vec![ - Part::full("ESP", "EFI System", gpt::partition_types::EFI, esp_guid, create_esp_volume(arch, bl_bytes, log_guid), Some(Volume::Fat32)), - Part::full("slot table", "ToyOS slots", TOYOS_SLOTS, table_guid, table_volume, None), + Part::full("ESP", "EFI System", Guid::EFI_SYSTEM, esp_guid, create_esp_volume(arch, bl_bytes, log_guid), Some(Volume::Fat32)), + Part::full("slot table", "ToyOS slots", Guid::TOYOS_SLOTS, table_guid, table_volume, None), // Microsoft Basic Data, and that type is the whole reason this is a // partition of its own: macOS never auto-mounts an EFI-typed partition // and this host refuses even a manual non-root mount of one, so a log on // the ESP is unreachable without the admin account. This type mounts in // Finder, in Windows and in Linux on plug-in, with nothing configured. - Part::full("log partition", "ToyOS log", gpt::partition_types::BASIC, log_guid, create_log_volume(), Some(Volume::Fat32)), - Part::full("slot A's volume", "ToyOS slot A", TOYOS_BOOT, a.0, a_boot, Some(Volume::Fat32)), - Part::full("slot A's ROOT", "ToyOS root A", TOYOS_ROOT, a.1, root_bytes.to_vec(), Some(Volume::Root)), + Part::full("log partition", "ToyOS log", Guid::MICROSOFT_BASIC, log_guid, create_log_volume(), Some(Volume::Fat32)), + Part::full("slot A's volume", "ToyOS slot A", Guid::TOYOS_BOOT, a.0, a_boot, Some(Volume::Fat32)), + Part::full("slot A's ROOT", "ToyOS root A", Guid::TOYOS_ROOT, a.1, root_bytes.to_vec(), Some(Volume::Root)), ]; if let Some((boot, root, room)) = b { - parts.push(Part::full("slot B's volume", "ToyOS slot B", TOYOS_BOOT, boot, create_slot_volume(None, slot_bytes), Some(Volume::Fat32))); + parts.push(Part::full("slot B's volume", "ToyOS slot B", Guid::TOYOS_BOOT, boot, create_slot_volume(None, slot_bytes), Some(Volume::Fat32))); let len = align_up(room.root_bytes as usize, PARTITION_ALIGN) as u64; - parts.push(Part { what: "slot B's ROOT", name: "ToyOS root B", kind: TOYOS_ROOT, guid: root, bytes: Vec::new(), len, judge: None }); + parts.push(Part { what: "slot B's ROOT", name: "ToyOS root B", kind: Guid::TOYOS_ROOT, guid: root, bytes: Vec::new(), len, judge: None }); } create_gpt_disk(&parts) } @@ -588,7 +586,7 @@ fn populate(volume: &mut [u8], label: &str, files: &[(&str, &[u8])]) { /// partition the kernel's log goes on. The kernel and its parameter are a /// slot's (`create_slot_volume`), because the loader is the one part of the /// machine that is not slotted. -fn create_esp_volume(arch: Arch, bootloader: &[u8], log_guid: uuid::Uuid) -> Vec { +fn create_esp_volume(arch: Arch, bootloader: &[u8], log_guid: Guid) -> Vec { let total_size = round_up_sectors(((bootloader.len() + ESP_FREE_BYTES) * 64 / 63).max(FAT32_MIN_BYTES)); let mut volume = format_fat32(total_size, "TOYOS-BOOT"); populate( @@ -602,7 +600,7 @@ fn create_esp_volume(arch: Arch, bootloader: &[u8], log_guid: uuid::Uuid) -> Vec // order: nothing converts them on the way to the kernel and nothing // converts the table's, so the comparison that decides which // partition holds the log cannot be got backwards. - ("toyos/log.guid", &log_guid.to_bytes_le()), + ("toyos/log.guid", &log_guid.0), ], ); volume @@ -643,33 +641,10 @@ fn create_log_volume() -> Vec { volume } -/// `B350BC93-…`, the TOYOS-ROOT partition type, as the writer names a type. -/// -/// `toyos_gpt::Guid::TOYOS_ROOT` is the same sixteen bytes as the kernel -/// matches them, and `toyos_root_text_is_the_type_guid` is what keeps the two -/// spellings one constant — and the same for each type below. -const TOYOS_ROOT: gpt::partition_types::Type = gpt::partition_types::Type { - guid: toyos_gpt::Guid::TOYOS_ROOT_TEXT, - os: gpt::partition_types::OperatingSystem::None, -}; - -/// `064E3777-…`, the TOYOS-DATA partition type, the same way round. -const TOYOS_DATA: gpt::partition_types::Type = gpt::partition_types::Type { - guid: toyos_gpt::Guid::TOYOS_DATA_TEXT, - os: gpt::partition_types::OperatingSystem::None, -}; - -/// `94464329-…`, the slot table's partition type. -const TOYOS_SLOTS: gpt::partition_types::Type = gpt::partition_types::Type { - guid: toyos_gpt::Guid::TOYOS_SLOTS_TEXT, - os: gpt::partition_types::OperatingSystem::None, -}; - -/// `037719D7-…`, a slot's FAT volume. -const TOYOS_BOOT: gpt::partition_types::Type = gpt::partition_types::Type { - guid: toyos_gpt::Guid::TOYOS_BOOT_TEXT, - os: gpt::partition_types::OperatingSystem::None, -}; +/// A partition's or a disk's GUID, drawn once. +fn new_guid() -> Guid { + Guid(uuid::Uuid::new_v4().to_bytes_le()) +} /// Lay a table on the disk at `path`, already `len` bytes long, carrying one /// TOYOS-DATA partition, stamp the designation at its first block, and answer @@ -684,26 +659,26 @@ pub fn designate_data_disk(path: &Path, len: u64) -> (u64, u64) { else { panic!("a {len}-byte disk has no room for a DATA partition"); }; - let file = std::fs::OpenOptions::new() + let mut file = std::fs::OpenOptions::new() .read(true) .write(true) .open(path) .unwrap_or_else(|e| panic!("open {} to partition it: {e}", path.display())); - let (mut device, starts) = lay(Box::new(file), len, &[data_row(uuid::Uuid::new_v4(), data_bytes)]); - designate(&mut device, starts[0], data_bytes); - device.flush().expect("flush the data disk"); + let starts = lay(&mut file, len, &[data_row(new_guid(), data_bytes)]); + write_at(&mut file, starts[0], &designation(data_bytes / SECTOR as u64), "DATA partition's designation"); (starts[0], data_bytes) } /// A TOYOS-DATA partition's entry. -fn data_row(guid: uuid::Uuid, len: u64) -> Row { - Row { what: "DATA partition".into(), name: "ToyOS data".into(), kind: TOYOS_DATA, guid, len } +fn data_row(guid: Guid, len: u64) -> Row { + Row { what: "DATA partition".into(), name: "ToyOS data".into(), kind: Guid::TOYOS_DATA, guid, len } } -/// Stamp the designation on the `bytes`-long partition at byte `at` of `device`. -fn designate(device: &mut gpt::DiskDeviceObject<'_>, at: u64, bytes: u64) { - device.seek(SeekFrom::Start(at)).expect("seek to the data partition"); - device.write_all(&designation(bytes / SECTOR as u64)).expect("stamp the data partition"); +/// Write `bytes` at byte `at` of `disk`; `what` they are is what a refusal names. +fn write_at(disk: &mut (impl Write + Seek), at: u64, bytes: &[u8], what: &str) { + disk.seek(SeekFrom::Start(at)) + .and_then(|_| disk.write_all(bytes)) + .unwrap_or_else(|e| panic!("write the {what} at byte {at}: {e}")); } /// What a machine's own disk holds once the boot image `image` is installed @@ -716,29 +691,21 @@ fn designate(device: &mut gpt::DiskDeviceObject<'_>, at: u64, bytes: u64) { /// blocks that are not zero are written, so the file costs the host what the /// image does. pub fn install(image: &[u8], disk: &Path, data_bytes: u64) { - use gpt::disk::LogicalBlockSize::Lb512; let mut listed = [None; 16]; let scan = toyos_gpt::list(&mut ImageSectors(image), &mut listed) .unwrap_or_else(|e| panic!("the image to install carries no partition table: {e:?}")); assert!(scan.matched as usize <= listed.len(), "the image to install carries {} partitions", scan.matched); - // The names, which the reader above does not read; the types, which this one does not keep. - let mut names: BTreeMap = gpt::header::read_header_from_arbitrary_device(&mut Cursor::new(image), Lb512) - .and_then(|header| gpt::partition::file_read_partitions(&mut Cursor::new(image), &header, Lb512)) - .unwrap_or_else(|e| panic!("the image to install carries no readable partition entries: {e}")) - .into_values() - .map(|part| (part.part_guid, part.name)) - .collect(); let carried: Vec<(Row, &[u8])> = listed .iter() .flatten() .map(|entry| { let part = entry.unwrap_or_else(|unplaced| panic!("the image to install states no partition: {unplaced:?}")); - let guid = uuid::Uuid::from_bytes_le(part.unique_guid().0); - let kind = [gpt::partition_types::EFI, gpt::partition_types::BASIC, TOYOS_SLOTS, TOYOS_BOOT, TOYOS_ROOT] - .into_iter() - .find(|kind| uuid::Uuid::parse_str(kind.guid).is_ok_and(|text| text.to_bytes_le() == part.type_guid().0)) - .unwrap_or_else(|| panic!("partition {guid} is of type {}, which no boot image carries", part.type_guid())); - let name = names.remove(&guid).unwrap_or_else(|| panic!("partition {guid} has no name")); + let (guid, kind) = (part.unique_guid(), part.type_guid()); + assert!( + [Guid::EFI_SYSTEM, Guid::MICROSOFT_BASIC, Guid::TOYOS_SLOTS, Guid::TOYOS_BOOT, Guid::TOYOS_ROOT].contains(&kind), + "partition {guid} is of type {kind}, which no boot image carries" + ); + let name = name_of(image, part.index()); let at = part.first_lba() as usize * LBA as usize; let bytes = &image[at..at + part.lba_count().get() as usize * LBA as usize]; (Row { what: format!("installed {name}"), name, kind, guid, len: bytes.len() as u64 }, bytes) @@ -746,10 +713,10 @@ pub fn install(image: &[u8], disk: &Path, data_bytes: u64) { .collect(); let (mut rows, volumes): (Vec, Vec<&[u8]>) = carried.into_iter().unzip(); - rows.insert(0, data_row(uuid::Uuid::new_v4(), data_bytes)); + rows.insert(0, data_row(new_guid(), data_bytes)); let total = disk_bytes(rows.iter().map(|row| row.len)); - let file = std::fs::OpenOptions::new() + let mut file = std::fs::OpenOptions::new() .read(true) .write(true) .create_new(true) @@ -757,18 +724,26 @@ pub fn install(image: &[u8], disk: &Path, data_bytes: u64) { .unwrap_or_else(|e| panic!("{} is not installed on, being no file this install made: {e}", disk.display())); file.set_len(total).unwrap_or_else(|e| panic!("size {} to {total} bytes: {e}", disk.display())); - let (mut device, starts) = lay(Box::new(file), total, &rows); - designate(&mut device, starts[0], data_bytes); + let starts = lay(&mut file, total, &rows); + write_at(&mut file, starts[0], &designation(data_bytes / SECTOR as u64), "DATA partition's designation"); for ((row, volume), start) in rows[1..].iter().zip(volumes).zip(&starts[1..]) { for (i, block) in volume.chunks(PARTITION_ALIGN).enumerate().filter(|(_, block)| block.iter().any(|byte| *byte != 0)) { - let at = start + (i * PARTITION_ALIGN) as u64; - device - .seek(SeekFrom::Start(at)) - .and_then(|_| device.write_all(block)) - .unwrap_or_else(|e| panic!("write the {} at byte {at}: {e}", row.what)); + write_at(&mut file, start + (i * PARTITION_ALIGN) as u64, block, &row.what); } } - device.flush().unwrap_or_else(|e| panic!("flush {}: {e}", disk.display())); +} + +/// The name `image`'s table gives its entry `index`, which `toyos-gpt` does +/// not read: the header at block 1 places the array and sizes its entries, +/// and a name is the UTF-16 units from byte 56 of one, up to the first zero. +fn name_of(image: &[u8], index: u32) -> String { + let field = |at: usize, len: usize| &image[LBA as usize + at..][..len]; + let array = u64::from_le_bytes(field(72, 8).try_into().expect("eight bytes")) as usize * LBA as usize; + let size = u32::from_le_bytes(field(84, 4).try_into().expect("four bytes")) as usize; + let entry = &image[array + index as usize * size..][..size]; + let units: Vec = + entry[56..128].chunks(2).map(|unit| u16::from_le_bytes([unit[0], unit[1]])).take_while(|unit| *unit != 0).collect(); + String::from_utf16(&units).unwrap_or_else(|e| panic!("partition {index}'s name is no UTF-16: {e}")) } /// Block 0 of a volume: the magic and its block count. @@ -807,8 +782,8 @@ impl toyos_gpt::Sectors for FileSectors<'_> { struct Part { what: &'static str, name: &'static str, - kind: gpt::partition_types::Type, - guid: uuid::Uuid, + kind: Guid, + guid: Guid, bytes: Vec, len: u64, judge: Option, @@ -816,14 +791,7 @@ struct Part { impl Part { /// A partition exactly as long as its bytes. - fn full( - what: &'static str, - name: &'static str, - kind: gpt::partition_types::Type, - guid: uuid::Uuid, - bytes: Vec, - judge: Option, - ) -> Self { + fn full(what: &'static str, name: &'static str, kind: Guid, guid: Guid, bytes: Vec, judge: Option) -> Self { let len = bytes.len() as u64; Self { what, name, kind, guid, bytes, len, judge } } @@ -834,8 +802,8 @@ impl Part { struct Row { what: String, name: String, - kind: gpt::partition_types::Type, - guid: uuid::Uuid, + kind: Guid, + guid: Guid, len: u64, } @@ -847,87 +815,40 @@ fn disk_bytes(lens: impl Iterator) -> u64 { round_up_sectors(align_up(end, PARTITION_ALIGN) + PARTITION_ALIGN) as u64 } -/// Write a protective MBR and a GPT on `device`, `total` bytes long, placing -/// `rows` in their order, each on a [`PARTITION_ALIGN`] boundary and under -/// its own GUID: the device, and the byte each row starts at. -fn lay<'a>( - mut device: gpt::DiskDeviceObject<'a>, - total: u64, - rows: &[Row], -) -> (gpt::DiskDeviceObject<'a>, Vec) { - assert_eq!(total % 512, 0, "image must be a whole number of 512-byte sectors to be flashable"); - let mbr = gpt::mbr::ProtectiveMBR::with_lb_size(u32::try_from(total / 512 - 1).unwrap_or(0xFF_FF_FF_FF)); - mbr.overwrite_lba0(&mut device).expect("failed to write MBR"); - - let mut gdisk = gpt::GptConfig::default() - .initialized(false) - .writable(true) - .logical_block_size(gpt::disk::LogicalBlockSize::Lb512) - .create_from_device(device, None) - .expect("failed to create GPT disk"); - - gdisk - .update_partitions(BTreeMap::::new()) - .expect("failed to initialize partition table"); - - let align = Some((PARTITION_ALIGN / 512) as u64); - let ids: Vec = rows +/// Write a protective MBR and a GPT on `disk`, `total` bytes long, placing +/// `rows` in their order, each on the first [`PARTITION_ALIGN`] boundary after +/// the last and under its own GUID: the byte each row starts at. +fn lay(disk: &mut (impl Write + Seek), total: u64, rows: &[Row]) -> Vec { + assert_eq!(total % u64::from(LBA), 0, "image must be a whole number of {LBA}-byte sectors to be flashable"); + let mut end = 0; + let starts: Vec = rows .iter() .map(|row| { - gdisk - .add_partition(&row.name, row.len, row.kind.clone(), 0, align) - .unwrap_or_else(|e| panic!("failed to add the {}: {e}", row.what)) + // The invariant [`PARTITION_ALIGN`] exists for: the kernel mounts + // several at once over one 4 KiB block device, and a device block + // belonging to two volumes would be cached twice. + assert_eq!(row.len % SECTOR as u64, 0, "the {} is {} bytes, not whole {SECTOR}-byte blocks", row.what, row.len); + let start = align_up(end.max(1), PARTITION_ALIGN) as u64; + end = (start + row.len) as usize; + start }) .collect(); - - // The GUID `add_partition` drew for each is discarded for the one its row - // names: the log's is written on the ESP, every slot partition's in the - // slot table, and the ESP's own because a firmware boot entry names a - // partition by GUID and every name is drawn once. - let mut table = gdisk.partitions().clone(); - for (row, id) in rows.iter().zip(&ids) { - table.get_mut(id).expect("a partition that was just added").part_guid = row.guid; - } - gdisk.update_partitions(table).expect("failed to stamp the partitions' unique GUIDs"); - - let placed: Vec<(&str, u64, u64)> = rows + let lba = u64::from(LBA); + let entries: Vec> = rows .iter() - .zip(&ids) - .map(|(row, id)| { - let entry = gdisk.partitions().get(id).expect("a partition that was just added"); - let start = entry.bytes_start(gpt::disk::LogicalBlockSize::Lb512).expect("a partition's start"); - let len = entry.bytes_len(gpt::disk::LogicalBlockSize::Lb512).expect("a partition's length"); - // A slot's ROOT is read for exactly its signed length, and a - // partition the table made any other length than asked is one - // whose contents nothing here placed. - assert_eq!(len, row.len, "the table gives the {} {len} bytes for a {}-byte partition", row.what, row.len); - (row.what.as_str(), start, row.len) + .zip(&starts) + .map(|(row, start)| crate::gptwrite::Entry { + kind: row.kind, + unique: row.guid, + first_lba: start / lba, + last_lba: (start + row.len) / lba - 1, + name: &row.name, }) .collect(); - - // The invariant [`PARTITION_ALIGN`] exists for, checked rather than - // assumed: the kernel mounts several at once over one 4 KiB block device, - // and a device block belonging to two volumes would be cached twice. - let sector = SECTOR as u64; - for (what, start, len) in &placed { - assert_eq!(start % sector, 0, "the {what} starts at byte {start}, off a {SECTOR}-byte block"); - assert_eq!(len % sector, 0, "the {what} is {len} bytes, not whole {SECTOR}-byte blocks"); - } - let mut by_start = placed.clone(); - by_start.sort_by_key(|(_, start, _)| *start); - for (before, after) in by_start.iter().zip(&by_start[1..]) { - assert!( - before.1 + before.2 <= after.1, - "the {} runs to {} and the {} starts at {}", - before.0, - before.1 + before.2, - after.0, - after.1 - ); - } - - let device = gdisk.write().expect("failed to write GPT"); - (device, placed.iter().map(|(_, start, _)| *start).collect()) + let table = crate::gptwrite::table(total / lba, new_guid(), &entries); + write_at(disk, 0, &table.primary, "partition table"); + write_at(disk, total - table.backup.len() as u64, &table.backup, "backup partition table"); + starts } fn create_gpt_disk(parts: &[Part]) -> Vec { @@ -936,32 +857,24 @@ fn create_gpt_disk(parts: &[Part]) -> Vec { } let rows: Vec = parts .iter() - .map(|part| Row { what: part.what.into(), name: part.name.into(), kind: part.kind.clone(), guid: part.guid, len: part.len }) + .map(|part| Row { what: part.what.into(), name: part.name.into(), kind: part.kind, guid: part.guid, len: part.len }) .collect(); let total_size = disk_bytes(rows.iter().map(|row| row.len)); let mut disk = vec![0u8; total_size as usize]; - let (mut disk_device, starts) = lay(Box::new(Cursor::new(&mut disk)), total_size, &rows); - - disk_device.seek(std::io::SeekFrom::Start(0)).expect("failed to seek"); - let mut final_bytes = vec![0u8; total_size as usize]; - disk_device.read_exact(&mut final_bytes).expect("failed to read disk"); - + let starts = lay(&mut Cursor::new(&mut disk), total_size, &rows); for (part, start) in parts.iter().zip(&starts) { let start = *start as usize; - final_bytes[start..start + part.bytes.len()].copy_from_slice(&part.bytes); + disk[start..start + part.bytes.len()].copy_from_slice(&part.bytes); } - let judged: Vec<(&str, toyos_gpt::Guid, Volume)> = parts - .iter() - .filter_map(|part| part.judge.map(|kind| (part.what, toyos_gpt::Guid(part.guid.to_bytes_le()), kind))) - .collect(); - certify(&final_bytes, &judged).unwrap_or_else(|refusal| panic!("{refusal}")); - - final_bytes + let judged: Vec<(&str, Guid, Volume)> = + parts.iter().filter_map(|part| part.judge.map(|kind| (part.what, part.guid, kind))).collect(); + certify(&disk, &judged).unwrap_or_else(|refusal| panic!("{refusal}")); + disk } /// A disk image as logical blocks, so a GPT parser can read it without a file. -struct ImageSectors<'a>(&'a [u8]); +pub(crate) struct ImageSectors<'a>(pub(crate) &'a [u8]); impl toyos_gpt::Sectors for ImageSectors<'_> { fn lba_bytes(&self) -> u32 { @@ -1099,7 +1012,7 @@ mod tests { let key = key(); let s = sections(b"kernel", &tiny_root(), "", signing(&key)); for (what, volume) in [ - ("ESP", create_esp_volume(Arch::X86_64, b"bootloader", uuid::Uuid::new_v4())), + ("ESP", create_esp_volume(Arch::X86_64, b"bootloader", new_guid())), ("slot volume", create_slot_volume(Some(&s), FAT32_MIN_BYTES)), ("empty slot volume", create_slot_volume(None, FAT32_MIN_BYTES)), ("log volume", create_log_volume()), @@ -1186,7 +1099,7 @@ mod tests { #[test] fn the_esp_and_a_slot_carry_what_the_bootloader_looks_for() { assert_eq!( - files_of(create_esp_volume(Arch::X86_64, b"bootloader", uuid::Uuid::new_v4())), + files_of(create_esp_volume(Arch::X86_64, b"bootloader", new_guid())), ["EFI/BOOT/BOOTx64.EFI", "toyos/log.guid"] ); let key = key(); @@ -1243,9 +1156,13 @@ mod tests { assert_eq!(parts.signed, &signed); } - /// Every partition of `image` is on `disk` under its GUID with its bytes, - /// found by the reader the kernel and `diskserver` use. - fn carries_every_partition_of(disk: &mut std::fs::File, image: &[u8]) { + /// Every partition of `image` is on `disk` under its GUID, its name and with + /// its bytes, found by the reader the kernel and `diskserver` use: the + /// names, in the image's order. + fn carries_every_partition_of(disk: &mut std::fs::File, image: &[u8]) -> Vec { + let mut table = vec![0u8; 34 * LBA as usize]; + disk.seek(SeekFrom::Start(0)).and_then(|_| disk.read_exact(&mut table)).expect("the disk's table"); + let mut names = Vec::new(); let mut listed = [None; 16]; toyos_gpt::list(&mut ImageSectors(image), &mut listed).expect("the image's table"); let parts: Vec = listed.iter().flatten().map(|entry| entry.expect("a placed entry")).collect(); @@ -1261,7 +1178,10 @@ mod tests { .and_then(|_| disk.read_exact(&mut installed)) .expect("read it back"); assert!(installed == image[at..at + len], "{} was installed as other bytes", part.unique_guid()); + assert_eq!(name_of(&table, on_disk.index()), name_of(image, part.index()), "{}", part.unique_guid()); + names.push(name_of(image, part.index())); } + names } /// An install puts a designated DATA first and the image after it, on a @@ -1277,7 +1197,10 @@ mod tests { install(&image, &path, DATA); let mut disk = std::fs::File::open(&path).expect("open the disk"); - carries_every_partition_of(&mut disk, &image); + assert_eq!( + carries_every_partition_of(&mut disk, &image), + ["EFI System", "ToyOS slots", "ToyOS log", "ToyOS slot A", "ToyOS root A"] + ); let data = only_partition(&mut FileSectors(&mut disk), toyos_gpt::Guid::TOYOS_DATA).expect("one DATA partition"); assert_eq!( (data.first_lba() * u64::from(LBA), data.lba_count().get() * u64::from(LBA)), @@ -1349,7 +1272,7 @@ mod tests { /// **The independent oracle for ROOT**, asked of the finished image by /// readers that did not write it: `toyos-gpt` finds the partition by type - /// where the `gpt` crate placed it, `bcachefs`'s mount-and-read path lists + /// where the table placed it, `bcachefs`'s mount-and-read path lists /// what its format-and-write path put there, and `toyos-fat32` reads the /// boot parameter off the ESP. /// diff --git a/src/lib.rs b/src/lib.rs index 7a2adcff8bc..66c74b7592b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod fatformat; pub mod firmware; #[cfg(test)] pub mod gitfixture; +pub mod gptwrite; pub mod flags; pub mod hostws; pub mod identity; diff --git a/src/metal.rs b/src/metal.rs index c2abba366bf..c27fecd8916 100644 --- a/src/metal.rs +++ b/src/metal.rs @@ -2681,38 +2681,27 @@ mod tests { /// A disk carrying `parts` in order, so `admit`'s refusals are exercised on /// tables rather than on prose about tables. - fn disk(parts: &[(&str, &gpt::partition_types::Type)]) -> Vec { - use std::io::Cursor; - const TOTAL: usize = 16 * 1024 * 1024; - let mut bytes = vec![0u8; TOTAL]; - let mut cursor = Cursor::new(&mut bytes); - gpt::mbr::ProtectiveMBR::with_lb_size((TOTAL / 512 - 1) as u32) - .overwrite_lba0(&mut cursor) - .expect("the protective MBR"); - let mut gdisk = gpt::GptConfig::default() - .initialized(false) - .writable(true) - .logical_block_size(gpt::disk::LogicalBlockSize::Lb512) - .create_from_device(Box::new(cursor), None) - .expect("a table"); - gdisk.update_partitions(std::collections::BTreeMap::new()).expect("an empty table"); - for (name, kind) in parts { - gdisk - .add_partition(name, 256 * 1024, (*kind).clone(), 0, Some(2048)) - .expect("a partition"); - } - let mut device = gdisk.write().expect("the table"); - device.seek(SeekFrom::Start(0)).expect("rewind"); - let mut out = vec![0u8; TOTAL]; - device.read_exact(&mut out).expect("read back"); + fn disk(parts: &[(&str, toyos_gpt::Guid)]) -> Vec { + const TOTAL: u64 = 16 * 1024 * 1024; + const ALIGN: u64 = 2048; + let entries: Vec> = (1..) + .zip(parts) + .map(|(i, (name, kind))| crate::gptwrite::Entry { + kind: *kind, + unique: toyos_gpt::Guid(uuid::Uuid::new_v4().to_bytes_le()), + first_lba: i * ALIGN, + last_lba: i * ALIGN + 511, + name, + }) + .collect(); + let table = crate::gptwrite::table(TOTAL / u64::from(LBA), toyos_gpt::Guid(uuid::Uuid::new_v4().to_bytes_le()), &entries); + let mut out = vec![0u8; TOTAL as usize]; + out[..table.primary.len()].copy_from_slice(&table.primary); + let back = out.len() - table.backup.len(); + out[back..].copy_from_slice(&table.backup); out } - const TOYOS_ROOT: gpt::partition_types::Type = gpt::partition_types::Type { - guid: toyos_gpt::Guid::TOYOS_ROOT_TEXT, - os: gpt::partition_types::OperatingSystem::None, - }; - #[test] fn an_image_admits_only_the_table_the_installed_rule_names() { let dir = toyos_tmpdir::TempDir::new("metal"); @@ -2722,8 +2711,7 @@ mod tests { std::fs::write(&at, bytes).expect("write"); at }; - let esp = gpt::partition_types::EFI; - let basic = gpt::partition_types::BASIC; + let (esp, basic, root) = (toyos_gpt::Guid::EFI_SYSTEM, toyos_gpt::Guid::MICROSOFT_BASIC, toyos_gpt::Guid::TOYOS_ROOT); assert_eq!( admit(&write("ragged.img", &vec![0u8; 1000]), &t), @@ -2743,24 +2731,24 @@ mod tests { Err(Refusal::BackupHeader { .. }) )); - let two = disk(&[("a", &esp), ("b", &esp), ("log", &basic), ("root", &TOYOS_ROOT)]); + let two = disk(&[("a", esp), ("b", esp), ("log", basic), ("root", root)]); assert_eq!( admit(&write("two-esps.img", &two), &t), Err(Refusal::Partitions { what: "ESP", matched: 2 }) ); - let no_log = disk(&[("esp", &esp), ("root", &TOYOS_ROOT)]); + let no_log = disk(&[("esp", esp), ("root", root)]); assert_eq!( admit(&write("no-log.img", &no_log), &t), Err(Refusal::Partitions { what: "TOYOS-LOG", matched: 0 }) ); // The log where the installed rule does not name it: p2, not p3. - let moved = disk(&[("esp", &esp), ("log", &basic), ("root", &TOYOS_ROOT)]); + let moved = disk(&[("esp", esp), ("log", basic), ("root", root)]); assert_eq!( admit(&write("moved-log.img", &moved), &t), Err(Refusal::PartitionIndex { what: "TOYOS-LOG", want: 3, got: 2 }) ); // And the shape `src/image.rs` writes, which is the one admitted. - let built = disk(&[("esp", &esp), ("root", &TOYOS_ROOT), ("log", &basic)]); + let built = disk(&[("esp", esp), ("root", root), ("log", basic)]); let ok = admit(&write("built.img", &built), &t).expect("the built shape is admitted"); assert_eq!((ok.esp.index, ok.log.index), (1, 3)); assert_eq!(ok.bytes % u64::from(LBA), 0); diff --git a/toyos-gpt/src/guid.rs b/toyos-gpt/src/guid.rs index 0564ef80de6..dec1c9895e3 100644 --- a/toyos-gpt/src/guid.rs +++ b/toyos-gpt/src/guid.rs @@ -49,11 +49,6 @@ impl Guid { [0x95, 0x89, 0xA5, 0xC3, 0xCF, 0xD5, 0x55, 0xFD], ); - /// [`Guid::TOYOS_ROOT`]'s canonical text, for a host partition-table writer - /// that names a type by string. `toyos_root_text_is_the_type_guid` is what - /// holds the two spellings together. - pub const TOYOS_ROOT_TEXT: &'static str = "B350BC93-BB6A-4C5E-9589-A5C3CFD555FD"; - /// `064E3777-5076-4C71-8E07-90AD24CFE8D6` — the TOYOS-DATA partition type, /// the writable volume `/apps` and `/home` are two paths into. pub const TOYOS_DATA: Self = Self::from_fields( @@ -63,8 +58,6 @@ impl Guid { [0x8E, 0x07, 0x90, 0xAD, 0x24, 0xCF, 0xE8, 0xD6], ); - pub const TOYOS_DATA_TEXT: &'static str = "064E3777-5076-4C71-8E07-90AD24CFE8D6"; - /// `94464329-E06E-4288-A9DA-7FC7154F5E92` — the slot table's partition /// type: which partitions make each slot, and which slot is marked /// (`toyos_update::slots`). A disk carries one. @@ -75,8 +68,6 @@ impl Guid { [0xA9, 0xDA, 0x7F, 0xC7, 0x15, 0x4F, 0x5E, 0x92], ); - pub const TOYOS_SLOTS_TEXT: &'static str = "94464329-E06E-4288-A9DA-7FC7154F5E92"; - /// `037719D7-DEA5-481A-AA07-6AF8BE6D51E2` — a slot's FAT partition: its /// kernel, its boot parameter and its signed header. A *type*, so it /// selects nothing; the slot table names each one by its unique GUID. @@ -87,8 +78,6 @@ impl Guid { [0xAA, 0x07, 0x6A, 0xF8, 0xBE, 0x6D, 0x51, 0xE2], ); - pub const TOYOS_BOOT_TEXT: &'static str = "037719D7-DEA5-481A-AA07-6AF8BE6D51E2"; - pub const fn from_fields(a: u32, b: u16, c: u16, d: [u8; 8]) -> Self { let a = a.to_le_bytes(); let b = b.to_le_bytes(); @@ -142,21 +131,6 @@ mod tests { assert_eq!(&text[..], b"C12A7328-F81F-11D2-BA4B-00A0C93EC93B"); } - /// The host writes the partition table by naming the type in text and the - /// kernel matches it as bytes; nothing else compares the two spellings. - #[test] - fn toyos_root_text_is_the_type_guid() { - let text = heapless_format(Guid::TOYOS_ROOT); - assert_eq!(&text[..], Guid::TOYOS_ROOT_TEXT.as_bytes()); - let text = heapless_format(Guid::TOYOS_DATA); - assert_eq!(&text[..], Guid::TOYOS_DATA_TEXT.as_bytes()); - let text = heapless_format(Guid::TOYOS_SLOTS); - assert_eq!(&text[..], Guid::TOYOS_SLOTS_TEXT.as_bytes()); - let text = heapless_format(Guid::TOYOS_BOOT); - assert_eq!(&text[..], Guid::TOYOS_BOOT_TEXT.as_bytes()); - assert_ne!(Guid::TOYOS_ROOT, Guid::TOYOS_DATA); - } - #[test] fn zero_is_zero() { assert!(Guid::ZERO.is_zero()); From d82fef92a46ad713953ea6dbbdb186a35bed1e80 Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 18:10:18 +0200 Subject: [PATCH 07/22] A partition table's GUIDs are sixteen bytes from getrandom, and `uuid` leaves the build The build drew every disk and partition GUID with `uuid::Uuid::new_v4` and converted it to the on-disk order. `gptwrite::random_guid` draws the sixteen bytes from the `getrandom` the build already takes for a throwaway key's seed, already in the on-disk order, and sets RFC 9562's version 4 in the high nibble of byte 7 (the third field is little-endian there) and the variant in the top two bits of byte 8. `a_random_guid_is_version_4_of_the_rfc_variant` reads both where the canonical text shows them; with the version set in byte 6 it reds, three runs of three (a mutant drawing a 4 there by chance passes one run in 16). `uuid` stays in the root Cargo.lock only through the `gpt` crate, the dev-dependency oracle. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.lock | 1 - Cargo.toml | 4 ++-- src/gptwrite.rs | 23 +++++++++++++++++++++-- src/image.rs | 21 ++++++++------------- src/metal.rs | 4 ++-- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf0fe79ccb8..e2405e52544 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4664,7 +4664,6 @@ dependencies = [ "toyos-wallclock", "toyos-xhci", "ureq", - "uuid", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e2786e099a5..a750ed442e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -158,7 +158,6 @@ default-run = "toyos-build" fontdue = "0.9" libc = "0.2" toml = "0.8" -uuid = { version = "1", features = ["v4"] } serde = { version = "1", features = ["derive"] } serde_json = "1" bcachefs = { path = "bcachefs" } @@ -195,7 +194,8 @@ toyos-blackbox = { path = "toyos-blackbox" } # The signed image, the slot table and the signer: `src/signing.rs` signs with # the same crate the loader and `/system/bin/update` verify with. toyos-update = { path = "toyos-update", features = ["sign"] } -# A throwaway key's seed, from the operating system. Already resolved here. +# A throwaway key's seed and every GUID a partition table names, from the +# operating system. getrandom = "0.3" # `classify`, so the host reading a log volume and `logkeeper` writing it cannot # disagree about which files on it are `logkeeper`'s. diff --git a/src/gptwrite.rs b/src/gptwrite.rs index 8294a8af2e0..6f2e5e44f46 100644 --- a/src/gptwrite.rs +++ b/src/gptwrite.rs @@ -105,6 +105,17 @@ fn protective_mbr(lbas: u64) -> Vec { block } +/// A version 4 GUID from the operating system's random source, in the +/// on-disk order: the version is the high nibble of byte 7, the third field +/// being little-endian, and the variant the top two bits of byte 8. +pub(crate) fn random_guid() -> Guid { + let mut bytes = [0u8; 16]; + getrandom::fill(&mut bytes).expect("the operating system's random source"); + bytes[7] = (bytes[7] & 0x0F) | 0x40; + bytes[8] = (bytes[8] & 0x3F) | 0x80; + Guid(bytes) +} + #[cfg(test)] mod tests { use super::*; @@ -192,15 +203,23 @@ mod tests { } } + /// RFC 9562's version and variant, where the canonical text shows them. + #[test] + fn a_random_guid_is_version_4_of_the_rfc_variant() { + let text = random_guid().to_string(); + assert_eq!(&text[14..15], "4", "{text}"); + assert!(matches!(&text[19..20], "8" | "9" | "A" | "B"), "{text}"); + } + /// `toyos-gpt`, the parser the loader and the kernel read with, finds /// every partition at its blocks under its type, from the primary and, /// with the primary torn, from the backup. #[test] fn toyos_gpt_reads_it_from_either_copy() { let total: u64 = 128 << 20; - let uniques: Vec = ROWS.iter().map(|_| Guid(uuid::Uuid::new_v4().to_bytes_le())).collect(); + let uniques: Vec = ROWS.iter().map(|_| random_guid()).collect(); let entries = entries(&uniques); - let disk = disk_of(total, &table(total / LBA, Guid(uuid::Uuid::new_v4().to_bytes_le()), &entries)); + let disk = disk_of(total, &table(total / LBA, random_guid(), &entries)); let mut torn = disk.clone(); torn[LBA as usize + 30] ^= 1; for image in [&disk, &torn] { diff --git a/src/image.rs b/src/image.rs index 0573d27eb32..1ad2492c486 100644 --- a/src/image.rs +++ b/src/image.rs @@ -237,9 +237,9 @@ pub fn create_boot_image( // kernel. The kernel is given the partition by name; nothing anywhere goes // looking for one by type or by format. Every slot partition is named the // same way, by the slot table. - let (log_guid, esp_guid, table_guid) = (new_guid(), new_guid(), new_guid()); - let a = (new_guid(), new_guid()); - let b = second.map(|room| (new_guid(), new_guid(), room)); + let (log_guid, esp_guid, table_guid) = (crate::gptwrite::random_guid(), crate::gptwrite::random_guid(), crate::gptwrite::random_guid()); + let a = (crate::gptwrite::random_guid(), crate::gptwrite::random_guid()); + let b = second.map(|room| (crate::gptwrite::random_guid(), crate::gptwrite::random_guid(), room)); let s = sections(kernel_bytes, root_bytes, params, signing); // Room for a kernel twice this one's size beside it, so an update can @@ -641,11 +641,6 @@ fn create_log_volume() -> Vec { volume } -/// A partition's or a disk's GUID, drawn once. -fn new_guid() -> Guid { - Guid(uuid::Uuid::new_v4().to_bytes_le()) -} - /// Lay a table on the disk at `path`, already `len` bytes long, carrying one /// TOYOS-DATA partition, stamp the designation at its first block, and answer /// where it landed. The table and the stamp are all this writes, so a sparse @@ -664,7 +659,7 @@ pub fn designate_data_disk(path: &Path, len: u64) -> (u64, u64) { .write(true) .open(path) .unwrap_or_else(|e| panic!("open {} to partition it: {e}", path.display())); - let starts = lay(&mut file, len, &[data_row(new_guid(), data_bytes)]); + let starts = lay(&mut file, len, &[data_row(crate::gptwrite::random_guid(), data_bytes)]); write_at(&mut file, starts[0], &designation(data_bytes / SECTOR as u64), "DATA partition's designation"); (starts[0], data_bytes) } @@ -713,7 +708,7 @@ pub fn install(image: &[u8], disk: &Path, data_bytes: u64) { .collect(); let (mut rows, volumes): (Vec, Vec<&[u8]>) = carried.into_iter().unzip(); - rows.insert(0, data_row(new_guid(), data_bytes)); + rows.insert(0, data_row(crate::gptwrite::random_guid(), data_bytes)); let total = disk_bytes(rows.iter().map(|row| row.len)); let mut file = std::fs::OpenOptions::new() @@ -845,7 +840,7 @@ fn lay(disk: &mut (impl Write + Seek), total: u64, rows: &[Row]) -> Vec { name: &row.name, }) .collect(); - let table = crate::gptwrite::table(total / lba, new_guid(), &entries); + let table = crate::gptwrite::table(total / lba, crate::gptwrite::random_guid(), &entries); write_at(disk, 0, &table.primary, "partition table"); write_at(disk, total - table.backup.len() as u64, &table.backup, "backup partition table"); starts @@ -1012,7 +1007,7 @@ mod tests { let key = key(); let s = sections(b"kernel", &tiny_root(), "", signing(&key)); for (what, volume) in [ - ("ESP", create_esp_volume(Arch::X86_64, b"bootloader", new_guid())), + ("ESP", create_esp_volume(Arch::X86_64, b"bootloader", crate::gptwrite::random_guid())), ("slot volume", create_slot_volume(Some(&s), FAT32_MIN_BYTES)), ("empty slot volume", create_slot_volume(None, FAT32_MIN_BYTES)), ("log volume", create_log_volume()), @@ -1099,7 +1094,7 @@ mod tests { #[test] fn the_esp_and_a_slot_carry_what_the_bootloader_looks_for() { assert_eq!( - files_of(create_esp_volume(Arch::X86_64, b"bootloader", new_guid())), + files_of(create_esp_volume(Arch::X86_64, b"bootloader", crate::gptwrite::random_guid())), ["EFI/BOOT/BOOTx64.EFI", "toyos/log.guid"] ); let key = key(); diff --git a/src/metal.rs b/src/metal.rs index c27fecd8916..3d4af51a98d 100644 --- a/src/metal.rs +++ b/src/metal.rs @@ -2688,13 +2688,13 @@ mod tests { .zip(parts) .map(|(i, (name, kind))| crate::gptwrite::Entry { kind: *kind, - unique: toyos_gpt::Guid(uuid::Uuid::new_v4().to_bytes_le()), + unique: crate::gptwrite::random_guid(), first_lba: i * ALIGN, last_lba: i * ALIGN + 511, name, }) .collect(); - let table = crate::gptwrite::table(TOTAL / u64::from(LBA), toyos_gpt::Guid(uuid::Uuid::new_v4().to_bytes_le()), &entries); + let table = crate::gptwrite::table(TOTAL / u64::from(LBA), crate::gptwrite::random_guid(), &entries); let mut out = vec![0u8; TOTAL as usize]; out[..table.primary.len()].copy_from_slice(&table.primary); let back = out.len() - table.backup.len(); From a0e5b76bab9d0ea010e14187ba57b310d38b418a Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 18:15:53 +0200 Subject: [PATCH 08/22] The desktop's eight icons are drawn at build time, and resvg leaves the image The compositor and files rasterized eight committed Phosphor SVGs at start through resvg, usvg and tiny-skia: 33 third-party crates in each program, inside the server that owns the framebuffer, for icons that never change and are drawn at three fixed sizes (cursors 20, title-bar buttons 14, files' entries 32). Nothing in the tree draws at another scale: the compositor has no scale factor. So the build draws them, as it already draws the console font: src/icons.rs reads the SVG subset the icons are written in, refuses anything past it by name, and ships each as share/icons/.alpha, a coverage mask the program colours. No shipped program carries a rasterizer; userland/sprite keeps only the mask loader and the blit, and the programs lay out by the size the mask carries, so the size is declared once, beside the icon. The owner forbids a visible change, so the rasterizer reproduces resvg's pixels rather than better ones: tiny-skia's 4x4 point samples worth 16 each (63 on a pixel's last sample row), kurbo's arc-to-cubic split at usvg's 0.1 tolerance, tiny-skia's chord counts for a cubic edge and for the quads its stroker approximates an offset curve with, and source-over between shapes. Exact-area coverage was measured first and differed from resvg by up to 45/255 on 597 of 3836 pixels, all of it resvg's coarser sampling; with the emulation 35 pixels differ by one sample (16/255) and the rest are equal. A one-off differential against resvg 0.47, outside the tree, gives the numbers; the host test pins the digest of the pixels it compared. The SVGs no longer ship. Removed from the root lock: 22 packages; from the compositor and files: all 33 third-party crates each. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.lock | 217 +---- NOTICE | 3 +- ...ystem-font-by-a-path-only-this-tree-has.md | 7 +- src/assets.rs | 14 +- src/icons.rs | 819 ++++++++++++++++++ src/lib.rs | 1 + userland/compositor/src/main.rs | 4 - userland/compositor/src/session.rs | 46 +- userland/files/src/main.rs | 19 +- userland/sprite/Cargo.toml | 5 +- userland/sprite/README.md | 5 - userland/sprite/src/lib.rs | 41 +- 12 files changed, 880 insertions(+), 301 deletions(-) create mode 100644 src/icons.rs delete mode 100644 userland/sprite/README.md diff --git a/Cargo.lock b/Cargo.lock index 75516233810..a8a29ad8676 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,12 +206,6 @@ dependencies = [ "password-hash", ] -[[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.8" @@ -242,12 +236,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "base64" version = "0.23.1" @@ -987,12 +975,6 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" -[[package]] -name = "data-url" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" - [[package]] name = "defmt" version = "0.3.100" @@ -1364,15 +1346,6 @@ dependencies = [ "arrayvec", ] -[[package]] -name = "euclid" -version = "0.22.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63" -dependencies = [ - "num-traits", -] - [[package]] name = "faster-hex" version = "0.10.1" @@ -1403,15 +1376,6 @@ dependencies = [ "log", ] -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - [[package]] name = "ff" version = "0.13.1" @@ -1497,16 +1461,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" dependencies = [ "crc32fast", - "miniz_oxide 0.9.1", + "miniz_oxide", "zlib-rs", ] -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" - [[package]] name = "fnv" version = "1.0.7" @@ -2771,12 +2729,6 @@ dependencies = [ "zune-jpeg", ] -[[package]] -name = "imagesize" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" - [[package]] name = "indexmap" version = "2.13.0" @@ -3086,17 +3038,6 @@ dependencies = [ "toyos-abi", ] -[[package]] -name = "kurbo" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7564e90fe3c0d5771e1f0bc95322b21baaeaa0d9213fa6a0b61c99f8b17b3bfb" -dependencies = [ - "arrayvec", - "euclid", - "smallvec", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -3256,16 +3197,6 @@ dependencies = [ "toyos-tco", ] -[[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 = "miniz_oxide" version = "0.9.1" @@ -4031,12 +3962,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - [[package]] name = "pin-project" version = "1.1.11" @@ -4156,19 +4081,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -[[package]] -name = "png" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" -dependencies = [ - "bitflags 2.11.0", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide 0.8.9", -] - [[package]] name = "polling" version = "3.11.0" @@ -4513,20 +4425,6 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" -[[package]] -name = "resvg" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be183ad6a216aa96f33e4c8033b0988b8b3ea6fd2359d19af5bac4643fd8e81" -dependencies = [ - "log", - "pico-args", - "rgb", - "svgtypes", - "tiny-skia", - "usvg", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -4547,15 +4445,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "rgb" -version = "0.8.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" -dependencies = [ - "bytemuck", -] - [[package]] name = "ring" version = "0.17.14" @@ -4570,15 +4459,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "roxmltree" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" -dependencies = [ - "memchr", -] - [[package]] name = "rsa" version = "0.9.10" @@ -5154,21 +5034,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" -[[package]] -name = "simplecss" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" -dependencies = [ - "log", -] - -[[package]] -name = "siphasher" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" - [[package]] name = "slab" version = "0.4.12" @@ -5320,9 +5185,6 @@ dependencies = [ [[package]] name = "sprite" version = "0.1.0" -dependencies = [ - "resvg", -] [[package]] name = "ssh-cipher" @@ -5375,15 +5237,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" -[[package]] -name = "strict-num" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" -dependencies = [ - "float-cmp", -] - [[package]] name = "subtle" version = "2.6.1" @@ -5407,16 +5260,6 @@ dependencies = [ "toyos-wallclock", ] -[[package]] -name = "svgtypes" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d" -dependencies = [ - "kurbo", - "siphasher", -] - [[package]] name = "swap" version = "0.1.0" @@ -5556,32 +5399,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "tiny-skia" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea" -dependencies = [ - "arrayref", - "arrayvec", - "bytemuck", - "cfg-if", - "log", - "png", - "tiny-skia-path", -] - -[[package]] -name = "tiny-skia-path" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" -dependencies = [ - "arrayref", - "bytemuck", - "strict-num", -] - [[package]] name = "tinyvec" version = "1.13.3" @@ -6352,7 +6169,7 @@ version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a7ac20be9b7726e0bbdbf974c059676d9acb1cd414961f570a4e8231cacd7fc" dependencies = [ - "base64 0.23.1", + "base64", "log", "percent-encoding", "rustls", @@ -6368,34 +6185,12 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86fd172ccca569e458f61b6bdd6220965a9ef36e672a6852953b51a0e1583be" dependencies = [ - "base64 0.23.1", + "base64", "http", "httparse", "log", ] -[[package]] -name = "usvg" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d46cf96c5f498d36b7a9693bc6a7075c0bb9303189d61b2249b0dc3d309c07de" -dependencies = [ - "base64 0.22.1", - "data-url", - "flate2", - "imagesize", - "kurbo", - "log", - "pico-args", - "roxmltree", - "simplecss", - "siphasher", - "strict-num", - "svgtypes", - "tiny-skia-path", - "xmlwriter", -] - [[package]] name = "utf8-zero" version = "0.8.1" @@ -7147,12 +6942,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" -[[package]] -name = "xmlwriter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" - [[package]] name = "zerocopy" version = "0.8.47" diff --git a/NOTICE b/NOTICE index 224294bec76..a07379a5b89 100644 --- a/NOTICE +++ b/NOTICE @@ -185,7 +185,8 @@ would have arrived unremarked. `assets/` is walked whole for that reason. MIT requires the notice to be included in copies. Before this file the only copy of it in reach was a `phosphor-icons/` directory on one developer's disk, which `.gitignore` line 7 keeps out of the repository. They ship as -`share/icons/*.svg` on every ROOT that carries `assets/`. +`share/icons/*.alpha`, drawn from them at build time by `src/icons.rs`, on +every ROOT that carries `assets/`. assets/fonts/OpenSans-*.ttf — Open Sans, SIL Open Font License 1.1 diff --git a/issues/five-apps-read-the-system-font-by-a-path-only-this-tree-has.md b/issues/five-apps-read-the-system-font-by-a-path-only-this-tree-has.md index 3d790b4ead6..e9d3418eb83 100644 --- a/issues/five-apps-read-the-system-font-by-a-path-only-this-tree-has.md +++ b/issues/five-apps-read-the-system-font-by-a-path-only-this-tree-has.md @@ -12,10 +12,11 @@ ToyOS (root `CLAUDE.md`), and stage 7 of builds each one outside this repository against published SDK crates alone. Five of the six apps cannot, because of how they find JetBrains Mono: -- `editor` (`src/main.rs:1444`), `files` (`:60`) and `paint` (`:173`) read +- `editor` (`src/main.rs:1444`), `files` (`:59`) and `paint` (`:173`) read `/system/share/fonts/JetBrainsMono-Regular-8x16.font` and `expect` it, so on - a host they build and then panic at start; `files` reads - `/system/share/icons/*.svg` the same way (`:63-64`). + a host they build and then panic at start; `files` reads the icons the build + draws, `/system/share/icons/*.alpha`, the same way (`:62-63`, through + `userland/sprite`). - `calc` (`build.rs:32`) and `snake` (`build.rs:7`) read `../../assets/JetBrainsMono-Regular.ttf` in their build scripts, a path into this tree. diff --git a/src/assets.rs b/src/assets.rs index 55f3fb77201..8864eacbb86 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -334,6 +334,12 @@ pub fn collect(dirs: &[String], programs: &BTreeSet<&str>) -> Vec<(String, Vec = collect(&[dir.display().to_string()], &BTreeSet::new()) .into_iter() @@ -416,7 +422,7 @@ mod tests { shipped, BTreeSet::from([ "share/kept.wad".to_string(), - "share/icons/kept.svg".to_string(), + "share/icons/kept.png".to_string(), "share/music.sf2".to_string(), ]), "ROOT's asset list is not what the repository says it is" @@ -437,7 +443,7 @@ mod tests { without, BTreeSet::from([ "share/kept.wad".to_string(), - "share/icons/kept.svg".to_string(), + "share/icons/kept.png".to_string(), ]), "a committed asset that is not there took something else with it" ); diff --git a/src/icons.rs b/src/icons.rs new file mode 100644 index 00000000000..6c2f2bb7070 --- /dev/null +++ b/src/icons.rs @@ -0,0 +1,819 @@ +//! The desktop's icons, drawn at build time: every `icons/.svg` an image +//! carries ships as `share/icons/.alpha`, its coverage at the one size +//! [`SIZES`] gives it, and the program that draws it only colours that mask — +//! no program carries a rasterizer, and none needs one while no icon is drawn +//! at a size the build did not know. +//! +//! An `.alpha` file is the width and height as little-endian `u32`, then one +//! byte of coverage per pixel, row by row. +//! +//! The SVG is read as the subset the icons are written in, and anything past it +//! is refused by name: a root `svg` with a square `viewBox`, then `path`, +//! `line`, `circle` and `rect`, each painted `currentColor` or `none`. A literal +//! colour is refused because the mask cannot carry it; an attribute this does +//! not read is refused because it would ship drawn without it. A stroke must be +//! round-capped and round-joined, which makes it exactly the points within half +//! its width of its path, the region drawn here. +//! +//! The pixels are the ones resvg drew these icons with before the build drew +//! them, because the desktop's look is not this file's to change: a pixel +//! samples four rows of four points, a sample worth 16 of 255; a fill is +//! nonzero, its arcs become cubics as `kurbo` splits them and each cubic, cut +//! where it turns in y, becomes `2^shift` chords by tiny-skia's count; and each +//! shape is laid over the ones before it. + +/// Each icon and the edge, in pixels, it is drawn at: the compositor's cursors +/// at 20, its title-bar buttons at 14, and `files`' entries at 32. +const SIZES: &[(&str, u32)] = &[ + ("cursor-bold", 20), + ("arrow-down-right-bold", 20), + ("crosshair-simple-bold", 20), + ("minus-bold", 14), + ("square-bold", 14), + ("x-bold", 14), + ("folder-bold", 32), + ("file-bold", 32), +]; + +/// Sample points per pixel along each axis. +const GRID: usize = 4; + +type Point = (f64, f64); + +/// The `.alpha` file the icon `stem` ships as. +pub fn rasterize(stem: &str, svg: &[u8]) -> Vec { + let size = SIZES + .iter() + .find(|(name, _)| *name == stem) + .unwrap_or_else(|| panic!("icons/{stem}.svg has no size in src/icons.rs's SIZES")) + .1; + let svg = std::str::from_utf8(svg).unwrap_or_else(|e| panic!("icons/{stem}.svg: {e}")); + let mut out = Vec::with_capacity(8 + (size * size) as usize); + out.extend(size.to_le_bytes()); + out.extend(size.to_le_bytes()); + out.extend(coverage(&Icon::parse(svg), size as usize)); + out +} + +/// A subpath: its start, then one cubic per segment, a line as the cubic +/// that runs along it. +#[derive(Clone)] +struct Subpath { + start: Point, + cubics: Vec<[Point; 3]>, + closed: bool, +} + +struct Shape { + subpaths: Vec, + fill: bool, + /// Half the stroke's width; `None` where it is not stroked. + stroke: Option, +} + +struct Icon { + /// The `viewBox`'s origin and edge, in user units. + origin: Point, + edge: f64, + shapes: Vec, +} + +impl Icon { + fn parse(svg: &str) -> Icon { + let mut tags = Tags { rest: svg.trim() }; + let (name, attrs, open) = tags.next().expect("an empty SVG"); + assert!(name == "svg" && open, "the root element is <{name}>, not an open "); + let mut root_fill = None; + let mut view_box = None; + for (key, value) in attrs { + match key { + "xmlns" => assert_eq!(value, "http://www.w3.org/2000/svg", "xmlns"), + "viewBox" => view_box = Some(numbers(value)), + "fill" => root_fill = Some(paint(value)), + _ => panic!(" is not read"), + } + } + let view_box = view_box.expect("an with no viewBox"); + let [x, y, w, h] = view_box[..] else { panic!("viewBox {view_box:?} is not four numbers") }; + assert!(w == h && w > 0.0, "viewBox {view_box:?} is not square"); + + let mut shapes = vec![]; + loop { + let (name, attrs, open) = tags.next().expect("an that never closes"); + if name == "/svg" { + break; + } + assert!(!open, "<{name}> has children"); + shapes.push(Shape::parse(name, &attrs, root_fill)); + } + assert!(tags.rest.trim().is_empty(), "text after : {:?}", tags.rest); + Icon { origin: (x, y), edge: w, shapes } + } +} + +impl Shape { + fn parse(name: &str, attrs: &[(&str, &str)], root_fill: Option) -> Shape { + let mut fill = root_fill; + let mut stroke = false; + let mut width = 1.0; + let mut round = (false, false); + let mut path = Path::default(); + let num = |value: &str| -> f64 { value.parse().unwrap_or_else(|_| panic!("<{name}> {value:?} is not a number")) }; + let get = |key: &str| attrs.iter().find(|(k, _)| *k == key).map(|(_, v)| num(v)); + let geometry: &[&str] = match name { + "path" => { + let d = attrs.iter().find(|(k, _)| *k == "d").expect("a with no d").1; + path.data(d); + &["d"] + } + "line" => { + let at = |k| get(k).unwrap_or(0.0); + path.move_to((at("x1"), at("y1"))); + path.line_to((at("x2"), at("y2"))); + &["x1", "y1", "x2", "y2"] + } + "circle" => { + let (x, y, r) = (get("cx").unwrap_or(0.0), get("cy").unwrap_or(0.0), get("r").expect("r")); + path.move_to((x + r, y)); + for to in [(x, y + r), (x - r, y), (x, y - r), (x + r, y)] { + path.arc(r, r, 0.0, false, true, to); + } + path.close(); + &["cx", "cy", "r"] + } + "rect" => { + let (x, y) = (get("x").unwrap_or(0.0), get("y").unwrap_or(0.0)); + let (w, h) = (get("width").expect("width"), get("height").expect("height")); + let (rx, ry) = match (get("rx"), get("ry")) { + (None, None) => (0.0, 0.0), + (Some(r), None) | (None, Some(r)) => (r, r), + (Some(rx), Some(ry)) => (rx, ry), + }; + let (rx, ry) = (rx.min(w / 2.0), ry.min(h / 2.0)); + path.move_to((x + rx, y)); + path.line_to((x + w - rx, y)); + path.arc(rx, ry, 0.0, false, true, (x + w, y + ry)); + path.line_to((x + w, y + h - ry)); + path.arc(rx, ry, 0.0, false, true, (x + w - rx, y + h)); + path.line_to((x + rx, y + h)); + path.arc(rx, ry, 0.0, false, true, (x, y + h - ry)); + path.line_to((x, y + ry)); + path.arc(rx, ry, 0.0, false, true, (x + rx, y)); + path.close(); + &["x", "y", "width", "height", "rx", "ry"] + } + _ => panic!("<{name}> is not drawn"), + }; + for &(key, value) in attrs { + match key { + "fill" => fill = Some(paint(value)), + "stroke" => stroke = paint(value), + "stroke-width" => width = num(value), + "stroke-linecap" => round.0 = value == "round", + "stroke-linejoin" => round.1 = value == "round", + _ if geometry.contains(&key) => {} + _ => panic!("<{name} {key}> is not read"), + } + } + let fill = fill.unwrap_or_else(|| panic!("<{name}> fills black, a colour no mask carries")); + assert!(!stroke || round == (true, true), "<{name}> is stroked without round caps and joins"); + Shape { subpaths: path.finish(), fill, stroke: stroke.then_some(width / 2.0) } + } +} + +/// Whether a paint draws: `currentColor` does, `none` does not. +fn paint(value: &str) -> bool { + match value { + "currentColor" => true, + "none" => false, + _ => panic!("paint {value:?} is neither currentColor nor none"), + } +} + +fn numbers(value: &str) -> Vec { + let mut data = Data { rest: value.as_bytes() }; + std::iter::from_fn(|| data.number()).collect() +} + +/// An SVG's elements, each as its name, its attributes and whether it opens. +struct Tags<'a> { + rest: &'a str, +} + +impl<'a> Tags<'a> { + fn next(&mut self) -> Option<(&'a str, Vec<(&'a str, &'a str)>, bool)> { + self.rest = self.rest.trim_start(); + if self.rest.is_empty() { + return None; + } + let end = self.rest.find('>').unwrap_or_else(|| panic!("an unclosed tag: {:?}", self.rest)); + let tag = self.rest[..end].strip_prefix('<').unwrap_or_else(|| panic!("text where a tag goes: {:?}", self.rest)); + self.rest = &self.rest[end + 1..]; + let (tag, open) = match tag.strip_suffix('/') { + Some(tag) => (tag, false), + None => (tag, !tag.starts_with('/')), + }; + let tag = tag.trim(); + let (name, mut attrs) = tag.split_once(char::is_whitespace).unwrap_or((tag, "")); + let mut out = vec![]; + loop { + attrs = attrs.trim_start(); + if attrs.is_empty() { + break; + } + let (key, rest) = attrs.split_once("=\"").unwrap_or_else(|| panic!("<{name}>: {attrs:?}")); + let (value, rest) = rest.split_once('"').unwrap_or_else(|| panic!("<{name}>: {attrs:?}")); + out.push((key.trim(), value)); + attrs = rest; + } + Some((name, out, open)) + } +} + +/// Path data, read one number or command at a time. +struct Data<'a> { + rest: &'a [u8], +} + +impl Data<'_> { + fn skip(&mut self) { + while let [b' ' | b'\t' | b'\n' | b'\r' | b',', rest @ ..] = self.rest { + self.rest = rest; + } + } + + fn command(&mut self) -> Option { + self.skip(); + match self.rest { + [c, rest @ ..] if c.is_ascii_alphabetic() => { + self.rest = rest; + Some(*c) + } + _ => None, + } + } + + fn number(&mut self) -> Option { + self.skip(); + let mut end = 0; + let digits = |at: &mut usize, rest: &[u8]| { + while rest.get(*at).is_some_and(u8::is_ascii_digit) { + *at += 1; + } + }; + if matches!(self.rest.first(), Some(b'+' | b'-')) { + end += 1; + } + digits(&mut end, self.rest); + if self.rest.get(end) == Some(&b'.') { + end += 1; + digits(&mut end, self.rest); + } + if matches!(self.rest.get(end), Some(b'e' | b'E')) { + end += 1; + if matches!(self.rest.get(end), Some(b'+' | b'-')) { + end += 1; + } + digits(&mut end, self.rest); + } + if end == 0 { + return None; + } + let text = std::str::from_utf8(&self.rest[..end]).unwrap(); + self.rest = &self.rest[end..]; + Some(text.parse().unwrap_or_else(|_| panic!("{text:?} is not a number"))) + } + + fn flag(&mut self) -> bool { + self.skip(); + match self.rest { + [c @ (b'0' | b'1'), rest @ ..] => { + self.rest = rest; + *c == b'1' + } + _ => panic!("an arc flag that is not 0 or 1"), + } + } + + fn point(&mut self) -> Point { + let x = self.number().expect("a coordinate"); + (x, self.number().expect("a coordinate")) + } +} + +/// A shape's subpaths as they are read. +#[derive(Default)] +struct Path { + done: Vec, + open: Option, +} + +impl Path { + fn at(&self) -> Point { + let open = self.open.as_ref().expect("a drawing command before any moveto"); + open.cubics.last().map_or(open.start, |c| c[2]) + } + + /// Ends the current subpath; a lone moveto draws nothing. + fn end(&mut self, closed: bool) { + if let Some(open) = self.open.take().filter(|open| !open.cubics.is_empty()) { + self.done.push(Subpath { closed, ..open }); + } + } + + fn finish(mut self) -> Vec { + self.end(false); + self.done + } + + fn move_to(&mut self, p: Point) { + self.end(false); + self.open = Some(Subpath { start: p, cubics: vec![], closed: false }); + } + + fn cubic_to(&mut self, c1: Point, c2: Point, p: Point) { + self.at(); + self.open.as_mut().unwrap().cubics.push([c1, c2, p]); + } + + fn line_to(&mut self, p: Point) { + let a = self.at(); + let third = |t: f64| (a.0 + (p.0 - a.0) * t, a.1 + (p.1 - a.1) * t); + self.cubic_to(third(1.0 / 3.0), third(2.0 / 3.0), p); + } + + fn close(&mut self) { + let start = self.open.as_ref().expect("a closepath before any moveto").start; + self.end(true); + self.open = Some(Subpath { start, cubics: vec![], closed: false }); + } + + /// An elliptical arc: its centre by the SVG specification's conversion + /// (SVG 1.1, appendix F.6.5 and F.6.6), then the cubics `kurbo` splits it + /// into at the 0.1 user units usvg asks of it. + fn arc(&mut self, rx: f64, ry: f64, degrees: f64, large: bool, sweep: bool, p: Point) { + let p0 = self.at(); + let (mut rx, mut ry) = (rx.abs(), ry.abs()); + if p0 == p { + return; + } + if rx <= 1e-5 || ry <= 1e-5 { + return self.line_to(p); + } + let (sin, cos) = degrees.to_radians().sin_cos(); + let (hx, hy) = ((p0.0 - p.0) / 2.0, (p0.1 - p.1) / 2.0); + let (x1, y1) = (cos * hx + sin * hy, -sin * hx + cos * hy); + let lambda = (x1 * x1) / (rx * rx) + (y1 * y1) / (ry * ry); + if lambda > 1.0 { + rx *= lambda.sqrt(); + ry *= lambda.sqrt(); + } + let num = rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1; + let den = rx * rx * y1 * y1 + ry * ry * x1 * x1; + let k = (num / den).abs().sqrt() * if large == sweep { -1.0 } else { 1.0 }; + let (cx1, cy1) = (k * rx * y1 / ry, -k * ry * x1 / rx); + let centre = (cos * cx1 - sin * cy1 + (p0.0 + p.0) / 2.0, sin * cx1 + cos * cy1 + (p0.1 + p.1) / 2.0); + let start = ((y1 - cy1) / ry).atan2((x1 - cx1) / rx); + let tau = std::f64::consts::TAU; + let mut delta = (((-y1 - cy1) / ry).atan2((-x1 - cx1) / rx) - start) % tau; + if sweep && delta < 0.0 { + delta += tau; + } else if !sweep && delta > 0.0 { + delta -= tau; + } + + let n = ((1.1163 * rx.max(ry) / 0.1).powf(1.0 / 6.0).max(3.999_999) * delta.abs() / tau).ceil(); + let step = delta / n; + let arm = 4.0 / 3.0 * (step / 4.0).tan(); + let at = |angle: f64| { + let (s, c) = angle.sin_cos(); + (rx * cos * c - ry * sin * s, rx * sin * c + ry * cos * s) + }; + for i in 0..n as usize { + let (a0, a1) = (start + step * i as f64, start + step * (i + 1) as f64); + let (q0, d0) = (at(a0), at(a0 + tau / 4.0)); + let (q1, d1) = (at(a1), at(a1 + tau / 4.0)); + let c1 = (centre.0 + q0.0 + arm * d0.0, centre.1 + q0.1 + arm * d0.1); + let c2 = (centre.0 + q1.0 - arm * d1.0, centre.1 + q1.1 - arm * d1.1); + let end = if i + 1 == n as usize { p } else { (centre.0 + q1.0, centre.1 + q1.1) }; + self.cubic_to(c1, c2, end); + } + } + + fn data(&mut self, d: &str) { + let mut data = Data { rest: d.as_bytes() }; + let mut command = data.command().expect("path data that does not start with a command"); + loop { + let at = self.open.as_ref().map_or((0.0, 0.0), |_| self.at()); + let relative = command.is_ascii_lowercase(); + let abs = |p: Point| if relative { (at.0 + p.0, at.1 + p.1) } else { p }; + match command.to_ascii_uppercase() { + b'M' => { + // A relative one after a closepath is from the closed + // subpath's start, which `close` leaves as the current point. + self.move_to(abs(data.point())); + // Coordinates after a moveto are linetos. + command = if relative { b'l' } else { b'L' }; + } + b'L' => self.line_to(abs(data.point())), + b'H' => { + let x = data.number().expect("an x"); + self.line_to((if relative { at.0 + x } else { x }, at.1)); + } + b'V' => { + let y = data.number().expect("a y"); + self.line_to((at.0, if relative { at.1 + y } else { y })); + } + b'C' => { + let (c1, c2) = (abs(data.point()), abs(data.point())); + let p = abs(data.point()); + self.cubic_to(c1, c2, p); + } + b'A' => { + let (rx, ry) = (data.number().expect("rx"), data.number().expect("ry")); + let degrees = data.number().expect("an x-axis rotation"); + let (large, sweep) = (data.flag(), data.flag()); + let p = abs(data.point()); + self.arc(rx, ry, degrees, large, sweep, p); + } + b'Z' => self.close(), + _ => panic!("path command {:?} is not read", command as char), + } + if let Some(next) = data.command() { + command = next; + } else if data.rest.is_empty() { + break; + } else if command.eq_ignore_ascii_case(&b'Z') { + panic!("a number after a closepath"); + } + } + } +} + +impl Subpath { + fn map(&self, f: impl Fn(Point) -> Point) -> Subpath { + Subpath { + start: f(self.start), + cubics: self.cubics.iter().map(|c| c.map(&f)).collect(), + closed: self.closed, + } + } + + /// The subpath as chords, each cubic cut into as many as `chords` says. + fn flatten(&self, chords: impl Fn(&[Point; 4]) -> Vec) -> Vec { + let mut points = vec![self.start]; + for c in &self.cubics { + let p0 = *points.last().unwrap(); + points.extend(chords(&[p0, c[0], c[1], c[2]])); + } + points + } +} + +fn eval(c: &[Point; 4], t: f64) -> Point { + let u = 1.0 - t; + let (a, b, d, e) = (u * u * u, 3.0 * u * u * t, 3.0 * u * t * t, t * t * t); + (a * c[0].0 + b * c[1].0 + d * c[2].0 + e * c[3].0, a * c[0].1 + b * c[1].1 + d * c[2].1 + e * c[3].1) +} + +fn derivative(c: &[Point; 4], t: f64) -> Point { + let u = 1.0 - t; + let (a, b, d) = (3.0 * u * u, 6.0 * u * t, 3.0 * t * t); + ( + a * (c[1].0 - c[0].0) + b * (c[2].0 - c[1].0) + d * (c[3].0 - c[2].0), + a * (c[1].1 - c[0].1) + b * (c[2].1 - c[1].1) + d * (c[3].1 - c[2].1), + ) +} + +/// A device coordinate in tiny-skia's fixed point: 1/64ths of a sample. +fn dot6(v: f64) -> i64 { + (v * (GRID * 64) as f64) as i64 +} + +/// A stroke's path, as many chords as tiny-skia's outline of it has: the +/// offset `r` out from the cubic in quads, each halved until its middle is +/// within a quarter of a pixel of the offset's, then each quad in as many +/// chords as tiny-skia steps it in. +fn stroked(c: &[Point; 4], r: f64) -> Vec { + let tangent = |t: f64| { + let (x, y) = derivative(c, t); + let length = x.hypot(y); + assert!(length > 0.0, "a stroked curve with no direction at {t}"); + (x / length, y / length) + }; + let offset = |t: f64| { + let (p, d) = (eval(c, t), tangent(t)); + (p.0 - d.1 * r, p.1 + d.0 * r) + }; + let mut out = vec![]; + let mut pieces = vec![(0.0, 1.0)]; + while let Some((t0, t1)) = pieces.pop() { + let (o0, o1, d0, d1) = (offset(t0), offset(t1), tangent(t0), tangent(t1)); + let cross = d0.0 * d1.1 - d0.1 * d1.0; + if cross.abs() < 1e-9 { + // Straight: one chord. + out.push((t1, 1)); + continue; + } + // Where the offset's end tangents meet: the quad's control point. + let s = ((o1.0 - o0.0) * d1.1 - (o1.1 - o0.1) * d1.0) / cross; + let q = (o0.0 + d0.0 * s, o0.1 + d0.1 * s); + let mid = ((o0.0 + 2.0 * q.0 + o1.0) / 4.0, (o0.1 + 2.0 * q.1 + o1.1) / 4.0); + let want = offset((t0 + t1) / 2.0); + if (mid.0 - want.0).hypot(mid.1 - want.1) > 0.25 { + pieces.push(((t0 + t1) / 2.0, t1)); + pieces.push((t0, (t0 + t1) / 2.0)); + continue; + } + let bend = |a: f64, b: f64, c: f64| (2 * dot6(b) - dot6(a) - dot6(c)) >> 2; + out.push((t1, chords(bend(o0.0, q.0, o1.0), bend(o0.1, q.1, o1.1), 0))); + } + let mut points = vec![]; + let mut t0 = 0.0; + for (t1, n) in out { + points.extend((1..=n).map(|i| eval(c, t0 + (t1 - t0) * i as f64 / n as f64))); + t0 = t1; + } + points +} + +/// How many chords tiny-skia steps a curve in, from how far it strays from +/// its chord in each axis, in 1/64ths of a sample: `2^(shift + extra)`, at +/// least two and at most 64. +fn chords(dx: i64, dy: i64, extra: i64) -> usize { + let (dx, dy) = (dx.abs(), dy.abs()); + let distance = (dx.max(dy) + (dx.min(dy) >> 1) + 16) >> 5; + let shift = ((64 - distance.leading_zeros() as i64) >> 1) + extra; + 1 << shift.clamp(1, 6) +} + +/// A fill's edges as tiny-skia steps them: the cubic cut where it turns in y, +/// and each piece in `2^shift` chords, `shift` from how far its control points +/// stray from its chord in 1/64ths of a sample. +fn stepped(c: &[Point; 4]) -> Vec { + let (a, b, d) = (c[1].1 - c[0].1, c[2].1 - c[1].1, c[3].1 - c[2].1); + // Where dy/dt, `(a - 2b + d)t^2 + 2(b - a)t + a`, is zero. + let (qa, qb) = (a - 2.0 * b + d, 2.0 * (b - a)); + let mut turns: Vec = if qa.abs() < 1e-12 { + if qb != 0.0 { vec![-a / qb] } else { vec![] } + } else { + let disc = qb * qb - 4.0 * qa * a; + if disc < 0.0 { vec![] } else { [-1.0, 1.0].map(|s| (-qb + s * disc.sqrt()) / (2.0 * qa)).to_vec() } + }; + turns.retain(|t| *t > 0.0 && *t < 1.0); + turns.sort_by(f64::total_cmp); + turns.dedup(); + let mut bounds = vec![0.0]; + bounds.extend(turns); + bounds.push(1.0); + + let mut out = vec![]; + for piece in bounds.windows(2) { + let (t0, t1) = (piece[0], piece[1]); + let at = |s: f64| eval(c, t0 + (t1 - t0) * s); + // The piece's own control points, by its end tangents. + let span = t1 - t0; + let (p0, p3) = (at(0.0), at(1.0)); + let (d0, d3) = (derivative(c, t0), derivative(c, t1)); + let p1 = (p0.0 + d0.0 * span / 3.0, p0.1 + d0.1 * span / 3.0); + let p2 = (p3.0 - d3.0 * span / 3.0, p3.1 - d3.1 * span / 3.0); + // How far the curve at 1/3 and 2/3 strays from the control points + // there, with 19/512 for 1/27. + let delta = |a: f64, b: f64, c: f64, d: f64| { + let (a, b, c, d) = (dot6(a), dot6(b), dot6(c), dot6(d)); + let third = ((a * 8 - b * 15 + 6 * c + d) * 19) >> 9; + let two_thirds = ((a + 6 * b - c * 15 + d * 8) * 19) >> 9; + third.abs().max(two_thirds.abs()) + }; + let n = chords(delta(p0.0, p1.0, p2.0, p3.0), delta(p0.1, p1.1, p2.1, p3.1), 1); + out.extend((1..=n).map(|i| at(i as f64 / n as f64))); + } + out +} + +/// Each pixel's coverage, `size` by `size`, row by row. +fn coverage(icon: &Icon, size: usize) -> Vec { + let scale = size as f64 / icon.edge; + let device = |(x, y): Point| ((x - icon.origin.0) * scale, (y - icon.origin.1) * scale); + + let mut out = vec![0u8; size * size]; + let mut spans: Vec<(f64, f64)> = vec![]; + let mut crossings: Vec<(f64, i32)> = vec![]; + for shape in &icon.shapes { + let subpaths: Vec = shape.subpaths.iter().map(|s| s.map(device)).collect(); + let fills: Vec> = if shape.fill { subpaths.iter().map(|s| s.flatten(stepped)).collect() } else { vec![] }; + let r = shape.stroke.unwrap_or(0.0) * scale; + let strokes: Vec<(Vec, bool)> = match shape.stroke { + Some(_) => subpaths.iter().map(|s| (s.flatten(|c| stroked(c, r)), s.closed)).collect(), + None => vec![], + }; + + let mut alpha = vec![0u32; size * size]; + for row in 0..size * GRID { + let y = (row as f64 + 0.5) / GRID as f64; + spans.clear(); + crossings.clear(); + for points in &fills { + for (a, b) in edges(points, true) { + if (a.1 < y && y <= b.1) || (b.1 < y && y <= a.1) { + let x = a.0 + (y - a.1) * (b.0 - a.0) / (b.1 - a.1); + crossings.push((x, if b.1 > a.1 { 1 } else { -1 })); + } + } + } + crossings.sort_by(|a, b| a.0.total_cmp(&b.0)); + let mut winding = 0; + for &(x, dir) in &crossings { + if winding == 0 { + spans.push((x, f64::INFINITY)); + } + winding += dir; + if winding == 0 { + spans.last_mut().unwrap().1 = x; + } + } + for (points, closed) in &strokes { + for (a, b) in edges(points, *closed) { + spans.extend(capsule(a, b, r, y)); + } + } + spans.sort_by(|a, b| a.0.total_cmp(&b.0)); + let mut counts = vec![0u32; size]; + let mut i = 0; + while i < spans.len() { + let (a, mut b) = spans[i]; + i += 1; + while i < spans.len() && spans[i].0 <= b { + b = b.max(spans[i].1); + i += 1; + } + // The sample points `(column + 0.5) / GRID` in `a < x <= b`. + let first = ((a * GRID as f64 - 0.5).floor() + 1.0).max(0.0); + let last = (b * GRID as f64 - 0.5).floor().min((size * GRID) as f64 - 1.0); + if first <= last { + for column in first as usize..=last as usize { + counts[column / GRID] += 1; + } + } + } + // A row of four is worth 64, but 63 in a pixel's last row, so that + // a covered pixel sums to 255 and not 256. + let full = if row % GRID == GRID - 1 { 63 } else { 64 }; + let pixels = &mut alpha[(row / GRID) * size..][..size]; + for (pixel, &n) in pixels.iter_mut().zip(&counts) { + *pixel += if n == GRID as u32 { full } else { n * 16 }; + } + } + for (o, &a) in out.iter_mut().zip(&alpha) { + *o = ((255 * a + *o as u32 * (255 - a) + 255) >> 8) as u8; + } + } + out +} + +/// A polyline's segments, with the closing one where `closed`. +fn edges(points: &[Point], closed: bool) -> impl Iterator + '_ { + let closing = (closed && points.len() > 1).then(|| (points[points.len() - 1], points[0])); + points.windows(2).map(|w| (w[0], w[1])).chain(closing) +} + +/// Where the row `y` crosses the points within `r` of the segment `a`-`b`. +fn capsule(a: Point, b: Point, r: f64, y: f64) -> Option<(f64, f64)> { + let (mut lo, mut hi) = (f64::INFINITY, f64::NEG_INFINITY); + for c in [a, b] { + let dy = y - c.1; + if dy.abs() <= r { + let h = (r * r - dy * dy).sqrt(); + lo = lo.min(c.0 - h); + hi = hi.max(c.0 + h); + } + } + let (dx, dy) = (b.0 - a.0, b.1 - a.1); + let length = dx.hypot(dy); + if length > 0.0 { + // Along the segment, 0..=1, and across it, -r..=r, are each linear in x. + let along = solve(dx / (length * length), (y - a.1) * dy / (length * length), 0.0, 1.0); + let across = solve(dy / length, -(y - a.1) * dx / length, -r, r); + if let (Some(p), Some(q)) = (along, across) { + let (from, to) = (p.0.max(q.0), p.1.min(q.1)); + if from <= to { + lo = lo.min(from + a.0); + hi = hi.max(to + a.0); + } + } + } + (lo <= hi).then_some((lo, hi)) +} + +/// The `x` at which `slope * x + offset` lies in `low..=high`, relative to +/// the segment's start. +fn solve(slope: f64, offset: f64, low: f64, high: f64) -> Option<(f64, f64)> { + if slope == 0.0 { + return (low..=high).contains(&offset).then_some((f64::NEG_INFINITY, f64::INFINITY)); + } + let (p, q) = ((low - offset) / slope, (high - offset) / slope); + Some((p.min(q), p.max(q))) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn draw(body: &str, edge: u32, size: usize) -> Vec { + let svg = format!( + "{body}" + ); + coverage(&Icon::parse(&svg), size) + } + + /// A covered pixel is 255, and one a quarter covered is four samples of 16: + /// a square on pixel boundaries, and one half a pixel off them. + #[test] + fn a_square_covers_its_samples() { + let on = draw("", 4, 4); + assert_eq!(on, [0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0]); + let off = draw("", 4, 4); + assert_eq!(off, [64, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + } + + /// Against the area of a disc and of a ring, the oracle for the arc + /// conversion and the stroke that needs no resvg: a filled circle drawn as + /// two arcs, and a circle's round stroke, each within 0.5% of its area. + #[test] + fn a_disc_and_a_ring_cover_their_areas() { + let area = |cov: &[u8]| cov.iter().map(|&a| a as f64 / 255.0).sum::(); + let pi = std::f64::consts::PI; + let disc = draw("", 256, 256); + let want = pi * 100.0 * 100.0; + assert!((area(&disc) - want).abs() < want * 5e-3, "disc: {} of {want}", area(&disc)); + let ring = draw( + "", + 256, + 256, + ); + let want = pi * (108.0f64.powi(2) - 84.0f64.powi(2)); + assert!((area(&ring) - want).abs() < want * 5e-3, "ring: {} of {want}", area(&ring)); + } + + /// The committed icons draw to the pixels that were compared with resvg's, + /// which no reading of this file can see: a change that moves one is + /// compared with resvg again before this digest moves with it. + #[test] + fn the_icons_are_the_pixels_compared_with_resvg() { + use sha2::{Digest, Sha256}; + let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")); + let mut digest = Sha256::new(); + for (stem, _) in SIZES { + let svg = std::fs::read(root.join(format!("assets/icons/{stem}.svg"))).expect("a committed icon"); + digest.update(rasterize(stem, &svg)); + } + let hex: String = digest.finalize().iter().map(|b| format!("{b:02x}")).collect(); + assert_eq!(hex, "bc246dcfb81736e4aef449383ea3c666e38122ca47d0b2a2dfead9302653929e", "the icons' pixels moved"); + } + + /// A contour wound against its outer one is a hole; one wound with it is not. + #[test] + fn a_fill_is_nonzero() { + let hole = draw("", 3, 3); + assert_eq!(hole, [255, 255, 255, 255, 0, 255, 255, 255, 255]); + let solid = draw("", 3, 3); + assert_eq!(solid, [255; 9]); + } + + #[test] + #[should_panic(expected = "paint \"#ff0000\" is neither currentColor nor none")] + fn a_literal_colour_is_refused() { + draw("", 4, 4); + } + + #[test] + #[should_panic(expected = " fills black")] + fn an_unpainted_shape_is_refused() { + draw("", 4, 4); + } + + #[test] + #[should_panic(expected = " is stroked without round caps and joins")] + fn a_square_cap_is_refused() { + draw("", 4, 4); + } + + #[test] + #[should_panic(expected = " is not read")] + fn an_unread_attribute_is_refused() { + draw("", 4, 4); + } + + #[test] + #[should_panic(expected = " has children")] + fn a_group_is_refused() { + draw("", 4, 4); + } + + #[test] + #[should_panic(expected = "path command 'Q' is not read")] + fn an_unread_command_is_refused() { + draw("", 4, 4); + } +} diff --git a/src/lib.rs b/src/lib.rs index 45229856279..8ef77377f0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub mod firmware; pub mod gitfixture; pub mod flags; pub mod hostws; +pub mod icons; pub mod identity; pub mod image; pub mod kernelconsole; diff --git a/userland/compositor/src/main.rs b/userland/compositor/src/main.rs index e0c199c0078..42c1e4f8806 100644 --- a/userland/compositor/src/main.rs +++ b/userland/compositor/src/main.rs @@ -58,10 +58,6 @@ pub const FIXED_POLL_HANDLES: u32 = 3; /// binds. pub const MAX_WINDOW_SLOTS: u32 = Poller::MAX_HANDLES - FIXED_POLL_HANDLES - MAX_PENDING_CONNS; -/// Edge of the cursor sprites, in pixels — the size they are rasterized at and -/// the size the software cursor damages. -pub const CURSOR_PX: u32 = 20; - /// What the launcher offers before `/apps` is read: the label it shows and the /// program it starts. pub const BUILT_IN_APPS: &[(&str, &str)] = diff --git a/userland/compositor/src/session.rs b/userland/compositor/src/session.rs index ba31a622ca8..8cd669da173 100644 --- a/userland/compositor/src/session.rs +++ b/userland/compositor/src/session.rs @@ -10,6 +10,7 @@ use std::process::Command; use std::time::{Duration, Instant}; +use sprite::Sprite; use toyos::endow; use toyos::ipc::RxStep; use toyos::poller::{Poller, READABLE}; @@ -33,7 +34,7 @@ use crate::client::{ use crate::render::{self, Assets, BackBuffer, SystemStats, TitleBarIcons}; use crate::stats::{FrameStats, FrameTotals}; use crate::{ - launcher_apps, CURSOR_PX, DOUBLE_CLICK_TIME, DRAIN_BUDGET, FIXED_POLL_HANDLES, + launcher_apps, DOUBLE_CLICK_TIME, DRAIN_BUDGET, FIXED_POLL_HANDLES, FLAG_HARDWARE_CURSOR, FRAME_INTERVAL, MAX_WINDOW_SLOTS, STATS_INTERVAL, }; @@ -43,19 +44,27 @@ const _: () = assert!( ); struct Cursors { - default: sprite::Sprite, - crosshair: sprite::Sprite, - resize: sprite::Sprite, + default: Sprite, + crosshair: Sprite, + resize: Sprite, } impl Cursors { - fn get(&self, style: CursorStyle) -> &sprite::Sprite { + fn get(&self, style: CursorStyle) -> &Sprite { match style { CursorStyle::Crosshair => &self.crosshair, CursorStyle::Resize => &self.resize, CursorStyle::Default => &self.default, } } + + /// What the software cursor damages, whichever cursor it moves from and to. + fn extent(&self) -> (i32, i32) { + let all = [&self.default, &self.crosshair, &self.resize]; + let w = all.iter().map(|s| s.width()).max().unwrap(); + let h = all.iter().map(|s| s.height()).max().unwrap(); + (w as i32, h as i32) + } } /// The wallpaper as it is stored: width, height, then RGB triples. @@ -174,13 +183,9 @@ impl Session { let mut cursor_shm = SharedMemory::adopt(fb_info.cursor, 64 * 64 * 4) .expect("the cursor buffer the framebuffer claim just handed over"); let cursors = Cursors { - default: read_sprite("/system/share/icons/cursor-bold.svg", CURSOR_PX, [255, 255, 255]), - resize: read_sprite( - "/system/share/icons/arrow-down-right-bold.svg", - CURSOR_PX, - [255, 255, 255], - ), - crosshair: read_sprite("/system/share/icons/crosshair-simple-bold.svg", CURSOR_PX, [0, 0, 0]), + default: Sprite::icon("cursor-bold", [255, 255, 255]), + resize: Sprite::icon("arrow-down-right-bold", [255, 255, 255]), + crosshair: Sprite::icon("crosshair-simple-bold", [0, 0, 0]), }; render::upload_cursor(&fb_dev, cursor_shm.as_mut_slice(), &cursors.default, hw_cursor); @@ -205,9 +210,9 @@ impl Session { wallpaper.rescale(&screen); let icons = TitleBarIcons { - minimize: read_sprite("/system/share/icons/minus-bold.svg", 14, [255, 255, 255]), - maximize: read_sprite("/system/share/icons/square-bold.svg", 14, [255, 255, 255]), - close: read_sprite("/system/share/icons/x-bold.svg", 14, [255, 255, 255]), + minimize: Sprite::icon("minus-bold", [255, 255, 255]), + maximize: Sprite::icon("square-bold", [255, 255, 255]), + close: Sprite::icon("x-bold", [255, 255, 255]), }; let apps = launcher_apps(); @@ -450,9 +455,9 @@ impl Session { self.fb_dev.move_cursor(self.cursor.x as u32, self.cursor.y as u32) .expect("compositor holds the framebuffer claim"); } else { - let px = CURSOR_PX as i32; - self.damage.add(Rect::new(was.x, was.y, px, px)); - self.damage.add(Rect::new(self.cursor.x, self.cursor.y, px, px)); + let (w, h) = self.cursors.extent(); + self.damage.add(Rect::new(was.x, was.y, w, h)); + self.damage.add(Rect::new(self.cursor.x, self.cursor.y, w, h)); } let delta = Point { x: self.cursor.x - was.x, y: self.cursor.y - was.y }; @@ -1388,11 +1393,6 @@ fn desk_of(screen: &Screen, font: &font::Font, apps: usize) -> Desk { } } -fn read_sprite(path: &str, size: u32, color: [u8; 3]) -> sprite::Sprite { - let svg = std::fs::read(path).unwrap_or_else(|e| panic!("failed to read {path}: {e}")); - sprite::Sprite::from_svg_colored(&svg, size, color) -} - /// Total physical memory, as the kernel reports it. fn total_memory() -> u64 { let mut buf = [0u8; system::SYSINFO_HEADER_SIZE]; diff --git a/userland/files/src/main.rs b/userland/files/src/main.rs index 792a64da88c..de74fbe9c5f 100644 --- a/userland/files/src/main.rs +++ b/userland/files/src/main.rs @@ -13,7 +13,6 @@ const PATH_COLOR: Color = Color { r: 0x80, g: 0x80, b: 0x90 }; const SCROLLBAR_TRACK: Color = Color { r: 0x25, g: 0x25, b: 0x35 }; const SCROLLBAR_THUMB: Color = Color { r: 0x55, g: 0x55, b: 0x65 }; -const ICON_SIZE: usize = 32; const ITEM_WIDTH: usize = 80; const ITEM_HEIGHT: usize = 64; const PADDING: usize = 8; @@ -60,10 +59,8 @@ impl FileBrowser { let font_data = fs::read("/system/share/fonts/JetBrainsMono-Regular-8x16.font").expect("failed to read font"); let font = font::Font::from_prebuilt(&font_data); - let folder_svg = fs::read("/system/share/icons/folder-bold.svg").expect("failed to read folder icon"); - let file_svg = fs::read("/system/share/icons/file-bold.svg").expect("failed to read file icon"); - let folder_icon = Sprite::from_svg_colored(&folder_svg, ICON_SIZE as u32, [0xf0, 0xc8, 0x50]); - let file_icon = Sprite::from_svg_colored(&file_svg, ICON_SIZE as u32, [0xd0, 0xd0, 0xd8]); + let folder_icon = Sprite::icon("folder-bold", [0xf0, 0xc8, 0x50]); + let file_icon = Sprite::icon("file-bold", [0xd0, 0xd0, 0xd8]); let current_dir = std::env::home_dir().expect("files: the supervisor starts every program with HOME"); @@ -167,13 +164,9 @@ impl FileBrowser { self.fb.fill_rect(x, clip_y, ITEM_WIDTH, clip_h, SELECTED_BG); } - if y >= content_top && y + ICON_SIZE <= content_bottom { - let icon_x = x + (ITEM_WIDTH - ICON_SIZE) / 2; - let icon = if entry.is_dir { - &self.folder_icon - } else { - &self.file_icon - }; + let icon = if entry.is_dir { &self.folder_icon } else { &self.file_icon }; + if y >= content_top && y + icon.height() <= content_bottom { + let icon_x = x + (ITEM_WIDTH - icon.width()) / 2; icon.draw( self.fb.ptr(), self.fb.stride(), @@ -190,7 +183,7 @@ impl FileBrowser { let max_chars = ITEM_WIDTH / self.font.width(); let name: String = entry.name.chars().take(max_chars).collect(); let text_x = x + (ITEM_WIDTH.saturating_sub(name.len() * self.font.width())) / 2; - let text_y = y + ICON_SIZE + 2; + let text_y = y + icon.height() + 2; if text_y >= content_top && text_y + self.font.height() <= content_bottom { self.font.draw_string(&self.fb, text_x, text_y, &name, TEXT_COLOR, text_bg); } diff --git a/userland/sprite/Cargo.toml b/userland/sprite/Cargo.toml index 0856af22ce9..86090427671 100644 --- a/userland/sprite/Cargo.toml +++ b/userland/sprite/Cargo.toml @@ -1,12 +1,9 @@ [package] name = "sprite" -description = "An SVG rasterized through resvg into an RGBA pixel buffer, optionally in one colour." +description = "An icon the build drew, in one colour, as an RGBA pixel buffer, and its alpha-blended blit." version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" [lib] doctest = false - -[dependencies] -resvg = { version = "0.47", default-features = false } diff --git a/userland/sprite/README.md b/userland/sprite/README.md deleted file mode 100644 index 6ee2855e057..00000000000 --- a/userland/sprite/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# sprite - -SVG rasterizer that converts vector graphics to RGBA pixel buffers, with support for color substitution. - -Used by compositor and files. diff --git a/userland/sprite/src/lib.rs b/userland/sprite/src/lib.rs index b1fd10922f0..d2096b69f65 100644 --- a/userland/sprite/src/lib.rs +++ b/userland/sprite/src/lib.rs @@ -1,5 +1,4 @@ -use resvg::tiny_skia; -use resvg::usvg; +//! An icon the build drew (`src/icons.rs`), in one colour, and its blit. pub struct Sprite { width: usize, @@ -8,34 +7,16 @@ pub struct Sprite { } impl Sprite { - /// Rasterize an SVG at the given pixel size. The SVG is scaled to fit a `size x size` square. - pub fn from_svg(svg_bytes: &[u8], size: u32) -> Self { - let tree = usvg::Tree::from_data(svg_bytes, &usvg::Options::default()) - .expect("failed to parse SVG"); - let mut pixmap = tiny_skia::Pixmap::new(size, size).expect("failed to create pixmap"); - let svg_size = tree.size(); - let sx = size as f32 / svg_size.width(); - let sy = size as f32 / svg_size.height(); - resvg::render(&tree, tiny_skia::Transform::from_scale(sx, sy), &mut pixmap.as_mut()); - // resvg outputs premultiplied RGBA; convert to straight alpha - let mut data = pixmap.take(); - for chunk in data.chunks_exact_mut(4) { - let a = chunk[3] as u16; - if a > 0 && a < 255 { - chunk[0] = ((chunk[0] as u16 * 255) / a) as u8; - chunk[1] = ((chunk[1] as u16 * 255) / a) as u8; - chunk[2] = ((chunk[2] as u16 * 255) / a) as u8; - } - } - Self { width: size as usize, height: size as usize, data } - } - - /// Rasterize an SVG, replacing `currentColor` with the given RGB color. - pub fn from_svg_colored(svg_bytes: &[u8], size: u32, color: [u8; 3]) -> Self { - let svg_str = String::from_utf8_lossy(svg_bytes); - let hex = format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2]); - let replaced = svg_str.replace("currentColor", &hex); - Self::from_svg(replaced.as_bytes(), size) + /// The icon `/system/share/icons/.alpha`, in `color`. + pub fn icon(stem: &str, color: [u8; 3]) -> Self { + let path = format!("/system/share/icons/{stem}.alpha"); + let file = std::fs::read(&path).unwrap_or_else(|e| panic!("failed to read {path}: {e}")); + let (size, mask) = file.split_at_checked(8).unwrap_or_else(|| panic!("{path} has no header")); + let width = u32::from_le_bytes(size[..4].try_into().unwrap()) as usize; + let height = u32::from_le_bytes(size[4..].try_into().unwrap()) as usize; + assert_eq!(mask.len(), width * height, "{path} is not {width}x{height}"); + let data = mask.iter().flat_map(|&a| [color[0], color[1], color[2], a]).collect(); + Self { width, height, data } } pub fn width(&self) -> usize { From ea95e75aca418a23ab36d675fc33efc83bb5190c Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 18:04:59 +0200 Subject: [PATCH 09/22] An ignored SIGALRM drops a due alarm, the corpus reads libc's new names back, and the bootstrap defect stays open Answers the review of b9f562d9d on #809. libc: `signal` and `sigaction` keep SIGALRM's disposition, and a due alarm under SIG_IGN is dropped instead of ending the process (`alarmreq::ends`, held on the host). `signal` takes and answers a pointer, as signal.h declares it: SIG_DFL is null, which no Rust fn pointer may be. A SIGALRM blocked in every thread still ends the process, since libc keeps each thread's mask in that thread and std's threads are none of libc's; the issue records it with its exit extended. The corpus: 206_libc_refusals reads utimes' ENOSYS, wait's and wait4's ECHILD and pathconf's EINVAL; 207_libc_names reads truncate through stat, setbuf's buffer and none, an fseeko/ftello round trip, lround's halves and its EDOM, pathconf's _PC_PATH_MAX, SIGALRM's disposition through signal and sigaction, and alarm(5), alarm(0), alarm(0). The owed lines go from the issues that carried them. Build: hostedclang's export is llvm::check_out_committed, which now takes the git directory it reads; static_elf goes, no test having shown it refuse anything; release.rs's layers are a Part of their own, so the hosted clang is no layer by type and NOT_A_LAYER goes. Issues: the bootstrap defect is open again, re-scoped: the CMake build in src/hostedclang.rs goes once bootstrap's ToyOS-host LLVM makes clang and lld, owner M3. remove_all's race is a defect of its own with an owner and an exit that removes REMOVE_ALL_USE_DIRECTORY_ITERATOR. The host-tools rows name src/hostedclang.rs; the track no longer reads as if M2 waits on HTTPS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- issues/an-alarm-reaches-no-sigalrm-handler.md | 42 +++++++---- ...ild-llvm-clang-and-lld-for-a-toyos-host.md | 42 +++++++++++ ...lacks-names-llvm-for-a-toyos-host-calls.md | 10 +-- ...bc-refuses-what-toyos-cannot-yet-answer.md | 3 +- issues/no-guest-case-reads-std-filesystem.md | 10 +-- ...-all-follows-a-link-swapped-in-mid-walk.md | 26 +++++++ ...d-runs-host-tools-outside-rust-and-qemu.md | 10 +-- issues/toyos-builds-itself.md | 10 +-- src/hostedclang.rs | 52 +++----------- src/libcxx.rs | 3 +- src/llvm.rs | 21 +++--- src/release.rs | 56 +++++++++------ tests/libc-arch/src/alarm_requests.rs | 13 +++- tests/testcases/tinycc/206_libc_refusals.c | 14 +++- .../testcases/tinycc/206_libc_refusals.expect | 4 ++ tests/testcases/tinycc/207_libc_names.c | 72 ++++++++++++++++++- tests/testcases/tinycc/207_libc_names.expect | 11 +++ userland/libc/src/alarm.rs | 35 +++++++-- userland/libc/src/alarmreq.rs | 17 ++++- userland/libc/src/misc.rs | 38 +++++++--- 20 files changed, 352 insertions(+), 137 deletions(-) create mode 100644 issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md create mode 100644 issues/remove-all-follows-a-link-swapped-in-mid-walk.md diff --git a/issues/an-alarm-reaches-no-sigalrm-handler.md b/issues/an-alarm-reaches-no-sigalrm-handler.md index 76ec1f667f7..51d9c183715 100644 --- a/issues/an-alarm-reaches-no-sigalrm-handler.md +++ b/issues/an-alarm-reaches-no-sigalrm-handler.md @@ -8,19 +8,33 @@ opened: 2026-09-30 libc's `alarm` (`userland/libc/src/alarm.rs`) arms one alarm per process and answers the seconds the one it replaces had left, and when it is due a thread -of libc's ends the process with exit code 142, `SIGALRM`'s default action. A -handler for `SIGALRM` never runs: `sigaction` keeps none, and answers 0 -whatever it is given. LLVM bounds its wait on a child with one: a `SIGALRM` -handler makes `wait4` answer `EINTR` (`llvm/lib/Support/Unix/Program.inc`, -`Wait`). POSIX gives `alarm` no refusal, and its `SIGALRM` reaches a handler -only through the signals libc imitates from stage 3 of -`issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md` -on; the handler waits on that stage. +of libc's drops it if `SIGALRM` is ignored and otherwise ends the process with +exit code 142, `SIGALRM`'s default action. POSIX keeps the process in two of +those cases: -The seconds left are held to their rule on the host -(`tests/libc-arch/src/alarm_requests.rs`); no guest case runs an alarm. +- **A handler.** `signal` and `sigaction` keep `SIGALRM`'s disposition, and a + handler never runs. LLVM bounds its wait on a child with one: a `SIGALRM` + handler makes `wait4` answer `EINTR` (`llvm/lib/Support/Unix/Program.inc`, + `Wait`). +- **A mask.** `SIGALRM` blocked in every thread stays pending until a thread + unblocks it, and libc ends the process at once. libc keeps each thread's + mask in that thread alone (`userland/libc/src/pthread.rs`, `MASK`), and a + thread Rust's std starts is none of libc's, so nothing can read whether + every thread blocks it. -**Exit**: `alarm` arms and disarms `SIGALRM` as POSIX says, which a guest C -case shows: a handler installed without `SA_RESTART` runs, and a `wait4` on a -child that has not ended answers `EINTR`; and after `alarm(5)`, `alarm(0)` -answers from 1 to 5 and a second `alarm(0)` answers 0. +POSIX gives `alarm` no refusal, and its `SIGALRM` reaches a handler, or waits +pending on a mask, only through the signals libc imitates from stage 3 of +`issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md` on; +both wait on that stage, its owner. + +What a due alarm does under each disposition is held on the host +(`tests/libc-arch/src/alarm_requests.rs`); `207_libc_names.c` reads the +disposition back and arms and disarms an alarm. No guest case lets one come +due. + +**Exit**: a guest C case shows `SIGALRM` delivered as POSIX says: a handler +installed without `SA_RESTART` runs, and a `wait4` on a child that has not +ended answers `EINTR`; with `SIGALRM` blocked in every thread, a due alarm +leaves the process running and `sigpending` names it, until an unblock ends +the process with 142; and with it ignored, a due alarm leaves the process +running. diff --git a/issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md b/issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md new file mode 100644 index 00000000000..19e5ad5ea68 --- /dev/null +++ b/issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md @@ -0,0 +1,42 @@ +--- +status: open +kind: defect +opened: 2026-09-30 +--- + +# Bootstrap cannot build LLVM, clang and lld for a ToyOS host + +The track holds one build of one fork (`issues/toyos-builds-itself.md`), and +the tree builds LLVM for a ToyOS host by two paths. M2's clang and `ld.lld` +come from a CMake configure and n2 build of their own (`src/hostedclang.rs`). +M3's rustc carries an LLVM that bootstrap's `Llvm` step builds for +`x86_64-unknown-toyos` (`issues/rustc-llvm-cannot-build-for-a-toyos-host.md`), +and bootstrap's `Llvm` step, with `clang = true`, and its `Lld` step make that +host's clang and lld too. One LLVM, one host, two code paths. + +Bootstrap's build names no `llvm-config` for the build triple, and so builds +that triple's LLVM, and its `clang-tblgen`, itself. CMake takes its toolchain +file from `CMAKE_TOOLCHAIN_FILE_x86_64_unknown_toyos`: one that includes the C +sysroot's `toolchain.cmake` and adds the ToyOS LLVM's install to +`CMAKE_FIND_ROOT_PATH`, because the `Lld` step names that LLVM to +`find_package` by a hint, and the sysroot's file has CMake find a package +under a root alone. libc and libc++ now give what stopped a CMake build of +clang and lld from the same commit, measured in #809: `alarm`, `wait`, `wait4`, +`lround` and `std::filesystem`. Bootstrap's build, which builds all of LLVM, +has not run since; what is known to stop it besides: + +- ORC's `shm_open` and `shm_unlink`, the interpreter's `scanf` and + `llvm-objdump`'s `ctime` + (`issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md`). +- LLVM's shared libraries, `libLTO`, `libRemarks`, `libclang` and + `libclang-cpp`, do not link against the C sysroot + (`issues/a-shared-object-does-not-link-against-the-c-sysroot-with-z-defs.md`). +- Bootstrap configures the build machine as LLVM's host + (`issues/a-toyos-hosted-llvm-is-configured-as-running-on-the-build-machine.md`). + +Owner: `issues/toyos-builds-itself.md`, M3. + +**Exit**: ToyOS's build, with nothing supplied by hand, has bootstrap install +a clang and an `ld.lld` for `x86_64-unknown-toyos`, `cargo run -- +--hosted-clang` places those, and `src/hostedclang.rs`'s CMake configure and +build are gone. diff --git a/issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md b/issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md index 2c3c955a071..a628c47fa84 100644 --- a/issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md +++ b/issues/libc-lacks-names-llvm-for-a-toyos-host-calls.md @@ -9,7 +9,8 @@ opened: 2026-10-01 LLVM's tools built for `x86_64-unknown-toyos` call names libc neither declares nor defines. None is in the clang and `ld.lld` the build makes for ToyOS (`src/hostedclang.rs`), which compile and link without them; each -stops a build of LLVM's other tools: +stops a build of LLVM's other tools, bootstrap's among them +(`issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md`): - `shm_open` and `shm_unlink`, with which ORC maps memory on every Unix but Android (`llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp`, @@ -18,10 +19,5 @@ stops a build of LLVM's other tools: (`llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp`). - `ctime`, with which `llvm-objdump` prints a file's time stamp. -`lround`, which clang calls through libc++'s `std::lround`, is defined -(`userland/libc/src/math.rs`) and held to the host's on the host -(`tests/libc-arch/src/fparts_differential.rs`); no guest case reads it. - **Exit**: libc declares and defines each, doing what POSIX says or refusing in -POSIX's form, asserted by a guest C case that reads its effect back, `lround` -among them. +POSIX's form, asserted by a guest C case that reads its effect back. diff --git a/issues/libc-refuses-what-toyos-cannot-yet-answer.md b/issues/libc-refuses-what-toyos-cannot-yet-answer.md index a2d65210d5c..4a02e7fd988 100644 --- a/issues/libc-refuses-what-toyos-cannot-yet-answer.md +++ b/issues/libc-refuses-what-toyos-cannot-yet-answer.md @@ -14,8 +14,7 @@ These answer failure in their POSIX form and do nothing - `symlink`, `ENOSYS`: `SYS_SYMLINK` displaces what its name held (`issues/a-symbolic-link-on-tmp-displaces-its-name-and-lists-nowhere.md`). - `chmod` and `fchmod`, `ENOSYS`: a file has no mode bits to set. -- `utimes`, `ENOSYS`: no call sets a file's times. The one refusal here - `206_libc_refusals.c` does not yet assert. +- `utimes`, `ENOSYS`: no call sets a file's times. - `statvfs` and `fstatvfs`, `ENOSYS`: no call answers a filesystem's size or free space. - `getrlimit` and `setrlimit`, `ENOSYS`: no call answers a process's limits. diff --git a/issues/no-guest-case-reads-std-filesystem.md b/issues/no-guest-case-reads-std-filesystem.md index 486729c372c..ef1f371e49c 100644 --- a/issues/no-guest-case-reads-std-filesystem.md +++ b/issues/no-guest-case-reads-std-filesystem.md @@ -9,10 +9,12 @@ opened: 2026-09-30 libc++ for ToyOS is built with `std::filesystem`, and `` with it, over what libc gives `src/filesystem`: `setbuf`, `fseeko`, `ftello`, `truncate`, `pathconf`'s `_PC_PATH_MAX`, and `utimes`, which refuses -`ENOSYS`, so `last_write_time` sets no time. `open` refuses every directory, -so no descriptor names one: `remove_all` walks a directory iterator -(`src/libcxx.rs`), which a link swapped in under it mid-walk can redirect, as -on libc++'s Windows. No C++ program in a guest uses any of it. +`ENOSYS`, so `last_write_time` sets no time, and `remove_all` walks a +directory by its path (`issues/remove-all-follows-a-link-swapped-in-mid-walk.md`). +Each of libc's is read back by `tests/testcases/tinycc/207_libc_names.c` +and `206_libc_refusals.c`; no C++ program in a guest uses any of it. + +Owner: `issues/toyos-builds-itself.md`, M2. **Exit**: a guest test lists a directory through `std::filesystem`, and reads a file back through `std::ifstream`. diff --git a/issues/remove-all-follows-a-link-swapped-in-mid-walk.md b/issues/remove-all-follows-a-link-swapped-in-mid-walk.md new file mode 100644 index 00000000000..11bcbb68338 --- /dev/null +++ b/issues/remove-all-follows-a-link-swapped-in-mid-walk.md @@ -0,0 +1,26 @@ +--- +status: open +kind: defect +opened: 2026-10-09 +--- + +# `remove_all` follows a link swapped in mid-walk + +Every C++ program on ToyOS gets libc++'s `std::filesystem::remove_all` built +with `-DREMOVE_ALL_USE_DIRECTORY_ITERATOR` (`src/libcxx.rs`): it walks a +directory by its path, and a directory swapped for a symbolic link between the +walk's check and its descent sends the deletes wherever the link points, +outside the tree it was asked to remove. libc++ says so of that walk +(`libcxx/src/filesystem/operations.cpp`, "vulnerable to some race conditions", +https://reviews.llvm.org/D118134), the class of CVE-2022-21658. Its other walk +holds a descriptor for each directory and resolves every name against it +(`openat`, `fdopendir`, `unlinkat`, `O_DIRECTORY`, `O_NOFOLLOW`, +`AT_REMOVEDIR`), and ToyOS has no such descriptor: `open` refuses every +directory, and the kernel resolves every path from the root. + +Owner: `issues/toyos-builds-itself.md`, M2, whose clang brought +`std::filesystem` in. + +**Exit**: a directory opens as a handle that the kernel resolves names +against, libc defines `openat`, `fdopendir` and `unlinkat` over it, and +`src/libcxx.rs` passes no `REMOVE_ALL_USE_DIRECTORY_ITERATOR`. diff --git a/issues/the-build-runs-host-tools-outside-rust-and-qemu.md b/issues/the-build-runs-host-tools-outside-rust-and-qemu.md index d45c5a44edf..d889517c60d 100644 --- a/issues/the-build-runs-host-tools-outside-rust-and-qemu.md +++ b/issues/the-build-runs-host-tools-outside-rust-and-qemu.md @@ -14,12 +14,12 @@ arrives and is not one. M4 and M5 are stages of `issues/toyos-builds-itself.md`. | tool | runs | verdict | exit | |---|---|---|---| -| Python | LLVM's CMake, whenever this host builds an LLVM (`src/llvm.rs`); the C++ runtime's CMake, in every sysroot build (`src/libcxx.rs`), and its build, which runs `libcxx/utils/generate_iwyu_mapping.py` for a header it installs | admitted: no Rust tool does the job, LLVM's CMake requires one (`find_package(Python3 … REQUIRED)` in `rust/src/llvm-project/llvm/CMakeLists.txt`), and so does the runtimes', unconditionally (`runtimes/CMakeLists.txt`): configured as `src/libcxx.rs` does with no Python on `PATH` or in CMake's search, it found none and stopped, exit 1, and with only `python3` added it configured, exit 0 | M5 runs it in the guest | -| CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key; `src/libcxx.rs`, for the C++ runtime in every sysroot build | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest | -| `sh` running LLVM's `config.guess`, and the POSIX tools and `cc` it runs | LLVM's CMake, whenever this host builds an LLVM, and the C++ runtime's, in every sysroot build, ask it the host's triple, unconditionally (`get_host_triple` in `rust/src/llvm-project/llvm/cmake/modules/GetHostTriple.cmake`, which runs `sh` by name) | refused: a Rust tool does the shell's part, brush 0.4.0: on the development host (macOS, arm64) `config.guess` printed `/bin/sh`'s triple under it, `arm64-apple-darwin27.0.0`, exit 0 each. The script runs `sed`, `uname`, `mktemp`, `grep`, `rm`, `rmdir` and `cc` there under either shell, and that `cc` is the `cc` rows'. Five of the other six are refused, uutils' doing each: under brush with sed 0.2.0, grep 0.2.0 and coreutils 0.12.0's `mktemp`, `rm` and `rmdir`, and nothing else on `PATH` but the host's `uname` and `cc`, it printed that triple, exit 0. `uname` is admitted: coreutils 0.12.0's answers `-p` with `unknown` where macOS's answers `arm`, and `config.guess` reads that as PowerPC, `powerpc-apple-darwin27.0.0`, exit 0 | CMake finds brush as its `sh`, uutils' `sed`, `grep`, `mktemp`, `rm` and `rmdir`, and a Rust `uname` that answers `-p` as the host's does; or M5 runs it in the guest | +| Python | LLVM's CMake, whenever this host builds an LLVM (`src/llvm.rs`) and when it builds the ToyOS-hosted clang and LLD (`src/hostedclang.rs`); the C++ runtime's CMake, in every sysroot build (`src/libcxx.rs`), and its build, which runs `libcxx/utils/generate_iwyu_mapping.py` for a header it installs | admitted: no Rust tool does the job, LLVM's CMake requires one (`find_package(Python3 … REQUIRED)` in `rust/src/llvm-project/llvm/CMakeLists.txt`), and so does the runtimes', unconditionally (`runtimes/CMakeLists.txt`): configured as `src/libcxx.rs` does with no Python on `PATH` or in CMake's search, it found none and stopped, exit 1, and with only `python3` added it configured, exit 0 | M5 runs it in the guest | +| CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key; `src/libcxx.rs`, for the C++ runtime in every sysroot build; `src/hostedclang.rs`, for the ToyOS-hosted clang and LLD and the tablegens of its nested `NATIVE` build | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest | +| `sh` running LLVM's `config.guess`, and the POSIX tools and `cc` it runs | LLVM's CMake, whenever this host builds an LLVM, the nested `NATIVE` configure of the ToyOS-hosted clang's build (`src/hostedclang.rs`), which is named no `LLVM_HOST_TRIPLE`, and the C++ runtime's, in every sysroot build, ask it the host's triple, unconditionally (`get_host_triple` in `rust/src/llvm-project/llvm/cmake/modules/GetHostTriple.cmake`, which runs `sh` by name) | refused: a Rust tool does the shell's part, brush 0.4.0: on the development host (macOS, arm64) `config.guess` printed `/bin/sh`'s triple under it, `arm64-apple-darwin27.0.0`, exit 0 each. The script runs `sed`, `uname`, `mktemp`, `grep`, `rm`, `rmdir` and `cc` there under either shell, and that `cc` is the `cc` rows'. Five of the other six are refused, uutils' doing each: under brush with sed 0.2.0, grep 0.2.0 and coreutils 0.12.0's `mktemp`, `rm` and `rmdir`, and nothing else on `PATH` but the host's `uname` and `cc`, it printed that triple, exit 0. `uname` is admitted: coreutils 0.12.0's answers `-p` with `unknown` where macOS's answers `arm`, and `config.guess` reads that as PowerPC, `powerpc-apple-darwin27.0.0`, exit 0 | CMake finds brush as its `sh`, uutils' `sed`, `grep`, `mktemp`, `rm` and `rmdir`, and a Rust `uname` that answers `-p` as the host's does; or M5 runs it in the guest | | `git` for worktrees, submodules, checkouts, fixtures and rustc's bootstrap | adds worktrees (`src/sysroot.rs`); updates submodules (`src/lib.rs`, `src/sysroot.rs`); fetches the fork from the primary's and checks it out (`src/sysroot.rs`); makes the tests' fixture repositories; runs inside rustc's bootstrap | admitted: no Rust tool does the job, gitoxide 0.85 adds, removes and prunes no worktree, updates no submodule, stages, resets and pushes nothing, checks out only a fresh clone and fetches a local path by spawning `git`; a fixture must be what `git` makes, and bootstrap runs `git` itself | M4 runs it in the guest | -| `git` for reads, a config write, a commit's paths written out, and clones and fetches over HTTPS | `rev-parse`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `config --blob`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `config --global --add safe.directory` in CI's containers; `checkout -- ` through an index of its own, which writes the C++ runtime's sources out of the LLVM commit into the stored LLVM (`src/llvm.rs`); every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, adds a value to a config file and writes it (gix-config 0.58's `File::section_mut_or_create_new`, `SectionMut::push`, `File::write_to`), walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names; and gitoxide's CLI 0.59 (gix 0.88) wrote the runtimes' sources of LLVM `849da7d6` into an empty directory, each path's tree through `gix rev parse`, `gix index from-tree` and `gix free index checkout-exclusive`, exit 0 each: the 18759 files `git` writes there, byte for byte and mode for mode | those are gitoxide's | -| `cc`, `c++` and `ar` on a Linux host, `build-essential` in CI's containers | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap); `cc` compiles ring's C and assembly in every build of the build system itself, whose HTTP agent is rustls on ring (`src/release.rs`); `ar` archives what `cc::Build` compiles, ring's included | admitted: no Rust tool compiles C or C++, or takes rustc's host link; ring is the one TLS provider the tree takes (owner, 2026-10-02), over a provider in Rust alone | M5: no host in the loop | +| `git` for reads, a config write, a commit's paths written out, and clones and fetches over HTTPS | `rev-parse`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `config --blob`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `config --global --add safe.directory` in CI's containers; `checkout -- ` through an index of its own, which writes the C++ runtime's sources out of the LLVM commit into the stored LLVM, and the ToyOS-hosted clang's out of it into its build (`src/llvm.rs`, `src/hostedclang.rs`); every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, adds a value to a config file and writes it (gix-config 0.58's `File::section_mut_or_create_new`, `SectionMut::push`, `File::write_to`), walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names; and gitoxide's CLI 0.59 (gix 0.88) wrote the runtimes' sources of LLVM `849da7d6` into an empty directory, each path's tree through `gix rev parse`, `gix index from-tree` and `gix free index checkout-exclusive`, exit 0 each: the 18759 files `git` writes there, byte for byte and mode for mode | those are gitoxide's | +| `cc`, `c++` and `ar` on a Linux host, `build-essential` in CI's containers | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap), and the tablegens of the ToyOS-hosted clang's `NATIVE` build (`src/hostedclang.rs`); `cc` compiles ring's C and assembly in every build of the build system itself, whose HTTP agent is rustls on ring (`src/release.rs`); `ar` archives what `cc::Build` compiles, ring's included | admitted: no Rust tool compiles C or C++, or takes rustc's host link; ring is the one TLS provider the tree takes (owner, 2026-10-02), over a provider in Rust alone | M5: no host in the loop | | the toolchain's own `clang`, `llvm-ar`, `rust-lld` and `llvm-config`, built from `ToyOSOrg/llvm-project` | rustc links every guest binary with `rust-lld`; `clang` compiles the C corpus (`tests/common/compile.rs`) and, with `llvm-ar`, doomgeneric through `cc::Build` (`src/clang.rs`); rustc's bootstrap asks `llvm-config` how to link LLVM | admitted: our fork's C++, which ToyOS can one day build and run; no Rust tool compiles C, `cc::Build` archives with an `ar`, bootstrap reads LLVM through `llvm-config`, and `CLAUDE.md` links everything with `rust-lld` | M5: no host in the loop | | `ovmf-generic`, `qemu-efi-aarch64` | the x86-64 and AArch64 UEFI firmware of CI's guest containers (`src/firmware.rs`), packaged by Debian apart from QEMU | admitted: QEMU's own firmware, and no Rust firmware does its job | the instrument's QEMU carries its own firmware | | `ca-certificates` | the trust store `git` and `curl` verify against in CI's containers | admitted: data both of them need | goes when neither runs there | diff --git a/issues/toyos-builds-itself.md b/issues/toyos-builds-itself.md index 2aeabff1000..c04a8ea8e0a 100644 --- a/issues/toyos-builds-itself.md +++ b/issues/toyos-builds-itself.md @@ -105,12 +105,12 @@ libc's state it is `userland/libc` at `15625e0cb`. **Blocked on other tracks.** M2 needs room for about a gigabyte of toolchain, and threads and `mmap` mature enough for LLVM -(`issues/std-and-libc-drop-the-answer-thread-join-gives.md`); its package over +(`issues/std-and-libc-drop-the-answer-thread-join-gives.md`). Packages over HTTPS (`issues/a-package-is-a-directory-under-apps-and-the-installer-is-a-program.md`) -waits on the network stack under it +wait on the network stack under them (`issues/the-lan-is-not-yet-production-grade.md`, -`issues/the-internet-clients-work-unchanged.md`). +`issues/the-internet-clients-work-unchanged.md`), and M2 does not. M2 and M4 also need libc to start a child process (`issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md`). M4 needs git in the guest, storage durable and fast enough for an LLVM build tree @@ -134,7 +134,9 @@ static PIEs that name no library (`src/hostedclang.rs`): 147.5 MB and `issues/libc-stat-answers-one-serial-number-for-every-file.md`. **What M3 adds: a rustc that carries that LLVM**, after all of M2's. -- Build: `issues/rustc-llvm-cannot-build-for-a-toyos-host.md`. +- Build: `issues/rustc-llvm-cannot-build-for-a-toyos-host.md`, and + `issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md`, + whose build of clang and lld replaces M2's. - Link: `issues/a-rust-std-binary-cannot-link-the-cxx-runtime.md`. - Test: `issues/nothing-builds-the-toyos-hosted-rustc.md`. diff --git a/src/hostedclang.rs b/src/hostedclang.rs index 27c72a220f2..ddd86b5a340 100644 --- a/src/hostedclang.rs +++ b/src/hostedclang.rs @@ -1,6 +1,9 @@ -//! clang and `ld.lld` that run on ToyOS: built for `x86_64-unknown-toyos` from +//! clang and `ld.lld` for a ToyOS host: built for `x86_64-unknown-toyos` from //! the LLVM commit the host's LLVM is (`src/llvm.rs`), by the toolchain's own //! clang against its C sysroot (`clang::CSysroot`), and linked statically. +//! CMake builds them, beside bootstrap, until bootstrap's LLVM for a ToyOS +//! host makes both +//! (`issues/bootstrap-cannot-build-llvm-clang-and-lld-for-a-toyos-host.md`). //! //! **Made only when asked for** (`cargo run -- --hosted-clang`): its build is //! LLVM's, and its key moves with every sysroot's, so no other build makes it. @@ -16,8 +19,7 @@ //! //! `hosted-clang//` in the store holds `bin/clang`, `bin/ld.lld` and //! clang's resource headers in `lib/clang//include`, where clang looks -//! beside itself; once its [`SOURCE`] file exists it is read-only. Each binary -//! names no library it needs ([`static_elf`]). +//! beside itself; once its [`SOURCE`] file exists it is read-only. use std::fs; use std::path::{Path, PathBuf}; @@ -168,7 +170,6 @@ fn place(fork: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { // `fs::copy` follows the link the build installs clang as. let (from, to) = (built.join("bin").join(name), bin.join(kept)); fs::copy(&from, &to).unwrap_or_else(|e| panic!("copy {} -> {}: {e}", from.display(), to.display())); - static_elf(&to); } let resource = crate::clang::resource_version(&built); let version = resource.file_name().unwrap_or_else(|| panic!("{} names no version", resource.display())); @@ -185,30 +186,12 @@ fn place(fork: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { } /// Write [`SOURCES`] as the commit `fork`'s LLVM gitlink names holds them into -/// `dest`, from the LLVM repository of `fork`'s git directory, through an index -/// of their own: no checkout's files reach them. +/// `dest`, from the LLVM repository of `fork`'s git directory: a linked +/// worktree's `rust/src/llvm-project` is no checkout. fn export(fork: &Path, dest: &Path) { - let commit = gitlink(fork, LLVM); let common = git_out(fork, &["rev-parse", "--path-format=absolute", "--git-common-dir"]); let repository = Path::new(common.trim()).join("modules").join(LLVM); - fs::create_dir_all(dest).unwrap_or_else(|e| panic!("create {}: {e}", dest.display())); - let index = toyos_tmpdir::TempDir::new("hosted-clang-index"); - let out = Command::new("git") - .env("GIT_DIR", &repository) - .env("GIT_INDEX_FILE", index.join("index")) - .args(["-c", "core.sparseCheckout=false", "--work-tree"]) - .arg(dest) - .args(["checkout", &commit, "--"]) - .args(SOURCES) - .output() - .unwrap_or_else(|e| panic!("run git in {}: {e}", repository.display())); - assert!( - out.status.success(), - "git checkout {commit} from {} into {}: {}", - repository.display(), - dest.display(), - String::from_utf8_lossy(&out.stderr).trim(), - ); + crate::llvm::check_out_committed(&repository, &gitlink(fork, LLVM), &SOURCES, dest); } /// Configure LLVM at `sources`, the commit `fork` names, for `c`'s target, @@ -285,25 +268,6 @@ fn run(mut command: Command, what: &str, ninja: &Path) { assert!(status.success(), "the ToyOS-hosted clang's {what} failed ({status}): its output above says why"); } -/// Refuse `elf` unless it is an executable for [`TARGET`] that names no -/// library it needs. -fn static_elf(elf: &Path) { - let bytes = fs::read(elf).unwrap_or_else(|e| panic!("read {}: {e}", elf.display())); - let machine = match TARGET { - Arch::X86_64 => toyos_elf::Machine::X86_64, - Arch::Aarch64 => toyos_elf::Machine::Aarch64, - }; - let layout = toyos_elf::Layout::parse(&bytes, machine) - .unwrap_or_else(|e| panic!("{} is no {} executable: {e:?}", elf.display(), TARGET.userland())); - let needed = layout.dynamic().map_or(0, |dynamic| { - let start = dynamic.file_offset() as usize; - let table = bytes.get(start..start + dynamic.image().len() as usize); - let table = table.unwrap_or_else(|| panic!("{}'s PT_DYNAMIC is past its end", elf.display())); - toyos_elf::Dynamic::needed(table).count() - }); - assert_eq!(needed, 0, "{} names {needed} libraries it needs, and it is linked statically", elf.display()); -} - #[cfg(test)] mod tests { use toyos_tmpdir::TempDir; diff --git a/src/libcxx.rs b/src/libcxx.rs index c3ff6107ed6..35f57f0ecbc 100644 --- a/src/libcxx.rs +++ b/src/libcxx.rs @@ -42,7 +42,8 @@ pub(crate) const OPTIONS: [(&str, &str); 18] = [ ("LIBUNWIND_ADDITIONAL_COMPILE_FLAGS", "-D_LIBUNWIND_USE_DLADDR=0"), // `open` refuses every directory, so no descriptor names one for `openat` // and `unlinkat` to resolve against: `remove_all` walks a directory - // iterator, as libc++'s Windows does. + // iterator, as libc++'s Windows does + // (`issues/remove-all-follows-a-link-swapped-in-mid-walk.md`). ("LIBCXX_ADDITIONAL_COMPILE_FLAGS", "-DREMOVE_ALL_USE_DIRECTORY_ITERATOR"), ("LIBCXX_INCLUDE_BENCHMARKS", "OFF"), ("LIBCXX_INCLUDE_TESTS", "OFF"), diff --git a/src/llvm.rs b/src/llvm.rs index 0b41e8c9980..11fe103cf95 100644 --- a/src/llvm.rs +++ b/src/llvm.rs @@ -322,7 +322,8 @@ fn place(fork: &Path, key: &Key, dir: &Path, build: &impl Fn(&Path) -> PathBuf) built_from.trim(), fork.display(), ); - check_out_committed(&checkout, &commit, &crate::libcxx::SOURCES, &partial.join("src")); + let repository = git_out(&checkout, &["rev-parse", "--absolute-git-dir"]); + check_out_committed(Path::new(repository.trim()), &commit, &crate::libcxx::SOURCES, &partial.join("src")); fs::write(partial.join(SOURCE), format!("{key}\n")) .unwrap_or_else(|e| panic!("write {}: {e}", partial.join(SOURCE).display())); read_only(&partial); @@ -370,27 +371,27 @@ fn libraries(install: &Path) -> Vec { named } -/// Write `paths` as `commit` holds them, from the repository at `checkout`, +/// Write `paths` as `commit` holds them, from the git directory `repository`, /// under `dest`: through an index of their own and with no sparse pattern, so -/// nothing the checkout holds beside the commit, tracked, ignored or left out, -/// reaches them. -fn check_out_committed(checkout: &Path, commit: &str, paths: &[&str], dest: &Path) { +/// nothing a checkout of it holds beside the commit, tracked, ignored or left +/// out, reaches them. +pub(crate) fn check_out_committed(repository: &Path, commit: &str, paths: &[&str], dest: &Path) { fs::create_dir_all(dest).unwrap_or_else(|e| panic!("create {}: {e}", dest.display())); - let index = toyos_tmpdir::TempDir::new("llvm-runtimes-index"); + let index = toyos_tmpdir::TempDir::new("llvm-sources-index"); let out = Command::new("git") + .env("GIT_DIR", repository) .env("GIT_INDEX_FILE", index.join("index")) .args(["-c", "core.sparseCheckout=false", "--work-tree"]) .arg(dest) .args(["checkout", commit, "--"]) .args(paths) - .current_dir(checkout) .output() - .unwrap_or_else(|e| panic!("run git in {}: {e}", checkout.display())); + .unwrap_or_else(|e| panic!("run git in {}: {e}", repository.display())); assert!( out.status.success(), - "git checkout {commit} -- {paths:?} into {} in {}: {}", + "git checkout {commit} -- {paths:?} into {} from {}: {}", dest.display(), - checkout.display(), + repository.display(), String::from_utf8_lossy(&out.stderr).trim(), ); } diff --git a/src/release.rs b/src/release.rs index 87d5826f6b8..410172e70b3 100644 --- a/src/release.rs +++ b/src/release.rs @@ -47,21 +47,39 @@ const USER_AGENT: &str = "toyos-build (https://github.com/ToyOSOrg/ToyOS)"; /// The products a toolchain is, in the order a build makes them, each under the /// name its cache entry and its job's outputs carry. -const LAYERS: [(Keyed, &str); 4] = [ - (Keyed::Llvm, "llvm"), - (Keyed::Compiler, "compiler"), - (Keyed::Freestanding, "freestanding"), - (Keyed::Sysroot, "sysroot"), +const LAYERS: [(Part, &str); 4] = [ + (Part::Llvm, "llvm"), + (Part::Compiler, "compiler"), + (Part::Freestanding, "freestanding"), + (Part::Sysroot, "sysroot"), ]; -/// Why no layer is the ToyOS-hosted clang: it is made only when asked for -/// (`src/hostedclang.rs`), and a release carries what every build reads. -const NOT_A_LAYER: &str = "a toolchain release carries no ToyOS-hosted clang: it is made only when asked for"; +/// What a toolchain is made of: the products every build reads, of the kinds +/// the build system keys. The ToyOS-hosted clang is none, made only when asked +/// for (`src/hostedclang.rs`). +#[derive(Clone, Copy)] +enum Part { + Llvm, + Compiler, + Freestanding, + Sysroot, +} + +impl Part { + fn keyed(self) -> Keyed { + match self { + Part::Llvm => Keyed::Llvm, + Part::Compiler => Keyed::Compiler, + Part::Freestanding => Keyed::Freestanding, + Part::Sysroot => Keyed::Sysroot, + } + } +} /// One of [`LAYERS`] of this tree's toolchain: the key the build system files /// it under, and where it is, relative to the checkout. struct Layer { - kind: Keyed, + kind: Part, name: &'static str, key: Key, path: PathBuf, @@ -135,13 +153,12 @@ fn layers(root: &Path) -> Vec { .iter() .map(|&(kind, name)| { let key = match kind { - Keyed::Llvm => &llvm, - Keyed::Compiler => &compiler, - Keyed::Freestanding => &freestanding, - Keyed::Sysroot => &sysroot, - Keyed::HostedClang => unreachable!("{NOT_A_LAYER}"), + Part::Llvm => &llvm, + Part::Compiler => &compiler, + Part::Freestanding => &freestanding, + Part::Sysroot => &sysroot, }; - let dir = kind.store(&store(root)).join(key); + let dir = kind.keyed().store(&store(root)).join(key); let path = dir.strip_prefix(root).expect("a runner's store is in its checkout").to_path_buf(); Layer { kind, name, key: key.clone(), path } }) @@ -153,13 +170,12 @@ fn layers(root: &Path) -> Vec { fn defect(root: &Path, layer: &Layer) -> Option { let dir = root.join(&layer.path); match layer.kind { - Keyed::Llvm => crate::llvm::defect(&dir), - Keyed::Compiler => { + Part::Llvm => crate::llvm::defect(&dir), + Part::Compiler => { crate::compiler::unplaced(&dir).or_else(|| crate::toolchain::toolchain_defect(&dir.join("stage2"))) } - Keyed::Freestanding => crate::sysroot::unpublished(&dir), - Keyed::Sysroot => crate::sysroot::unfinished(&dir), - Keyed::HostedClang => unreachable!("{NOT_A_LAYER}"), + Part::Freestanding => crate::sysroot::unpublished(&dir), + Part::Sysroot => crate::sysroot::unfinished(&dir), } } diff --git a/tests/libc-arch/src/alarm_requests.rs b/tests/libc-arch/src/alarm_requests.rs index 5971595d361..035e3801607 100644 --- a/tests/libc-arch/src/alarm_requests.rs +++ b/tests/libc-arch/src/alarm_requests.rs @@ -1,8 +1,8 @@ //! What `alarm` answers and arms: the seconds an earlier alarm has left, -//! rounded up and 0 once it is due or when there is none; and 0 seconds arm -//! nothing. +//! rounded up and 0 once it is due or when there is none; 0 seconds arm +//! nothing; and a due alarm ends the process unless `SIGALRM` is ignored. -use crate::alarmreq::{due, left}; +use crate::alarmreq::{due, ends, left, SIG_DFL, SIG_IGN}; const SEC: u64 = 1_000_000_000; @@ -25,3 +25,10 @@ fn the_seconds_left_round_up_and_end_at_zero() { assert_eq!(left(None, 100), 0); assert_eq!(left(due(0, u32::MAX), 0), u32::MAX); } + +#[test] +fn a_due_alarm_ends_the_process_unless_sigalrm_is_ignored() { + assert!(!ends(SIG_IGN), "an ignored SIGALRM ended the process"); + assert!(ends(SIG_DFL)); + assert!(ends(0x40_1000), "a handler, which never runs, kept the process"); +} diff --git a/tests/testcases/tinycc/206_libc_refusals.c b/tests/testcases/tinycc/206_libc_refusals.c index 8bfc4d2ed5d..8e59332f71b 100644 --- a/tests/testcases/tinycc/206_libc_refusals.c +++ b/tests/testcases/tinycc/206_libc_refusals.c @@ -1,7 +1,7 @@ /* What libc refuses: each call answers failure in its own POSIX form, errno - says why, and nothing is done: ENOSYS where ToyOS lacks the function, and - the errno POSIX names for a lock or a mapping it cannot take, or memory it - cannot give. */ + says why, and nothing is done: ENOSYS where ToyOS lacks the function, ECHILD + for a wait on the child libc cannot start, and the errno POSIX names for a + lock, a limit or a mapping it cannot take, or memory it cannot give. */ #include #include #include @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #define FILE_PATH "/tmp/206_libc_refusals" @@ -19,6 +21,7 @@ static const char *errno_name(int e) { switch (e) { case 0: return "no errno"; + case ECHILD: return "ECHILD"; case ENOSYS: return "ENOSYS"; case EINVAL: return "EINVAL"; case ENODEV: return "ENODEV"; @@ -81,6 +84,11 @@ int main(void) { said("msync", msync(page, 4096, MS_SYNC)); said("mprotect", mprotect(page, 4096, PROT_READ)); said("realpath", realpath("/tmp", NULL) == NULL ? -1 : 0); + said("utimes", utimes(FILE_PATH, NULL)); + int status = 0; + said("wait", wait(&status)); + said("wait4", wait4(-1, &status, 0, NULL)); + said("pathconf 12345", pathconf(FILE_PATH, 12345)); said("fcntl F_SETLK", fcntl(fd, F_SETLK, &lock)); said("fcntl F_SETLKW", fcntl(fd, F_SETLKW, &lock)); said("fcntl F_GETLK", fcntl(fd, F_GETLK, &lock)); diff --git a/tests/testcases/tinycc/206_libc_refusals.expect b/tests/testcases/tinycc/206_libc_refusals.expect index daf32c2d78e..dc7daa9f70b 100644 --- a/tests/testcases/tinycc/206_libc_refusals.expect +++ b/tests/testcases/tinycc/206_libc_refusals.expect @@ -15,6 +15,10 @@ setrlimit: -1, ENOSYS msync: -1, ENOSYS mprotect: -1, ENOSYS realpath: -1, ENOSYS +utimes: -1, ENOSYS +wait: -1, ECHILD +wait4: -1, ECHILD +pathconf 12345: -1, EINVAL fcntl F_SETLK: -1, EINVAL fcntl F_SETLKW: -1, EINVAL fcntl F_GETLK: -1, EINVAL diff --git a/tests/testcases/tinycc/207_libc_names.c b/tests/testcases/tinycc/207_libc_names.c index 201f70b2716..450798d19da 100644 --- a/tests/testcases/tinycc/207_libc_names.c +++ b/tests/testcases/tinycc/207_libc_names.c @@ -1,7 +1,9 @@ /* What libc does for the names LLVM builds against: a directory listed with the name and kind of each entry; dladdr naming the image and the exported - symbol an address lies in; and strnlen, strsignal, modf, logb and the - conversions. */ + symbol an address lies in; a file truncated by its path; a stream on a + buffer of its caller's, or none, sought and told by off_t; SIGALRM's + disposition, and an alarm armed and disarmed; and strnlen, strsignal, modf, + lround, logb, pathconf and the conversions. */ #include #include #include @@ -46,6 +48,7 @@ int main(void); static const char *errno_name(int e) { switch (e) { + case EDOM: return "EDOM"; case EEXIST: return "EEXIST"; case EINVAL: return "EINVAL"; case ENOENT: return "ENOENT"; @@ -85,6 +88,61 @@ static void links(void) { refused("readlink of nothing", readlink(DIR_PATH "/none", buf, sizeof buf)); } +static void truncated(void) { + struct stat st; + int answer = truncate(TARGET, 2); + printf("truncate to 2: %d; stat size: %ld\n", answer, stat(TARGET, &st) == 0 ? (long)st.st_size : -1L); + refused("truncate of nothing", truncate(DIR_PATH "/none", 0)); +} + +/* setbuf's buffer holds what is written until the stream is told or sought; + with none, a write reaches the file at once. */ +static void buffered(void) { + static char buf[BUFSIZ]; + struct stat st; + FILE *f = fopen(DIR_PATH "/buffered", "w+"); + if (!f) { + printf("fopen buffered failed\n"); + return; + } + setbuf(f, buf); + fputs("0123456789", f); + long held = stat(DIR_PATH "/buffered", &st) == 0 ? (long)st.st_size : -1L; + printf("setbuf: file %ld bytes, the buffer %s\n", held, memcmp(buf, "0123456789", 10) == 0 ? "holds them" : "not"); + long told = (long)ftello(f); + int sought = fseeko(f, 3, SEEK_SET); + long at = (long)ftello(f); + int c = fgetc(f); + printf("ftello: %ld; fseeko 3: %d; ftello: %ld; fgetc: %c\n", told, sought, at, c); + fclose(f); + + f = fopen(DIR_PATH "/unbuffered", "w"); + if (!f) { + printf("fopen unbuffered failed\n"); + return; + } + setbuf(f, NULL); + fputs("abc", f); + printf("setbuf NULL: file %ld bytes\n", stat(DIR_PATH "/unbuffered", &st) == 0 ? (long)st.st_size : -1L); + fclose(f); +} + +static void alarms(void) { + void (*was)(int) = signal(SIGALRM, SIG_IGN); + void (*then)(int) = signal(SIGALRM, SIG_DFL); + printf("signal SIGALRM: was %s, then %s\n", was == SIG_DFL ? "SIG_DFL" : "another", + then == SIG_IGN ? "SIG_IGN" : "another"); + struct sigaction ignore = { .sa_handler = SIG_IGN }, old = { .sa_handler = SIG_DFL }; + int set = sigaction(SIGALRM, &ignore, NULL); + int got = sigaction(SIGALRM, NULL, &old); + printf("sigaction SIGALRM: %d %d, %s\n", set, got, old.sa_handler == SIG_IGN ? "SIG_IGN" : "another"); + signal(SIGALRM, SIG_DFL); + unsigned first = alarm(5); + unsigned left = alarm(0); + unsigned again = alarm(0); + printf("alarm 5: %u; alarm 0: %s; again: %u\n", first, left >= 1 && left <= 5 ? "1 to 5" : "another", again); +} + static void listing(void) { if (mkdir(LISTED, 0755) != 0 || mkdir(LISTED "/sub", 0755) != 0 || close(creat(LISTED "/a", 0644)) != 0 || close(creat(LISTED "/b", 0644)) != 0 || close(creat(LISTED "/sub/inner", 0644)) != 0) { @@ -154,6 +212,9 @@ int main(void) { return 1; } links(); + truncated(); + buffered(); + alarms(); listing(); dl(); @@ -166,6 +227,13 @@ int main(void) { errno = 0; double pole = logb(0.0); printf("logb(0): %g, %s\n", pole, errno == ERANGE ? "ERANGE" : errno_name(errno)); + /* Volatile, so the compiler folds none of them. */ + volatile double halves[] = { 2.5, -2.5, 0.49999999999999994, 1e19 }; + printf("lround: %ld %ld %ld\n", lround(halves[0]), lround(halves[1]), lround(halves[2])); + errno = 0; + long far = lround(halves[3]); + printf("lround(1e19): %ld, %s\n", far, errno == EDOM ? "EDOM" : errno_name(errno)); + printf("pathconf _PC_PATH_MAX: %ld\n", pathconf(DIR_PATH, _PC_PATH_MAX)); printf("sysconf _SC_PAGE_SIZE: %ld\n", sysconf(_SC_PAGE_SIZE)); return 0; } diff --git a/tests/testcases/tinycc/207_libc_names.expect b/tests/testcases/tinycc/207_libc_names.expect index a5091a68a7f..861af38ad2e 100644 --- a/tests/testcases/tinycc/207_libc_names.expect +++ b/tests/testcases/tinycc/207_libc_names.expect @@ -4,6 +4,14 @@ readlink into 4: 4, "/sys#" readlink into 0: -1, EINVAL readlink of a file: -1, EINVAL readlink of nothing: -1, ENOENT +truncate to 2: 0; stat size: 2 +truncate of nothing: -1, ENOENT +setbuf: file 0 bytes, the buffer holds them +ftello: 10; fseeko 3: 0; ftello: 3; fgetc: 3 +setbuf NULL: file 3 bytes +signal SIGALRM: was SIG_DFL, then SIG_IGN +sigaction SIGALRM: 0 0, SIG_IGN +alarm 5: 0; alarm 0: 1 to 5; again: 0 entry: a DT_UNKNOWN entry: b DT_UNKNOWN entry: sub DT_DIR @@ -16,4 +24,7 @@ strsignal: Segmentation fault; Unknown signal modf(-3.25): -3 and -0.25 logb: -4 10 logb(0): -inf, ERANGE +lround: 3 -3 0 +lround(1e19): -9223372036854775808, EDOM +pathconf _PC_PATH_MAX: 4096 sysconf _SC_PAGE_SIZE: 4096 diff --git a/userland/libc/src/alarm.rs b/userland/libc/src/alarm.rs index bdc1de4f097..cfd0d6d4b08 100644 --- a/userland/libc/src/alarm.rs +++ b/userland/libc/src/alarm.rs @@ -1,11 +1,12 @@ //! `alarm`: one per process, kept by a thread of this library's, started by -//! the first alarm armed, that sleeps until it is due and then does what -//! `SIGALRM`'s default action does, ending the process. A handler `sigaction` -//! is given never runs: this library keeps none +//! the first alarm armed, that sleeps until it is due. Then, with `SIGALRM` +//! ignored, the alarm is gone; otherwise the keeper does what `SIGALRM`'s +//! default action does and ends the process. A handler `signal` or `sigaction` +//! is given never runs, and a mask that blocks `SIGALRM` holds nothing back //! (`issues/an-alarm-reaches-no-sigalrm-handler.md`). use core::ptr; -use core::sync::atomic::{AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; use toyos_abi::syscall; @@ -28,6 +29,19 @@ static ALARM: Lock = Lock::new(Alarm { due: None, kept: false }); /// Moved at every `alarm`, so a keeper asleep on an older one wakes. static TURN: AtomicU32 = AtomicU32::new(0); +/// `SIGALRM`'s disposition: `SIG_DFL`, `SIG_IGN` or a handler's address. +static DISPOSITION: AtomicUsize = AtomicUsize::new(alarmreq::SIG_DFL); + +/// Make `handler` `SIGALRM`'s disposition, and answer the one it replaces. +pub(crate) fn dispose(handler: usize) -> usize { + DISPOSITION.swap(handler, Ordering::AcqRel) +} + +/// `SIGALRM`'s disposition. +pub(crate) fn disposition() -> usize { + DISPOSITION.load(Ordering::Acquire) +} + fn now() -> u64 { toyos_abi::clock::nanos_since_boot() } @@ -52,19 +66,26 @@ pub extern "C" fn alarm(seconds: u32) -> u32 { left } -/// Sleep until the alarm is due or moved, and end the process once it is due. +/// Sleep until the alarm is due or moved, and once it is due, drop it or end +/// the process as [`alarmreq::ends`] says. unsafe extern "C" fn keep(_: *mut u8) -> *mut u8 { loop { // Read before the alarm, so an `alarm` between the two moves it and // the wait below returns at once. let turn = TURN.load(Ordering::Acquire); - let wait = match ALARM.lock().due { + let mut alarm = ALARM.lock(); + let wait = match alarm.due { None => None, Some(due) => match due.checked_sub(now()) { Some(wait) if wait > 0 => Some(wait), - _ => syscall::exit(ALARM_END), + _ if alarmreq::ends(disposition()) => syscall::exit(ALARM_END), + _ => { + alarm.due = None; + None + } }, }; + drop(alarm); // SAFETY: `TURN` is a live, aligned u32. unsafe { syscall::futex_wait(TURN.as_ptr(), turn, wait) }; } diff --git a/userland/libc/src/alarmreq.rs b/userland/libc/src/alarmreq.rs index e5653b00be0..d32a4230222 100644 --- a/userland/libc/src/alarmreq.rs +++ b/userland/libc/src/alarmreq.rs @@ -1,9 +1,20 @@ -//! What `alarm` answers and arms, in nanoseconds of the monotonic clock. It -//! reads nothing but what it is handed, so the host tests it -//! (`toyos-libc-copies`). +//! What `alarm` answers and arms, in nanoseconds of the monotonic clock, and +//! what a due one does. It reads nothing but what it is handed, so the host +//! tests it (`toyos-libc-copies`). const NANOS_PER_SEC: u64 = 1_000_000_000; +/// `signal.h`'s `SIG_DFL` and `SIG_IGN`, as addresses. +pub(crate) const SIG_DFL: usize = 0; +pub(crate) const SIG_IGN: usize = 1; + +/// Whether an alarm due under `SIGALRM`'s disposition `handler` ends the +/// process: it does unless `SIGALRM` is ignored, since no handler runs +/// (`issues/an-alarm-reaches-no-sigalrm-handler.md`). +pub(crate) fn ends(handler: usize) -> bool { + handler != SIG_IGN +} + /// When an alarm of `seconds` armed at `now` is due; none for 0, which /// disarms. pub(crate) fn due(now: u64, seconds: u32) -> Option { diff --git a/userland/libc/src/misc.rs b/userland/libc/src/misc.rs index e38e12ec1f2..571337c6b8c 100644 --- a/userland/libc/src/misc.rs +++ b/userland/libc/src/misc.rs @@ -207,20 +207,42 @@ pub unsafe extern "C" fn abort() -> ! { syscall::exit(134) // SIGABRT } -// Signal (stubs — ToyOS has no signals) +// Signal (stubs — ToyOS has no signals, but `SIGALRM`'s disposition decides +// what a due `alarm` does) -type SigHandlerT = unsafe extern "C" fn(i32); +const SIGALRM: i32 = 14; +/// `signal.h`'s `struct sigaction`. +#[repr(C)] +pub struct SigAction { + handler: usize, + flags: u64, + restorer: usize, + mask: u64, +} + +/// A handler by its address: `SIG_DFL` and `SIG_IGN` are no functions. #[no_mangle] -pub unsafe extern "C" fn signal(_signum: i32, handler: SigHandlerT) -> SigHandlerT { - handler // return the handler as "previous", effectively a no-op +pub unsafe extern "C" fn signal(signum: i32, handler: *const u8) -> *const u8 { + match signum { + SIGALRM => crate::alarm::dispose(handler as usize) as *const u8, + _ => handler, // return the handler as "previous", effectively a no-op + } } #[no_mangle] -pub unsafe extern "C" fn sigaction( - _signum: i32, _act: *const u8, _oldact: *mut u8, -) -> i32 { - 0 // success +pub unsafe extern "C" fn sigaction(signum: i32, act: *const SigAction, oldact: *mut SigAction) -> i32 { + if signum != SIGALRM { + return 0; // success + } + let old = match unsafe { act.as_ref() } { + Some(act) => crate::alarm::dispose(act.handler), + None => crate::alarm::disposition(), + }; + if let Some(oldact) = unsafe { oldact.as_mut() } { + *oldact = SigAction { handler: old, flags: 0, restorer: 0, mask: 0 }; + } + 0 } /// The calling thread's mask, which is what POSIX's process mask is in a From 3b36e8130c39c565db6139d44350e8487965005e Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 18:50:17 +0200 Subject: [PATCH 10/22] src/icons.rs takes the midpoints and the tag type clippy asks for The host gate's clippy pass denied manual midpoints and the tag tuple's complexity; the pixels do not move (the digest test holds). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- src/icons.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/icons.rs b/src/icons.rs index 6c2f2bb7070..868afc4ee70 100644 --- a/src/icons.rs +++ b/src/icons.rs @@ -195,13 +195,16 @@ fn numbers(value: &str) -> Vec { std::iter::from_fn(|| data.number()).collect() } -/// An SVG's elements, each as its name, its attributes and whether it opens. +/// An SVG element: its name, its attributes and whether it opens. +type Tag<'a> = (&'a str, Vec<(&'a str, &'a str)>, bool); + +/// An SVG's elements, one [`Tag`] at a time. struct Tags<'a> { rest: &'a str, } impl<'a> Tags<'a> { - fn next(&mut self) -> Option<(&'a str, Vec<(&'a str, &'a str)>, bool)> { + fn next(&mut self) -> Option> { self.rest = self.rest.trim_start(); if self.rest.is_empty() { return None; @@ -372,7 +375,7 @@ impl Path { let den = rx * rx * y1 * y1 + ry * ry * x1 * x1; let k = (num / den).abs().sqrt() * if large == sweep { -1.0 } else { 1.0 }; let (cx1, cy1) = (k * rx * y1 / ry, -k * ry * x1 / rx); - let centre = (cos * cx1 - sin * cy1 + (p0.0 + p.0) / 2.0, sin * cx1 + cos * cy1 + (p0.1 + p.1) / 2.0); + let centre = (cos * cx1 - sin * cy1 + f64::midpoint(p0.0, p.0), sin * cx1 + cos * cy1 + f64::midpoint(p0.1, p.1)); let start = ((y1 - cy1) / ry).atan2((x1 - cx1) / rx); let tau = std::f64::consts::TAU; let mut delta = (((-y1 - cy1) / ry).atan2((-x1 - cx1) / rx) - start) % tau; @@ -519,10 +522,11 @@ fn stroked(c: &[Point; 4], r: f64) -> Vec { let s = ((o1.0 - o0.0) * d1.1 - (o1.1 - o0.1) * d1.0) / cross; let q = (o0.0 + d0.0 * s, o0.1 + d0.1 * s); let mid = ((o0.0 + 2.0 * q.0 + o1.0) / 4.0, (o0.1 + 2.0 * q.1 + o1.1) / 4.0); - let want = offset((t0 + t1) / 2.0); + let half = f64::midpoint(t0, t1); + let want = offset(half); if (mid.0 - want.0).hypot(mid.1 - want.1) > 0.25 { - pieces.push(((t0 + t1) / 2.0, t1)); - pieces.push((t0, (t0 + t1) / 2.0)); + pieces.push((half, t1)); + pieces.push((t0, half)); continue; } let bend = |a: f64, b: f64, c: f64| (2 * dot6(b) - dot6(a) - dot6(c)) >> 2; From 00e4c6076d6e1d2ae57ed69c27d7b098c51ae551 Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 18:09:11 +0200 Subject: [PATCH 11/22] The loader calls UEFI through its own bindings, and uefi and uefi-services go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The owner ruled on the dependency audit's uefi row: own bindings, in place of the loader track's plan to move to the current uefi release. `bootloader/src/efi/` holds UEFI 2.10's tables, the protocols the loader opens (LoadedImage, DevicePath, SimpleFileSystem and File, PartitionInfo, BlockIo, GraphicsOutput, Rng, PciRootBridgeIo), the console it writes, the status codes and GUIDs, each struct cited to its section and pinned by compile-time size_of/offset_of! asserts that run on both loader targets at every build. A module and not a crate: the loader is its one user, and a crate would add a manifest, a description and a workspace entry for no second reader; a host test cannot link a no_std, no_main UEFI binary, and the asserts check the layout on the targets themselves. The wrappers are safe where the hazard was ours: - a name crosses to firmware only as CStr16, which carries its NUL; - a protocol is opened only through BootServices::get (GET_PROTOCOL) or ::exclusive, whose bound is the Exclusive marker; the opener is private, so the two clippy.toml rules that guarded uefi's openers go with them; - an open protocol closes when its Scoped drops, a handle buffer is freed; - the console and the allocator refuse once exit_boot_services has run, which nulls the table itself: no SIGNAL_EXIT_BOOT_SERVICES callback is registered, so end_this_pass has no event to close; - BlockIo reads OptimalTransferLengthGranularity only at revision 3 and later, which deletes the unsafe cast rootimage.rs needed to reach the revision through uefi's type; - the memory map is taken into &mut [u64], which deletes watchdog.rs's unsafe byte-slice cast. The panic handler says `[PANIC]: ` on the console, as uefi-services' did, and powers the machine off; uefi-services' ten-second stall before the power-off, a flat wait, does not come with it. One HARDDRIVE decoder (efi::HardDrive::parse, UEFI 2.10 §10.3.5.1) serves boot_partition, bootnext's protocol path and its NVRAM load options, and boot_disk; bootnext's own byte decoder goes, and a load option's HARDDRIVE node is now held to the spec's 42 bytes. The ESP's \toyos\log.guid is read off LoadedImage's DeviceHandle, the volume firmware loaded the image from (§9.1.1), not through LocateDevicePath. A status prints by its Appendix D name: `(NOT_FOUND)` where the loader wrote `(UEFI Error NOT_FOUND: ())`. That is the one change to the loader's text, and it is on refusal lines alone. The loader track's stage 4 loses its uefi bullet and its uefi-services exit, and the owner's ruling joins its bounds. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.lock | 91 --- bootloader/Cargo.toml | 4 - bootloader/src/attempt.rs | 22 +- bootloader/src/blackbox.rs | 11 +- bootloader/src/bootnext.rs | 63 +- bootloader/src/efi/boot.rs | 402 +++++++++++ bootloader/src/efi/mod.rs | 546 +++++++++++++++ bootloader/src/efi/proto.rs | 661 ++++++++++++++++++ bootloader/src/efi/runtime.rs | 175 +++++ bootloader/src/floor.rs | 28 +- bootloader/src/gcd.rs | 8 +- bootloader/src/loaderlog.rs | 43 +- bootloader/src/main.rs | 186 +++-- bootloader/src/protocol.rs | 41 -- bootloader/src/rootbridge.rs | 57 +- bootloader/src/rootimage.rs | 67 +- bootloader/src/seed.rs | 13 +- bootloader/src/slot.rs | 28 +- bootloader/src/stamp.rs | 2 +- bootloader/src/watchdog.rs | 21 +- clippy.toml | 2 - ...oes-only-what-must-precede-the-handover.md | 17 +- 22 files changed, 1997 insertions(+), 491 deletions(-) create mode 100644 bootloader/src/efi/boot.rs create mode 100644 bootloader/src/efi/mod.rs create mode 100644 bootloader/src/efi/proto.rs create mode 100644 bootloader/src/efi/runtime.rs delete mode 100644 bootloader/src/protocol.rs diff --git a/Cargo.lock b/Cargo.lock index 75516233810..08e3d4ca888 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,12 +278,6 @@ dependencies = [ "sha2 0.10.9", ] -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - [[package]] name = "bitflags" version = "1.3.2" @@ -387,8 +381,6 @@ dependencies = [ "toyos-tsc", "toyos-update", "toyos-wallclock", - "uefi", - "uefi-services", ] [[package]] @@ -4323,26 +4315,6 @@ dependencies = [ "parking_lot", ] -[[package]] -name = "ptr_meta" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "pxfm" version = "0.1.28" @@ -6213,69 +6185,6 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" -[[package]] -name = "ucs2" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad643914094137d475641b6bab89462505316ec2ce70907ad20102d28a79ab8" -dependencies = [ - "bit_field", -] - -[[package]] -name = "uefi" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ead9f748a4646479b850add36b527113a80e80a7e0f44d7b0334291850dcc5" -dependencies = [ - "bitflags 2.11.0", - "log", - "ptr_meta", - "ucs2", - "uefi-macros", - "uefi-raw", - "uguid", -] - -[[package]] -name = "uefi-macros" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a7b1c2c808c3db854a54d5215e3f7e7aaf5dcfbce095598cba6af29895695d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "uefi-raw" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864ac69eadd877bfb34e7814be1928122ed0057d9f975169a56ee496aa7bdfd7" -dependencies = [ - "bitflags 2.11.0", - "ptr_meta", - "uguid", -] - -[[package]] -name = "uefi-services" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a79fcb420624743c895bad0f9480fbc2f64e7c8d8611fb1ada6bdd799942feb4" -dependencies = [ - "cfg-if", - "log", - "uefi", -] - -[[package]] -name = "uguid" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab14ea9660d240e7865ce9d54ecdbd1cd9fa5802ae6f4512f093c7907e921533" - [[package]] name = "unicode-bom" version = "2.0.3" diff --git a/bootloader/Cargo.toml b/bootloader/Cargo.toml index aaf27e400f4..9250af93cee 100644 --- a/bootloader/Cargo.toml +++ b/bootloader/Cargo.toml @@ -39,7 +39,3 @@ toyos-update = { path = "../toyos-update" } # with: this target is soft-float, and the x86 backend reaches for SSE and # SHA-NI registers a UEFI application may not assume are its own. sha2 = { version = "0.10", default-features = false, features = ["force-soft"] } -# `alloc`: `variable_keys` and `get_variable_boxed`, which are how the boot -# entry pointing at this image is found among the firmware's own variables. -uefi = { version = "0.26.0", default-features = false, features = ["alloc"] } -uefi-services = { version = "0.23.0", features = ["panic_handler", "logger"] } diff --git a/bootloader/src/attempt.rs b/bootloader/src/attempt.rs index 069705f9ce0..64640669762 100644 --- a/bootloader/src/attempt.rs +++ b/bootloader/src/attempt.rs @@ -7,9 +7,7 @@ use alloc::string::String; use toyos_update::record::{self, Record}; -use uefi::proto::media::file::{Directory, File, FileAttribute, FileMode}; -use uefi::prelude::*; -use uefi::{cstr16, CStr16}; +use crate::efi::{cstr16, CStr16, File, Mode, Status, SystemTable}; use crate::loaderlog; @@ -25,12 +23,12 @@ const NAME: &CStr16 = cstr16!("attempts"); /// **`Err` is not zero.** A volume this cannot read is one the bound is off on, /// and the caller says so rather than treating an unreadable stick as a first /// attempt — which would be a bound that silently never fires. -pub fn read(system_table: &SystemTable, guid: &[u8; 16]) -> Result { +pub fn read(system_table: &SystemTable, guid: &[u8; 16]) -> Result { loaderlog::with_volume(system_table, guid, |root| { - let file = match root.open(NAME, FileMode::Read, FileAttribute::empty()) { + let file = match root.open(NAME, Mode::Read) { Ok(file) => file, // No file is a first attempt, which is every freshly flashed image. - Err(e) if e.status() == Status::NOT_FOUND => return Ok(Record::default()), + Err(Status::NOT_FOUND) => return Ok(Record::default()), Err(e) => return Err(alloc::format!("{NAME} would not open ({e})")), }; let Some(mut file) = file.into_regular_file() else { @@ -50,7 +48,7 @@ pub fn read(system_table: &SystemTable, guid: &[u8; 16]) -> Result, guid: &[u8; 16], record: &Record) -> Result<(), String> { +pub fn write(system_table: &SystemTable, guid: &[u8; 16], record: &Record) -> Result<(), String> { loaderlog::with_volume(system_table, guid, |root| put(root, guid, record)).and_then(|inner| inner) } @@ -60,25 +58,25 @@ pub fn write_chosen(guid: &[u8; 16], record: &Record) -> Result<(), String> { loaderlog::with_open_volume(|root| put(root, guid, record)).and_then(|inner| inner) } -fn put(root: &mut Directory, guid: &[u8; 16], record: &Record) -> Result<(), String> { +fn put(root: &mut File, guid: &[u8; 16], record: &Record) -> Result<(), String> { // Deleted and recreated rather than rewound: a fixed-width record is // still a record a shorter write would leave the tail of. - match root.open(NAME, FileMode::ReadWrite, FileAttribute::empty()) { + match root.open(NAME, Mode::ReadWrite) { Ok(stale) => { if let Err(e) = stale.delete() { return Err(alloc::format!("{NAME} would not delete ({e})")); } } - Err(e) if e.status() == Status::NOT_FOUND => {} + Err(Status::NOT_FOUND) => {} Err(e) => return Err(alloc::format!("{NAME} would not open ({e})")), } let file = root - .open(NAME, FileMode::CreateReadWrite, FileAttribute::empty()) + .open(NAME, Mode::CreateReadWrite) .map_err(|e| alloc::format!("{NAME} would not be created ({e})"))?; let Some(mut file) = file.into_regular_file() else { return Err(alloc::format!("{NAME} on the log partition is a directory")); }; - file.write(&record.encode(guid)).map_err(|e| alloc::format!("{NAME} would not write ({e})"))?; + file.write(&record.encode(guid)).map_err(|(e, _)| alloc::format!("{NAME} would not write ({e})"))?; // **Flushed here and not at the handoff.** What this file exists to // survive is a power cut, and a byte in a cache survives nothing. file.flush().map_err(|e| alloc::format!("{NAME} would not flush ({e})"))?; diff --git a/bootloader/src/blackbox.rs b/bootloader/src/blackbox.rs index 0f749810338..7ddf8fc8768 100644 --- a/bootloader/src/blackbox.rs +++ b/bootloader/src/blackbox.rs @@ -16,8 +16,7 @@ use alloc::string::String; use alloc::vec::Vec; -use uefi::prelude::*; -use uefi::table::boot::{AllocateType, MemoryType}; +use crate::efi::{AllocateType, SystemTable}; use toyos_blackbox::{BYTES, PHYS, State}; use toyos_wallclock::Civil; @@ -53,12 +52,8 @@ pub struct Page(u64); /// last one's file or replaces it is what the page decides — so a refusal is /// returned as a line for the caller to write rather than printed here, where a /// machine with no console would lose it. -pub fn claim(system_table: &SystemTable) -> (Option, Option) { - match system_table.boot_services().allocate_pages( - AllocateType::Address(PHYS), - MemoryType::LOADER_DATA, - toyos_blackbox::PAGES, - ) { +pub fn claim(system_table: &SystemTable) -> (Option, Option) { + match system_table.boot_services().allocate_pages(AllocateType::Address(PHYS), toyos_blackbox::PAGES) { Ok(at) => { // `AllocateType::Address` allocates that address or fails; firmware // answering with another one has not done what was asked of it. diff --git a/bootloader/src/bootnext.rs b/bootloader/src/bootnext.rs index b38e223a8bc..54c260c9fb0 100644 --- a/bootloader/src/bootnext.rs +++ b/bootloader/src/bootnext.rs @@ -15,12 +15,7 @@ //! that booted us from a removable-media fallback path has no entry of ours at //! all and must be told so rather than have one guessed at. -use uefi::prelude::*; -use uefi::proto::device_path::media::PartitionSignature; -use uefi::proto::device_path::{DevicePath, DeviceSubType, DeviceType}; -use uefi::proto::loaded_image::LoadedImage; -use uefi::table::runtime::{VariableAttributes, VariableVendor}; -use uefi::CStr16; +use crate::efi::{cstr16, CStr16, DevicePath, Handle, HardDrive, LoadedImage, SystemTable, VariableAttributes, GLOBAL_VARIABLE}; /// The head of every line this module writes. const HEAD: &str = "Boot chain:"; @@ -39,7 +34,7 @@ const LOAD_OPTION_HEAD: usize = 6; /// A refusal is not a failure of the boot: the kernel still runs and still seals /// its page. What is lost is the *next* boot, so the line says exactly that /// rather than reporting a variable write. -pub fn point_at_us(handle: Handle, system_table: &SystemTable) { +pub fn point_at_us(handle: Handle, system_table: &SystemTable) { let Some(ours) = our_partition(handle, system_table) else { return println!( "{HEAD} firmware did not load this image off a GPT partition, so there is no entry \ @@ -54,7 +49,7 @@ pub fn point_at_us(handle: Handle, system_table: &SystemTable) { }; let write = system_table.runtime_services().set_variable( cstr16!("BootNext"), - &VariableVendor::GLOBAL_VARIABLE, + &GLOBAL_VARIABLE, // Non-volatile, because it has to survive the reset that is the whole point. VariableAttributes::NON_VOLATILE | VariableAttributes::BOOTSERVICE_ACCESS @@ -71,24 +66,21 @@ pub fn point_at_us(handle: Handle, system_table: &SystemTable) { } /// The GPT partition GUID of the volume firmware loaded this image from. -fn our_partition(handle: Handle, system_table: &SystemTable) -> Option<[u8; 16]> { +fn our_partition(handle: Handle, system_table: &SystemTable) -> Option<[u8; 16]> { let bs = system_table.boot_services(); - let image = crate::protocol::exclusive::(bs, handle).ok()?; + let image = bs.exclusive::(handle).ok()?; let device = image.device()?; - let path = crate::protocol::exclusive::(bs, device).ok()?; - hard_drive_guid(path.node_iter()) + let path = bs.exclusive::(device).ok()?; + hard_drive_guid(path.nodes()) } /// The GPT signature of the first HARDDRIVE node in a device path, or `None` /// where the path has none — a network boot, or a disk with no GPT. -fn hard_drive_guid<'a>(nodes: impl Iterator) -> Option<[u8; 16]> { - for node in nodes { - if node.full_type() != (DeviceType::MEDIA, DeviceSubType::MEDIA_HARD_DRIVE) { - continue; - } - let hd = <&uefi::proto::device_path::media::HardDrive>::try_from(node).ok()?; - if let PartitionSignature::Guid(guid) = hd.partition_signature() { - return Some(guid.to_bytes()); +fn hard_drive_guid<'a>(nodes: impl Iterator) -> Option<[u8; 16]> { + for node in nodes.filter(|node| (node[0], node[1]) == HardDrive::TYPE) { + let hd = HardDrive::parse(node)?; + if hd.signature_type == HardDrive::GUID_SIGNATURE { + return Some(hd.signature); } } None @@ -98,17 +90,16 @@ fn hard_drive_guid<'a>(nodes: impl Iterator, ours: &[u8; 16]) -> Option { +fn entry_for(system_table: &SystemTable, ours: &[u8; 16]) -> Option { let rt = system_table.runtime_services(); let keys = rt.variable_keys().ok()?; let mut found: Option = None; - for key in keys { - if key.vendor != VariableVendor::GLOBAL_VARIABLE { + for (name, vendor) in keys { + if vendor != GLOBAL_VARIABLE { continue; } - let Ok(name) = key.name() else { continue }; - let Some(number) = entry_number(name) else { continue }; - let Ok((bytes, _)) = rt.get_variable_boxed(name, &key.vendor) else { continue }; + let Some(number) = entry_number(&name) else { continue }; + let Ok((bytes, _)) = rt.get_variable(&name, &vendor) else { continue }; if !load_option_names(&bytes, ours) { continue; } @@ -121,7 +112,7 @@ fn entry_for(system_table: &SystemTable, ours: &[u8; 16]) -> Option { /// `Boot0003` is entry 3; anything else here is some other global variable. fn entry_number(name: &CStr16) -> Option { - let mut chars = name.iter().map(|c| char::from(*c)); + let mut chars = name.units().iter().map(|&unit| char::from_u32(u32::from(unit)).unwrap_or(char::REPLACEMENT_CHARACTER)); for want in ENTRY_PREFIX.chars() { if chars.next()? != want { return None; @@ -162,7 +153,7 @@ fn load_option_names(option: &[u8], ours: &[u8; 16]) -> bool { // A node shorter than its own header, or longer than what is left, ends // the walk: neither can be stepped over. let Some(this) = path.get(..len).filter(|_| len >= NODE_HEADER) else { return false }; - if this[0] == MEDIA_HARD_DRIVE.0 && this[1] == MEDIA_HARD_DRIVE.1 { + if (this[0], this[1]) == HardDrive::TYPE { if let Some(guid) = gpt_signature(this) { return guid == *ours; } @@ -175,18 +166,8 @@ fn load_option_names(option: &[u8], ours: &[u8; 16]) -> bool { /// A device path node's type, subtype and length (UEFI 2.10 §10.2). const NODE_HEADER: usize = 4; -/// The MEDIA/HARD_DRIVE node this looks for, as the two bytes it is on the wire. -const MEDIA_HARD_DRIVE: (u8, u8) = (4, 1); - -/// A HARD_DRIVE node's GPT signature, or `None` where it names an MBR one or -/// the node is short (UEFI 2.10 §10.3.6: the signature is sixteen bytes at -/// offset 24, and `SignatureType` 2 is the GPT one). +/// A HARD_DRIVE node's GUID signature, or `None` where it carries another or +/// is not the length §10.3.5.1 gives it. fn gpt_signature(node: &[u8]) -> Option<[u8; 16]> { - const SIGNATURE: usize = 24; - const SIGNATURE_TYPE: usize = 41; - const GPT: u8 = 2; - if node.get(SIGNATURE_TYPE) != Some(&GPT) { - return None; - } - node.get(SIGNATURE..SIGNATURE + 16)?.try_into().ok() + HardDrive::parse(node).filter(|hd| hd.signature_type == HardDrive::GUID_SIGNATURE).map(|hd| hd.signature) } diff --git a/bootloader/src/efi/boot.rs b/bootloader/src/efi/boot.rs new file mode 100644 index 00000000000..8009db982e2 --- /dev/null +++ b/bootloader/src/efi/boot.rs @@ -0,0 +1,402 @@ +//! `EFI_BOOT_SERVICES` (UEFI 2.10 §4.4) and what this loader calls of them: +//! pages and pool, the memory map, the watchdog, handles, protocols, and the +//! exit. +//! +//! **A protocol is opened two ways and no other.** EXCLUSIVE calls `Stop` on +//! every driver holding the protocol BY_DRIVER (UEFI 2.10 §7.3.9, +//! `OpenProtocol()`), and on `GraphicsOutput` that is the firmware's graphics +//! console, whose screen the loader's own lines are on. [`BootServices::get`] +//! opens GET_PROTOCOL, which stops nothing; [`BootServices::exclusive`] opens +//! only an [`Exclusive`] protocol, one no firmware console drives. + +use core::ffi::c_void; +use core::mem::offset_of; +use core::ptr::{self, NonNull}; + +use super::{Guid, Handle, Status, TableHeader}; + +/// Every page UEFI counts (§7.2.1). +pub const PAGE_SIZE: usize = 4096; + +/// `EfiLoaderData` (§7.2.1): what this loader allocates, and what the +/// firmware gives an application's data. +const LOADER_DATA: u32 = 2; + +type Unused = *const c_void; + +/// `EFI_BOOT_SERVICES` (§4.4), in the spec's own field order. +#[repr(C)] +pub struct BootServices { + hdr: TableHeader, + raise_tpl: Unused, + restore_tpl: Unused, + allocate_pages: unsafe extern "efiapi" fn(kind: u32, memory: u32, pages: usize, at: *mut u64) -> Status, + free_pages: unsafe extern "efiapi" fn(at: u64, pages: usize) -> Status, + get_memory_map: unsafe extern "efiapi" fn( + size: *mut usize, + map: *mut u64, + key: *mut usize, + descriptor_size: *mut usize, + descriptor_version: *mut u32, + ) -> Status, + allocate_pool: unsafe extern "efiapi" fn(memory: u32, size: usize, at: *mut *mut u8) -> Status, + free_pool: unsafe extern "efiapi" fn(at: *mut u8) -> Status, + create_event: Unused, + set_timer: Unused, + wait_for_event: Unused, + signal_event: Unused, + close_event: Unused, + check_event: Unused, + install_protocol_interface: Unused, + reinstall_protocol_interface: Unused, + uninstall_protocol_interface: Unused, + handle_protocol: Unused, + reserved: Unused, + register_protocol_notify: Unused, + locate_handle: Unused, + locate_device_path: Unused, + install_configuration_table: Unused, + load_image: Unused, + start_image: Unused, + exit: Unused, + unload_image: Unused, + exit_boot_services: unsafe extern "efiapi" fn(image: *mut c_void, key: usize) -> Status, + get_next_monotonic_count: Unused, + stall: Unused, + set_watchdog_timer: + unsafe extern "efiapi" fn(seconds: usize, code: u64, data_size: usize, data: *const u16) -> Status, + connect_controller: Unused, + disconnect_controller: Unused, + open_protocol: unsafe extern "efiapi" fn( + handle: *mut c_void, + protocol: *const Guid, + interface: *mut *mut c_void, + agent: *mut c_void, + controller: *mut c_void, + attributes: u32, + ) -> Status, + close_protocol: unsafe extern "efiapi" fn( + handle: *mut c_void, + protocol: *const Guid, + agent: *mut c_void, + controller: *mut c_void, + ) -> Status, + open_protocol_information: Unused, + protocols_per_handle: Unused, + locate_handle_buffer: unsafe extern "efiapi" fn( + search: u32, + protocol: *const Guid, + key: *const c_void, + count: *mut usize, + buffer: *mut *mut Handle, + ) -> Status, + locate_protocol: Unused, + install_multiple_protocol_interfaces: Unused, + uninstall_multiple_protocol_interfaces: Unused, + calculate_crc32: Unused, + copy_mem: Unused, + set_mem: Unused, + create_event_ex: Unused, +} + +const _: () = { + assert!(size_of::() == 24 + 44 * 8); + assert!(offset_of!(BootServices, allocate_pages) == 40); + assert!(offset_of!(BootServices, free_pages) == 48); + assert!(offset_of!(BootServices, get_memory_map) == 56); + assert!(offset_of!(BootServices, allocate_pool) == 64); + assert!(offset_of!(BootServices, free_pool) == 72); + assert!(offset_of!(BootServices, exit_boot_services) == 232); + assert!(offset_of!(BootServices, set_watchdog_timer) == 256); + assert!(offset_of!(BootServices, open_protocol) == 280); + assert!(offset_of!(BootServices, close_protocol) == 288); + assert!(offset_of!(BootServices, locate_handle_buffer) == 312); +}; + +/// `EFI_ALLOCATE_TYPE` (§7.2.1), as this loader asks. +pub enum AllocateType { + AnyPages, + Address(u64), +} + +/// `OpenProtocol`'s two attributes this loader passes (§7.3.9). +const GET_PROTOCOL: u32 = 0x02; +const EXCLUSIVE: u32 = 0x20; + +/// `ByProtocol` of `EFI_LOCATE_SEARCH_TYPE` (§7.3.15). +const BY_PROTOCOL: u32 = 2; + +/// An interface firmware installs on a handle. +/// +/// # Safety +/// `Self` is the layout of the interface installed under [`Protocol::GUID`]. +pub unsafe trait Protocol { + const GUID: Guid; +} + +/// A protocol this loader may hold EXCLUSIVE: one no firmware console drives. +pub trait Exclusive: Protocol {} + +/// A protocol open on a handle, closed when this drops. +pub struct Scoped<'a, P: Protocol> { + bs: &'a BootServices, + handle: Handle, + interface: NonNull

, +} + +impl core::ops::Deref for Scoped<'_, P> { + type Target = P; + fn deref(&self) -> &P { + // SAFETY: firmware's interface, installed under `P::GUID` and held + // open for as long as `self`. + unsafe { self.interface.as_ref() } + } +} + +impl Scoped<'_, P> { + /// The interface as firmware's functions take it, `This`. + pub fn this(&self) -> *mut P { + self.interface.as_ptr() + } +} + +impl Drop for Scoped<'_, P> { + fn drop(&mut self) { + // SAFETY: the open this undoes, under the same agent. + let status = unsafe { + (self.bs.close_protocol)(self.handle.as_ptr(), &P::GUID, super::image().as_ptr(), ptr::null_mut()) + }; + // Only a close that names another open fails, and this names its own. + assert!(status.is_success(), "CloseProtocol({}) answered {status}", P::GUID); + } +} + +/// The handles `LocateHandleBuffer` answered, in its pool buffer. +pub struct Handles<'a> { + bs: &'a BootServices, + at: NonNull, + count: usize, +} + +impl core::ops::Deref for Handles<'_> { + type Target = [Handle]; + fn deref(&self) -> &[Handle] { + // SAFETY: firmware answered `count` handles at `at`. + unsafe { core::slice::from_raw_parts(self.at.as_ptr(), self.count) } + } +} + +impl Drop for Handles<'_> { + fn drop(&mut self) { + // SAFETY: the pool buffer `LocateHandleBuffer` allocated for this answer. + let freed = unsafe { self.bs.free_pool(self.at.as_ptr().cast()) }; + assert!(freed.is_ok(), "firmware would not take back the handle buffer it gave"); + } +} + +/// `EFI_MEMORY_DESCRIPTOR` (§7.2.3). Firmware's stride is its own +/// `DescriptorSize`, never this struct's size. +#[derive(Clone, Copy)] +#[repr(C)] +pub struct MemoryDescriptor { + pub ty: u32, + pub phys_start: u64, + pub virt_start: u64, + pub page_count: u64, + pub att: u64, +} + +const _: () = { + assert!(size_of::() == 40); + assert!(offset_of!(MemoryDescriptor, phys_start) == 8); + assert!(offset_of!(MemoryDescriptor, page_count) == 24); + assert!(offset_of!(MemoryDescriptor, att) == 32); +}; + +impl MemoryDescriptor { + /// `EfiMemoryMappedIO` and `EfiMemoryMappedIOPortSpace` (§7.2.1). + pub const MMIO: u32 = 11; + pub const MMIO_PORT_SPACE: u32 = 12; + /// `EFI_MEMORY_WB` (§7.2.3). + pub const WRITE_BACK: u64 = 0x8; +} + +/// What `GetMemoryMap` wrote: its key and its extent. +#[derive(Clone, Copy)] +pub(super) struct Filled { + pub(super) key: usize, + size: usize, + entry_size: usize, +} + +/// The memory map in the buffer it was taken into. +pub struct MemoryMap<'a> { + words: &'a [u64], + filled: Filled, +} + +impl<'a> MemoryMap<'a> { + pub(super) fn new(words: &'a [u64], filled: Filled) -> Self { + MemoryMap { words, filled } + } + + pub fn entries(&self) -> Entries<'_> { + Entries { map: self, next: 0 } + } +} + +/// A [`MemoryMap`]'s descriptors, in firmware's order. +pub struct Entries<'a> { + map: &'a MemoryMap<'a>, + next: usize, +} + +impl Iterator for Entries<'_> { + type Item = MemoryDescriptor; + + fn next(&mut self) -> Option { + let Filled { size, entry_size, .. } = self.map.filled; + if self.next >= size / entry_size { + return None; + } + let at = self.next * entry_size; + self.next += 1; + // SAFETY: `fill_memory_map` checked the descriptors lie inside the + // buffer and that each is at least a `MemoryDescriptor` long. + Some(unsafe { self.map.words.as_ptr().cast::().add(at).cast::().read_unaligned() }) + } +} + +impl BootServices { + /// `AllocatePages` (§7.2.1), as `EfiLoaderData`. + pub fn allocate_pages(&self, kind: AllocateType, pages: usize) -> Result { + let (kind, mut at) = match kind { + AllocateType::AnyPages => (0, 0), + AllocateType::Address(at) => (2, at), + }; + // SAFETY: the out parameter is a live `u64`. + unsafe { (self.allocate_pages)(kind, LOADER_DATA, pages, &mut at) }.ok().map(|()| at) + } + + /// `FreePages` (§7.2.2). + /// + /// # Safety + /// `at` and `pages` are an allocation `allocate_pages` made, and nothing + /// reads or writes it after. + pub unsafe fn free_pages(&self, at: u64, pages: usize) -> Result<(), Status> { + // SAFETY: the caller's contract. + unsafe { (self.free_pages)(at, pages) }.ok() + } + + /// `AllocatePool` (§7.2.4), as `EfiLoaderData`: 8-byte aligned. + pub fn allocate_pool(&self, size: usize) -> Result<*mut u8, Status> { + let mut at = ptr::null_mut(); + // SAFETY: the out parameter is a live pointer. + unsafe { (self.allocate_pool)(LOADER_DATA, size, &mut at) }.ok().map(|()| at) + } + + /// `FreePool` (§7.2.5). + /// + /// # Safety + /// `at` is a pool allocation of firmware's, and nothing reads or writes it + /// after. + pub unsafe fn free_pool(&self, at: *mut u8) -> Result<(), Status> { + // SAFETY: the caller's contract. + unsafe { (self.free_pool)(at) }.ok() + } + + /// The bytes the memory map takes now, and the size of one descriptor. + pub fn memory_map_size(&self) -> (usize, usize) { + let (mut size, mut key, mut entry_size, mut version) = (0, 0, 0, 0); + // SAFETY: a zero size with no buffer asks only for the size (§7.2.3). + let status = + unsafe { (self.get_memory_map)(&mut size, ptr::null_mut(), &mut key, &mut entry_size, &mut version) }; + assert!(status == Status::BUFFER_TOO_SMALL, "GetMemoryMap with no buffer answered {status}"); + (size, entry_size) + } + + /// The memory map, taken into `words`. + pub fn memory_map<'b>(&self, words: &'b mut [u64]) -> Result, Status> { + let filled = self.fill_memory_map(words)?; + Ok(MemoryMap::new(words, filled)) + } + + pub(super) fn fill_memory_map(&self, words: &mut [u64]) -> Result { + let capacity = size_of_val(words); + let (mut size, mut key, mut entry_size, mut version) = (capacity, 0, 0, 0); + // SAFETY: `words` is `size` writable bytes, aligned for a descriptor. + unsafe { (self.get_memory_map)(&mut size, words.as_mut_ptr(), &mut key, &mut entry_size, &mut version) } + .ok()?; + assert!( + size <= capacity && entry_size >= size_of::(), + "GetMemoryMap answered {size} bytes of {entry_size}-byte descriptors into {capacity}" + ); + Ok(Filled { key, size, entry_size }) + } + + /// `ExitBootServices` (§7.4.6). + pub(super) fn exit(&self, image: Handle, key: usize) -> Status { + // SAFETY: the call is the spec's; the caller stops using boot services + // when it succeeds. + unsafe { (self.exit_boot_services)(image.as_ptr(), key) } + } + + /// This image's handle. + pub fn image_handle(&self) -> Handle { + super::image() + } + + /// `SetWatchdogTimer` (§7.5.1) with no data. + pub fn set_watchdog_timer(&self, seconds: usize, code: u64) -> Result<(), Status> { + // SAFETY: no data, so no pointer is read. + unsafe { (self.set_watchdog_timer)(seconds, code, 0, ptr::null()) }.ok() + } + + /// Every handle carrying `P` (`LocateHandleBuffer`, §7.3.15). + pub fn handles(&self) -> Result, Status> { + let (mut count, mut at) = (0usize, ptr::null_mut()); + // SAFETY: both out parameters are live. + unsafe { (self.locate_handle_buffer)(BY_PROTOCOL, &P::GUID, ptr::null(), &mut count, &mut at) }.ok()?; + let at = NonNull::new(at).expect("LocateHandleBuffer answered success with no buffer"); + Ok(Handles { bs: self, at, count }) + } + + /// The first handle carrying `P`. + pub fn handle_for(&self) -> Result { + self.handles::

()?.first().copied().ok_or(Status::NOT_FOUND) + } + + /// `P` on `handle`, GET_PROTOCOL: it stops no driver. + /// + /// Nothing between the open and the drop can uninstall the protocol: the + /// loader is the one image running, it registers no event callback, and it + /// calls no boot service that connects or disconnects a controller. + pub fn get(&self, handle: Handle) -> Result, Status> { + self.open(handle, GET_PROTOCOL) + } + + /// `P` on `handle`, EXCLUSIVE. + pub fn exclusive(&self, handle: Handle) -> Result, Status> { + self.open(handle, EXCLUSIVE) + } + + fn open(&self, handle: Handle, attributes: u32) -> Result, Status> { + let mut interface = ptr::null_mut(); + // SAFETY: the out parameter is live, and the agent is this image. + unsafe { + (self.open_protocol)( + handle.as_ptr(), + &P::GUID, + &mut interface, + super::image().as_ptr(), + ptr::null_mut(), + attributes, + ) + } + .ok()?; + let interface = NonNull::new(interface.cast::

()) + .unwrap_or_else(|| panic!("OpenProtocol({}) answered success with no interface", P::GUID)); + Ok(Scoped { bs: self, handle, interface }) + } +} + diff --git a/bootloader/src/efi/mod.rs b/bootloader/src/efi/mod.rs new file mode 100644 index 00000000000..39b9ec9db6c --- /dev/null +++ b/bootloader/src/efi/mod.rs @@ -0,0 +1,546 @@ +//! The UEFI this loader calls, and nothing it does not: UEFI 2.10's tables, +//! protocols, GUIDs and status codes, each laid out from the section cited at +//! it and held there by compile-time `size_of`/`offset_of!` asserts, so a field +//! added, dropped or resized fails the build of both targets. +//! +//! Firmware is the loader's host and is trusted to keep its own contracts; a +//! length it writes back about a buffer of this side's is still held to that +//! buffer. The safe wrappers each remove a hazard that is this side's: a +//! name handed over without its NUL, a protocol left open or opened in a way +//! that stops a driver, a boot service called once `ExitBootServices` has run. +//! +//! **Boot services end at [`SystemTable::exit_boot_services`]**, which consumes +//! the table; the console and the allocator, which reach firmware without it, +//! refuse from then on. + +mod boot; +mod proto; +mod runtime; + +use core::ffi::c_void; +use core::fmt; +use core::ptr::{self, NonNull}; +use core::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; + +use alloc::vec::Vec; + +pub use boot::{AllocateType, BootServices, MemoryDescriptor, MemoryMap, Scoped, PAGE_SIZE}; +pub use proto::{ + BlockIo, DevicePath, File, Gop, HardDrive, LoadedImage, Mode, PartitionInfo, PciRootBridgeIo, + PixelFormat, Rng, SimpleFileSystem, +}; +pub use runtime::{ResetType, RuntimeServices, Time, VariableAttributes, GLOBAL_VARIABLE}; + +/// `EFI_STATUS` (UEFI 2.10 Appendix D): success, a warning, or an error, +/// which carries the top bit. +#[derive(Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +#[must_use] +pub struct Status(pub usize); + +const ERROR: usize = 1 << (usize::BITS - 1); + +/// Appendix D's codes by name: every refusal this loader writes carries one. +const NAMES: [(usize, &str); 41] = [ + (0, "SUCCESS"), + (1, "WARN_UNKNOWN_GLYPH"), + (2, "WARN_DELETE_FAILURE"), + (3, "WARN_WRITE_FAILURE"), + (4, "WARN_BUFFER_TOO_SMALL"), + (5, "WARN_STALE_DATA"), + (6, "WARN_FILE_SYSTEM"), + (7, "WARN_RESET_REQUIRED"), + (ERROR | 1, "LOAD_ERROR"), + (ERROR | 2, "INVALID_PARAMETER"), + (ERROR | 3, "UNSUPPORTED"), + (ERROR | 4, "BAD_BUFFER_SIZE"), + (ERROR | 5, "BUFFER_TOO_SMALL"), + (ERROR | 6, "NOT_READY"), + (ERROR | 7, "DEVICE_ERROR"), + (ERROR | 8, "WRITE_PROTECTED"), + (ERROR | 9, "OUT_OF_RESOURCES"), + (ERROR | 10, "VOLUME_CORRUPTED"), + (ERROR | 11, "VOLUME_FULL"), + (ERROR | 12, "NO_MEDIA"), + (ERROR | 13, "MEDIA_CHANGED"), + (ERROR | 14, "NOT_FOUND"), + (ERROR | 15, "ACCESS_DENIED"), + (ERROR | 16, "NO_RESPONSE"), + (ERROR | 17, "NO_MAPPING"), + (ERROR | 18, "TIMEOUT"), + (ERROR | 19, "NOT_STARTED"), + (ERROR | 20, "ALREADY_STARTED"), + (ERROR | 21, "ABORTED"), + (ERROR | 22, "ICMP_ERROR"), + (ERROR | 23, "TFTP_ERROR"), + (ERROR | 24, "PROTOCOL_ERROR"), + (ERROR | 25, "INCOMPATIBLE_VERSION"), + (ERROR | 26, "SECURITY_VIOLATION"), + (ERROR | 27, "CRC_ERROR"), + (ERROR | 28, "END_OF_MEDIA"), + (ERROR | 31, "END_OF_FILE"), + (ERROR | 32, "INVALID_LANGUAGE"), + (ERROR | 33, "COMPROMISED_DATA"), + (ERROR | 34, "IP_ADDRESS_CONFLICT"), + (ERROR | 35, "HTTP_ERROR"), +]; + +impl Status { + pub const SUCCESS: Status = Status(0); + pub const BUFFER_TOO_SMALL: Status = Status(ERROR | 5); + pub const NOT_FOUND: Status = Status(ERROR | 14); + pub const ABORTED: Status = Status(ERROR | 21); + + pub fn is_success(self) -> bool { + self == Self::SUCCESS + } + + /// `Ok` for `SUCCESS` alone: a warning is not what was asked for, and is + /// refused like an error. + pub fn ok(self) -> Result<(), Status> { + if self.is_success() { Ok(()) } else { Err(self) } + } +} + +impl fmt::Debug for Status { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match NAMES.iter().find(|(code, _)| *code == self.0) { + Some((_, name)) => f.write_str(name), + None => write!(f, "Status({:#x})", self.0), + } + } +} + +impl fmt::Display for Status { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +/// `EFI_GUID` (UEFI 2.10 Appendix A): its three leading fields little-endian, +/// as it is held in memory and on a GPT disk. +#[derive(Clone, Copy, PartialEq, Eq)] +#[repr(C, align(4))] +pub struct Guid([u8; 16]); + +const _: () = assert!(size_of::() == 16); + +impl Guid { + /// The GUID the specification prints as `{a, b, c, {d...}}`. + pub const fn new(a: u32, b: u16, c: u16, d: [u8; 8]) -> Self { + let (a, b, c) = (a.to_le_bytes(), b.to_le_bytes(), c.to_le_bytes()); + Guid([a[0], a[1], a[2], a[3], b[0], b[1], c[0], c[1], d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]]) + } +} + +impl fmt::Display for Guid { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let b = &self.0; + write!( + f, + "{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", + u32::from_le_bytes([b[0], b[1], b[2], b[3]]), + u16::from_le_bytes([b[4], b[5]]), + u16::from_le_bytes([b[6], b[7]]), + b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], + ) + } +} + +/// `EFI_HANDLE` (UEFI 2.10 §2.3.1): opaque, and never null where firmware +/// hands one back. +#[derive(Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +pub struct Handle(NonNull); + +impl Handle { + fn from_ptr(ptr: *mut c_void) -> Option { + NonNull::new(ptr).map(Handle) + } + + fn as_ptr(self) -> *mut c_void { + self.0.as_ptr() + } +} + +/// A NUL-terminated `CHAR16` string (UEFI 2.10 §2.3.1), the only form a name +/// crosses to firmware in: the type is what keeps firmware from reading past +/// one handed over without its terminator. +#[repr(transparent)] +pub struct CStr16([u16]); + +impl CStr16 { + /// `units` as a name, where its last unit is its only NUL. + pub const fn from_units(units: &[u16]) -> Option<&CStr16> { + let Some((last, body)) = units.split_last() else { return None }; + if *last != 0 { + return None; + } + let mut i = 0; + while i < body.len() { + if body[i] == 0 { + return None; + } + i += 1; + } + // SAFETY: `CStr16` is `repr(transparent)` over `[u16]`. + Some(unsafe { &*(units as *const [u16] as *const CStr16) }) + } + + fn as_ptr(&self) -> *const u16 { + self.0.as_ptr() + } + + /// The units before the NUL. + pub fn units(&self) -> &[u16] { + &self.0[..self.0.len() - 1] + } +} + +impl fmt::Display for CStr16 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for unit in self.units() { + fmt::Write::write_char(f, char::from_u32(u32::from(*unit)).unwrap_or(char::REPLACEMENT_CHARACTER))?; + } + Ok(()) + } +} + +/// An owned [`CStr16`]. +pub struct CString16(Vec); + +impl CString16 { + /// `text` as a name, or `None` where it holds a NUL or a character past + /// UCS-2, which `CHAR16` cannot carry. + pub fn new(text: &str) -> Option { + let mut units = Vec::with_capacity(text.len() + 1); + for ch in text.chars() { + let unit = u16::try_from(u32::from(ch)).ok().filter(|&u| u != 0)?; + units.push(unit); + } + units.push(0); + Some(CString16(units)) + } +} + +impl core::ops::Deref for CString16 { + type Target = CStr16; + fn deref(&self) -> &CStr16 { + CStr16::from_units(&self.0).expect("a CString16 ends in its only NUL") + } +} + +impl fmt::Display for CString16 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +/// `text`, ASCII, as `CHAR16` units with the NUL: [`cstr16!`]'s body. +pub const fn ucs2(text: &str) -> [u16; N] { + let bytes = text.as_bytes(); + assert!(bytes.len() + 1 == N, "the array is the text and its NUL"); + let mut units = [0u16; N]; + let mut i = 0; + while i < bytes.len() { + assert!(bytes[i] != 0 && bytes[i] < 0x80, "a literal name is ASCII with no NUL"); + units[i] = bytes[i] as u16; + i += 1; + } + units +} + +/// A literal name as a `&'static CStr16`, checked at compile time. +macro_rules! cstr16 { + ($text:literal) => {{ + const UNITS: [u16; $text.len() + 1] = $crate::efi::ucs2($text); + const NAME: &$crate::efi::CStr16 = match $crate::efi::CStr16::from_units(&UNITS) { + Some(name) => name, + None => panic!("a literal name is its text and one NUL"), + }; + NAME + }}; +} +pub(crate) use cstr16; + +/// `EFI_TABLE_HEADER` (UEFI 2.10 §4.2). +#[repr(C)] +struct TableHeader { + signature: u64, + revision: u32, + header_size: u32, + crc32: u32, + reserved: u32, +} + +const _: () = assert!(size_of::() == 24); + +/// `EFI_SYSTEM_TABLE` (UEFI 2.10 §4.3). +#[repr(C)] +struct RawSystemTable { + hdr: TableHeader, + firmware_vendor: *const u16, + firmware_revision: u32, + console_in_handle: *mut c_void, + con_in: *mut c_void, + console_out_handle: *mut c_void, + con_out: *mut proto::TextOutput, + standard_error_handle: *mut c_void, + std_err: *mut c_void, + runtime_services: *const RuntimeServices, + boot_services: *const BootServices, + number_of_table_entries: usize, + configuration_table: *const ConfigurationTable, +} + +const _: () = { + assert!(size_of::() == 120); + assert!(core::mem::offset_of!(RawSystemTable, firmware_revision) == 32); + assert!(core::mem::offset_of!(RawSystemTable, con_out) == 64); + assert!(core::mem::offset_of!(RawSystemTable, runtime_services) == 88); + assert!(core::mem::offset_of!(RawSystemTable, boot_services) == 96); + assert!(core::mem::offset_of!(RawSystemTable, number_of_table_entries) == 104); + assert!(core::mem::offset_of!(RawSystemTable, configuration_table) == 112); +}; + +/// `EFI_CONFIGURATION_TABLE` (UEFI 2.10 §4.6). +#[repr(C)] +pub struct ConfigurationTable { + pub guid: Guid, + pub address: *const c_void, +} + +const _: () = assert!(size_of::() == 24); +const _: () = assert!(core::mem::offset_of!(ConfigurationTable, address) == 16); + +/// `EFI_ACPI_20_TABLE_GUID` (UEFI 2.10 §4.6.1). +pub const ACPI2_GUID: Guid = Guid::new(0x8868e871, 0xe4f1, 0x11d3, [0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81]); + +/// The system table firmware handed `efi_main`, while boot services live: +/// null before the entry and from [`SystemTable::exit_boot_services`] on. The +/// console and the allocator read it; nothing else does. +static SYSTEM: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + +/// This image's handle, the agent every protocol open names. +static IMAGE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + +/// The system table while boot services live: made once, by the entry, and +/// consumed by [`SystemTable::exit_boot_services`]. +pub struct SystemTable { + raw: &'static RawSystemTable, +} + +impl SystemTable { + pub fn boot_services(&self) -> &BootServices { + // SAFETY: firmware's table names its boot services for as long as they + // live, which is as long as `self`. + unsafe { &*self.raw.boot_services } + } + + pub fn runtime_services(&self) -> &RuntimeServices { + // SAFETY: as `boot_services`; runtime services outlive them. + unsafe { &*self.raw.runtime_services } + } + + pub fn config_table(&self) -> &[ConfigurationTable] { + // SAFETY: firmware's table names this many entries at this address. + unsafe { core::slice::from_raw_parts(self.raw.configuration_table, self.raw.number_of_table_entries) } + } + + /// `ClearScreen` (UEFI 2.10 §12.4.8), which also homes the cursor. + pub fn clear_screen(&self) -> Result<(), Status> { + let out = self.raw.con_out; + // SAFETY: `ConOut` is firmware's console for as long as boot services live. + unsafe { ((*out).clear_screen)(out) }.ok() + } + + /// `ExitBootServices` (UEFI 2.10 §7.4.6) on the map it is handed, taken + /// into pool memory it never frees; tried twice, as a map key gone stale + /// between the two calls is answered by asking again, and a machine that + /// refuses twice is reset. The console and the allocator refuse from here. + pub fn exit_boot_services(self) -> MemoryMap<'static> { + let bs = self.boot_services(); + let reset = |status: Status| -> ! { self.runtime_services().reset(ResetType::COLD, status) }; + // Eight descriptors past the measured map, for the ones the pool + // allocation below adds. + let (map_size, entry_size) = bs.memory_map_size(); + let Some(bytes) = entry_size.checked_mul(8).and_then(|extra| map_size.checked_add(extra)) else { + reset(Status::ABORTED) + }; + let words = bytes.div_ceil(size_of::()); + let buffer = match bs.allocate_pool(words * size_of::()) { + // SAFETY: the pool gives 8-byte-aligned memory (§7.2.4) of the + // size asked, never freed: it is this map's for good. + Ok(at) => unsafe { core::slice::from_raw_parts_mut(at.cast::(), words) }, + Err(status) => reset(status), + }; + let image = image(); + let mut status = Status::ABORTED; + for _ in 0..2 { + let filled = match bs.fill_memory_map(buffer) { + Ok(filled) => filled, + Err(why) => { + status = why; + continue; + } + }; + status = bs.exit(image, filled.key); + if status.is_success() { + SYSTEM.store(ptr::null_mut(), Ordering::Release); + return MemoryMap::new(buffer, filled); + } + } + reset(status) + } +} + +fn image() -> Handle { + Handle::from_ptr(IMAGE.load(Ordering::Acquire)).expect("the entry stored this image's handle") +} + +/// The system table while boot services live, for the two readers that run +/// without one in hand. +fn live() -> Option<&'static RawSystemTable> { + // SAFETY: `SYSTEM` is null or the table firmware handed the entry, whose + // boot services are live until `exit_boot_services` nulls it. + unsafe { SYSTEM.load(Ordering::Acquire).as_ref() } +} + +/// The image's entry (UEFI 2.10 §4.1, `EFI_IMAGE_ENTRY_POINT`), under the name +/// the UEFI targets link as the PE entry point. +#[unsafe(no_mangle)] +extern "efiapi" fn efi_main(image: *mut c_void, system_table: *mut RawSystemTable) -> Status { + // SAFETY: firmware hands its system table and this image's handle, live + // until `ExitBootServices`. + let raw = unsafe { system_table.as_ref() }.expect("firmware hands the entry its system table"); + let image = Handle::from_ptr(image).expect("firmware hands the entry this image's handle"); + IMAGE.store(image.as_ptr(), Ordering::Release); + SYSTEM.store(system_table, Ordering::Release); + crate::main(image, SystemTable { raw }) +} + +/// One line to firmware's console, `\n` as `\r\n`, in `CHAR16` chunks; a +/// character past UCS-2 is written as U+FFFD. +/// +/// # Panics +/// Once boot services are gone, and where the console refuses the line. +pub fn print(args: fmt::Arguments) { + let raw = live().expect("the console is gone with boot services"); + let mut out = Console { out: raw.con_out, units: [0; Console::CHUNK + 1], len: 0 }; + let written = fmt::write(&mut out, args).and_then(|()| out.flush()); + assert!(written.is_ok(), "firmware's console refused a line"); +} + +struct Console { + out: *mut proto::TextOutput, + units: [u16; Console::CHUNK + 1], + len: usize, +} + +impl Console { + const CHUNK: usize = 128; + + fn push(&mut self, unit: u16) -> fmt::Result { + self.units[self.len] = unit; + self.len += 1; + if self.len == Self::CHUNK { self.flush() } else { Ok(()) } + } + + fn flush(&mut self) -> fmt::Result { + if self.len == 0 { + return Ok(()); + } + self.units[self.len] = 0; + self.len = 0; + // SAFETY: `ConOut` is live while `SYSTEM` is set, and `units` is + // NUL-terminated at the count just written. + let status = unsafe { ((*self.out).output_string)(self.out, self.units.as_ptr()) }; + status.ok().map_err(|_| fmt::Error) + } +} + +impl fmt::Write for Console { + fn write_str(&mut self, s: &str) -> fmt::Result { + for ch in s.chars() { + if ch == '\n' { + self.push(u16::from(b'\r'))?; + } + self.push(u16::try_from(u32::from(ch)).unwrap_or(0xFFFD))?; + } + Ok(()) + } +} + +/// Rust's heap, in `EfiLoaderData` pool memory (UEFI 2.10 §7.2.4: a pool +/// allocation is 8-byte aligned; an application's data is `EfiLoaderData`, +/// §7.4.1), and null once boot services are gone. A wider alignment is cut +/// out of a larger allocation, the allocation's own address kept in the word +/// before it. +struct Pool; + +#[global_allocator] +static POOL: Pool = Pool; + +/// What `AllocatePool` aligns to. +const POOL_ALIGN: usize = 8; + +// SAFETY: every pointer handed out is pool memory of at least the layout's +// size at its alignment, and is given back only through `dealloc`. +unsafe impl core::alloc::GlobalAlloc for Pool { + unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { + let Some(raw) = live() else { return ptr::null_mut() }; + // SAFETY: live boot services. + let bs = unsafe { &*raw.boot_services }; + if layout.align() <= POOL_ALIGN { + return bs.allocate_pool(layout.size()).unwrap_or(ptr::null_mut()); + } + let Some(size) = layout.size().checked_add(layout.align()) else { return ptr::null_mut() }; + let Ok(whole) = bs.allocate_pool(size) else { return ptr::null_mut() }; + // At least one word ahead of the aligned address, for the allocation's own. + let offset = match whole.align_offset(layout.align()) { + 0 => layout.align(), + n => n, + }; + // SAFETY: `offset <= align`, inside the `size + align` bytes; the + // word before the aligned address is inside them too, as + // `offset >= POOL_ALIGN`, and aligned, as both addresses are. + unsafe { + let aligned = whole.add(offset); + aligned.cast::<*mut u8>().sub(1).write(whole); + aligned + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { + let raw = live().expect("nothing is freed once boot services are gone"); + let whole = if layout.align() <= POOL_ALIGN { + ptr + } else { + // SAFETY: `alloc` wrote the allocation's address in the word before. + unsafe { ptr.cast::<*mut u8>().sub(1).read() } + }; + // SAFETY: live boot services, and `whole` is a pool allocation of theirs. + let freed = unsafe { (*raw.boot_services).free_pool(whole) }; + assert!(freed.is_ok(), "firmware would not take back pool memory it gave"); + } +} + +/// Set by the first panic, so a panic while saying one goes straight to the +/// power-off. +static PANICKED: AtomicBool = AtomicBool::new(false); + +/// Say the panic on firmware's console and power the machine off; once boot +/// services are gone neither is there, and the CPU spins. +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + if let Some(raw) = live() { + if !PANICKED.swap(true, Ordering::Relaxed) { + print(format_args!("[PANIC]: {info}\n")); + } + // SAFETY: runtime services live as long as the table. + unsafe { &*raw.runtime_services }.reset(ResetType::SHUTDOWN, Status::ABORTED) + } + loop { + core::hint::spin_loop(); + } +} diff --git a/bootloader/src/efi/proto.rs b/bootloader/src/efi/proto.rs new file mode 100644 index 00000000000..d60c848a73b --- /dev/null +++ b/bootloader/src/efi/proto.rs @@ -0,0 +1,661 @@ +//! The protocols this loader opens, each in its spec section's own field +//! order, and the console it writes through. + +use core::ffi::c_void; +use core::mem::offset_of; +use core::ptr::{self, NonNull}; + +use alloc::vec; + +use super::boot::{Exclusive, Protocol}; +use super::{CStr16, Guid, Handle, Status}; + +type Unused = *const c_void; + +/// `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL` (UEFI 2.10 §12.4.1), firmware's console: +/// reached through the system table's `ConOut`, never opened. +#[repr(C)] +pub(super) struct TextOutput { + reset: Unused, + pub(super) output_string: unsafe extern "efiapi" fn(this: *mut TextOutput, string: *const u16) -> Status, + test_string: Unused, + query_mode: Unused, + set_mode: Unused, + set_attribute: Unused, + pub(super) clear_screen: unsafe extern "efiapi" fn(this: *mut TextOutput) -> Status, + set_cursor_position: Unused, + enable_cursor: Unused, + mode: Unused, +} + +const _: () = { + assert!(size_of::() == 80); + assert!(offset_of!(TextOutput, output_string) == 8); + assert!(offset_of!(TextOutput, clear_screen) == 48); +}; + +/// `EFI_LOADED_IMAGE_PROTOCOL` (UEFI 2.10 §9.1.1). +#[repr(C)] +pub struct LoadedImage { + revision: u32, + parent_handle: *mut c_void, + system_table: Unused, + device_handle: *mut c_void, + file_path: Unused, + reserved: Unused, + load_options_size: u32, + load_options: Unused, + image_base: *const c_void, + image_size: u64, + image_code_type: u32, + image_data_type: u32, + unload: Unused, +} + +const _: () = { + assert!(size_of::() == 96); + assert!(offset_of!(LoadedImage, device_handle) == 24); + assert!(offset_of!(LoadedImage, load_options_size) == 48); + assert!(offset_of!(LoadedImage, image_base) == 64); + assert!(offset_of!(LoadedImage, image_size) == 72); + assert!(offset_of!(LoadedImage, image_data_type) == 84); +}; + +// SAFETY: §9.1.1's layout, under its GUID. +unsafe impl Protocol for LoadedImage { + const GUID: Guid = Guid::new(0x5b1b31a1, 0x9562, 0x11d2, [0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b]); +} +impl Exclusive for LoadedImage {} + +impl LoadedImage { + /// The handle of the device firmware loaded this image from, if it says. + pub fn device(&self) -> Option { + Handle::from_ptr(self.device_handle) + } + + /// Where firmware loaded the image, and its size in bytes. + pub fn info(&self) -> (*const c_void, u64) { + (self.image_base, self.image_size) + } +} + +/// `EFI_DEVICE_PATH_PROTOCOL` (UEFI 2.10 §10.2): the first node's header, +/// which the rest of the path follows. +#[repr(C)] +pub struct DevicePath { + ty: u8, + sub_type: u8, + length: [u8; 2], +} + +const _: () = assert!(size_of::() == 4); + +// SAFETY: §10.2's layout, under its GUID. +unsafe impl Protocol for DevicePath { + const GUID: Guid = Guid::new(0x09576e91, 0x6d3f, 0x11d2, [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b]); +} +impl Exclusive for DevicePath {} + +/// A device path node's header: type, subtype, and a length that counts it. +const NODE_HEADER: usize = 4; + +/// End of Entire Device Path (§10.3.1). +const END_ENTIRE: (u8, u8) = (0x7f, 0xff); + +impl DevicePath { + /// Each node, whole, up to the End of Entire node. + /// + /// # Panics + /// Where a node's length does not cover its own header: the walk could + /// not step past it. + pub fn nodes(&self) -> impl Iterator { + let mut at = ptr::from_ref(self).cast::(); + core::iter::from_fn(move || { + // SAFETY: firmware's path is a run of nodes ending in End of + // Entire, and `at` is the start of one of them. + let header = unsafe { core::slice::from_raw_parts(at, NODE_HEADER) }; + if (header[0], header[1]) == END_ENTIRE { + return None; + } + let len = usize::from(u16::from_le_bytes([header[2], header[3]])); + assert!(len >= NODE_HEADER, "firmware's device path has a {len}-byte node"); + // SAFETY: the node's own length, which counts its header. + let node = unsafe { core::slice::from_raw_parts(at, len) }; + // SAFETY: the next node follows this one. + at = unsafe { at.add(len) }; + Some(node) + }) + } +} + +/// The MEDIA/HARDDRIVE node (§10.3.5.1). +pub struct HardDrive { + pub start: u64, + pub size: u64, + pub signature: [u8; 16], + /// `MBRType`: 2 for a GPT partition. + pub format: u8, + /// `SignatureType`: 2 for a GUID signature. + pub signature_type: u8, +} + +impl HardDrive { + pub const TYPE: (u8, u8) = (4, 1); + /// `MBRType` of a GPT partition. + pub const GPT: u8 = 2; + /// `SignatureType` of a GUID signature. + pub const GUID_SIGNATURE: u8 = 2; + const LEN: usize = 42; + + /// `node`, where it is a HARDDRIVE node of the length §10.3.5.1 gives it. + pub fn parse(node: &[u8]) -> Option { + if node.len() != Self::LEN || (node[0], node[1]) != Self::TYPE { + return None; + } + let u64_at = |at: usize| u64::from_le_bytes(node[at..at + 8].try_into().expect("eight bytes")); + Some(HardDrive { + start: u64_at(8), + size: u64_at(16), + signature: node[24..40].try_into().expect("sixteen bytes"), + format: node[40], + signature_type: node[41], + }) + } +} + +/// `EFI_SIMPLE_FILE_SYSTEM_PROTOCOL` (UEFI 2.10 §13.4.1). +#[repr(C)] +pub struct SimpleFileSystem { + revision: u64, + open_volume: unsafe extern "efiapi" fn(this: *mut SimpleFileSystem, root: *mut *mut FileProtocol) -> Status, +} + +const _: () = assert!(size_of::() == 16); + +// SAFETY: §13.4.1's layout, under its GUID. +unsafe impl Protocol for SimpleFileSystem { + const GUID: Guid = Guid::new(0x964e5b22, 0x6459, 0x11d2, [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b]); +} +impl Exclusive for SimpleFileSystem {} + +impl super::Scoped<'_, SimpleFileSystem> { + /// `OpenVolume` (§13.4.2): the volume's root directory. + pub fn open_volume(&mut self) -> Result { + let mut root = ptr::null_mut(); + // SAFETY: the open interface, and a live out parameter. + unsafe { (self.open_volume)(self.this(), &mut root) }.ok()?; + Ok(File(NonNull::new(root).expect("OpenVolume answered success with no root"))) + } +} + +/// `EFI_FILE_PROTOCOL` (UEFI 2.10 §13.5.1), through `Flush`: the revision 2 +/// functions after it are never called. +#[repr(C)] +pub struct FileProtocol { + revision: u64, + open: unsafe extern "efiapi" fn( + this: *mut FileProtocol, + new: *mut *mut FileProtocol, + name: *const u16, + mode: u64, + attributes: u64, + ) -> Status, + close: unsafe extern "efiapi" fn(this: *mut FileProtocol) -> Status, + delete: unsafe extern "efiapi" fn(this: *mut FileProtocol) -> Status, + read: unsafe extern "efiapi" fn(this: *mut FileProtocol, size: *mut usize, buffer: *mut u8) -> Status, + write: unsafe extern "efiapi" fn(this: *mut FileProtocol, size: *mut usize, buffer: *const u8) -> Status, + get_position: Unused, + set_position: unsafe extern "efiapi" fn(this: *mut FileProtocol, position: u64) -> Status, + get_info: unsafe extern "efiapi" fn( + this: *mut FileProtocol, + kind: *const Guid, + size: *mut usize, + buffer: *mut u8, + ) -> Status, + set_info: Unused, + flush: unsafe extern "efiapi" fn(this: *mut FileProtocol) -> Status, +} + +const _: () = { + assert!(size_of::() == 88); + assert!(offset_of!(FileProtocol, open) == 8); + assert!(offset_of!(FileProtocol, close) == 16); + assert!(offset_of!(FileProtocol, delete) == 24); + assert!(offset_of!(FileProtocol, read) == 32); + assert!(offset_of!(FileProtocol, write) == 40); + assert!(offset_of!(FileProtocol, set_position) == 56); + assert!(offset_of!(FileProtocol, get_info) == 64); + assert!(offset_of!(FileProtocol, flush) == 80); +}; + +/// `Open`'s modes (§13.5.2). +#[derive(Clone, Copy)] +pub enum Mode { + Read, + ReadWrite, + CreateReadWrite, +} + +impl Mode { + fn bits(self) -> u64 { + const READ: u64 = 0x1; + const WRITE: u64 = 0x2; + const CREATE: u64 = 0x8000_0000_0000_0000; + match self { + Mode::Read => READ, + Mode::ReadWrite => READ | WRITE, + Mode::CreateReadWrite => CREATE | READ | WRITE, + } + } +} + +/// An open file or directory, closed when this drops. +pub struct File(NonNull); + +/// `EFI_FILE_INFO` (§13.5.16), up to the name this loader never reads. +#[repr(C)] +struct RawFileInfo { + size: u64, + file_size: u64, + physical_size: u64, + create_time: super::Time, + last_access_time: super::Time, + modification_time: super::Time, + attribute: u64, +} + +const _: () = { + assert!(size_of::() == 80); + assert!(offset_of!(RawFileInfo, file_size) == 8); + assert!(offset_of!(RawFileInfo, attribute) == 72); +}; + +/// `EFI_FILE_INFO_ID` (§13.5.16). +const FILE_INFO: Guid = Guid::new(0x09576e92, 0x6d3f, 0x11d2, [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b]); + +/// `EFI_FILE_DIRECTORY` (§13.5.16). +const DIRECTORY: u64 = 0x10; + +/// What this loader reads of a file's `EFI_FILE_INFO`. +pub struct FileInfo { + pub file_size: u64, + pub directory: bool, +} + +impl File { + fn call(&mut self, f: impl FnOnce(&FileProtocol, *mut FileProtocol) -> R) -> R { + // SAFETY: an open handle's interface, live until it is closed. + f(unsafe { self.0.as_ref() }, self.0.as_ptr()) + } + + /// `Open` (§13.5.2), relative to this directory. + pub fn open(&mut self, name: &CStr16, mode: Mode) -> Result { + let mut new = ptr::null_mut(); + // SAFETY: a NUL-terminated name and a live out parameter. + self.call(|f, this| unsafe { (f.open)(this, &mut new, name.as_ptr(), mode.bits(), 0) }).ok()?; + Ok(File(NonNull::new(new).expect("Open answered success with no handle"))) + } + + /// `Delete` (§13.5.4), which closes the handle whatever it answers. + pub fn delete(mut self) -> Result<(), Status> { + // SAFETY: the handle, which `Delete` closes, so `Drop` must not. + let status = self.call(|f, this| unsafe { (f.delete)(this) }); + #[expect(clippy::disallowed_methods, reason = "`Delete` closed the handle `Drop` would close again")] + core::mem::forget(self); + status.ok() + } + + /// `Read` (§13.5.5): the bytes read, at most `buffer`'s length. + pub fn read(&mut self, buffer: &mut [u8]) -> Result { + let mut size = buffer.len(); + // SAFETY: `buffer` is `size` writable bytes. + self.call(|f, this| unsafe { (f.read)(this, &mut size, buffer.as_mut_ptr()) }).ok()?; + assert!(size <= buffer.len(), "Read answered {size} bytes into {}", buffer.len()); + Ok(size) + } + + /// `Write` (§13.5.6): on a refusal, the status and the bytes written + /// before it. + pub fn write(&mut self, buffer: &[u8]) -> Result<(), (Status, usize)> { + let mut size = buffer.len(); + // SAFETY: `buffer` is `size` readable bytes. + self.call(|f, this| unsafe { (f.write)(this, &mut size, buffer.as_ptr()) }).ok().map_err(|status| (status, size)) + } + + /// `SetPosition` (§13.5.8); `u64::MAX` is the end of the file. + pub fn set_position(&mut self, position: u64) -> Result<(), Status> { + // SAFETY: a plain call on the handle. + self.call(|f, this| unsafe { (f.set_position)(this, position) }).ok() + } + + /// `Flush` (§13.5.11). + pub fn flush(&mut self) -> Result<(), Status> { + // SAFETY: a plain call on the handle. + self.call(|f, this| unsafe { (f.flush)(this) }).ok() + } + + /// `GetInfo` (§13.5.12) of `EFI_FILE_INFO`, sized by asking first. + pub fn info(&mut self) -> Result { + let mut size = 0usize; + // SAFETY: a zero size with no buffer asks for the size. + let status = self.call(|f, this| unsafe { (f.get_info)(this, &FILE_INFO, &mut size, ptr::null_mut()) }); + if status != Status::BUFFER_TOO_SMALL { + return Err(if status.is_success() { Status::BUFFER_TOO_SMALL } else { status }); + } + assert!(size >= size_of::(), "GetInfo wants {size} bytes for an EFI_FILE_INFO"); + let mut words = vec![0u64; size.div_ceil(size_of::())]; + // SAFETY: `words` is at least `size` writable bytes, aligned for the info. + self.call(|f, this| unsafe { (f.get_info)(this, &FILE_INFO, &mut size, words.as_mut_ptr().cast()) }).ok()?; + // SAFETY: firmware wrote an `EFI_FILE_INFO`, whose head is this. + let info = unsafe { words.as_ptr().cast::().read() }; + Ok(FileInfo { file_size: info.file_size, directory: info.attribute & DIRECTORY != 0 }) + } + + /// This handle, where it is a file and not a directory; `None` for a + /// directory, and for a handle that would not say which it is. + pub fn into_regular_file(mut self) -> Option { + match self.info() { + Ok(FileInfo { directory: false, .. }) => Some(self), + _ => None, + } + } +} + +impl Drop for File { + fn drop(&mut self) { + // SAFETY: the handle, closed once. `Close` always succeeds (§13.5.3). + let _ = self.call(|f, this| unsafe { (f.close)(this) }); + } +} + +/// `EFI_PARTITION_INFO_PROTOCOL` (UEFI 2.10 §13.18), packed as the spec +/// declares it; the record is MBR or GPT by `kind`, read as bytes. +#[repr(C, packed)] +pub struct PartitionInfo { + revision: u32, + kind: u32, + system: u8, + reserved: [u8; 7], + record: [u8; 128], +} + +const _: () = { + assert!(size_of::() == 144); + assert!(offset_of!(PartitionInfo, kind) == 4); + assert!(offset_of!(PartitionInfo, system) == 8); + assert!(offset_of!(PartitionInfo, record) == 16); +}; + +// SAFETY: §13.18's layout, under its GUID. +unsafe impl Protocol for PartitionInfo { + const GUID: Guid = Guid::new(0x8cf2f62c, 0xbc9b, 0x4821, [0x80, 0x8d, 0xec, 0x9e, 0xc4, 0x21, 0xa1, 0xa0]); +} + +impl PartitionInfo { + /// `EFI_PARTITION_INFO_PROTOCOL_REVISION`, which the spec spells `0x0001000`. + const REVISION: u32 = 0x1000; + /// `PARTITION_TYPE_GPT`. + const GPT: u32 = 0x02; + + /// The unique partition GUID of the GPT entry this carries (UEFI 2.10 + /// §5.3.3, bytes 16 to 32 of the entry), or `None` for any other record. + pub fn gpt_unique_guid(&self) -> Option<[u8; 16]> { + let (revision, kind) = (self.revision, self.kind); + if revision != Self::REVISION || kind != Self::GPT { + return None; + } + let record = self.record; + Some(record[16..32].try_into().expect("sixteen bytes")) + } +} + +/// `EFI_BLOCK_IO_PROTOCOL` (UEFI 2.10 §13.9.1). +#[repr(C)] +pub struct BlockIo { + pub revision: u64, + media: *const BlockIoMedia, + reset: Unused, + read_blocks: unsafe extern "efiapi" fn( + this: *mut BlockIo, + media_id: u32, + lba: u64, + size: usize, + buffer: *mut u8, + ) -> Status, + write_blocks: Unused, + flush_blocks: Unused, +} + +const _: () = { + assert!(size_of::() == 48); + assert!(offset_of!(BlockIo, media) == 8); + assert!(offset_of!(BlockIo, read_blocks) == 24); +}; + +// SAFETY: §13.9.1's layout, under its GUID. +unsafe impl Protocol for BlockIo { + const GUID: Guid = Guid::new(0x964e5b21, 0x6459, 0x11d2, [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b]); +} + +/// `EFI_BLOCK_IO_MEDIA` (§13.9.1); `optimal_transfer_length_granularity` is +/// there only from `EFI_BLOCK_IO_PROTOCOL_REVISION3` on. +#[derive(Clone, Copy)] +#[repr(C)] +pub struct BlockIoMedia { + pub media_id: u32, + removable_media: u8, + media_present: u8, + logical_partition: u8, + read_only: u8, + write_caching: u8, + pub block_size: u32, + pub io_align: u32, + pub last_block: u64, +} + +/// The revision 2 and 3 fields after `LastBlock`. +#[repr(C)] +struct BlockIoMediaRevision3 { + head: BlockIoMedia, + lowest_aligned_lba: u64, + logical_blocks_per_physical_block: u32, + optimal_transfer_length_granularity: u32, +} + +const _: () = { + assert!(size_of::() == 32); + assert!(offset_of!(BlockIoMedia, media_present) == 5); + assert!(offset_of!(BlockIoMedia, block_size) == 12); + assert!(offset_of!(BlockIoMedia, io_align) == 16); + assert!(offset_of!(BlockIoMedia, last_block) == 24); + assert!(size_of::() == 48); + assert!(offset_of!(BlockIoMediaRevision3, optimal_transfer_length_granularity) == 44); +}; + +impl BlockIoMedia { + pub fn is_media_present(&self) -> bool { + self.media_present != 0 + } +} + +impl BlockIo { + /// The first revision whose media carries `OptimalTransferLengthGranularity`. + pub const REVISION3: u64 = 0x0002_001f; + + /// The media as firmware describes it now, through `LastBlock`. + pub fn media(&self) -> BlockIoMedia { + // SAFETY: every revision's media begins with this head. + unsafe { self.media.read() } + } + + /// `OptimalTransferLengthGranularity`, where the revision carries it. + pub fn optimal_transfer_length_granularity(&self) -> Option { + if self.revision < Self::REVISION3 { + return None; + } + // SAFETY: a revision 3 media carries the field. + Some(unsafe { (*self.media.cast::()).optimal_transfer_length_granularity }) + } +} + +impl super::Scoped<'_, BlockIo> { + /// `ReadBlocks` (§13.9.3): `buffer`'s length in blocks from `lba`. + pub fn read_blocks(&self, media_id: u32, lba: u64, buffer: &mut [u8]) -> Result<(), Status> { + // SAFETY: the open interface, and `buffer` is its length of writable bytes. + unsafe { (self.read_blocks)(self.this(), media_id, lba, buffer.len(), buffer.as_mut_ptr()) }.ok() + } +} + +/// `EFI_GRAPHICS_OUTPUT_PROTOCOL` (UEFI 2.10 §12.9.2). +#[repr(C)] +pub struct Gop { + query_mode: Unused, + set_mode: Unused, + blt: Unused, + mode: *const GopMode, +} + +/// `EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE` (§12.9.2). +#[repr(C)] +struct GopMode { + max_mode: u32, + mode: u32, + info: *const GopModeInfo, + size_of_info: usize, + frame_buffer_base: u64, + frame_buffer_size: usize, +} + +/// `EFI_GRAPHICS_OUTPUT_MODE_INFORMATION` (§12.9.2). +#[repr(C)] +pub struct GopModeInfo { + version: u32, + pub horizontal_resolution: u32, + pub vertical_resolution: u32, + pub pixel_format: PixelFormat, + pixel_information: [u32; 4], + pub pixels_per_scan_line: u32, +} + +const _: () = { + assert!(size_of::() == 32); + assert!(offset_of!(Gop, mode) == 24); + assert!(size_of::() == 40); + assert!(offset_of!(GopMode, info) == 8); + assert!(offset_of!(GopMode, frame_buffer_base) == 24); + assert!(offset_of!(GopMode, frame_buffer_size) == 32); + assert!(size_of::() == 36); + assert!(offset_of!(GopModeInfo, pixel_format) == 12); + assert!(offset_of!(GopModeInfo, pixels_per_scan_line) == 32); +}; + +/// `EFI_GRAPHICS_PIXEL_FORMAT` (§12.9.2), as the raw word firmware wrote. +#[derive(Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +pub struct PixelFormat(pub u32); + +impl PixelFormat { + pub const RGB: PixelFormat = PixelFormat(0); + pub const BGR: PixelFormat = PixelFormat(1); + pub const BIT_MASK: PixelFormat = PixelFormat(2); + pub const BLT_ONLY: PixelFormat = PixelFormat(3); +} + +impl core::fmt::Debug for PixelFormat { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match *self { + Self::RGB => f.write_str("PixelRedGreenBlueReserved8BitPerColor"), + Self::BGR => f.write_str("PixelBlueGreenRedReserved8BitPerColor"), + Self::BIT_MASK => f.write_str("PixelBitMask"), + Self::BLT_ONLY => f.write_str("PixelBltOnly"), + PixelFormat(other) => write!(f, "PixelFormat({other})"), + } + } +} + +// SAFETY: §12.9.2's layout, under its GUID. +unsafe impl Protocol for Gop { + const GUID: Guid = Guid::new(0x9042a9de, 0x23dc, 0x4a38, [0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a]); +} + +impl Gop { + /// The mode firmware set. + pub fn current_mode_info(&self) -> &GopModeInfo { + // SAFETY: an open GOP names its mode and the mode its information. + unsafe { &*(*self.mode).info } + } + + /// The frame buffer's physical base and size in bytes. + pub fn frame_buffer(&self) -> (u64, u64) { + // SAFETY: an open GOP names its mode. + let mode = unsafe { &*self.mode }; + (mode.frame_buffer_base, mode.frame_buffer_size as u64) + } +} + +/// `EFI_RNG_PROTOCOL` (UEFI 2.10 §37.5.1). +#[repr(C)] +pub struct Rng { + get_info: Unused, + get_rng: unsafe extern "efiapi" fn(this: *mut Rng, algorithm: *const Guid, size: usize, value: *mut u8) -> Status, +} + +const _: () = assert!(size_of::() == 16); + +// SAFETY: §37.5.1's layout, under its GUID. +unsafe impl Protocol for Rng { + const GUID: Guid = Guid::new(0x3152bca5, 0xeade, 0x433d, [0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44]); +} + +impl super::Scoped<'_, Rng> { + /// `GetRNG` (§37.5.3) with no algorithm named: firmware's default. + pub fn get_rng(&self, into: &mut [u8]) -> Result<(), Status> { + // SAFETY: the open interface, and `into` is its length of writable bytes. + unsafe { (self.get_rng)(self.this(), ptr::null(), into.len(), into.as_mut_ptr()) }.ok() + } +} + +/// `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL` (UEFI 2.10 §14.2.1). +#[repr(C)] +pub struct PciRootBridgeIo { + parent_handle: Unused, + poll_mem: Unused, + poll_io: Unused, + mem_read: Unused, + mem_write: Unused, + io_read: Unused, + io_write: Unused, + pci_read: Unused, + pci_write: Unused, + copy_mem: Unused, + map: Unused, + unmap: Unused, + allocate_buffer: Unused, + free_buffer: Unused, + flush: Unused, + get_attributes: Unused, + set_attributes: Unused, + configuration: unsafe extern "efiapi" fn(this: *mut PciRootBridgeIo, resources: *mut *const c_void) -> Status, + pub segment_number: u32, +} + +const _: () = { + assert!(size_of::() == 18 * 8 + 8); + assert!(offset_of!(PciRootBridgeIo, configuration) == 17 * 8); + assert!(offset_of!(PciRootBridgeIo, segment_number) == 18 * 8); +}; + +// SAFETY: §14.2.1's layout, under its GUID. +unsafe impl Protocol for PciRootBridgeIo { + const GUID: Guid = Guid::new(0x2f707ebb, 0x4a1a, 0x11d4, [0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d]); +} + +impl super::Scoped<'_, PciRootBridgeIo> { + /// `Configuration()` (§14.2.13): the bridge's ACPI resource descriptors, + /// in memory firmware owns. + pub fn configuration(&self) -> Result<*const c_void, Status> { + let mut resources = ptr::null(); + // SAFETY: the open interface, and a live out parameter. + unsafe { (self.configuration)(self.this(), &mut resources) }.ok().map(|()| resources) + } +} diff --git a/bootloader/src/efi/runtime.rs b/bootloader/src/efi/runtime.rs new file mode 100644 index 00000000000..16bca2e3487 --- /dev/null +++ b/bootloader/src/efi/runtime.rs @@ -0,0 +1,175 @@ +//! `EFI_RUNTIME_SERVICES` (UEFI 2.10 §4.5) and what this loader calls of +//! them: the time, variables, and the reset. + +use core::ffi::c_void; +use core::mem::{offset_of, MaybeUninit}; +use core::ptr; + +use alloc::vec; +use alloc::vec::Vec; + +use super::{CStr16, CString16, Guid, Status, TableHeader}; + +type Unused = *const c_void; + +/// `EFI_RUNTIME_SERVICES` (§4.5), in the spec's own field order. +#[repr(C)] +pub struct RuntimeServices { + hdr: TableHeader, + get_time: unsafe extern "efiapi" fn(time: *mut Time, capabilities: *mut c_void) -> Status, + set_time: Unused, + get_wakeup_time: Unused, + set_wakeup_time: Unused, + set_virtual_address_map: Unused, + convert_pointer: Unused, + get_variable: unsafe extern "efiapi" fn( + name: *const u16, + vendor: *const Guid, + attributes: *mut u32, + size: *mut usize, + data: *mut u8, + ) -> Status, + get_next_variable_name: unsafe extern "efiapi" fn(size: *mut usize, name: *mut u16, vendor: *mut Guid) -> Status, + set_variable: unsafe extern "efiapi" fn( + name: *const u16, + vendor: *const Guid, + attributes: u32, + size: usize, + data: *const u8, + ) -> Status, + get_next_high_monotonic_count: Unused, + reset_system: unsafe extern "efiapi" fn(kind: ResetType, status: Status, size: usize, data: *const c_void) -> !, + update_capsule: Unused, + query_capsule_capabilities: Unused, + query_variable_info: Unused, +} + +const _: () = { + assert!(size_of::() == 24 + 14 * 8); + assert!(offset_of!(RuntimeServices, get_time) == 24); + assert!(offset_of!(RuntimeServices, get_variable) == 72); + assert!(offset_of!(RuntimeServices, get_next_variable_name) == 80); + assert!(offset_of!(RuntimeServices, set_variable) == 88); + assert!(offset_of!(RuntimeServices, reset_system) == 104); +}; + +/// `EFI_TIME` (§8.3). +#[derive(Clone, Copy)] +#[repr(C)] +pub struct Time { + pub year: u16, + pub month: u8, + pub day: u8, + pub hour: u8, + pub minute: u8, + pub second: u8, + pad1: u8, + pub nanosecond: u32, + pub time_zone: i16, + pub daylight: u8, + pad2: u8, +} + +const _: () = { + assert!(size_of::

(handle) -} - -#[allow(clippy::disallowed_methods, reason = "the one attribute it passes stops no driver")] -pub fn get(bs: &BootServices, handle: Handle) -> uefi::Result> { - // SAFETY: `open_protocol`'s obligation is that the handle and its protocol - // stay installed until the `ScopedProtocol` drops. Nothing between the two - // can uninstall either: the loader is the one image running, it registers - // no event callback, and it calls no boot service that connects or - // disconnects a controller. - unsafe { - bs.open_protocol::

( - OpenProtocolParams { handle, agent: bs.image_handle(), controller: None }, - OpenProtocolAttributes::GetProtocol, - ) - } -} diff --git a/bootloader/src/rootbridge.rs b/bootloader/src/rootbridge.rs index c1682f0d55b..f6d3060e8d9 100644 --- a/bootloader/src/rootbridge.rs +++ b/bootloader/src/rootbridge.rs @@ -12,47 +12,14 @@ //! the reason [`toyos_abi::boot::KernelArgs::root_bridge_windows`] states: a //! list missing one window is worse than no list. -use core::ffi::c_void; use core::ptr::read_volatile; use toyos_abi::boot::RootBridgeWindow; use toyos_acpi::{memory_windows, Phys, MAX_LIST_BYTES}; -use uefi::prelude::*; -use uefi::proto::unsafe_protocol; +use crate::efi::{PciRootBridgeIo, Status, SystemTable}; const HEAD: &str = "Root bridge:"; -/// UEFI 2.10 §14.2.2, in the spec's own field order. -#[repr(C)] -#[unsafe_protocol("2f707ebb-4a1a-11d4-9a38-0090273fc14d")] -struct PciRootBridgeIo { - parent_handle: *mut c_void, - poll_mem: *mut c_void, - poll_io: *mut c_void, - mem_read: *mut c_void, - mem_write: *mut c_void, - io_read: *mut c_void, - io_write: *mut c_void, - pci_read: *mut c_void, - pci_write: *mut c_void, - copy_mem: *mut c_void, - map: *mut c_void, - unmap: *mut c_void, - allocate_buffer: *mut c_void, - free_buffer: *mut c_void, - flush: *mut c_void, - get_attributes: *mut c_void, - set_attributes: *mut c_void, - configuration: - unsafe extern "efiapi" fn(this: *const PciRootBridgeIo, resources: *mut *const c_void) - -> Status, - segment_number: u32, -} - -/// A field added or dropped above moves `configuration`, and the symptom is -/// firmware calling something else. -const _: () = assert!(core::mem::size_of::() == 18 * 8 + 8); - /// The descriptor list firmware answered with. /// /// Boot services identity-map physical memory, so the pointer is the address @@ -79,9 +46,9 @@ impl Phys for List { /// Every memory window this machine's root bridges decode, written into `out`; /// the count, or zero on a machine that would not say. -pub fn windows(system_table: &SystemTable, out: &mut [RootBridgeWindow]) -> usize { +pub fn windows(system_table: &SystemTable, out: &mut [RootBridgeWindow]) -> usize { let bs = system_table.boot_services(); - let handles = match bs.find_handles::() { + let handles = match bs.handles::() { Ok(handles) => handles, Err(e) => { println!("{HEAD} no handle carries the PCI Root Bridge I/O protocol ({e}), so the kernel is handed no window"); @@ -91,7 +58,7 @@ pub fn windows(system_table: &SystemTable, out: &mut [RootBridgeWindow]) - let mut found = 0usize; for (index, handle) in handles.iter().enumerate() { - let bridge = match crate::protocol::get::(bs, *handle) { + let bridge = match bs.get::(*handle) { Ok(bridge) => bridge, Err(e) => { println!("{HEAD} handle {index} would not open ({e}), so the kernel is handed no window"); @@ -99,19 +66,15 @@ pub fn windows(system_table: &SystemTable, out: &mut [RootBridgeWindow]) - } }; - let mut resources: *const c_void = core::ptr::null(); - let this: *const PciRootBridgeIo = &*bridge; - // SAFETY: `this` is the protocol firmware installed on this handle and - // the call is the spec's — one out parameter, which firmware fills with - // a pointer it owns and this loader only reads. - let status = unsafe { (bridge.configuration)(this, &mut resources) }; - if !status.is_success() || resources.is_null() { + let answer = bridge.configuration(); + let Some(&resources) = answer.as_ref().ok().filter(|resources| !resources.is_null()) else { println!( - "{HEAD} {index} (segment {}) answered {status:?} to Configuration(), so the kernel is handed no window", - bridge.segment_number + "{HEAD} {index} (segment {}) answered {:?} to Configuration(), so the kernel is handed no window", + bridge.segment_number, + answer.err().unwrap_or(Status::SUCCESS), ); return 0; - } + }; let list = List { at: resources as u64 }; match memory_windows(list, list.at, &mut out[found..]) { diff --git a/bootloader/src/rootimage.rs b/bootloader/src/rootimage.rs index c0f93626e12..dac9adddfbc 100644 --- a/bootloader/src/rootimage.rs +++ b/bootloader/src/rootimage.rs @@ -24,11 +24,7 @@ use core::num::NonZeroU64; use toyos_gpt::{Guid, Located, Sectors}; use toyos_rootimage::chunk; use toyos_update::slots::{self, Table}; -use uefi::prelude::*; -use uefi::proto::device_path::{DevicePath, DevicePathNode, DeviceSubType, DeviceType}; -use uefi::proto::loaded_image::LoadedImage; -use uefi::proto::media::block::{BlockIO, BlockIoProtocol}; -use uefi::table::boot::{AllocateType, MemoryType, ScopedProtocol}; +use crate::efi::{AllocateType, BlockIo, BootServices, DevicePath, Handle, HardDrive, LoadedImage, Scoped, Status}; /// The unit ROOT's filesystem is written in, and the alignment every buffer /// here is allocated at. @@ -44,10 +40,6 @@ const BLOCK: usize = 4096; /// a read that fails is named to within 1 MiB. const CHUNK_BOUND: usize = 1 << 20; -/// UEFI 2.11 §13.9's `EFI_BLOCK_IO_PROTOCOL_REVISION3`, the first whose media -/// carries `OptimalTransferLengthGranularity`. -const BLOCK_IO_REVISION3: u64 = 0x0002_001F; - /// The line a read ROOT is reported on, with where it went and what it cost. pub const READ_AT: &str = "ROOT: read into memory at"; @@ -92,31 +84,30 @@ impl RootImage { /// image from: the one handle whose device path is the partition's without /// its last node, the HARDDRIVE one. pub fn boot_disk(handle: Handle, bs: &BootServices) -> Result { - let image = crate::protocol::exclusive::(bs, handle) + let image = bs + .exclusive::(handle) .map_err(|e| alloc::format!("this image's LoadedImage: {e:?}"))?; let device = image.device().ok_or("firmware names no device this image was loaded from")?; - let path = crate::protocol::get::(bs, device) - .map_err(|e| alloc::format!("the boot device's path: {e:?}"))?; - let nodes: alloc::vec::Vec<&DevicePathNode> = path.node_iter().collect(); + let path = bs.get::(device).map_err(|e| alloc::format!("the boot device's path: {e:?}"))?; + let nodes: alloc::vec::Vec<&[u8]> = path.nodes().collect(); let Some((last, disk_nodes)) = nodes.split_last() else { return Err("the boot device's path is empty".into()); }; - if last.full_type() != (DeviceType::MEDIA, DeviceSubType::MEDIA_HARD_DRIVE) { + if (last[0], last[1]) != HardDrive::TYPE { return Err("the boot device is not a partition, so there is no disk to find the slots on".into()); } - let handles = bs - .find_handles::() - .map_err(|e| alloc::format!("firmware lists no block devices: {e:?}"))?; + let handles = bs.handles::().map_err(|e| alloc::format!("firmware lists no block devices: {e:?}"))?; let disks: alloc::vec::Vec = handles - .into_iter() + .iter() + .copied() // Not the partition itself, whose path is held open above: a second // open by this agent is closed along with the first, and the second // close then fails. .filter(|&candidate| candidate != device) .filter(|&candidate| { - let Ok(path) = crate::protocol::get::(bs, candidate) else { return false }; - path.node_iter().eq(disk_nodes.iter().copied()) + let Ok(path) = bs.get::(candidate) else { return false }; + path.nodes().eq(disk_nodes.iter().copied()) }) .collect(); match disks[..] { @@ -127,7 +118,7 @@ pub fn boot_disk(handle: Handle, bs: &BootServices) -> Result { /// The boot disk, read through the firmware's block I/O. pub struct Disk<'a> { - io: ScopedProtocol<'a, BlockIO>, + io: Scoped<'a, BlockIo>, media_id: u32, lba_bytes: u32, lba_count: u64, @@ -138,21 +129,21 @@ pub struct Disk<'a> { impl<'a> Disk<'a> { pub fn open(bs: &'a BootServices, handle: Handle) -> Result { - let io = crate::protocol::get::(bs, handle).map_err(|e| alloc::format!("the boot disk's block I/O: {e:?}"))?; + let io = bs.get::(handle).map_err(|e| alloc::format!("the boot disk's block I/O: {e:?}"))?; let media = io.media(); if !media.is_media_present() { return Err("the boot disk reports no media".into()); } - let lba_bytes = media.block_size(); + let lba_bytes = media.block_size; // UEFI 2.11 §13.9: `IoAlign` is 0 or 1 for none, else a power of two. - let align = media.io_align().max(1) as usize; + let align = media.io_align.max(1) as usize; if !align.is_power_of_two() || align > BLOCK { return Err(alloc::format!("the boot disk wants buffers aligned to {align} bytes")); } if lba_bytes == 0 || !BLOCK.is_multiple_of(lba_bytes as usize) { return Err(alloc::format!("the boot disk's {lba_bytes}-byte block does not divide {BLOCK}")); } - let (media_id, lba_count) = (media.media_id(), media.last_block() + 1); + let (media_id, lba_count) = (media.media_id, media.last_block + 1); Ok(Disk { media_id, lba_bytes, lba_count, io, scratch: aligned(BLOCK) }) } @@ -185,7 +176,7 @@ impl<'a> Disk<'a> { let at = part.first_lba() + i as u64 * lbas; self.io .read_blocks(self.media_id, at, self.scratch) - .map_err(|e| alloc::format!("the slot table's copy {i} would not read: {:?}", e.status()))?; + .map_err(|e| alloc::format!("the slot table's copy {i} would not read: {e:?}"))?; copy.copy_from_slice(self.scratch); } slots::current([&copies[0], &copies[1]]) @@ -212,7 +203,7 @@ impl<'a> Disk<'a> { // `LoaderData`, as the black box's page is, for the reason its module // header gives. let at = bs - .allocate_pages(AllocateType::AnyPages, MemoryType::LOADER_DATA, pages) + .allocate_pages(AllocateType::AnyPages, pages) .map_err(|e| alloc::format!("firmware would not give {len} bytes for ROOT: {e:?}"))?; // SAFETY: the `pages` pages at `at` were just allocated to this loader, // are identity-mapped while boot services live, and nothing else holds them. @@ -231,7 +222,7 @@ impl<'a> Disk<'a> { "the read of {} blocks at LBA {} failed: {:?}, after {} of {len} bytes read", failed.blocks, failed.lba, - failed.error.status(), + failed.error, failed.read ); image.free(bs); @@ -253,27 +244,19 @@ impl<'a> Disk<'a> { /// `OptimalTransferLengthGranularity`, where the media is revision 3 or /// later and so carries the field, and reports a non-zero one. fn granularity_lbas(&self) -> Option { - let io: &BlockIO = &self.io; - // SAFETY: uefi 0.26 declares `BlockIO` `repr(transparent)` over - // `BlockIoProtocol`, so the one is the other's layout; `revision` is - // the field the crate does not expose. - let revision = unsafe { &*core::ptr::from_ref(io).cast::() }.revision; - if revision < BLOCK_IO_REVISION3 { - return None; - } - Some(self.io.media().optimal_transfer_length_granularity()).filter(|&lbas| lbas != 0) + self.io.optimal_transfer_length_granularity().filter(|&lbas| lbas != 0) } } /// The boot disk as [`chunk::read`] asks for it. -struct Firmware<'a> { - io: &'a BlockIO, +struct Firmware<'a, 'b> { + io: &'a Scoped<'b, BlockIo>, media_id: u32, } -impl chunk::Blocks for Firmware<'_> { - type Error = uefi::Error; - fn read(&mut self, lba: u64, into: &mut [u8]) -> uefi::Result { +impl chunk::Blocks for Firmware<'_, '_> { + type Error = Status; + fn read(&mut self, lba: u64, into: &mut [u8]) -> Result<(), Status> { self.io.read_blocks(self.media_id, lba, into) } } diff --git a/bootloader/src/seed.rs b/bootloader/src/seed.rs index 890f8887ae4..c67a58b4cca 100644 --- a/bootloader/src/seed.rs +++ b/bootloader/src/seed.rs @@ -6,30 +6,27 @@ use toyos_abi::boot::SEED_LEN; use toyos_random::{wipe, Seed}; -use uefi::prelude::*; -use uefi::proto::rng::Rng; - -use crate::protocol; +use crate::efi::{Rng, SystemTable}; /// Fill `into` with firmware's seed and answer its length: [`SEED_LEN`], or 0 /// with `into` zero. Judged with the kernel's own [`Seed::judge`], so the line /// here says what the kernel will find. -pub fn read(system_table: &SystemTable, into: &mut [u8; SEED_LEN]) -> u64 { +pub fn read(system_table: &SystemTable, into: &mut [u8; SEED_LEN]) -> u64 { let bs = system_table.boot_services(); let none = |why: core::fmt::Arguments| { println!("Seed: {why}, so the kernel's generator is handed none"); 0 }; - let Ok(handle) = bs.get_handle_for_protocol::() else { + let Ok(handle) = bs.handle_for::() else { return none(format_args!("firmware has no EFI_RNG_PROTOCOL")); }; // GET_PROTOCOL: an exclusive open would stop the driver behind it. - let mut rng = match protocol::get::(bs, handle) { + let rng = match bs.get::(handle) { Ok(rng) => rng, Err(e) => return none(format_args!("EFI_RNG_PROTOCOL would not open ({e})")), }; // No algorithm named: firmware's default (§37.5.2). - if let Err(e) = rng.get_rng(None, into) { + if let Err(e) = rng.get_rng(into) { wipe(into); return none(format_args!("EFI_RNG_PROTOCOL's GetRNG failed ({e})")); } diff --git a/bootloader/src/slot.rs b/bootloader/src/slot.rs index e5130ef5f07..aa1da111752 100644 --- a/bootloader/src/slot.rs +++ b/bootloader/src/slot.rs @@ -27,10 +27,7 @@ use toyos_update::policy::{self, Refusal}; use toyos_update::record::{self, Booted, Record}; use toyos_update::slots::{self, Slot, Which}; use toyos_update::{sig, Digest}; -use uefi::prelude::*; -use uefi::proto::media::file::{File, FileAttribute, FileInfo, FileMode}; -use uefi::proto::media::fs::SimpleFileSystem; -use uefi::CString16; +use crate::efi::{BootServices, CString16, Handle, Mode, SimpleFileSystem, Status, SystemTable}; use crate::rootimage::{Disk, RootImage}; @@ -57,7 +54,7 @@ pub struct Chosen { /// The slot to boot, or every refusal and why there is nothing to boot. pub fn choose( handle: Handle, - system_table: &SystemTable, + system_table: &SystemTable, floor: u64, record: &Record, ) -> Result { @@ -192,7 +189,7 @@ fn signed_header(bs: &BootServices, which: Which, slot: &Slot) -> Result<(Header /// The version the image the record says the last boot proved carries, read /// out of its slot's signed header, verified in this pass; or why no version /// is. -pub fn proven(handle: Handle, system_table: &SystemTable, booted: &Booted) -> Result { +pub fn proven(handle: Handle, system_table: &SystemTable, booted: &Booted) -> Result { let bs = system_table.boot_services(); let letter = booted.slot.letter(); let mut disk = Disk::open(bs, crate::rootimage::boot_disk(handle, bs)?)?; @@ -246,21 +243,22 @@ enum FileRefused { /// `max` bytes. fn read_file(bs: &BootServices, guid: &[u8; 16], path: &str, max: u64) -> Result, FileRefused> { let handle = crate::loaderlog::volume_handle(bs, guid).map_err(FileRefused::Other)?; - let mut fs = crate::protocol::exclusive::(bs, handle) + let mut fs = bs + .exclusive::(handle) .map_err(|e| FileRefused::Other(alloc::format!("would not open its volume ({e})")))?; let mut root = fs.open_volume().map_err(|e| FileRefused::Other(alloc::format!("has no volume ({e})")))?; - let name = CString16::try_from(path.replace('/', "\\").as_str()) - .map_err(|_| FileRefused::Other(String::from("is no UCS-2 path")))?; - let file = match root.open(&name, FileMode::Read, FileAttribute::empty()) { + let name = CString16::new(&path.replace('/', "\\")) + .ok_or_else(|| FileRefused::Other(String::from("is no UCS-2 path")))?; + let file = match root.open(&name, Mode::Read) { Ok(file) => file, - Err(e) if e.status() == Status::NOT_FOUND => return Err(FileRefused::Missing), + Err(Status::NOT_FOUND) => return Err(FileRefused::Missing), Err(e) => return Err(FileRefused::Other(alloc::format!("would not open ({e})"))), }; let mut file = file.into_regular_file().ok_or(FileRefused::Other(String::from("is a directory")))?; - let info = file - .get_boxed_info::() - .map_err(|e| FileRefused::Other(alloc::format!("would not say its size ({e})")))?; - let size = info.file_size(); + let size = file + .info() + .map_err(|e| FileRefused::Other(alloc::format!("would not say its size ({e})")))? + .file_size; if size > max { return Err(FileRefused::Other(alloc::format!("is {size} bytes, past the {max} expected"))); } diff --git a/bootloader/src/stamp.rs b/bootloader/src/stamp.rs index 803d53b291d..e146ab8ac75 100644 --- a/bootloader/src/stamp.rs +++ b/bootloader/src/stamp.rs @@ -35,6 +35,6 @@ pub fn now() -> Head<'static> { /// One line, stamped, to the console and then to `loader.log`. pub fn say(args: fmt::Arguments) { let head = now(); - uefi_services::println!("{head} {args}"); + crate::efi::print(format_args!("{head} {args}\n")); crate::loaderlog::line(format_args!("{head} {args}")); } diff --git a/bootloader/src/watchdog.rs b/bootloader/src/watchdog.rs index 4440cfd59b5..6adae80274d 100644 --- a/bootloader/src/watchdog.rs +++ b/bootloader/src/watchdog.rs @@ -12,7 +12,6 @@ //! Every machine this cannot arm is refused by name on the console and boots //! anyway. -use core::mem::{align_of, size_of}; use core::ptr::read_volatile; use toyos_acpi::Phys; @@ -20,8 +19,7 @@ use toyos_tco::{ Chipset, TCO1_CNT, TCO1_CNT_LOCK, TCO1_CNT_NO_REBOOT, TCO1_CNT_RUN, TCO1_STS, TCO2_STS, TCO1_STS_TIMEOUT, TCO_RLD, TCO_TMR, }; -use uefi::prelude::*; -use uefi::table::boot::{MemoryDescriptor, PAGE_SIZE}; +use crate::efi::{SystemTable, PAGE_SIZE}; /// x86-64's 52-bit physical-address ceiling. const MAX_PHYS: u64 = 1 << 52; @@ -49,7 +47,7 @@ impl Phys for Identity { /// Arm the watchdog when `cmdline` names it, and say on the console what was /// armed or why nothing was. -pub fn arm(system_table: &SystemTable, rsdp_addr: u64, cmdline: &str) { +pub fn arm(system_table: &SystemTable, rsdp_addr: u64, cmdline: &str) { if !toyos_abi::boot::actuators(cmdline).any(|token| token == toyos_tco::PARAM) { return; } @@ -152,21 +150,14 @@ fn chipset(ecam: u64) -> Option<(&'static Chipset, u32, u32)> { } /// Whether firmware's own map describes `[at, at + len)` inside one region. -fn described(system_table: &SystemTable, at: u64, len: u64) -> bool { +fn described(system_table: &SystemTable, at: u64, len: u64) -> bool { let bs = system_table.boot_services(); - let size = bs.memory_map_size(); + let (map_size, entry_size) = bs.memory_map_size(); // Eight descriptors of slack: the map can grow between the two calls, and // this one allocates in between. - let bytes = size.map_size + 8 * size.entry_size; + let bytes = map_size + 8 * entry_size; let mut words: alloc::vec::Vec = alloc::vec![0; bytes.div_ceil(size_of::())]; - const _: () = assert!(align_of::() <= align_of::()); - // SAFETY: `words` is a live allocation of exactly this many bytes, aligned - // for `u64` and so for `MemoryDescriptor`, and nothing else names it while - // the slice is alive. - let buffer = unsafe { - core::slice::from_raw_parts_mut(words.as_mut_ptr().cast::(), words.len() * 8) - }; - let Ok(map) = bs.memory_map(buffer) else { return false }; + let Ok(map) = bs.memory_map(&mut words) else { return false }; let Some(end) = at.checked_add(len) else { return false }; // Every field here is firmware's, so a region whose own end overflows // describes nothing rather than wrapping into one that covers `at`. diff --git a/clippy.toml b/clippy.toml index 6f96d7356d0..c83c33fcdf9 100644 --- a/clippy.toml +++ b/clippy.toml @@ -4,6 +4,4 @@ disallowed-methods = [ { path = "alloc::sync::Arc::increment_strong_count", reason = "hand-rolled refcounting is the bug class the object layer deletes" }, { path = "alloc::sync::Arc::decrement_strong_count", reason = "hand-rolled refcounting, and the half that frees" }, { path = "core::mem::forget", reason = "a resource nobody gives back is a leak unless its site says why" }, - { path = "uefi::table::boot::BootServices::open_protocol_exclusive", reason = "EXCLUSIVE stops every driver holding the protocol, the firmware's graphics console among them: open through `protocol::exclusive`" }, - { path = "uefi::table::boot::BootServices::open_protocol", reason = "its caller picks the attribute, and EXCLUSIVE or BY_DRIVER stops the driver holding the protocol: open through `protocol::get`" }, ] diff --git a/issues/the-loader-does-only-what-must-precede-the-handover.md b/issues/the-loader-does-only-what-must-precede-the-handover.md index 9c05b2a802f..45755df5684 100644 --- a/issues/the-loader-does-only-what-must-precede-the-handover.md +++ b/issues/the-loader-does-only-what-must-precede-the-handover.md @@ -13,7 +13,9 @@ The owner's bounds: - the kernel calls no UEFI service, and every UEFI call ToyOS makes is the loader's, before `ExitBootServices` (root `CLAUDE.md`); - the anti-rollback floor counts a signed security version, raised only by a - release that fixes a security hole. + release that fixes a security hole; +- the loader calls UEFI through its own bindings (`bootloader/src/efi/`), + never the `uefi` crate's (the owner's ruling on the dependency audit). PR #539 does not land. Its pieces: @@ -145,11 +147,8 @@ Each stage lands on its own, in this order. (`fwvars::live` in `tests/common/fwvars.rs`): each floor's name and its UEFI 2.10 §8.2 attributes. -4. **The loader on current `uefi`, sound, with a typed handover.** - - `uefi` and `uefi-raw` move to their current releases, and `uefi-services` - goes. The unsafe `BlockIO` media cast in `rootimage.rs` goes with the old - layout. - - The loader's own `#[panic_handler]` writes `loader: panicked at +4. **The loader sound, with a typed handover.** + - The loader's `#[panic_handler]` writes `loader: panicked at :: ` through `loaderlog`, then powers the machine off. It never resets: a panic with a fixed cause would reset into itself. The refused-floor site stops writing its reason to `loader.log` before @@ -181,11 +180,11 @@ Each stage lands on its own, in this order. change. - `toyos-update`'s slot table takes `toyos-gpt`'s CRC32 and loses its own. - **Exit**: `bootloader/Cargo.toml` names no `uefi-services`. - `loader_panic_powers_off` plants this key's floor in 9 bytes. It finds the + **Exit**: `loader_panic_powers_off` plants this key's floor in 9 bytes. It finds the handler's `loader: panicked at bootloader/src/` line in `loader.log`, which no other code writes, and QEMU reports `guest-shutdown`. It fails under - `uefi::helpers`' handler, which writes no `loader.log`. + the handler `bootloader/src/efi/mod.rs` holds before this stage, which + writes no `loader.log`. `kernel_args_last_layout_refused` boots with `loader-writes-the-last-layout` and finds the kernel's refusal naming both words before any `black box:` record. Moving `layout` after From d7cf6591ab564c3e9cf6d6b0ec5a95310ecc1c3f Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 19:12:23 +0200 Subject: [PATCH 12/22] The wallpaper's powf and expf are libm's, a host test pins its bytes, and OPENED_BY names its reader `f32::powf` and `f32::exp` call the host C library's, which no standard holds to one answer, and ROOT's UUID is derived from the bytes the wallpaper draws: one tree could name a different ROOT on Linux, macOS and later ToyOS. The pure-Rust `libm` crate, already in the lock at 0.2.16, computes both the same on every host. The rest of `draw` is IEEE arithmetic and sqrt, floor and round, each exactly specified, and Rust contracts no multiply-add. Measured on the development host (macOS, arm64): the libm draw is byte for byte the std draw, 0 of 6220808 bytes differ, so the picture is unchanged. `the_wallpaper_is_the_same_on_every_host` pins its SHA-256, 675f4fbc...1d91, so `--ci host` on CI's Linux host reds where its draw differs. `wallpaper::READER` was a second table of which program opens a ROOT file beside `assets::OPENED_BY`. The wallpaper is a row of `OPENED_BY` now, the build asks it through `assets::wanted`, and `only_its_reader_opens_an_owned_file` holds that row as it held doom's. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- Cargo.lock | 1 + Cargo.toml | 3 +++ src/assets.rs | 56 +++++++++++++++++++++++++----------------------- src/build.rs | 6 +++--- src/wallpaper.rs | 28 +++++++++++++++++------- 5 files changed, 56 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2405e52544..43ed0248290 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4639,6 +4639,7 @@ dependencies = [ "gpt", "kernel", "libc", + "libm", "serde", "serde_json", "sha2 0.10.9", diff --git a/Cargo.toml b/Cargo.toml index a750ed442e3..46dfe08246a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -197,6 +197,9 @@ toyos-update = { path = "toyos-update", features = ["sign"] } # A throwaway key's seed and every GUID a partition table names, from the # operating system. getrandom = "0.3" +# The wallpaper's `powf` and `expf`, in Rust and the same on every host, where +# `f32`'s own call the host's C library and ROOT's UUID is derived from its bytes. +libm = "0.2.16" # `classify`, so the host reading a log volume and `logkeeper` writing it cannot # disagree about which files on it are `logkeeper`'s. toyos-wallclock = { path = "toyos-wallclock" } diff --git a/src/assets.rs b/src/assets.rs index bd282eb352f..b48b58c1616 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -242,16 +242,30 @@ fn absentees(dir: &Path, declared: &BTreeSet) -> Vec { declared.iter().map(|name| dir.join(name)).filter(|path| !path.exists()).collect() } -/// An asset on ROOT, and the one program that opens it. +/// A file of ROOT's `share/`, and the one program that opens it. /// /// **`assets = [..]` names a directory and sweeps it whole**, so a config that -/// builds no reader for a file still shipped it: these two are 19.7 MB of the -/// 20.8 MB `assets/` holds. Named here rather than per config, because which program -/// opens a file is a property of the program and not of any one image, and a -/// list repeated in five configs is a list that goes stale in four of them. -/// The names are ROOT's, which [`collect`] lower-cases. -/// `only_doom_opens_doom_s_assets` is what keeps the right-hand column true. -const OPENED_BY: &[(&str, &str)] = &[("doom1.wad", "doom"), ("soundfont.sf2", "doom")]; +/// builds no reader for a file would still ship it. Named here rather than per +/// config, because which program opens a file is a property of the program and +/// not of any one image, and a list repeated in five configs is a list that goes +/// stale in four of them. The names are ROOT's, which [`collect`] lower-cases; +/// `wallpaper.rgb` is the build's own drawing ([`crate::wallpaper`]) rather than +/// a swept file. `only_its_reader_opens_an_owned_file` is what keeps the +/// right-hand column true. +const OPENED_BY: &[(&str, &str)] = + &[("doom1.wad", "doom"), ("soundfont.sf2", "doom"), ("wallpaper.rgb", "compositor")]; + +/// Whether ROOT's `share/` goes into an image building exactly +/// `programs`: unless [`OPENED_BY`] names a reader the image does not build. +pub fn wanted(name: &str, programs: &BTreeSet<&str>) -> bool { + match OPENED_BY.iter().find(|(file, _)| *file == name) { + Some((_, reader)) if !programs.contains(reader) => { + eprintln!("assets: leaving out share/{name} — only /system/bin/{reader} opens it and this image builds no {reader}"); + false + } + _ => true, + } +} /// ROOT's asset files, for an image building exactly `programs`. pub fn collect(dirs: &[String], programs: &BTreeSet<&str>) -> Vec<(String, Vec)> { @@ -274,18 +288,7 @@ pub fn collect(dirs: &[String], programs: &BTreeSet<&str>) -> Vec<(String, Vec| -> BTreeSet { collect(&[dir.display().to_string()], &programs) @@ -464,13 +467,13 @@ mod tests { BTreeSet::from([ "share/doom1.wad".to_string(), "share/soundfont.sf2".to_string(), - "share/wallpaper.rgb".to_string(), + "share/readme.txt".to_string(), ]), "an image that builds doom did not get doom's assets" ); assert_eq!( without, - BTreeSet::from(["share/wallpaper.rgb".to_string()]), + BTreeSet::from(["share/readme.txt".to_string()]), "an image with no doom in it still carries what only doom opens" ); } @@ -535,10 +538,9 @@ mod tests { /// /// The claim is that one program opens the file, so a second program naming /// its path is an image losing a file it needs. `userland/` only: the - /// harness names both paths in assertions about doom, and it runs on the - /// host. + /// harness names doom's paths in its assertions, and it runs on the host. #[test] - fn only_doom_opens_doom_s_assets() { + fn only_its_reader_opens_an_owned_file() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); for (asset, reader) in OPENED_BY { let out = Command::new("git") diff --git a/src/build.rs b/src/build.rs index 39631e12e95..2b7614e56fb 100644 --- a/src/build.rs +++ b/src/build.rs @@ -710,12 +710,12 @@ fn build_and_assemble( build_programs(root, config, env, quiet, arch, &mut root_files); root_files.push((toyos_manifest::PATH.to_string(), render_manifest(config))); + let programs: BTreeSet<&str> = config.programs.keys().map(String::as_str).collect(); if !config.assets.is_empty() { - let programs: BTreeSet<&str> = config.programs.keys().map(String::as_str).collect(); root_files.extend(assets::collect(&config.assets, &programs)); } - if config.programs.contains_key(crate::wallpaper::READER) { - root_files.push((crate::wallpaper::PATH.to_string(), crate::wallpaper::rgb())); + if assets::wanted(crate::wallpaper::NAME, &programs) { + root_files.push((format!("share/{}", crate::wallpaper::NAME), crate::wallpaper::rgb())); } // Extra files (test binaries, shared libs) diff --git a/src/wallpaper.rs b/src/wallpaper.rs index c1eeda1ac69..41a6bb94651 100644 --- a/src/wallpaper.rs +++ b/src/wallpaper.rs @@ -8,10 +8,13 @@ //! All compositing is in **linear light**, converted to sRGB once per pixel at //! the end. Mixing two colours in sRGB mixes two numbers that were never linear //! to begin with, which is what sends a naive gradient grey through its middle. +//! +//! **The bytes are the same on every host**, because ROOT's UUID is derived +//! from them: every transcendental is `libm`'s, never the host C library's, and +//! `the_wallpaper_is_the_same_on_every_host` pins their digest. -/// Where ROOT carries the wallpaper, and the one program that opens it. -pub const PATH: &str = "share/wallpaper.rgb"; -pub const READER: &str = "compositor"; +/// The wallpaper's name in ROOT's `share/`. +pub const NAME: &str = "wallpaper.rgb"; /// Drawn at the panel this project targets, the T14's 1920x1080. The /// compositor scales whatever it is handed, so this is the size at which it @@ -144,7 +147,7 @@ const RIDGE_OCTAVES: u32 = 4; /// span the screen. /// /// This is the difference between a sky and a diagram of three ellipses. Both -/// octaves are slow: anything faster costs JPEG bits and reads as texture. +/// octaves are slow: anything faster reads as texture. const DRIFT: f32 = 0.42; const DRIFT_CELLS: f32 = 2.4; @@ -168,7 +171,7 @@ fn srgb_to_linear(c: u8) -> f32 { if s <= 0.040_45 { s / 12.92 } else { - ((s + 0.055) / 1.055).powf(2.4) + libm::powf((s + 0.055) / 1.055, 2.4) } } @@ -177,7 +180,7 @@ fn linear_to_srgb(v: f32) -> f32 { if v <= 0.003_130_8 { v * 12.92 } else { - 1.055 * v.powf(1.0 / 2.4) - 0.055 + 1.055 * libm::powf(v, 1.0 / 2.4) - 0.055 } } @@ -291,7 +294,7 @@ pub fn draw(width: u32, height: u32) -> Vec { let dx = (u - light.x) / light.rx; let dy = (v - light.y) / light.ry; let warped = (dx * dx + dy * dy) * (1.0 + DRIFT * drift(u, v, light.seed)); - let fall = (-warped).exp() * light.gain; + let fall = libm::expf(-warped) * light.gain; for c in 0..3 { rgb[c] += color[c] * fall; } @@ -329,7 +332,7 @@ pub fn draw(width: u32, height: u32) -> Vec { out } -/// The file ROOT carries at [`PATH`]: the width and the height as +/// The file ROOT carries as `share/`[`NAME`]: the width and the height as /// little-endian `u32`s, then [`draw`]'s RGB triples at that size, unencoded — /// a lossy codec here would throw away the dither first. pub fn rgb() -> Vec { @@ -368,6 +371,15 @@ mod tests { worst } + /// The file that ships is the one every host draws: a host whose floating + /// point answers differently reds here rather than naming a different ROOT. + #[test] + fn the_wallpaper_is_the_same_on_every_host() { + use sha2::{Digest, Sha256}; + let digest: String = Sha256::digest(rgb()).iter().map(|b| format!("{b:02x}")).collect(); + assert_eq!(digest, "675f4fbc92985dc5e60b899fd869fa8e574b1147e2b1c9b42808a72bcfff1d91"); + } + /// The file that ships, read the way the compositor reads it, does not band. #[test] fn the_wallpaper_does_not_band() { From cae83442671a38796fcd659356a1c0fbdfa4feaa Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 19:36:01 +0200 Subject: [PATCH 13/22] An icon ships drawn only when git tracks it, and a moved pixel says how to re-measure it The asset test carries a tracked and an untracked committed icon again, so dropping the `.svg` arm's `ships` guard goes red: the untracked icon would ship as `minus-bold.alpha`. The digest test's failure message now says what to do (draw the icons against resvg 0.47 out of tree with the differential posted on #814 and ask the owner again on any visible change) instead of naming an oracle that exists only in a comment, and the module header no longer claims the pixels are resvg's exactly: they follow resvg's. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- src/assets.rs | 11 +++++++---- src/icons.rs | 17 +++++++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/assets.rs b/src/assets.rs index 8864eacbb86..33896c67b22 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -397,7 +397,10 @@ mod tests { fs::create_dir_all(dir.join("target")).expect("make a stray target/"); fs::write(dir.join("kept.wad"), b"tracked").expect("write kept.wad"); - fs::write(dir.join("icons/kept.png"), b"tracked").expect("write icons/kept.png"); + // An icon ships drawn, and only when tracked: both are committed icons. + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + fs::copy(root.join("assets/icons/x-bold.svg"), dir.join("icons/x-bold.svg")).expect("copy x-bold.svg"); + fs::copy(root.join("assets/icons/minus-bold.svg"), dir.join("icons/minus-bold.svg")).expect("copy minus-bold.svg"); fs::write(dir.join("music.sf2"), b"tracked").expect("write music.sf2"); fs::write(dir.join(".DS_Store"), b"finder").expect("write .DS_Store"); fs::write(dir.join("target/.deps-stamp"), b"cargo").expect("write target/.deps-stamp"); @@ -411,7 +414,7 @@ mod tests { assert!(out.status.success(), "git {args:?}: {}", String::from_utf8_lossy(&out.stderr)); }; git(&["init", "-q"]); - git(&["add", "kept.wad", "icons/kept.png", "music.sf2"]); + git(&["add", "kept.wad", "icons/x-bold.svg", "music.sf2"]); let shipped: BTreeSet = collect(&[dir.display().to_string()], &BTreeSet::new()) .into_iter() @@ -422,7 +425,7 @@ mod tests { shipped, BTreeSet::from([ "share/kept.wad".to_string(), - "share/icons/kept.png".to_string(), + "share/icons/x-bold.alpha".to_string(), "share/music.sf2".to_string(), ]), "ROOT's asset list is not what the repository says it is" @@ -443,7 +446,7 @@ mod tests { without, BTreeSet::from([ "share/kept.wad".to_string(), - "share/icons/kept.png".to_string(), + "share/icons/x-bold.alpha".to_string(), ]), "a committed asset that is not there took something else with it" ); diff --git a/src/icons.rs b/src/icons.rs index 868afc4ee70..4086d9520a0 100644 --- a/src/icons.rs +++ b/src/icons.rs @@ -15,8 +15,8 @@ //! round-capped and round-joined, which makes it exactly the points within half //! its width of its path, the region drawn here. //! -//! The pixels are the ones resvg drew these icons with before the build drew -//! them, because the desktop's look is not this file's to change: a pixel +//! The pixels follow resvg's, which drew these icons before the build did, +//! because the desktop's look is not this file's to change: a pixel //! samples four rows of four points, a sample worth 16 of 255; a fill is //! nonzero, its arcs become cubics as `kurbo` splits them and each cubic, cut //! where it turns in y, becomes `2^shift` chords by tiny-skia's count; and each @@ -760,9 +760,8 @@ mod tests { assert!((area(&ring) - want).abs() < want * 5e-3, "ring: {} of {want}", area(&ring)); } - /// The committed icons draw to the pixels that were compared with resvg's, - /// which no reading of this file can see: a change that moves one is - /// compared with resvg again before this digest moves with it. + /// The committed icons draw to the pixels the owner accepted against + /// resvg's, which no reading of this file can see. #[test] fn the_icons_are_the_pixels_compared_with_resvg() { use sha2::{Digest, Sha256}; @@ -773,7 +772,13 @@ mod tests { digest.update(rasterize(stem, &svg)); } let hex: String = digest.finalize().iter().map(|b| format!("{b:02x}")).collect(); - assert_eq!(hex, "bc246dcfb81736e4aef449383ea3c666e38122ca47d0b2a2dfead9302653929e", "the icons' pixels moved"); + assert_eq!( + hex, + "bc246dcfb81736e4aef449383ea3c666e38122ca47d0b2a2dfead9302653929e", + "the icons' pixels moved: draw them against resvg 0.47 out of tree with the differential \ + posted on pull request #814, and ask the owner again on any visible change before \ + pinning the new digest" + ); } /// A contour wound against its outer one is a hole; one wound with it is not. From 51050041be1638f6d550309424ce487bd4e9e8b7 Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 19:12:48 +0200 Subject: [PATCH 14/22] toyos-gpt answers an entry's name from the array it checked, and the build's own GPT name decoder goes `image::name_of` decoded the primary header and its array by hand, beside `toyos-gpt`, with neither CRC checked: where `toyos_gpt::list` had taken the backup over a torn primary, `install` named partitions from bytes the parser had refused. A `Partition` now carries its entry's name field, decoded in the walk whose CRC licenses it, and `Partition::name` answers its UTF-16 units up to the first zero; decoding them is the caller's. `Stated` stays as it was, so the `Err` side of an `Entry` does not grow; the name rides beside it through the walk to `Partition::place`. The suites carry names now: the generator gives every entry a random name of 0 to 36 non-zero units, `oracle.rs` holds each placed entry's name to the `gpt` crate's reading of it, and `mutate.rs` holds every answered name to the copy of the table it came from. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- src/image.rs | 22 +++++----------- toyos-gpt/src/lib.rs | 51 ++++++++++++++++++++++++++---------- toyos-gpt/tests/mutate.rs | 5 +++- toyos-gpt/tests/oracle.rs | 17 ++++++------ toyos-gpt/tests/parse.rs | 2 +- toyos-gpt/tests/table/mod.rs | 26 ++++++++++++++++-- 6 files changed, 81 insertions(+), 42 deletions(-) diff --git a/src/image.rs b/src/image.rs index 1ad2492c486..c156a7e7a68 100644 --- a/src/image.rs +++ b/src/image.rs @@ -700,7 +700,7 @@ pub fn install(image: &[u8], disk: &Path, data_bytes: u64) { [Guid::EFI_SYSTEM, Guid::MICROSOFT_BASIC, Guid::TOYOS_SLOTS, Guid::TOYOS_BOOT, Guid::TOYOS_ROOT].contains(&kind), "partition {guid} is of type {kind}, which no boot image carries" ); - let name = name_of(image, part.index()); + let name = name_of(&part); let at = part.first_lba() as usize * LBA as usize; let bytes = &image[at..at + part.lba_count().get() as usize * LBA as usize]; (Row { what: format!("installed {name}"), name, kind, guid, len: bytes.len() as u64 }, bytes) @@ -728,17 +728,9 @@ pub fn install(image: &[u8], disk: &Path, data_bytes: u64) { } } -/// The name `image`'s table gives its entry `index`, which `toyos-gpt` does -/// not read: the header at block 1 places the array and sizes its entries, -/// and a name is the UTF-16 units from byte 56 of one, up to the first zero. -fn name_of(image: &[u8], index: u32) -> String { - let field = |at: usize, len: usize| &image[LBA as usize + at..][..len]; - let array = u64::from_le_bytes(field(72, 8).try_into().expect("eight bytes")) as usize * LBA as usize; - let size = u32::from_le_bytes(field(84, 4).try_into().expect("four bytes")) as usize; - let entry = &image[array + index as usize * size..][..size]; - let units: Vec = - entry[56..128].chunks(2).map(|unit| u16::from_le_bytes([unit[0], unit[1]])).take_while(|unit| *unit != 0).collect(); - String::from_utf16(&units).unwrap_or_else(|e| panic!("partition {index}'s name is no UTF-16: {e}")) +/// The name a table this build wrote gives `part`. +fn name_of(part: &toyos_gpt::Partition) -> String { + String::from_utf16(part.name()).unwrap_or_else(|e| panic!("partition {}'s name is no UTF-16: {e}", part.unique_guid())) } /// Block 0 of a volume: the magic and its block count. @@ -1155,8 +1147,6 @@ mod tests { /// its bytes, found by the reader the kernel and `diskserver` use: the /// names, in the image's order. fn carries_every_partition_of(disk: &mut std::fs::File, image: &[u8]) -> Vec { - let mut table = vec![0u8; 34 * LBA as usize]; - disk.seek(SeekFrom::Start(0)).and_then(|_| disk.read_exact(&mut table)).expect("the disk's table"); let mut names = Vec::new(); let mut listed = [None; 16]; toyos_gpt::list(&mut ImageSectors(image), &mut listed).expect("the image's table"); @@ -1173,8 +1163,8 @@ mod tests { .and_then(|_| disk.read_exact(&mut installed)) .expect("read it back"); assert!(installed == image[at..at + len], "{} was installed as other bytes", part.unique_guid()); - assert_eq!(name_of(&table, on_disk.index()), name_of(image, part.index()), "{}", part.unique_guid()); - names.push(name_of(image, part.index())); + assert_eq!(name_of(&on_disk), name_of(&part), "{}", part.unique_guid()); + names.push(name_of(&part)); } names } diff --git a/toyos-gpt/src/lib.rs b/toyos-gpt/src/lib.rs index bef84611d09..90ba80cb907 100644 --- a/toyos-gpt/src/lib.rs +++ b/toyos-gpt/src/lib.rs @@ -54,6 +54,11 @@ pub const MAX_ENTRY_ARRAY_BYTES: u64 = 128 * 1024; const MIN_HEADER_BYTES: u32 = 92; /// The smallest a partition entry may be, from the UEFI specification. const MIN_ENTRY_BYTES: u32 = 128; +/// UTF-16 units in an entry's name field, from byte 56 to the end of the +/// 128 bytes every entry has. +const NAME_UNITS: usize = 36; +/// An entry's name field whole, zero units included. +type Name = [u16; NAME_UNITS]; const HEADER_SIGNATURE: &[u8; 8] = b"EFI PART"; const HEADER_REVISION_1_0: u32 = 0x0001_0000; /// The MBR partition type that says "this disk is GPT, keep out". @@ -164,11 +169,12 @@ pub struct Partition { first_lba: u64, last_lba: u64, lba_count: NonZeroU64, + name: Name, } impl Partition { /// `stated`, if its blocks are a partition inside `header`'s usable range. - fn place(stated: Stated, header: &Header) -> Result { + fn place(stated: Stated, name: Name, header: &Header) -> Result { if stated.first < header.first_usable_lba || stated.last > header.last_usable_lba { return Err(stated); } @@ -185,6 +191,7 @@ impl Partition { first_lba: stated.first, last_lba: stated.last, lba_count, + name, }) } @@ -214,6 +221,12 @@ impl Partition { self.lba_count } + /// The entry's name, UTF-16 as the table states it, up to the first zero + /// unit: what it says is the caller's to decode. + pub fn name(&self) -> &[u16] { + self.name.split(|unit| *unit == 0).next().unwrap_or_default() + } + /// Whether this is an ESP *by type*. A sanity check for a log line and /// nothing more — the selection has already happened, by unique GUID. pub fn is_efi_system(&self) -> bool { @@ -455,13 +468,13 @@ fn scan_type_at( let mut slots = out.iter_mut(); // Meaningless unless `walk_entries` returns `Ok`: the array's CRC is // checked at the end of the walk, and an `Err` hands the caller nothing. - let used_entries = walk_entries(dev, &header, disk.lba, &mut |stated| { + let used_entries = walk_entries(dev, &header, disk.lba, &mut |stated, name| { if !keep(stated.type_guid) { return; } matched = matched.saturating_add(1); if let Some(slot) = slots.next() { - *slot = Some(Partition::place(stated, &header)); + *slot = Some(Partition::place(stated, name, &header)); } })?; @@ -483,10 +496,10 @@ fn locate_at( let header = parse_header(block, disk, header_lba)?; let (found, used_entries) = scan_entries(dev, &header, target, disk.lba)?; - let Some(stated) = found else { + let Some((stated, name)) = found else { return Err(GptError::NotFound { used_entries }); }; - let partition = Partition::place(stated, &header) + let partition = Partition::place(stated, name, &header) .map_err(|stated| GptError::PartitionRange { first: stated.first, last: stated.last })?; check_no_overlap(dev, &header, &partition, disk.lba)?; @@ -682,7 +695,7 @@ fn walk_entries( dev: &mut dyn Sectors, header: &Header, lba: LbaSize, - visit: &mut dyn FnMut(Stated), + visit: &mut dyn FnMut(Stated, Name), ) -> Result { let mut block: Block = [0; 4096]; let block = lba.of_block(&mut block); @@ -699,12 +712,12 @@ fn walk_entries( for entry in block.chunks_exact(header.entry_len) { let Some(index) = indices.next() else { break }; crc.update(entry); - let Some(stated) = Stated::decode(index, entry) else { + let (Some(stated), Some(name)) = (Stated::decode(index, entry), name(entry)) else { return Err(GptError::EntrySize(header.entry_bytes)); }; if !stated.type_guid.is_zero() { used = used.saturating_add(1); - visit(stated); + visit(stated, name); } } } @@ -735,17 +748,17 @@ fn scan_entries( header: &Header, target: Guid, lba: LbaSize, -) -> Result<(Option, u32), GptError> { - let mut found: Option = None; +) -> Result<(Option<(Stated, Name)>, u32), GptError> { + let mut found: Option<(Stated, Name)> = None; let mut duplicate: Option<(u32, u32)> = None; - let used = walk_entries(dev, header, lba, &mut |stated| { + let used = walk_entries(dev, header, lba, &mut |stated, name| { if stated.unique_guid != target { return; } match &found { - None => found = Some(stated), - Some(first) if duplicate.is_none() => duplicate = Some((first.index, stated.index)), + None => found = Some((stated, name)), + Some((first, _)) if duplicate.is_none() => duplicate = Some((first.index, stated.index)), Some(_) => {} } })?; @@ -769,7 +782,7 @@ fn check_no_overlap( lba: LbaSize, ) -> Result<(), GptError> { let mut overlap = None; - walk_entries(dev, header, lba, &mut |other| { + walk_entries(dev, header, lba, &mut |other, _| { if overlap.is_none() && other.index != matched.index && other.first <= other.last @@ -790,6 +803,16 @@ fn bytes(buf: &[u8], at: usize) -> Option<[u8; N]> { buf.get(at..)?.first_chunk::().copied() } +/// An entry's name field as UTF-16 units, `None` only where `entry` ends first. +fn name(entry: &[u8]) -> Option { + let field: [u8; 72] = bytes(entry, 56)?; + let mut units = [0; NAME_UNITS]; + for (unit, pair) in units.iter_mut().zip(field.as_chunks::<2>().0) { + *unit = u16::from_le_bytes(*pair); + } + Some(units) +} + fn le_u32(buf: &[u8], at: usize) -> Option { bytes(buf, at).map(u32::from_le_bytes) } diff --git a/toyos-gpt/tests/mutate.rs b/toyos-gpt/tests/mutate.rs index 84d68f18164..e8f5baf106a 100644 --- a/toyos-gpt/tests/mutate.rs +++ b/toyos-gpt/tests/mutate.rs @@ -29,6 +29,7 @@ struct Seen { first: u64, last: u64, count: u64, + name: Vec, } /// An entry the parser handed back as no partition. @@ -59,6 +60,7 @@ fn observe(img: &mut Image, targets: &[Guid]) -> (Result, Answ first: p.first_lba(), last: p.last_lba(), count: p.lba_count().get(), + name: p.name().to_vec(), }; let mut out = [None; 64]; let listed = toyos_gpt::list(img, &mut out).map(|scan| Listed { @@ -78,7 +80,8 @@ fn observe(img: &mut Image, targets: &[Guid]) -> (Result, Answ } fn is(e: &RawEntry, s: &Seen) -> bool { - (e.index, e.type_guid, e.unique, e.first, e.last) == (s.index, s.type_guid, s.unique, s.first, s.last) + let name: Vec = e.name.iter().copied().take_while(|unit| *unit != 0).collect(); + (e.index, e.type_guid, e.unique, e.first, e.last, &name) == (s.index, s.type_guid, s.unique, s.first, s.last, &s.name) } /// A partition's own invariant, against the copy it came from and the device. diff --git a/toyos-gpt/tests/oracle.rs b/toyos-gpt/tests/oracle.rs index 998c115ef6c..26c56f9afcd 100644 --- a/toyos-gpt/tests/oracle.rs +++ b/toyos-gpt/tests/oracle.rs @@ -25,14 +25,15 @@ const VALID: u64 = 2_000; const BENT: u64 = 4_000; const SEED: u64 = 0x6770_745F_6F72_636C; -/// One entry: index, type as text, unique GUID, first and last block. -type Row = (u32, String, Guid, u64, u64); +/// One entry: index, type as text, unique GUID, first and last block, name. +type Row = (u32, String, Guid, u64, u64, String); /// toyos-gpt's reading. struct Ours { disk: Guid, placed: BTreeMap, - unplaced: BTreeMap, + /// Unique GUID, first and last block. + unplaced: BTreeMap, } fn ours(img: &mut Image) -> Result { @@ -43,11 +44,11 @@ fn ours(img: &mut Image) -> Result { for entry in out.iter().flatten() { match entry { Ok(p) => { - let row = (p.index(), p.type_guid().to_string(), p.unique_guid(), p.first_lba(), p.last_lba()); + let row = (p.index(), p.type_guid().to_string(), p.unique_guid(), p.first_lba(), p.last_lba(), String::from_utf16_lossy(p.name())); read.placed.insert(p.index(), row); } Err(u) => { - read.unplaced.insert(u.index, (u.index, u.type_guid.to_string(), u.unique_guid, u.first, u.last)); + read.unplaced.insert(u.index, (u.unique_guid, u.first, u.last)); } } } @@ -80,7 +81,7 @@ fn theirs(img: &Image) -> Theirs { rows: parts .iter() .map(|(&key, p)| { - let row = (key - 1, p.part_type_guid.guid.to_string(), Guid(p.part_guid.to_bytes_le()), p.first_lba, p.last_lba); + let row = (key - 1, p.part_type_guid.guid.to_string(), Guid(p.part_guid.to_bytes_le()), p.first_lba, p.last_lba, p.name.clone()); (key - 1, row) }) .collect(), @@ -128,10 +129,10 @@ fn differ(layout: &Layout, img: &Image, ours: &Result, theirs: & match (o.placed.get(index), o.unplaced.get(index)) { (Some(mine), None) if mine == row => {} // A type only toyos-gpt names: gpt answers the zero GUID. - (Some(mine), None) if row.1 == unnamed && (&mine.0, &mine.2, mine.3, mine.4) == (&row.0, &row.2, row.3, row.4) => { + (Some(mine), None) if row.1 == unnamed && (&mine.0, &mine.2, mine.3, mine.4, &mine.5) == (&row.0, &row.2, row.3, row.4, &row.5) => { named = "a type gpt's own table does not name"; } - (None, Some(stated)) if (stated.2, stated.3, stated.4) == (row.2, row.3, row.4) => { + (None, Some(stated)) if *stated == (row.2, row.3, row.4) => { named = "an entry toyos-gpt places as no partition: gpt checks no range"; } // gpt counts an entry by any non-zero byte, toyos-gpt by its type GUID. diff --git a/toyos-gpt/tests/parse.rs b/toyos-gpt/tests/parse.rs index fbdbc1d9676..9fe8565964a 100644 --- a/toyos-gpt/tests/parse.rs +++ b/toyos-gpt/tests/parse.rs @@ -30,7 +30,7 @@ fn guid(n: u8) -> Guid { } fn entry(index: u32, type_guid: Guid, unique: Guid, first: u64, last: u64) -> RawEntry { - RawEntry { index, type_guid, unique, first, last } + RawEntry { index, type_guid, unique, first, last, name: [0; 36] } } /// The disk every test here breaks one thing of, `edit`ed, with no backup diff --git a/toyos-gpt/tests/table/mod.rs b/toyos-gpt/tests/table/mod.rs index 4d1c0ebd481..252caedf1af 100644 --- a/toyos-gpt/tests/table/mod.rs +++ b/toyos-gpt/tests/table/mod.rs @@ -44,6 +44,15 @@ impl Rng { b[0] |= 1; Guid(b) } + + /// A name field: up to 36 units of any non-zero value, the rest zero. + pub fn name(&mut self) -> [u16; 36] { + let mut name = [0; 36]; + for unit in name.iter_mut().take(self.below(37) as usize) { + *unit = self.range(1, 0xFFFF) as u16; + } + name + } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -53,6 +62,8 @@ pub struct RawEntry { pub unique: Guid, pub first: u64, pub last: u64, + /// The name field whole, as UTF-16 units. + pub name: [u16; 36], } /// One copy of the table, every field as the image will state it. @@ -136,7 +147,7 @@ pub fn valid(rng: &mut Rng, shape: &Shape<'_>) -> Layout { break; } floor = last + 1; - entries.push(RawEntry { index, type_guid: rng.pick(shape.types), unique: rng.guid(), first, last }); + entries.push(RawEntry { index, type_guid: rng.pick(shape.types), unique: rng.guid(), first, last, name: rng.name() }); } let primary = Table { @@ -218,7 +229,7 @@ fn mutate_entry(rng: &mut Rng, t: &mut Table, lba_count: u64) { let index = rng.below(u64::from(t.entry_count.clamp(1, 256))) as u32; t.entries.retain(|e| e.index != index); let (first, last) = (edge(rng, t, lba_count), edge(rng, t, lba_count)); - t.entries.push(RawEntry { index, type_guid: Guid::EFI_SYSTEM, unique: rng.guid(), first, last }); + t.entries.push(RawEntry { index, type_guid: Guid::EFI_SYSTEM, unique: rng.guid(), first, last, name: rng.name() }); return; } let k = rng.below(t.entries.len() as u64) as usize; @@ -280,6 +291,14 @@ pub fn image(layout: &Layout) -> Image { slot[16..32].copy_from_slice(&e.unique.0); slot[32..40].copy_from_slice(&e.first.to_le_bytes()); slot[40..48].copy_from_slice(&e.last.to_le_bytes()); + // A nameless entry writes its first 48 bytes alone, so an array laid + // over LBA 0 leaves the MBR's records as they are. + let name = at.and_then(|at| disk.get_mut(at + 56..at + 128)); + if let Some(name) = name.filter(|_| e.name != [0; 36]) { + for (pair, unit) in name.as_chunks_mut::<2>().0.iter_mut().zip(e.name) { + *pair = unit.to_le_bytes(); + } + } } } for &(header_lba, t) in &copies { @@ -393,6 +412,9 @@ impl OnDisk { unique: Guid(e[16..32].try_into().expect("16")), first: u64_at(e, 32), last: u64_at(e, 40), + name: e.get(56..128).map_or([0; 36], |field| { + std::array::from_fn(|i| u16::from_le_bytes([field[2 * i], field[2 * i + 1]])) + }), }) .filter(|e| !e.type_guid.is_zero()) .collect(); From ce7cd518290c1e9baf1a5873f0d93f728a1e110a Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 19:12:48 +0200 Subject: [PATCH 15/22] The FAT32 format keeps only the branches a volume reaches The cluster size past 8 GiB was reached by no volume the build makes and by no test; an assert at 8 GiB stands where it was. The 16-bit sector count was written only below 65,536 sectors, which `format`'s cluster-count assert already refuses. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- src/fatformat.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/fatformat.rs b/src/fatformat.rs index f22e415e95f..b1219263b52 100644 --- a/src/fatformat.rs +++ b/src/fatformat.rs @@ -74,17 +74,12 @@ pub(crate) fn format(bytes: usize, label: [u8; 11]) -> Vec { volume } -/// 512 bytes up to 260 MiB, 4 KiB up to 8 GiB, and past that 1 KiB a 2 GiB -/// of the size rounded up to a power of two, at most 32 KiB. +/// 512 bytes up to 260 MiB and 4 KiB up to 8 GiB, past anything the build +/// formats. fn sectors_per_cluster(bytes: u64) -> u32 { const MIB: u64 = 1024 * 1024; - let cluster = if bytes <= 260 * MIB { - 512 - } else if bytes <= 8 * 1024 * MIB { - 4096 - } else { - (bytes.next_power_of_two() / (2 * 1024 * MIB) * 1024).clamp(512, 32 * 1024) - }; + assert!(bytes <= 8 * 1024 * MIB, "a {bytes}-byte volume is larger than this format lays out"); + let cluster = if bytes <= 260 * MIB { 512 } else { 4096 }; (cluster / SECTOR as u64) as u32 } @@ -105,17 +100,13 @@ fn boot_sector(total: u32, per_cluster: u32, per_fat: u32, label: [u8; 11]) -> [ s[13] = per_cluster as u8; put(&mut s, 14, &(RESERVED_SECTORS as u16).to_le_bytes()); s[16] = FATS as u8; - // The FAT12/16 root entry count and 16-bit sizes stay zero on FAT32. - if total < 0x1_0000 { - put(&mut s, 19, &(total as u16).to_le_bytes()); - } + // The FAT12/16 root entry count and 16-bit sizes stay zero on FAT32, whose + // volumes `format` holds to more sectors than 16 bits count. s[21] = MEDIA; // Sectors per track and heads: no reader of a FAT32 volume uses either. put(&mut s, 24, &0x20u16.to_le_bytes()); put(&mut s, 26, &0x40u16.to_le_bytes()); - if total >= 0x1_0000 { - put(&mut s, 32, &total.to_le_bytes()); - } + put(&mut s, 32, &total.to_le_bytes()); put(&mut s, 36, &per_fat.to_le_bytes()); put(&mut s, 44, &ROOT_CLUSTER.to_le_bytes()); put(&mut s, 48, &(FSINFO_SECTOR as u16).to_le_bytes()); From 24b3fb66ee8b1e7c3e530f38df6690ac06b323e4 Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 19:12:48 +0200 Subject: [PATCH 16/22] The host-tools row admits only os-release's git reads, and two citations of the JPEG go The owner's ruling, "Drop gix, use git", covers the reads that replace gitoxide's: `release`'s `log` and `status`. The row of `git` reads, the config write, the index checkout and the HTTPS clones is main's again, refused in gitoxide's favour, and a row of its own admits those two reads. README.md and issues/the-tree-says-who-uses-each-thing.md named the deleted `assets/wallpaper.jpg`. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- README.md | 2 +- issues/the-build-runs-host-tools-outside-rust-and-qemu.md | 3 ++- issues/the-tree-says-who-uses-each-thing.md | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 53175ad69d6..9c64ba1416f 100644 --- a/README.md +++ b/README.md @@ -333,7 +333,7 @@ Licensed under either of at your option. Some of what the repository carries is not ours and is under other terms: -`userland/doom` is GPL-2.0, `assets/` holds a font, a set of icons, a wallpaper +`userland/doom` is GPL-2.0, `assets/` holds a font, a set of icons and id Software's Doom shareware IWAD, and `tests/testcases/` holds TinyCC's test corpus. Third-party crates keep their own upstream licenses. **[NOTICE](NOTICE) is the list**, item by item, diff --git a/issues/the-build-runs-host-tools-outside-rust-and-qemu.md b/issues/the-build-runs-host-tools-outside-rust-and-qemu.md index 6fb48fedbf0..b37ef9fdbbc 100644 --- a/issues/the-build-runs-host-tools-outside-rust-and-qemu.md +++ b/issues/the-build-runs-host-tools-outside-rust-and-qemu.md @@ -18,7 +18,8 @@ arrives and is not one. M4 and M5 are stages of `issues/toyos-builds-itself.md`. | CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key; `src/libcxx.rs`, for the C++ runtime in every sysroot build | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest | | `sh` running LLVM's `config.guess`, and the POSIX tools and `cc` it runs | LLVM's CMake, whenever this host builds an LLVM, and the C++ runtime's, in every sysroot build, ask it the host's triple, unconditionally (`get_host_triple` in `rust/src/llvm-project/llvm/cmake/modules/GetHostTriple.cmake`, which runs `sh` by name) | refused: a Rust tool does the shell's part, brush 0.4.0: on the development host (macOS, arm64) `config.guess` printed `/bin/sh`'s triple under it, `arm64-apple-darwin27.0.0`, exit 0 each. The script runs `sed`, `uname`, `mktemp`, `grep`, `rm`, `rmdir` and `cc` there under either shell, and that `cc` is the `cc` rows'. Five of the other six are refused, uutils' doing each: under brush with sed 0.2.0, grep 0.2.0 and coreutils 0.12.0's `mktemp`, `rm` and `rmdir`, and nothing else on `PATH` but the host's `uname` and `cc`, it printed that triple, exit 0. `uname` is admitted: coreutils 0.12.0's answers `-p` with `unknown` where macOS's answers `arm`, and `config.guess` reads that as PowerPC, `powerpc-apple-darwin27.0.0`, exit 0 | CMake finds brush as its `sh`, uutils' `sed`, `grep`, `mktemp`, `rm` and `rmdir`, and a Rust `uname` that answers `-p` as the host's does; or M5 runs it in the guest | | `git` for worktrees, submodules, checkouts, fixtures and rustc's bootstrap | adds worktrees (`src/sysroot.rs`); updates submodules (`src/lib.rs`, `src/sysroot.rs`); fetches the fork from the primary's and checks it out (`src/sysroot.rs`); makes the tests' fixture repositories; runs inside rustc's bootstrap | admitted: no Rust tool does the job, gitoxide 0.85 adds, removes and prunes no worktree, updates no submodule, stages, resets and pushes nothing, checks out only a fresh clone and fetches a local path by spawning `git`; a fixture must be what `git` makes, and bootstrap runs `git` itself | M4 runs it in the guest | -| `git` for reads, a config write, a commit's paths written out, and clones and fetches over HTTPS | `rev-parse`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `config --blob`, `status`, `log`, `diff`, `ls-remote` and `grep`, in the build system and its tests, the commit, its time and whether the tree is that commit's among them (`src/build.rs`'s `release`); `config --global --add safe.directory` in CI's containers; `checkout -- ` through an index of its own, which writes the C++ runtime's sources out of the LLVM commit into the stored LLVM (`src/llvm.rs`); every workflow's checkout | admitted: the owner's ruling on the dependency audit (2026-10-09), "Drop gix, use git", over this row's earlier refusal in gitoxide's favour: gitoxide is no tool the build sheds while `git` stays for the row above, and for these reads it held 84 of the root `Cargo.lock`'s packages | M4 runs it in the guest | +| `git` for reads, a config write, a commit's paths written out, and clones and fetches over HTTPS | `rev-parse`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `config --blob`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `config --global --add safe.directory` in CI's containers; `checkout -- ` through an index of its own, which writes the C++ runtime's sources out of the LLVM commit into the stored LLVM (`src/llvm.rs`); every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, adds a value to a config file and writes it (gix-config 0.58's `File::section_mut_or_create_new`, `SectionMut::push`, `File::write_to`), walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names; and gitoxide's CLI 0.59 (gix 0.88) wrote the runtimes' sources of LLVM `849da7d6` into an empty directory, each path's tree through `gix rev parse`, `gix index from-tree` and `gix free index checkout-exclusive`, exit 0 each: the 18759 files `git` writes there, byte for byte and mode for mode | those are gitoxide's | +| `git log` and `git status` for os-release | the commit, its committer time and whether the tree is that commit's, which `src/build.rs`'s `release` writes into `/system/etc/os-release` in every image build | admitted: the owner's ruling on the dependency audit (2026-10-09), "Drop gix, use git", which covers these two reads and nothing else this table names: they were gitoxide's, gitoxide is no tool the build sheds while `git` stays for the worktree row, and for them it held 84 of the root `Cargo.lock`'s packages | M4 runs it in the guest | | `cc`, `c++` and `ar` on a Linux host, `build-essential` in CI's containers | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap); `cc` compiles ring's C and assembly in every build of the build system itself, whose HTTP agent is rustls on ring (`src/release.rs`); `ar` archives what `cc::Build` compiles, ring's included | admitted: no Rust tool compiles C or C++, or takes rustc's host link; ring is the one TLS provider the tree takes (owner, 2026-10-02), over a provider in Rust alone | M5: no host in the loop | | the toolchain's own `clang`, `llvm-ar`, `rust-lld` and `llvm-config`, built from `ToyOSOrg/llvm-project` | rustc links every guest binary with `rust-lld`; `clang` compiles the C corpus (`tests/common/compile.rs`) and, with `llvm-ar`, doomgeneric through `cc::Build` (`src/clang.rs`); rustc's bootstrap asks `llvm-config` how to link LLVM | admitted: our fork's C++, which ToyOS can one day build and run; no Rust tool compiles C, `cc::Build` archives with an `ar`, bootstrap reads LLVM through `llvm-config`, and `CLAUDE.md` links everything with `rust-lld` | M5: no host in the loop | | `ovmf-generic`, `qemu-efi-aarch64` | the x86-64 and AArch64 UEFI firmware of CI's guest containers (`src/firmware.rs`), packaged by Debian apart from QEMU | admitted: QEMU's own firmware, and no Rust firmware does its job | the instrument's QEMU carries its own firmware | diff --git a/issues/the-tree-says-who-uses-each-thing.md b/issues/the-tree-says-who-uses-each-thing.md index 07e68c8d47b..9695fc2ee79 100644 --- a/issues/the-tree-says-who-uses-each-thing.md +++ b/issues/the-tree-says-who-uses-each-thing.md @@ -121,7 +121,7 @@ Cargo.toml Cargo.lock clippy.toml .cargo/config.toml rule step 1: on loader/ the UEFI loader (today bootloader/) kernel/ CLAUDE.md; src/ pure/ loom/ sim/ pci/ gicv3/ ps2/ dma/ cpuvuln/ microcode/ (+ intel-ucode, licence) system/ CLAUDE.md (the server doctrine); one directory per /system/bin name: - supervisor compositor (desktop/ sprite/ wallpaper.jpg) + supervisor compositor (desktop/ sprite/) netstack (mdns/ dns/ and the net family) soundserver (mixer/) console diskserver fileserver logkeeper filepicker pkg update swap sshserver shell terminal toybox inspect host apps/ CLAUDE.md (sdk/ and registries only; Linux under Wayland, macOS, Windows) From a29d650e828f873dc049e3abe8d22a52db7343ff Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 19:56:44 +0200 Subject: [PATCH 17/22] A load option's HARDDRIVE node is read by main's rule again, and a panic after a refused ExitBootServices goes straight to the reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The round-1 review of #815 found the load-option walk in bootnext.rs narrowed from main's rule (SignatureType at byte 41, signature at 24..40, any node at least 42 bytes long) to HardDrive::parse's exact 42 bytes. Those bytes are any OS's to write through runtime variable access, and no test at any tier can see the rule change: QEMU only reaches the "no Boot#### entry" arm. Main's decoder is restored byte for byte; HardDrive::parse stays for device paths firmware built (boot_partition, our_partition), and the loader track's stage 2 still unifies the two under its host tests. UEFI 2.10 §7.4.6 allows only the memory allocation services after a first ExitBootServices call, failed or not. A panic in the retry (fill_memory_map's assert) reached a handler that still wrote through ConOut. EXITING is set before each exit call; print and the panic handler read the console only while it is clear, so the handler goes straight to ResetSystem. The loader track's bound no longer puts the module path in the owner's ruling, and the arm64 issue no longer says the bootloader is the uefi crate. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- bootloader/src/bootnext.rs | 18 +++++++++++---- bootloader/src/efi/mod.rs | 22 +++++++++++++++---- bootloader/src/efi/proto.rs | 4 +++- ...oes-only-what-must-precede-the-handover.md | 4 ++-- issues/toyos-runs-on-arm64.md | 4 ++-- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/bootloader/src/bootnext.rs b/bootloader/src/bootnext.rs index 54c260c9fb0..4a19e33eadc 100644 --- a/bootloader/src/bootnext.rs +++ b/bootloader/src/bootnext.rs @@ -153,7 +153,7 @@ fn load_option_names(option: &[u8], ours: &[u8; 16]) -> bool { // A node shorter than its own header, or longer than what is left, ends // the walk: neither can be stepped over. let Some(this) = path.get(..len).filter(|_| len >= NODE_HEADER) else { return false }; - if (this[0], this[1]) == HardDrive::TYPE { + if this[0] == MEDIA_HARD_DRIVE.0 && this[1] == MEDIA_HARD_DRIVE.1 { if let Some(guid) = gpt_signature(this) { return guid == *ours; } @@ -166,8 +166,18 @@ fn load_option_names(option: &[u8], ours: &[u8; 16]) -> bool { /// A device path node's type, subtype and length (UEFI 2.10 §10.2). const NODE_HEADER: usize = 4; -/// A HARD_DRIVE node's GUID signature, or `None` where it carries another or -/// is not the length §10.3.5.1 gives it. +/// The MEDIA/HARD_DRIVE node this looks for, as the two bytes it is on the wire. +const MEDIA_HARD_DRIVE: (u8, u8) = (4, 1); + +/// A HARD_DRIVE node's GPT signature, or `None` where it names an MBR one or +/// the node is short (UEFI 2.10 §10.3.6: the signature is sixteen bytes at +/// offset 24, and `SignatureType` 2 is the GPT one). fn gpt_signature(node: &[u8]) -> Option<[u8; 16]> { - HardDrive::parse(node).filter(|hd| hd.signature_type == HardDrive::GUID_SIGNATURE).map(|hd| hd.signature) + const SIGNATURE: usize = 24; + const SIGNATURE_TYPE: usize = 41; + const GPT: u8 = 2; + if node.get(SIGNATURE_TYPE) != Some(&GPT) { + return None; + } + node.get(SIGNATURE..SIGNATURE + 16)?.try_into().ok() } diff --git a/bootloader/src/efi/mod.rs b/bootloader/src/efi/mod.rs index 39b9ec9db6c..b0525001e80 100644 --- a/bootloader/src/efi/mod.rs +++ b/bootloader/src/efi/mod.rs @@ -321,6 +321,11 @@ pub const ACPI2_GUID: Guid = Guid::new(0x8868e871, 0xe4f1, 0x11d3, [0xbc, 0x22, /// console and the allocator read it; nothing else does. static SYSTEM: AtomicPtr = AtomicPtr::new(ptr::null_mut()); +/// Set before the first `ExitBootServices` call: from then on only the memory +/// allocation services may be called, even where the call fails (UEFI 2.10 +/// §7.4.6), so firmware's console is not written again. +static EXITING: AtomicBool = AtomicBool::new(false); + /// This image's handle, the agent every protocol open names. static IMAGE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); @@ -384,6 +389,7 @@ impl SystemTable { continue; } }; + EXITING.store(true, Ordering::Release); status = bs.exit(image, filled.key); if status.is_success() { SYSTEM.store(ptr::null_mut(), Ordering::Release); @@ -406,6 +412,12 @@ fn live() -> Option<&'static RawSystemTable> { unsafe { SYSTEM.load(Ordering::Acquire).as_ref() } } +/// The system table while firmware's console may be written: until the first +/// `ExitBootServices` call. +fn console() -> Option<&'static RawSystemTable> { + live().filter(|_| !EXITING.load(Ordering::Acquire)) +} + /// The image's entry (UEFI 2.10 §4.1, `EFI_IMAGE_ENTRY_POINT`), under the name /// the UEFI targets link as the PE entry point. #[unsafe(no_mangle)] @@ -423,9 +435,10 @@ extern "efiapi" fn efi_main(image: *mut c_void, system_table: *mut RawSystemTabl /// character past UCS-2 is written as U+FFFD. /// /// # Panics -/// Once boot services are gone, and where the console refuses the line. +/// From the first `ExitBootServices` call, and where the console refuses the +/// line. pub fn print(args: fmt::Arguments) { - let raw = live().expect("the console is gone with boot services"); + let raw = console().expect("the console is gone with boot services"); let mut out = Console { out: raw.con_out, units: [0; Console::CHUNK + 1], len: 0 }; let written = fmt::write(&mut out, args).and_then(|()| out.flush()); assert!(written.is_ok(), "firmware's console refused a line"); @@ -529,12 +542,13 @@ unsafe impl core::alloc::GlobalAlloc for Pool { /// power-off. static PANICKED: AtomicBool = AtomicBool::new(false); -/// Say the panic on firmware's console and power the machine off; once boot +/// Say the panic on firmware's console and power the machine off; from the +/// first `ExitBootServices` call the console is not written, and once boot /// services are gone neither is there, and the CPU spins. #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { if let Some(raw) = live() { - if !PANICKED.swap(true, Ordering::Relaxed) { + if console().is_some() && !PANICKED.swap(true, Ordering::Relaxed) { print(format_args!("[PANIC]: {info}\n")); } // SAFETY: runtime services live as long as the table. diff --git a/bootloader/src/efi/proto.rs b/bootloader/src/efi/proto.rs index d60c848a73b..c33d49b2f85 100644 --- a/bootloader/src/efi/proto.rs +++ b/bootloader/src/efi/proto.rs @@ -147,7 +147,9 @@ impl HardDrive { pub const GUID_SIGNATURE: u8 = 2; const LEN: usize = 42; - /// `node`, where it is a HARDDRIVE node of the length §10.3.5.1 gives it. + /// `node`, where it is a HARDDRIVE node of the length §10.3.5.1 gives it: + /// a node of a device path firmware built. A load option's path is any + /// writer's bytes, and `bootnext` walks it by its own rule. pub fn parse(node: &[u8]) -> Option { if node.len() != Self::LEN || (node[0], node[1]) != Self::TYPE { return None; diff --git a/issues/the-loader-does-only-what-must-precede-the-handover.md b/issues/the-loader-does-only-what-must-precede-the-handover.md index 45755df5684..df223edec5e 100644 --- a/issues/the-loader-does-only-what-must-precede-the-handover.md +++ b/issues/the-loader-does-only-what-must-precede-the-handover.md @@ -14,8 +14,8 @@ The owner's bounds: loader's, before `ExitBootServices` (root `CLAUDE.md`); - the anti-rollback floor counts a signed security version, raised only by a release that fixes a security hole; -- the loader calls UEFI through its own bindings (`bootloader/src/efi/`), - never the `uefi` crate's (the owner's ruling on the dependency audit). +- the loader calls UEFI through its own bindings, never the `uefi` crate's + (the owner's ruling on the dependency audit). PR #539 does not land. Its pieces: diff --git a/issues/toyos-runs-on-arm64.md b/issues/toyos-runs-on-arm64.md index 6f98b613235..0caf929a530 100644 --- a/issues/toyos-runs-on-arm64.md +++ b/issues/toyos-runs-on-arm64.md @@ -182,8 +182,8 @@ refuses anything but `EM_X86_64` (`toyos-elf/src/header.rs:24,75`). `irq_guard`, `halt`, `need_resched`, `switch`), with `kernel/src/arch/x86_64/hw.rs` as the one x86 implementation and a simulator as the other. PCI is ECAM/MMIO-only (`drivers/pci.rs:134-154`), no `0xCF8`. NVMe, xHCI and virtio -have no ISA dependence beyond TSC-based waits. The bootloader is the `uefi` -crate (0.26, aarch64-capable already); only 12 of its 2,881 lines are x86. +have no ISA dependence beyond TSC-based waits. The bootloader calls UEFI +through its own bindings, which boot both targets. The pure decision crates carry no arch at all: `toyos-acpi`, `-gpt`, `-fat32`, `-dma`, `-userbound`, `-proclife`, `-blackbox`, `-elide` and others. From a5d7972345aa00abffeab0f0d9bdf085510b1f6b Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 20:08:07 +0200 Subject: [PATCH 18/22] SIGALRM is declared once, sigaction answers the previous action whole, and the hosted clang's export folds into place Round 2's review of #809 asked three things. SIGALRM's number was written twice in libc, as 128 + 14 in alarm.rs and as a const in misc.rs. It is now alarmreq's SIGALRM, beside SIG_DFL and SIG_IGN, read by both; the host test compares it with signal.h's, which also gives the const a reader in toyos-libc-copies. sigaction's oldact for SIGALRM answered sa_flags and sa_mask 0 whatever the last act set. POSIX answers the previous action whole, so libc keeps the whole struct sigaction under a lock in place of the handler's atomic, and signal installs an action of the handler alone. 207_libc_names sets SA_RESTART and SIGUSR1's bit and reads both back; the C corpus runs only on metal, so the line is read by the T14's boot:testcases. hostedclang's export had one caller and three lines; place does it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- issues/an-alarm-reaches-no-sigalrm-handler.md | 2 +- src/hostedclang.rs | 17 ++++------- tests/libc-arch/src/alarm_requests.rs | 11 +++++-- tests/testcases/tinycc/207_libc_names.c | 9 ++++-- tests/testcases/tinycc/207_libc_names.expect | 2 +- userland/libc/src/alarm.rs | 30 ++++++++++--------- userland/libc/src/alarmreq.rs | 3 +- userland/libc/src/misc.rs | 22 ++++++++------ 8 files changed, 54 insertions(+), 42 deletions(-) diff --git a/issues/an-alarm-reaches-no-sigalrm-handler.md b/issues/an-alarm-reaches-no-sigalrm-handler.md index 51d9c183715..015deb5b6d7 100644 --- a/issues/an-alarm-reaches-no-sigalrm-handler.md +++ b/issues/an-alarm-reaches-no-sigalrm-handler.md @@ -29,7 +29,7 @@ both wait on that stage, its owner. What a due alarm does under each disposition is held on the host (`tests/libc-arch/src/alarm_requests.rs`); `207_libc_names.c` reads the -disposition back and arms and disarms an alarm. No guest case lets one come +action back whole and arms and disarms an alarm. No guest case lets one come due. **Exit**: a guest C case shows `SIGALRM` delivered as POSIX says: a handler diff --git a/src/hostedclang.rs b/src/hostedclang.rs index ddd86b5a340..8830107c92d 100644 --- a/src/hostedclang.rs +++ b/src/hostedclang.rs @@ -13,7 +13,7 @@ //! host's tools, n2 and CMake among them; the sysroot's, which names the C //! library, the C++ runtime and the clang that builds against them; and //! [`RECIPE`] with [`OPTIONS`]. Its sources are the commit's, written from the -//! fork's LLVM repository ([`export`]), never a checkout's files. CMake builds +//! fork's LLVM repository, never a checkout's files. CMake builds //! LLVM's tablegens for the build machine first, in a nested build of its own //! (`NATIVE`), with the C and C++ compilers the LLVM key names. //! @@ -157,8 +157,12 @@ fn place(fork: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { eprintln!("Building the ToyOS-hosted clang and LLD {key}: nobody on this host has"); let scratch = dir.with_extension("build"); keystore::remove(&scratch); + // From the LLVM repository of `fork`'s git directory: a linked worktree's + // `rust/src/llvm-project` is no checkout. let sources = scratch.join("src"); - export(fork, &sources); + let common = git_out(fork, &["rev-parse", "--path-format=absolute", "--git-common-dir"]); + let repository = Path::new(common.trim()).join("modules").join(LLVM); + crate::llvm::check_out_committed(&repository, &gitlink(fork, LLVM), &SOURCES, &sources); let built = scratch.join("build"); build(fork, &sources, &built, &CSysroot::of(sysroot, TARGET), ninja, &scratch); @@ -185,15 +189,6 @@ fn place(fork: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { keystore::remove(&scratch); } -/// Write [`SOURCES`] as the commit `fork`'s LLVM gitlink names holds them into -/// `dest`, from the LLVM repository of `fork`'s git directory: a linked -/// worktree's `rust/src/llvm-project` is no checkout. -fn export(fork: &Path, dest: &Path) { - let common = git_out(fork, &["rev-parse", "--path-format=absolute", "--git-common-dir"]); - let repository = Path::new(common.trim()).join("modules").join(LLVM); - crate::llvm::check_out_committed(&repository, &gitlink(fork, LLVM), &SOURCES, dest); -} - /// Configure LLVM at `sources`, the commit `fork` names, for `c`'s target, /// in `built`, and build clang and LLD there under `ninja`; `scratch` holds /// the links CMake runs the compilers by. diff --git a/tests/libc-arch/src/alarm_requests.rs b/tests/libc-arch/src/alarm_requests.rs index 035e3801607..e82db69a011 100644 --- a/tests/libc-arch/src/alarm_requests.rs +++ b/tests/libc-arch/src/alarm_requests.rs @@ -1,8 +1,10 @@ //! What `alarm` answers and arms: the seconds an earlier alarm has left, //! rounded up and 0 once it is due or when there is none; 0 seconds arm -//! nothing; and a due alarm ends the process unless `SIGALRM` is ignored. +//! nothing; and a due alarm ends the process unless `SIGALRM` is ignored, the +//! signal `signal.h` numbers. -use crate::alarmreq::{due, ends, left, SIG_DFL, SIG_IGN}; +use crate::alarmreq::{due, ends, left, SIGALRM, SIG_DFL, SIG_IGN}; +use crate::header::{self, SIGNAL_H}; const SEC: u64 = 1_000_000_000; @@ -32,3 +34,8 @@ fn a_due_alarm_ends_the_process_unless_sigalrm_is_ignored() { assert!(ends(SIG_DFL)); assert!(ends(0x40_1000), "a handler, which never runs, kept the process"); } + +#[test] +fn sigalrm_is_the_number_signal_h_gives_it() { + assert_eq!(SIGALRM, header::int(SIGNAL_H, "SIGALRM")); +} diff --git a/tests/testcases/tinycc/207_libc_names.c b/tests/testcases/tinycc/207_libc_names.c index 450798d19da..70512871cfb 100644 --- a/tests/testcases/tinycc/207_libc_names.c +++ b/tests/testcases/tinycc/207_libc_names.c @@ -2,7 +2,7 @@ the name and kind of each entry; dladdr naming the image and the exported symbol an address lies in; a file truncated by its path; a stream on a buffer of its caller's, or none, sought and told by off_t; SIGALRM's - disposition, and an alarm armed and disarmed; and strnlen, strsignal, modf, + action, read back whole, and an alarm armed and disarmed; and strnlen, strsignal, modf, lround, logb, pathconf and the conversions. */ #include #include @@ -132,10 +132,13 @@ static void alarms(void) { void (*then)(int) = signal(SIGALRM, SIG_DFL); printf("signal SIGALRM: was %s, then %s\n", was == SIG_DFL ? "SIG_DFL" : "another", then == SIG_IGN ? "SIG_IGN" : "another"); - struct sigaction ignore = { .sa_handler = SIG_IGN }, old = { .sa_handler = SIG_DFL }; + struct sigaction ignore = { .sa_handler = SIG_IGN, .sa_flags = SA_RESTART }, old = { .sa_handler = SIG_DFL }; + sigemptyset(&ignore.sa_mask); + sigaddset(&ignore.sa_mask, SIGUSR1); int set = sigaction(SIGALRM, &ignore, NULL); int got = sigaction(SIGALRM, NULL, &old); - printf("sigaction SIGALRM: %d %d, %s\n", set, got, old.sa_handler == SIG_IGN ? "SIG_IGN" : "another"); + printf("sigaction SIGALRM: %d %d, %s, flags 0x%lx, mask 0x%lx\n", set, got, + old.sa_handler == SIG_IGN ? "SIG_IGN" : "another", old.sa_flags, (unsigned long)old.sa_mask); signal(SIGALRM, SIG_DFL); unsigned first = alarm(5); unsigned left = alarm(0); diff --git a/tests/testcases/tinycc/207_libc_names.expect b/tests/testcases/tinycc/207_libc_names.expect index 861af38ad2e..7723ab5c435 100644 --- a/tests/testcases/tinycc/207_libc_names.expect +++ b/tests/testcases/tinycc/207_libc_names.expect @@ -10,7 +10,7 @@ setbuf: file 0 bytes, the buffer holds them ftello: 10; fseeko 3: 0; ftello: 3; fgetc: 3 setbuf NULL: file 3 bytes signal SIGALRM: was SIG_DFL, then SIG_IGN -sigaction SIGALRM: 0 0, SIG_IGN +sigaction SIGALRM: 0 0, SIG_IGN, flags 0x10000000, mask 0x200 alarm 5: 0; alarm 0: 1 to 5; again: 0 entry: a DT_UNKNOWN entry: b DT_UNKNOWN diff --git a/userland/libc/src/alarm.rs b/userland/libc/src/alarm.rs index cfd0d6d4b08..391af7d15b5 100644 --- a/userland/libc/src/alarm.rs +++ b/userland/libc/src/alarm.rs @@ -6,16 +6,17 @@ //! (`issues/an-alarm-reaches-no-sigalrm-handler.md`). use core::ptr; -use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering}; use toyos_abi::syscall; use crate::alarmreq; +use crate::misc::SigAction; use crate::pthread::Lock; /// What the process ends with when its alarm is due: the code of an end by -/// `SIGALRM` (14), as `abort`'s is `SIGABRT`'s. -const ALARM_END: i32 = 128 + 14; +/// `SIGALRM`, as `abort`'s is `SIGABRT`'s. +const ALARM_END: i32 = 128 + alarmreq::SIGALRM; struct Alarm { /// When the alarm is due, in the monotonic clock's nanoseconds. @@ -29,17 +30,18 @@ static ALARM: Lock = Lock::new(Alarm { due: None, kept: false }); /// Moved at every `alarm`, so a keeper asleep on an older one wakes. static TURN: AtomicU32 = AtomicU32::new(0); -/// `SIGALRM`'s disposition: `SIG_DFL`, `SIG_IGN` or a handler's address. -static DISPOSITION: AtomicUsize = AtomicUsize::new(alarmreq::SIG_DFL); +/// `SIGALRM`'s action, whose handler is its disposition: `SIG_DFL`, `SIG_IGN` +/// or a handler's address. +static ACTION: Lock = Lock::new(SigAction::of(alarmreq::SIG_DFL)); -/// Make `handler` `SIGALRM`'s disposition, and answer the one it replaces. -pub(crate) fn dispose(handler: usize) -> usize { - DISPOSITION.swap(handler, Ordering::AcqRel) -} - -/// `SIGALRM`'s disposition. -pub(crate) fn disposition() -> usize { - DISPOSITION.load(Ordering::Acquire) +/// Make `new`, if any, `SIGALRM`'s action, and answer the one it replaces whole. +pub(crate) fn act(new: Option) -> SigAction { + let mut action = ACTION.lock(); + let old = *action; + if let Some(new) = new { + *action = new; + } + old } fn now() -> u64 { @@ -78,7 +80,7 @@ unsafe extern "C" fn keep(_: *mut u8) -> *mut u8 { None => None, Some(due) => match due.checked_sub(now()) { Some(wait) if wait > 0 => Some(wait), - _ if alarmreq::ends(disposition()) => syscall::exit(ALARM_END), + _ if alarmreq::ends(act(None).handler) => syscall::exit(ALARM_END), _ => { alarm.due = None; None diff --git a/userland/libc/src/alarmreq.rs b/userland/libc/src/alarmreq.rs index d32a4230222..e8c7f2c1d7f 100644 --- a/userland/libc/src/alarmreq.rs +++ b/userland/libc/src/alarmreq.rs @@ -4,7 +4,8 @@ const NANOS_PER_SEC: u64 = 1_000_000_000; -/// `signal.h`'s `SIG_DFL` and `SIG_IGN`, as addresses. +/// `signal.h`'s `SIGALRM`, and its `SIG_DFL` and `SIG_IGN` as addresses. +pub(crate) const SIGALRM: i32 = 14; pub(crate) const SIG_DFL: usize = 0; pub(crate) const SIG_IGN: usize = 1; diff --git a/userland/libc/src/misc.rs b/userland/libc/src/misc.rs index 571337c6b8c..e707e1478a4 100644 --- a/userland/libc/src/misc.rs +++ b/userland/libc/src/misc.rs @@ -6,6 +6,7 @@ use core::sync::atomic::{AtomicU32, Ordering}; use toyos_abi::syscall; +use crate::alarmreq::SIGALRM; use crate::errno::{ECHILD, ENOSYS}; use crate::strtonum; @@ -210,22 +211,28 @@ pub unsafe extern "C" fn abort() -> ! { // Signal (stubs — ToyOS has no signals, but `SIGALRM`'s disposition decides // what a due `alarm` does) -const SIGALRM: i32 = 14; - /// `signal.h`'s `struct sigaction`. #[repr(C)] +#[derive(Clone, Copy)] pub struct SigAction { - handler: usize, + pub(crate) handler: usize, flags: u64, restorer: usize, mask: u64, } +impl SigAction { + /// The action of `handler` alone, as `signal` makes one. + pub(crate) const fn of(handler: usize) -> Self { + Self { handler, flags: 0, restorer: 0, mask: 0 } + } +} + /// A handler by its address: `SIG_DFL` and `SIG_IGN` are no functions. #[no_mangle] pub unsafe extern "C" fn signal(signum: i32, handler: *const u8) -> *const u8 { match signum { - SIGALRM => crate::alarm::dispose(handler as usize) as *const u8, + SIGALRM => crate::alarm::act(Some(SigAction::of(handler as usize))).handler as *const u8, _ => handler, // return the handler as "previous", effectively a no-op } } @@ -235,12 +242,9 @@ pub unsafe extern "C" fn sigaction(signum: i32, act: *const SigAction, oldact: * if signum != SIGALRM { return 0; // success } - let old = match unsafe { act.as_ref() } { - Some(act) => crate::alarm::dispose(act.handler), - None => crate::alarm::disposition(), - }; + let old = crate::alarm::act(unsafe { act.as_ref() }.copied()); if let Some(oldact) = unsafe { oldact.as_mut() } { - *oldact = SigAction { handler: old, flags: 0, restorer: 0, mask: 0 }; + *oldact = old; } 0 } From ab977259620c694ff897869443af26b8ddeb72ce Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 20:27:02 +0200 Subject: [PATCH 19/22] The loader issue's stage 4 panics straight to the shutdown from EXITING on, and stage 2 names both HARDDRIVE decoders it folds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stage 4's handler writes loader.log through the File protocol, which UEFI 2.10 §7.4.6 forbids from the first ExitBootServices call as it forbids the console; as written it would undo the EXITING fix. It now skips loaderlog from EXITING on and goes straight to ResetSystem's shutdown. Stage 2 called toyos_update::entry::partition the one HARDDRIVE rule but named neither of the loader's two decoders going, efi::HardDrive::parse and bootnext::gpt_signature, so it could close with three. Both are named, and the exit gains an rg that finds them today. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- ...loader-does-only-what-must-precede-the-handover.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/issues/the-loader-does-only-what-must-precede-the-handover.md b/issues/the-loader-does-only-what-must-precede-the-handover.md index df223edec5e..8ade7486848 100644 --- a/issues/the-loader-does-only-what-must-precede-the-handover.md +++ b/issues/the-loader-does-only-what-must-precede-the-handover.md @@ -85,7 +85,10 @@ Each stage lands on its own, in this order. 2. **One boot disk.** - `toyos_update::entry::partition` is the one HARDDRIVE rule, taken by - `boot_partition`, `rootimage::boot_disk` and `bootnext.rs`. + `boot_partition`, `rootimage::boot_disk` and `bootnext.rs`. The loader's + two decoders go into it: `efi::HardDrive::parse` (`efi/proto.rs`), which + reads firmware-built paths, and `bootnext::gpt_signature`, which reads a + load option's. - Every volume the loader opens (the slot's FAT partition, the log partition and the attempts file on it) is found on the boot disk, where exactly one match is taken. `loaderlog::volume_handle`'s machine-wide @@ -96,7 +99,8 @@ Each stage lands on its own, in this order. one `Disk::open` and slot-table read, and one file reader. `load_file_bytes`, `MAX_ESP_FILE` and the unsound `alloc_uninit` go. - **Exit**: `a_path_names_the_partition_of_its_one_hard_drive_node` and + **Exit**: `rg 'fn gpt_signature|fn parse' bootloader/src/{bootnext.rs,efi/proto.rs}` + finds nothing. `a_path_names_the_partition_of_its_one_hard_drive_node` and `a_partitions_disk_is_the_path_before_its_hard_drive_node` pass on the host, and fail under two mutations: cutting the disk before the path's last node, and taking a second HARDDRIVE node. `root_named_twice` plants a twin whose @@ -151,6 +155,9 @@ Each stage lands on its own, in this order. - The loader's `#[panic_handler]` writes `loader: panicked at :: ` through `loaderlog`, then powers the machine off. It never resets: a panic with a fixed cause would reset into itself. + From `EXITING` on (the first `ExitBootServices` call) it skips `loaderlog` + and goes straight to `ResetSystem`'s shutdown, since UEFI 2.10 §7.4.6 + forbids the File protocol from that call on as it forbids the console. The refused-floor site stops writing its reason to `loader.log` before its `panic!`: the handler writes it. - `alloc_kernel_memory` stops building a `Vec` over a 2 MiB-aligned From 4ce7ce79a3f9aac8fe844d529333b469470035b4 Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 20:41:15 +0200 Subject: [PATCH 20/22] The ToyOS-hosted clang builds from the sources the host's LLVM keeps in the store `--hosted-clang` read the LLVM commit from the primary checkout's `.git/modules/rust/modules/src/llvm-project`, a repository no build fetches into: after #790 moved the gitlink to ToyOSOrg/llvm-project b7420fe it held no such commit (its origin is rust-lang's), and the build died with `unable to read tree`. The normal build obtains the commit one way: bootstrap's `Llvm` step checks the gitlink's commit out in the fork checkout and fetches it there, and `llvm::place` writes what builds read of it into `llvm//src` from that checkout; the C++ runtime is built from there. The LLVM now keeps the hosted clang's pathspecs there too, and the hosted clang builds from that directory of the LLVM it holds in use: the commit is the one the host LLVM's key names on any host, whether the LLVM was built here or found in the store, and no checkout is read. The pathspecs an LLVM keeps are now part of its key, so a change to either list moves it; the recipe moves to 5, and every LLVM key with it. The hosted clang's key names the LLVM's key, which now names its sources, so it drops its own copy of them; its recipe moves to 3. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- src/hostedclang.rs | 85 +++++++++++++++++++++++----------------------- src/llvm.rs | 68 +++++++++++++++++++++++-------------- 2 files changed, 85 insertions(+), 68 deletions(-) diff --git a/src/hostedclang.rs b/src/hostedclang.rs index 8830107c92d..0b117aa1b6b 100644 --- a/src/hostedclang.rs +++ b/src/hostedclang.rs @@ -8,14 +8,15 @@ //! **Made only when asked for** (`cargo run -- --hosted-clang`): its build is //! LLVM's, and its key moves with every sysroot's, so no other build makes it. //! -//! **A function of its key** ([`key`]): the host LLVM's key, which names the -//! commit, the revision and repository it says it was built from, and the -//! host's tools, n2 and CMake among them; the sysroot's, which names the C -//! library, the C++ runtime and the clang that builds against them; and -//! [`RECIPE`] with [`OPTIONS`]. Its sources are the commit's, written from the -//! fork's LLVM repository, never a checkout's files. CMake builds -//! LLVM's tablegens for the build machine first, in a nested build of its own -//! (`NATIVE`), with the C and C++ compilers the LLVM key names. +//! **A function of its key** ([`key_of`]): the host LLVM's key, which names the +//! commit, what of it the LLVM keeps, the revision and repository it says it +//! was built from, and the host's tools, n2 and CMake among them; the +//! sysroot's, which names the C library, the C++ runtime and the clang that +//! builds against them; and [`RECIPE`] with [`OPTIONS`]. Its sources are +//! [`SOURCES`] of the commit as that LLVM keeps them in the store +//! (`src/llvm.rs`), never a checkout's files. CMake builds LLVM's tablegens for +//! the build machine first, in a nested build of its own (`NATIVE`), with the C +//! and C++ compilers the LLVM key names. //! //! `hosted-clang//` in the store holds `bin/clang`, `bin/ld.lld` and //! clang's resource headers in `lib/clang//include`, where clang looks @@ -28,25 +29,24 @@ use std::process::Command; use crate::arch::Arch; use crate::buildlock::{Guard, Keyed}; use crate::clang::CSysroot; -use crate::compiler::LLVM; use crate::keystore::{self, Key}; -use crate::sysroot::{clone_tree, git_out, gitlink}; +use crate::sysroot::clone_tree; /// What changes how the key's sources become this product and is none of the /// other parts. Moving it moves every key. -const RECIPE: &str = "CMake and n2 build of clang and lld from the LLVM commit's SOURCES, for the TARGET \ +const RECIPE: &str = "CMake and n2 build of clang and lld from the SOURCES the host's LLVM keeps, for the TARGET \ against its C sysroot, saying the version, revision and repository the host's clang \ says; of the build, clang as bin/clang, lld as bin/ld.lld and clang's resource \ - headers; 2"; + headers; 3"; /// The ToyOS the binaries run on. const TARGET: Arch = Arch::X86_64; -/// What of the commit the build reads, as git's pathspecs: LLVM, clang and -/// LLD, the CMake modules they share, the third-party sources LLVM compiles in, -/// and libunwind's headers, which LLD's Mach-O port reads. No test, which the -/// configuration builds none of. -const SOURCES: [&str; 12] = [ +/// What of the commit the build reads, as git's pathspecs the host's LLVM keeps: +/// LLVM, clang and LLD, the CMake modules they share, the third-party sources +/// LLVM compiles in, and libunwind's headers, which LLD's Mach-O port reads. No +/// test, which the configuration builds none of. +pub(crate) const SOURCES: [&str; 12] = [ "llvm", "clang", "lld", @@ -100,7 +100,11 @@ pub fn dispatch(root: &Path) { let mut lock = crate::buildlock::shared(root, "the ToyOS-hosted clang"); let sysroot = crate::toolchain::ensure(root, &mut lock); let fork = crate::sysroot::fork_checkout(root, &mut lock); - let hosted = resolve(&keystore::host(), &fork, sysroot.dir(), &crate::n2::ninja(root)); + let store = keystore::host(); + // Inside the worktree lock, which keeps every build in `fork` but an + // LLVM's, whose key's lock serialises them, out. + let llvm = crate::llvm::resolve(root, &store, &fork); + let hosted = resolve(&store, &fork, &llvm.dir, sysroot.dir(), &crate::n2::ninja(root)); for (_, kept) in BINARIES { let binary = hosted.dir.join("bin").join(kept); let size = fs::metadata(&binary).unwrap_or_else(|e| panic!("stat {}: {e}", binary.display())).len(); @@ -108,27 +112,26 @@ pub fn dispatch(root: &Path) { } } -/// The product the LLVM fork `fork` names and the sysroot `sysroot` holds, in -/// `store`: made if nobody on this host has made it, under `ninja`. -pub fn resolve(store: &Path, fork: &Path, sysroot: &Path, ninja: &Path) -> HostedClang { - let key = key(fork, sysroot); +/// The product of the LLVM at `llvm`, the one the fork `fork` names, and the +/// sysroot at `sysroot`, both held in use in `store`: made if nobody on this +/// host has made it, under `ninja`. +pub fn resolve(store: &Path, fork: &Path, llvm: &Path, sysroot: &Path, ninja: &Path) -> HostedClang { + let key = key_of(&stored(llvm), &stored(sysroot), &options()); let dir = Keyed::HostedClang.store(store).join(&key); - let make = || place(fork, sysroot, ninja, &key, &dir); + let make = || place(fork, llvm, sysroot, ninja, &key, &dir); let using = keystore::made(store, Keyed::HostedClang, &key, || defect(&dir), make); HostedClang { dir, _using: using } } -/// The key of what `fork`'s LLVM and the sysroot at `sysroot` make. -fn key(fork: &Path, sysroot: &Path) -> Key { - let named = sysroot.file_name().and_then(|n| n.to_str()).and_then(Key::parse); - let sysroot = - named.unwrap_or_else(|| panic!("{} is no sysroot of the store: its name is no key", sysroot.display())); - key_of(&crate::llvm::key(fork), &sysroot, &options()) +/// The key the store product at `dir` is filed under. +fn stored(dir: &Path) -> Key { + let named = dir.file_name().and_then(|n| n.to_str()).and_then(Key::parse); + named.unwrap_or_else(|| panic!("{} is no product of the store: its name is no key", dir.display())) } fn key_of(llvm: &Key, sysroot: &Key, options: &[(String, String)]) -> Key { let options: Vec = options.iter().map(|(name, value)| format!("{name}={value}")).collect(); - let parts = [RECIPE, TARGET.userland(), &SOURCES.join(" "), &options.join("\n"), llvm.as_str(), sysroot.as_str()]; + let parts = [RECIPE, TARGET.userland(), &options.join("\n"), llvm.as_str(), sysroot.as_str()]; Key::of(parts.join("\n\0\n").as_bytes()) } @@ -153,18 +156,12 @@ fn defect(dir: &Path) -> Option { } /// Build what `key` names and put it at `dir`. The caller holds the key's lock. -fn place(fork: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { +fn place(fork: &Path, llvm: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { eprintln!("Building the ToyOS-hosted clang and LLD {key}: nobody on this host has"); let scratch = dir.with_extension("build"); keystore::remove(&scratch); - // From the LLVM repository of `fork`'s git directory: a linked worktree's - // `rust/src/llvm-project` is no checkout. - let sources = scratch.join("src"); - let common = git_out(fork, &["rev-parse", "--path-format=absolute", "--git-common-dir"]); - let repository = Path::new(common.trim()).join("modules").join(LLVM); - crate::llvm::check_out_committed(&repository, &gitlink(fork, LLVM), &SOURCES, &sources); let built = scratch.join("build"); - build(fork, &sources, &built, &CSysroot::of(sysroot, TARGET), ninja, &scratch); + build(fork, &llvm.join("src"), &built, &CSysroot::of(sysroot, TARGET), ninja, &scratch); let partial = dir.with_extension("partial"); keystore::remove(&partial); @@ -178,9 +175,13 @@ fn place(fork: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { let resource = crate::clang::resource_version(&built); let version = resource.file_name().unwrap_or_else(|| panic!("{} names no version", resource.display())); clone_tree(&resource.join("include"), &partial.join("lib/clang").join(version).join("include")); - // What was built is what the key names, or it is not that key's. - let again = self::key(fork, sysroot); - assert!(again == *key, "the sources moved while {key} was being built (they now name {again}); nothing was kept"); + // The fork the version stamp was read from names the LLVM built, or this + // is not the key's. + let again = crate::llvm::key(fork); + assert!( + again == stored(llvm), + "the fork moved while {key} was being built (it now names LLVM {again}); nothing was kept" + ); let source = partial.join(SOURCE); fs::write(&source, format!("{key}\n")).unwrap_or_else(|e| panic!("write {}: {e}", source.display())); crate::llvm::read_only(&partial); @@ -189,7 +190,7 @@ fn place(fork: &Path, sysroot: &Path, ninja: &Path, key: &Key, dir: &Path) { keystore::remove(&scratch); } -/// Configure LLVM at `sources`, the commit `fork` names, for `c`'s target, +/// Configure LLVM at `sources`, of the commit `fork` names, for `c`'s target, /// in `built`, and build clang and LLD there under `ninja`; `scratch` holds /// the links CMake runs the compilers by. fn build(fork: &Path, sources: &Path, built: &Path, c: &CSysroot, ninja: &Path, scratch: &Path) { diff --git a/src/llvm.rs b/src/llvm.rs index 11fe103cf95..68e1cdd9f9d 100644 --- a/src/llvm.rs +++ b/src/llvm.rs @@ -5,12 +5,13 @@ //! the fork checkout's gitlink names (`sysroot::gitlink`, which refuses a //! checkout holding what no commit does and a gitlink staged and not committed), //! the committed tree of its `src/bootstrap` (one holding what no commit does is -//! refused), the bootstrap configuration below, [`RECIPE`], and the tools the +//! refused), the bootstrap configuration below, [`recipe`], and the tools the //! host builds it with ([`host_tools`]). `llvm//` in the store //! (`src/keystore.rs`) is what builds read of bootstrap's install of that LLVM and its clang //! ([`keep`]), with its LLD in `bin/` beside `llvm-config` and in `src/` the -//! runtimes' sources the C++ runtime is built from (`src/libcxx.rs`) as its -//! commit holds them, made by whichever build first needs it ([`resolve`]), and +//! sources the C++ runtime (`src/libcxx.rs`) and the ToyOS-hosted clang +//! (`src/hostedclang.rs`) are built from as its commit holds them ([`sources`]), +//! made by whichever build first needs it ([`resolve`]), and //! stored only when it was built from what the key names. Once its [`SOURCE`] //! file exists it is read-only, its directories as well as its files. //! Every compiler build names it as the host's `llvm-config` with @@ -50,7 +51,7 @@ use crate::toolchain::{self, host_triple}; const RECIPE: &str = "bootstrap build of src/llvm-project/llvm and src/llvm-project/lld; of the install, \ llvm-config, clang and llvm-ar in bin, and llvm-objcopy on an Apple host, LLVM's headers, \ every library llvm-config names and clang's resource headers; lld in bin, and the \ - runtimes' sources in src, read-only; 4"; + sources the C++ runtime and the ToyOS-hosted clang are built from in src, read-only; 5"; /// What of the caller's environment the LLVM build, and every tool its key /// asks, sees: @@ -127,7 +128,7 @@ pub fn host_lines(dir: &Path) -> String { /// changes no commit does. pub fn key(fork: &Path) -> Key { let tools = host_tools(); - key_of(fork, RECIPE, &config_text(Path::new(KEYED_BUILD_DIR), &host_triple(), tools, &stamp(fork)), &tools.identity) + key_of(fork, &recipe(), &config_text(Path::new(KEYED_BUILD_DIR), &host_triple(), tools, &stamp(fork)), &tools.identity) } /// What an LLVM, its clang and its LLD say they were built from. @@ -167,6 +168,17 @@ pub(crate) fn host_compilers() -> (PathBuf, PathBuf) { (tools.cc.clone(), tools.cxx.clone()) } +/// [`RECIPE`], with the pathspecs of what it keeps of the commit. +fn recipe() -> String { + format!("{RECIPE}\n{}", sources().join(" ")) +} + +/// What of the commit an LLVM keeps in `src/`, as git's pathspecs: what the C++ +/// runtime and the ToyOS-hosted clang are built from. +fn sources() -> Vec<&'static str> { + crate::libcxx::SOURCES.into_iter().chain(crate::hostedclang::SOURCES).collect() +} + /// [`key`], with what it reads beside `fork`'s committed `src/bootstrap`: /// `config` names the LLVM's commit ([`stamp`]). fn key_of(fork: &Path, recipe: &str, config: &str, tools: &str) -> Key { @@ -269,7 +281,7 @@ pub(crate) fn defect(dir: &Path) -> Option { .iter() .chain(&["lib/clang"]) .map(|k| dir.join(k)) - .chain(crate::libcxx::SOURCES.iter().map(|s| dir.join("src").join(s))); + .chain(sources().into_iter().filter(|s| !s.starts_with(':')).map(|s| dir.join("src").join(s))); let tools = tools().map(|t| dir.join("bin").join(t)).filter(|p| !p.is_file()); let gone: Vec = kept.filter(|p| !p.is_dir()).chain(tools).map(|p| p.display().to_string()).collect(); (!gone.is_empty()).then(|| format!("{} carries no {}", dir.display(), gone.join(", "))) @@ -322,8 +334,7 @@ fn place(fork: &Path, key: &Key, dir: &Path, build: &impl Fn(&Path) -> PathBuf) built_from.trim(), fork.display(), ); - let repository = git_out(&checkout, &["rev-parse", "--absolute-git-dir"]); - check_out_committed(Path::new(repository.trim()), &commit, &crate::libcxx::SOURCES, &partial.join("src")); + check_out_committed(&checkout, &commit, &sources(), &partial.join("src")); fs::write(partial.join(SOURCE), format!("{key}\n")) .unwrap_or_else(|e| panic!("write {}: {e}", partial.join(SOURCE).display())); read_only(&partial); @@ -371,27 +382,27 @@ fn libraries(install: &Path) -> Vec { named } -/// Write `paths` as `commit` holds them, from the git directory `repository`, +/// Write `paths` as `commit` holds them, from the repository at `checkout`, /// under `dest`: through an index of their own and with no sparse pattern, so -/// nothing a checkout of it holds beside the commit, tracked, ignored or left -/// out, reaches them. -pub(crate) fn check_out_committed(repository: &Path, commit: &str, paths: &[&str], dest: &Path) { +/// nothing the checkout holds beside the commit, tracked, ignored or left out, +/// reaches them. +fn check_out_committed(checkout: &Path, commit: &str, paths: &[&str], dest: &Path) { fs::create_dir_all(dest).unwrap_or_else(|e| panic!("create {}: {e}", dest.display())); let index = toyos_tmpdir::TempDir::new("llvm-sources-index"); let out = Command::new("git") - .env("GIT_DIR", repository) .env("GIT_INDEX_FILE", index.join("index")) .args(["-c", "core.sparseCheckout=false", "--work-tree"]) .arg(dest) .args(["checkout", commit, "--"]) .args(paths) + .current_dir(checkout) .output() - .unwrap_or_else(|e| panic!("run git in {}: {e}", repository.display())); + .unwrap_or_else(|e| panic!("run git in {}: {e}", checkout.display())); assert!( out.status.success(), - "git checkout {commit} -- {paths:?} into {} from {}: {}", + "git checkout {commit} -- {paths:?} into {} in {}: {}", dest.display(), - repository.display(), + checkout.display(), String::from_utf8_lossy(&out.stderr).trim(), ); } @@ -573,10 +584,10 @@ mod tests { if !checkout.join(".git").exists() { git(&checkout, &["init", "-q"]); } - write(&checkout.join("llvm/CMakeLists.txt"), content); - for source in crate::libcxx::SOURCES { + for source in sources().into_iter().filter(|s| !s.starts_with(':')) { write(&checkout.join(source).join("CMakeLists.txt"), &format!("the {source} of {content}")); } + write(&checkout.join("llvm/test/lit.cfg.py"), "what no build reads"); git(&checkout, &["add", "-A"]); let tree = git(&checkout, &["write-tree"]); let out = Command::new("git") @@ -749,7 +760,7 @@ mod tests { let tools = host_tools(); let config = config_text(Path::new(KEYED_BUILD_DIR), &host_triple(), tools, &stamp(&fork)); let base = key(&fork); - assert_eq!(key_of(&fork, RECIPE, &config, &tools.identity), base); + assert_eq!(key_of(&fork, &recipe(), &config, &tools.identity), base); let elsewhere = if host_triple() == "x86_64-unknown-linux-gnu" { "aarch64-unknown-linux-gnu" } else { @@ -758,9 +769,9 @@ mod tests { let elsewhere = config_text(Path::new(KEYED_BUILD_DIR), elsewhere, tools, &stamp(&fork)); for (what, other) in [ ("the recipe", key_of(&fork, "another recipe", &config, &tools.identity)), - ("the [llvm]", key_of(&fork, RECIPE, &config.replace("X86", "RISCV;X86"), &tools.identity)), - ("the host", key_of(&fork, RECIPE, &elsewhere, &tools.identity)), - ("the host's tools", key_of(&fork, RECIPE, &config, "/usr/bin/gcc\ngcc 14\n")), + ("the [llvm]", key_of(&fork, &recipe(), &config.replace("X86", "RISCV;X86"), &tools.identity)), + ("the host", key_of(&fork, &recipe(), &elsewhere, &tools.identity)), + ("the host's tools", key_of(&fork, &recipe(), &config, "/usr/bin/gcc\ngcc 14\n")), ] { assert_ne!(other, base, "{what} did not move the key"); } @@ -819,7 +830,7 @@ mod tests { "--show-sdk-version" => format!("{version}\n"), other => panic!("xcrun was asked {other}"), }); - key_of(&fork, RECIPE, &config_text(Path::new(KEYED_BUILD_DIR), &host_triple(), &tools, &stamp(&fork)), &tools.identity) + key_of(&fork, &recipe(), &config_text(Path::new(KEYED_BUILD_DIR), &host_triple(), &tools, &stamp(&fork)), &tools.identity) }); assert_ne!(older, newer, "two SDK versions at one SDK path named one LLVM"); } @@ -1013,11 +1024,13 @@ mod tests { assert!(stored.iter().all(|n| n.to_string_lossy().ends_with(".partial")), "stored: {stored:?}"); } - /// **The runtimes' sources are the commit's**: made while the LLVM was + /// **The sources it keeps are the commit's**: made while the LLVM was /// built, an edit to a file the commit holds is refused and nothing is - /// stored, and a file the checkout ignores is not stored with it. + /// stored, a file the checkout ignores is not stored with it, and the + /// ToyOS-hosted clang's are kept beside the runtimes' without the tests + /// its pathspecs leave out. #[test] - fn the_runtimes_sources_are_the_commit_s() { + fn the_kept_sources_are_the_commit_s() { let scratch = Scratch::new("llvm-runtimes"); let (_primary, store, [_same, a, _b]) = estate_built(&scratch); let fork = a.join("rust"); @@ -1042,6 +1055,9 @@ mod tests { assert_eq!(fs::read_to_string(dir.join("src/libcxx/CMakeLists.txt")).unwrap(), "the libcxx of A"); assert!(checkout.join("libcxx/utils/cache.pyc").is_file()); assert!(!dir.join("src/libcxx/utils").exists(), "a file the checkout ignores was stored"); + assert_eq!(fs::read_to_string(dir.join("src/clang/CMakeLists.txt")).unwrap(), "the clang of A"); + assert!(checkout.join("llvm/test/lit.cfg.py").is_file()); + assert!(!dir.join("src/llvm/test").exists(), "a test the pathspecs leave out was stored"); } const WORKTREE: &str = "TOYOS_LLVM_TEST_WORKTREE"; From 85d3eb4529adb71b5ebafbd7019b5c9b371ec2cf Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 21:37:32 +0200 Subject: [PATCH 21/22] An LLVM the hosted clang needs is made with the worktree lock held exclusively `--hosted-clang` resolved the host's LLVM holding its worktree's build lock only shared. When the store lacked it, bootstrap's `Llvm` step then ran in the fork checkout, updating `src/llvm-project` and writing `build/toyos-llvm`, beside every other shared holder of the same worktree, which `buildlock.rs` names as the exclusive mode's job; the compiler and sysroot builders reach `llvm::resolve` only inside exclusive phases. `llvm::resolve_held` asks under the shared lock whether the store holds the LLVM the fork names, and makes one only through `Held::act_if`, with the lock exclusive; one the store holds is found with the lock shared, at no cost of serialisation. `an_llvm_is_made_only_with_the_worktree_lock_exclusive` holds both halves: a shared acquirer is kept out while the LLVM is made, and a second worktree held shared by another process finds it without waiting. The store design stays, on two measurements. A linked worktree whose LLVM came from the store holds no LLVM commit in its fork's `src/llvm-project`: of the 16 on this host with a fork checkout, none did (`git cat-file -e ^{tree}` exits 128 in each, its directory empty), and only the one whose bootstrap built the LLVM held it. A fresh depth-1 fetch of the commit from the fork's remote took 23 s and 278 MiB per worktree. Keeping the hosted clang's sources in the stored LLVM costs 61.6 MB compressed per `llvm` entry, packed as actions/cache packs it (posix tar, zstd -T0 --long=30): 102,023,921 bytes at recipe 4 against 163,600,770 at recipe 5, of one LLVM with only its `src/` differing. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- src/buildlock.rs | 14 ++++++++++++++ src/hostedclang.rs | 4 +--- src/llvm.rs | 46 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/buildlock.rs b/src/buildlock.rs index ee6a4af25ab..e7c786ba094 100644 --- a/src/buildlock.rs +++ b/src/buildlock.rs @@ -602,6 +602,16 @@ pub(crate) mod tests { Elsewhere::hold("buildlock::tests::child_role", &env) } + /// `root`'s worktree lock held shared by a process of its own. + pub(crate) fn shared_elsewhere(root: &Path) -> Elsewhere { + held_elsewhere(root, "hold-shared") + } + + /// Whether `root`'s worktree lock would keep a shared acquirer out now. + pub(crate) fn keeps_out_shared(root: &Path) -> bool { + !try_lock(&open_lock_file(&worktree_lock_dir(root).join("state")), LOCK_SH) + } + /// What `role` of [`child_role`] takes in `root`, held by a process of its own. fn held_elsewhere(root: &Path, role: &str) -> Elsewhere { Elsewhere::hold("buildlock::tests::child_role", &[(ROLE, OsStr::new(role)), (ROOT, root.as_os_str())]) @@ -707,6 +717,10 @@ pub(crate) mod tests { let mut held = shared(&root, "child"); held.act_if("queued exclusive phase", || Some(()), |()| note(&root, "ex")); } + "hold-shared" => { + let _held = shared(&root, "child"); + hold_until_released(); + } "want-shared" => { let _held = shared(&root, "child"); note(&root, "sh"); diff --git a/src/hostedclang.rs b/src/hostedclang.rs index 0b117aa1b6b..a4480cf4b6d 100644 --- a/src/hostedclang.rs +++ b/src/hostedclang.rs @@ -101,9 +101,7 @@ pub fn dispatch(root: &Path) { let sysroot = crate::toolchain::ensure(root, &mut lock); let fork = crate::sysroot::fork_checkout(root, &mut lock); let store = keystore::host(); - // Inside the worktree lock, which keeps every build in `fork` but an - // LLVM's, whose key's lock serialises them, out. - let llvm = crate::llvm::resolve(root, &store, &fork); + let llvm = crate::llvm::resolve_held(root, &store, &fork, &mut lock); let hosted = resolve(&store, &fork, &llvm.dir, sysroot.dir(), &crate::n2::ninja(root)); for (_, kept) in BINARIES { let binary = hosted.dir.join("bin").join(kept); diff --git a/src/llvm.rs b/src/llvm.rs index 68e1cdd9f9d..2a7196b8bc6 100644 --- a/src/llvm.rs +++ b/src/llvm.rs @@ -40,7 +40,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::OnceLock; -use crate::buildlock::{Guard, Keyed}; +use crate::buildlock::{Guard, Held, Keyed}; use crate::compiler::LLVM; use crate::keystore::{self, Key}; use crate::sysroot::{clone_tree, git_bytes, git_out, gitlink}; @@ -257,6 +257,24 @@ pub fn resolve(root: &Path, store: &Path, fork: &Path) -> Llvm { choose(store, fork, |fork| build_in_fork(root, fork)) } +/// [`resolve`] for a build holding its worktree's lock shared as `lock`: an +/// LLVM the store lacks is made with that lock held exclusively, so no other +/// build of the worktree runs in `fork` beside bootstrap's. +pub fn resolve_held(root: &Path, store: &Path, fork: &Path, lock: &mut Held) -> Llvm { + choose_held(store, fork, lock, |fork| build_in_fork(root, fork)) +} + +/// [`resolve_held`] with the build passed in, as [`choose`] takes it. +fn choose_held(store: &Path, fork: &Path, lock: &mut Held, build: impl Fn(&Path) -> PathBuf) -> Llvm { + let mut made = None; + let lacking = || defect(&Keyed::Llvm.store(store).join(key(fork))).map(drop); + lock.act_if("make the host's LLVM", lacking, |()| made = Some(choose(store, fork, &build))); + let unbuilt = |_: &Path| -> PathBuf { + panic!("the LLVM {} names left the store while this build held its worktree lock shared, which builds none", fork.display()) + }; + made.unwrap_or_else(|| choose(store, fork, unbuilt)) +} + /// [`resolve`] with the build that makes an LLVM passed in, so a test can stand /// in for bootstrap: `build` builds in the fork checkout it is given and returns /// the build directory, holding `/llvm` and `/lld`. @@ -1115,6 +1133,32 @@ mod tests { assert_eq!(defect(&choose(&store, &b.join("rust"), never).dir), None); } + /// **An LLVM is made only with the worktree lock exclusive, and one the + /// store holds is found under the shared lock**: while `a`'s is made, a + /// shared acquirer of `a`'s lock is kept out; `b`, whose worktree another + /// build holds shared, finds that LLVM without waiting for it to finish. + #[test] + fn an_llvm_is_made_only_with_the_worktree_lock_exclusive() { + let scratch = Scratch::new("llvm-held"); + let (_primary, store, [_same, a, b]) = estate_built(&scratch); + let mut lock = buildlock::shared(&a, "the test's build"); + let makes = Cell::new(0); + let alone = |fork: &Path| { + makes.set(makes.get() + 1); + assert!(buildlock::tests::keeps_out_shared(&a), "an LLVM was built in {} beside shared holders", fork.display()); + fake_build(fork) + }; + let made = choose_held(&store, &a.join("rust"), &mut lock, alone); + assert_eq!(makes.get(), 1); + assert_eq!(defect(&made.dir), None); + + let other = buildlock::tests::shared_elsewhere(&b); + let mut lock = buildlock::shared(&b, "the test's build"); + let never = |_: &Path| -> PathBuf { panic!("an LLVM the store holds was made again") }; + assert_eq!(choose_held(&store, &b.join("rust"), &mut lock, never).dir, made.dir); + other.release(); + } + /// **A sweep takes an LLVM only once nothing has used it for the store's /// keep time and nobody uses it**: `a` moves to another LLVM while a /// process of its own still uses the first, which placing the second From 1bfc3e9d298146213e80c79e1767cd3a1e7c557d Mon Sep 17 00:00:00 2001 From: japabu Date: Fri, 9 Oct 2026 21:52:33 +0200 Subject: [PATCH 22/22] A held build decides whether its LLVM is whole under the key's use, and makes it if a sweep took it `choose_held` read `defect` with no lock on the LLVM's key, and only then took the key's use inside `keyed_made`. A placement elsewhere could sweep an LLVM unused for the keep time in that gap, since nobody held its key, and `keyed_made` then found a defect and ran `unbuilt`, which panicked where the right outcome is to make the LLVM. It now takes `buildlock::keyed_using` first and reads the defect under it, which no sweep takes from under it. A whole LLVM is returned held; one that is not has its use dropped, since the worktree lock orders before the key's, and goes through `act_if`, whose exclusive branch makes it; if the second look finds it whole, the loop takes the use again. `unbuilt` and its panic go. `choose_held` takes the whole-check as a parameter, as it takes the build, so `a_sweep_after_the_llvm_is_found_whole_fails_no_build` can run a real `keystore::sweep` right after the check answers: it panicked before this change and passes after. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C --- src/buildlock.rs | 2 +- src/llvm.rs | 69 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/buildlock.rs b/src/buildlock.rs index e7c786ba094..d6c679c9640 100644 --- a/src/buildlock.rs +++ b/src/buildlock.rs @@ -221,7 +221,7 @@ fn keyed_building(store: &Path, kind: Keyed, key: &Key) -> Guard { /// Use what `key` names: shared, so any number of builds use it at once, a /// builder of it is waited for, and a sweep cannot remove it; and dated now, /// which a sweep reads as its last use. -fn keyed_using(store: &Path, kind: Keyed, key: &Key) -> Guard { +pub(crate) fn keyed_using(store: &Path, kind: Keyed, key: &Key) -> Guard { let path = keyed_lock_path(store, kind, key); let file = open_lock_file(&path); if !try_lock(&file, LOCK_SH) { diff --git a/src/llvm.rs b/src/llvm.rs index 2a7196b8bc6..7306e9e008c 100644 --- a/src/llvm.rs +++ b/src/llvm.rs @@ -40,7 +40,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::OnceLock; -use crate::buildlock::{Guard, Held, Keyed}; +use crate::buildlock::{self, Guard, Held, Keyed}; use crate::compiler::LLVM; use crate::keystore::{self, Key}; use crate::sysroot::{clone_tree, git_bytes, git_out, gitlink}; @@ -261,18 +261,35 @@ pub fn resolve(root: &Path, store: &Path, fork: &Path) -> Llvm { /// LLVM the store lacks is made with that lock held exclusively, so no other /// build of the worktree runs in `fork` beside bootstrap's. pub fn resolve_held(root: &Path, store: &Path, fork: &Path, lock: &mut Held) -> Llvm { - choose_held(store, fork, lock, |fork| build_in_fork(root, fork)) + choose_held(store, fork, lock, defect, |fork| build_in_fork(root, fork)) } -/// [`resolve_held`] with the build passed in, as [`choose`] takes it. -fn choose_held(store: &Path, fork: &Path, lock: &mut Held, build: impl Fn(&Path) -> PathBuf) -> Llvm { - let mut made = None; - let lacking = || defect(&Keyed::Llvm.store(store).join(key(fork))).map(drop); - lock.act_if("make the host's LLVM", lacking, |()| made = Some(choose(store, fork, &build))); - let unbuilt = |_: &Path| -> PathBuf { - panic!("the LLVM {} names left the store while this build held its worktree lock shared, which builds none", fork.display()) - }; - made.unwrap_or_else(|| choose(store, fork, unbuilt)) +/// [`resolve_held`] with the build passed in, as [`choose`] takes it, and what +/// decides whether the stored LLVM is whole, so a test can sweep the store +/// once it has answered. +fn choose_held( + store: &Path, + fork: &Path, + lock: &mut Held, + whole: impl Fn(&Path) -> Option, + build: impl Fn(&Path) -> PathBuf, +) -> Llvm { + let key = key(fork); + let dir = Keyed::Llvm.store(store).join(&key); + loop { + // Decided under the key's use, which no sweep takes from under it. + let using = buildlock::keyed_using(store, Keyed::Llvm, &key); + if whole(&dir).is_none() { + return Llvm { dir, _using: using }; + } + // The worktree lock orders before the key's. + drop(using); + let mut made = None; + lock.act_if("make the host's LLVM", || whole(&dir).map(drop), |()| made = Some(choose(store, fork, &build))); + if let Some(made) = made { + return made; + } + } } /// [`resolve`] with the build that makes an LLVM passed in, so a test can stand @@ -1148,17 +1165,43 @@ mod tests { assert!(buildlock::tests::keeps_out_shared(&a), "an LLVM was built in {} beside shared holders", fork.display()); fake_build(fork) }; - let made = choose_held(&store, &a.join("rust"), &mut lock, alone); + let made = choose_held(&store, &a.join("rust"), &mut lock, defect, alone); assert_eq!(makes.get(), 1); assert_eq!(defect(&made.dir), None); let other = buildlock::tests::shared_elsewhere(&b); let mut lock = buildlock::shared(&b, "the test's build"); let never = |_: &Path| -> PathBuf { panic!("an LLVM the store holds was made again") }; - assert_eq!(choose_held(&store, &b.join("rust"), &mut lock, never).dir, made.dir); + assert_eq!(choose_held(&store, &b.join("rust"), &mut lock, defect, never).dir, made.dir); other.release(); } + /// **A sweep that lands once a held build has found its LLVM whole fails no + /// build**: the stored LLVM, unused for the keep time, is swept by a + /// placement elsewhere right after it is found whole, and the build goes on + /// with a whole LLVM. + #[test] + fn a_sweep_after_the_llvm_is_found_whole_fails_no_build() { + let scratch = Scratch::new("llvm-held-swept"); + let (_primary, store, [_same, a, _b]) = estate_built(&scratch); + let fork = a.join("rust"); + drop(choose(&store, &fork, fake_build)); + let unused = key(&fork); + let swept = Cell::new(None); + let then_swept = |dir: &Path| { + let found = defect(dir); + if swept.get().is_none() { + last_used(&store, Keyed::Llvm, &unused, LONG_AGO); + swept.set(Some(keystore::sweep(&store, Keyed::Llvm).len())); + } + found + }; + let mut lock = buildlock::shared(&a, "the test's build"); + let llvm = choose_held(&store, &fork, &mut lock, then_swept, fake_build); + assert_eq!(defect(&llvm.dir), None, "the build went on with an LLVM that is not whole"); + assert!(swept.get().is_some(), "the stand-in sweep never ran"); + } + /// **A sweep takes an LLVM only once nothing has used it for the store's /// keep time and nobody uses it**: `a` moves to another LLVM while a /// process of its own still uses the first, which placing the second