From bbe7fee51cb368343b91aea7dbc92afb67a19ea5 Mon Sep 17 00:00:00 2001 From: Kita Lembrik Date: Mon, 20 Apr 2026 02:41:53 +0400 Subject: [PATCH 1/4] Add gamemode: RetroArch session management, coin-based timing, game selector UI --- README.md | 212 +++++++++++++++++++++++++++ src/config.rs | 20 ++- src/main.rs | 141 ++++++++++++++++++ src/retroarch.rs | 89 ++++++++++++ src/sound.rs | 47 ++++-- ui/assets/one_minute_left.wav | Bin 0 -> 76950 bytes ui/assets/two_minutes_left.wav | Bin 0 -> 82658 bytes ui/main_window.slint | 40 ++++++ ui/pages/insert_coins.slint | 256 +++++++++++++++++++++++++++++++++ ui/pages/main.slint | 15 +- 10 files changed, 807 insertions(+), 13 deletions(-) create mode 100644 README.md create mode 100644 src/retroarch.rs create mode 100644 ui/assets/one_minute_left.wav create mode 100644 ui/assets/two_minutes_left.wav create mode 100644 ui/pages/insert_coins.slint diff --git a/README.md b/README.md new file mode 100644 index 0000000..e0f49b8 --- /dev/null +++ b/README.md @@ -0,0 +1,212 @@ +# dramma ๐ŸŽฎ๐Ÿ’ธ + +Donation kiosk + arcade machine for Hackerembassy. +Accepts cash (bills + coins), processes donations, and now lets people insert coins to play retro games on RetroArch. + +--- + +## Running + +```bash +nix-shell +cargo run +``` + +The app starts fullscreen. Tap the logo **5 times** to open the diagnostics panel. + +--- + +## Configuration + +Create `.config/dramma.toml` next to the binary (or in the working directory you run from): + +```toml +token = "your-bearer-token" + +# Optional overrides (these are the defaults): +home_assistant_url = "https://ha.hackem.cc/web-dramma/0?BrowserID=dramma" +cashcode_serial_port = "/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_D-if00-port0" +cctalk_serial_port = "/dev/ttyUSB0" +stats_db_path = "data/Stats.db" +``` + +--- + +## ๐Ÿ•น๏ธ Setting Up Games (Arcade Mode) + +Pressing **PLAY** on the main screen takes the user to the coin-insertion screen where they can select a game and insert money: + +> **100 AMD = 5 minutes of playtime** +> **50 AMD = 2 minutes 30 seconds** + +When they hit **Launch**, dramma starts RetroArch fullscreen + kiosk and auto-closes it when the time runs out. The speaker will announce "2 minutes left" and "1 minute left". + +### Step 1 โ€” Install RetroArch + +```bash +# NixOS +nix-env -iA nixpkgs.retroarch + +# Or add to your system configuration.nix: +environment.systemPackages = [ pkgs.retroarch ]; +``` + +Make sure `retroarch` is on `PATH`. By default dramma just calls `retroarch`. You can override this in the config: + +```toml +retroarch_command = "/run/current-system/sw/bin/retroarch" +``` + +### Step 2 โ€” Install cores (emulators) + +Each game needs a **libretro core** โ€” a `.so` plugin file that emulates a specific console. + +```bash +# Find available cores in nixpkgs: +nix search nixpkgs libretro + +# Install a core, e.g. nestopia (NES emulator): +nix-env -iA nixpkgs.libretro.nestopia + +# Or add to configuration.nix: +environment.systemPackages = with pkgs.libretro; [ + nestopia # NES (Tetris, Super Mario Bros) + fbneo # Arcade (Pac-Man, Street Fighter II) + picodrive # Sega Genesis (Sonic the Hedgehog) + dosbox # DOS (DOOM) + snes9x # SNES +]; +``` + +After install, find where the `.so` files ended up: + +```bash +find /nix/store -name "nestopia_libretro.so" 2>/dev/null +# โ†’ /nix/store/xxxx-nestopia-x.x.x/lib/retroarch/cores/nestopia_libretro.so +``` + +> **Tip:** Use a stable symlink if you don't want to update the path after every nixpkgs update: +> ```nix +> # In configuration.nix +> environment.etc."retroarch/cores".source = pkgs.symlinkJoin { +> name = "retroarch-cores"; +> paths = with pkgs.libretro; [ nestopia fbneo picodrive dosbox ]; +> } + "/lib/retroarch/cores"; +> ``` +> Then paths look like `/etc/retroarch/cores/nestopia_libretro.so`. + +### Step 3 โ€” Get your ROMs + +Put your ROM files somewhere on the machine, e.g. `/home/dramma/roms/`. + +``` +/home/dramma/roms/ +โ”œโ”€โ”€ tetris.nes +โ”œโ”€โ”€ pacman.zip +โ”œโ”€โ”€ sonic.md +โ””โ”€โ”€ doom.wad +``` + +> ROMs are not included for obvious copyright reasons. You know where to find them. + +### Step 4 โ€” Configure games in dramma.toml + +Add a `[[games]]` block for each game. `name` is what shows up in the UI, `core` is the path to the `.so`, `rom` is the path to your ROM file. + +```toml +retroarch_command = "retroarch" + +[[games]] +name = "๐Ÿงฑ Tetris" +core = "/etc/retroarch/cores/nestopia_libretro.so" +rom = "/home/dramma/roms/tetris.nes" + +[[games]] +name = "๐ŸŸก Pac-Man" +core = "/etc/retroarch/cores/fbneo_libretro.so" +rom = "/home/dramma/roms/pacman.zip" + +[[games]] +name = "๐Ÿฆ” Sonic the Hedgehog" +core = "/etc/retroarch/cores/picodrive_libretro.so" +rom = "/home/dramma/roms/sonic.md" + +[[games]] +name = "๐Ÿ”ซ DOOM" +core = "/etc/retroarch/cores/dosbox_pure_libretro.so" +rom = "/home/dramma/roms/doom.wad" + +[[games]] +name = "๐Ÿ‘Š Street Fighter II" +core = "/etc/retroarch/cores/fbneo_libretro.so" +rom = "/home/dramma/roms/sf2.zip" +``` + +If `[[games]]` is **not configured**, the UI shows a built-in placeholder list (same names, no actual cores/ROMs). RetroArch will still launch but will open its own menu โ€” not useful in production. + +### Step 5 โ€” Test it manually first + +Before trusting the machine to do it, test the exact command dramma will run: + +```bash +retroarch --fullscreen --kiosk -L /path/to/core_libretro.so /path/to/rom +``` + +If the game boots correctly, the config is right. If RetroArch opens its menu instead of loading the game, the core or ROM path is wrong. + +### Common issues + +| Problem | Fix | +|---|---| +| RetroArch opens the menu instead of the game | Wrong core or ROM path. Check paths are correct and the file exists. | +| `retroarch: command not found` | RetroArch not on PATH. Set `retroarch_command` to the full path. | +| Game loads but controls don't work | Configure controller mappings inside RetroArch first, then re-enable kiosk mode. | +| DOOM launches but shows "IWAD not found" | DOOM needs the `.wad` file. Use `doom1.wad` (shareware, freely distributable) or `doom.wad`. | +| Arcade ROMs (Pac-Man, SF2) don't load | FBNeo needs the ROM in a `.zip` file with the exact internal filenames. Use a verified ROM set. | +| Session ends but RetroArch is still open | Check that dramma has permission to `kill` the RetroArch process (usually fine if running as the same user). | + +--- + +## Money โ†’ Time conversion + +| Inserted | Play time | +|---|---| +| 50 ึ | 2 min 30 sec | +| 100 ึ | 5 min | +| 200 ึ | 10 min | +| 500 ึ | 25 min | +| 1000 ึ | 50 min | + +--- + +## Architecture + +``` +main.rs +โ”œโ”€โ”€ bill_acceptor โ€” CashCode bill acceptor driver (serial) +โ”œโ”€โ”€ coin_acceptor โ€” ccTalk coin acceptor driver (serial) +โ”œโ”€โ”€ donation_handler โ€” Donation flow + inactivity timeout +โ”œโ”€โ”€ game_handler โ€” Arcade mode: RetroArch lifecycle + session timer +โ”œโ”€โ”€ home_assistant_handler โ€” Chromium kiosk for HASS page +โ””โ”€โ”€ diagnostics_handler โ€” Debug log viewer + +src/ +โ”œโ”€โ”€ cashcode.rs โ€” CashCode serial protocol +โ”œโ”€โ”€ cctalk.rs โ€” ccTalk serial protocol +โ”œโ”€โ”€ config.rs โ€” dramma.toml loader +โ”œโ”€โ”€ retroarch.rs โ€” RetroArch process manager +โ”œโ”€โ”€ sound.rs โ€” Audio (yippee + time warnings) +โ””โ”€โ”€ ... + +ui/ +โ”œโ”€โ”€ pages/ +โ”‚ โ”œโ”€โ”€ main.slint โ€” Main screen (Donate / Play / HASS) +โ”‚ โ”œโ”€โ”€ insert_coins.slint โ€” Game selector + coin insertion +โ”‚ โ”œโ”€โ”€ insert_money.slint โ€” Donation coin insertion +โ”‚ โ”œโ”€โ”€ donate.slint โ€” Donation form +โ”‚ โ””โ”€โ”€ ... +โ””โ”€โ”€ assets/ + โ”œโ”€โ”€ yippee.wav + โ”œโ”€โ”€ two_minutes_left.wav + โ””โ”€โ”€ one_minute_left.wav +``` diff --git a/src/config.rs b/src/config.rs index b3a7c24..70b2cf0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,11 +15,22 @@ pub enum ConfigError { ParseError(#[from] toml::de::Error), } +/// A single playable game entry, configured via `dramma.toml`. +#[derive(Debug, Clone, Deserialize)] +pub struct GameEntry { + pub name: String, + /// Path to the libretro core `.so` file (e.g. `/path/to/nestopia_libretro.so`). + pub core: String, + /// Path to the ROM file. + pub rom: String, +} + #[derive(Debug, Clone, Deserialize)] #[serde(default)] pub struct Config { pub token: Option, pub home_assistant_url: String, + pub hass_api_port: u16, pub cashcode_serial_port: String, /// Serial port for the ccTalk coin acceptor. Set to `"auto"` (the /// default) to probe all available USB serial ports at startup and on @@ -32,6 +43,10 @@ pub struct Config { /// means position 1 โ†’ 50 AMD, position 3 โ†’ 500 AMD. pub cctalk_coin_overrides: Vec<[i32; 2]>, pub stats_db_path: String, + /// Command used to launch RetroArch (default: `"retroarch"`). + pub retroarch_command: String, + /// List of playable games. If empty, the UI shows a built-in demo list. + pub games: Vec, } impl Default for Config { @@ -39,12 +54,15 @@ impl Default for Config { Self { token: None, home_assistant_url: "https://ha.hackem.cc/web-dramma/0?BrowserID=dramma".to_string(), + hass_api_port: 8321, cashcode_serial_port: "/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_D-if00-port0" .to_string(), - cctalk_serial_port: "auto".to_string(), + cctalk_serial_port: "/dev/ttyUSB0".to_string(), cctalk_coin_overrides: Vec::new(), stats_db_path: "data/Stats.db".to_string(), + retroarch_command: "retroarch".to_string(), + games: Vec::new(), } } } diff --git a/src/main.rs b/src/main.rs index 072976f..fdffa5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ mod donation; mod error; mod funds; mod home_assistant; +mod retroarch; mod sound; use cashcode::{BillEvent, CashCode}; @@ -66,6 +67,7 @@ pub fn main() { ); donation_handler::init(&main_window, &config, cashcode_tx, cctalk_tx); home_assistant_handler::init(&main_window, &config); + game_handler::init(&main_window, &config); main_window.run().unwrap(); } @@ -1008,3 +1010,142 @@ mod home_assistant_handler { }); } } + +mod game_handler { + use super::*; + use crate::config::GameEntry; + use crate::retroarch::RetroArchManager; + use slint::{Timer, TimerMode}; + use std::sync::Arc; + + pub fn init(app: &MainWindow, config: &Config) { + // Populate game-names from config (empty list โ†’ UI uses built-in fallback) + if !config.games.is_empty() { + let names: Vec = config + .games + .iter() + .map(|g| slint::SharedString::from(g.name.clone())) + .collect(); + app.set_game_names(slint::ModelRc::new(slint::VecModel::from(names))); + } + + let retroarch = Arc::new(RetroArchManager::new(&config.retroarch_command)); + let games = config.games.clone(); + + // Active timers โ€” kept alive via Rc> + let session_timer: Rc>> = Rc::new(RefCell::new(None)); + let two_min_timer: Rc>> = Rc::new(RefCell::new(None)); + let one_min_timer: Rc>> = Rc::new(RefCell::new(None)); + let tick_timer: Rc>> = Rc::new(RefCell::new(None)); + + let weak = app.as_weak(); + + app.on_launch_game({ + let retroarch = retroarch.clone(); + let games = games.clone(); + let session_timer = session_timer.clone(); + let two_min_timer = two_min_timer.clone(); + let one_min_timer = one_min_timer.clone(); + let tick_timer = tick_timer.clone(); + let weak = weak.clone(); + + move |amount, game_name| { + // Compute session duration: 100 AMD = 300 seconds + let total_secs = (amount as u64) * 3; + info!( + "๐ŸŽฎ Game session: {} AMD โ†’ {} sec, game: {}", + amount, total_secs, game_name + ); + + // Find the matching GameEntry (if configured), otherwise use a blank entry + // so RetroArch launches with its own saved config. + let entry: GameEntry = games + .iter() + .find(|g| g.name == game_name.as_str()) + .cloned() + .unwrap_or_else(|| GameEntry { + name: game_name.to_string(), + core: String::new(), + rom: String::new(), + }); + + if let Err(e) = retroarch.launch(&entry) { + error!("๐ŸŽฎ Failed to launch RetroArch: {}", e); + // No RetroArch โ†’ still start the UI session so the user isn't stuck + } + + // Initialise countdown display + if let Some(w) = weak.upgrade() { + w.set_game_seconds_left(total_secs as i32); + } + + // โ”€โ”€ 1-second countdown ticker โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + { + let weak_tick = weak.clone(); + let ticker = Timer::default(); + ticker.start(TimerMode::Repeated, Duration::from_secs(1), move || { + if let Some(w) = weak_tick.upgrade() { + let cur = w.get_game_seconds_left(); + if cur > 0 { + w.set_game_seconds_left(cur - 1); + } + } + }); + *tick_timer.borrow_mut() = Some(ticker); + } + + // โ”€โ”€ "2 minutes left" milestone โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + if total_secs > 120 { + let fire_at = Duration::from_secs(total_secs - 120); + let t = Timer::default(); + t.start(TimerMode::SingleShot, fire_at, || { + info!("๐Ÿ”Š Announcing: 2 minutes left"); + crate::sound::play_two_minutes_left(); + }); + *two_min_timer.borrow_mut() = Some(t); + } + + // โ”€โ”€ "1 minute left" milestone โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + if total_secs > 60 { + let fire_at = Duration::from_secs(total_secs - 60); + let t = Timer::default(); + t.start(TimerMode::SingleShot, fire_at, || { + info!("๐Ÿ”Š Announcing: 1 minute left"); + crate::sound::play_one_minute_left(); + }); + *one_min_timer.borrow_mut() = Some(t); + } + + // โ”€โ”€ Session-end timer โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + { + let retroarch_end = retroarch.clone(); + let weak_end = weak.clone(); + let tick_end = tick_timer.clone(); + let two_end = two_min_timer.clone(); + let one_end = one_min_timer.clone(); + + let t = Timer::default(); + t.start( + TimerMode::SingleShot, + Duration::from_secs(total_secs), + move || { + info!("๐ŸŽฎ Game session expired โ€” closing RetroArch"); + retroarch_end.close(); + + // Stop all running timers + *tick_end.borrow_mut() = None; + *two_end.borrow_mut() = None; + *one_end.borrow_mut() = None; + + if let Some(w) = weak_end.upgrade() { + w.set_game_seconds_left(0); + w.invoke_game_time_expired(); + } + }, + ); + *session_timer.borrow_mut() = Some(t); + } + } + }); + } +} diff --git a/src/retroarch.rs b/src/retroarch.rs new file mode 100644 index 0000000..7e3fdc7 --- /dev/null +++ b/src/retroarch.rs @@ -0,0 +1,89 @@ +use crate::config::GameEntry; +use log::{error, info}; +use std::process::{Child, Command}; +use std::sync::{Arc, Mutex}; + +/// Manages a RetroArch subprocess for the arcade game mode. +pub struct RetroArchManager { + process: Arc>>, + retroarch_command: String, +} + +impl RetroArchManager { + pub fn new(retroarch_command: &str) -> Self { + Self { + process: Arc::new(Mutex::new(None)), + retroarch_command: retroarch_command.to_string(), + } + } + + /// Launch RetroArch fullscreen in kiosk mode with the given game entry. + /// If `game` has empty core/rom paths, RetroArch is launched bare (uses its own last-used config). + pub fn launch(&self, game: &GameEntry) -> Result<(), String> { + let mut process_guard = self.process.lock().unwrap(); + + // Kill any already-running session + if let Some(ref mut child) = *process_guard { + info!("๐ŸŽฎ Killing existing RetroArch process before relaunch"); + let _ = child.kill(); + let _ = child.wait(); + } + + info!( + "๐ŸŽฎ Launching RetroArch: game=\"{}\" core=\"{}\" rom=\"{}\"", + game.name, game.core, game.rom + ); + + let mut cmd = Command::new(&self.retroarch_command); + cmd.arg("--fullscreen").arg("--kiosk"); + + if !game.core.is_empty() { + cmd.arg("-L").arg(&game.core); + } + if !game.rom.is_empty() { + cmd.arg(&game.rom); + } + + match cmd.spawn() { + Ok(child) => { + info!("๐ŸŽฎ RetroArch launched with PID {}", child.id()); + *process_guard = Some(child); + Ok(()) + } + Err(e) => { + let msg = format!( + "Failed to launch RetroArch (command: \"{}\"): {}", + self.retroarch_command, e + ); + error!("{}", msg); + Err(msg) + } + } + } + + /// Kill the RetroArch process if running. + pub fn close(&self) { + let mut process_guard = self.process.lock().unwrap(); + if let Some(ref mut child) = *process_guard { + info!("๐ŸŽฎ Closing RetroArch process"); + if let Err(e) = child.kill() { + error!("Failed to kill RetroArch: {}", e); + } else { + let _ = child.wait(); + info!("๐ŸŽฎ RetroArch process closed"); + } + } + *process_guard = None; + } + + /// Returns `true` if RetroArch is currently running. + pub fn is_running(&self) -> bool { + self.process.lock().unwrap().is_some() + } +} + +impl Drop for RetroArchManager { + fn drop(&mut self) { + self.close(); + } +} diff --git a/src/sound.rs b/src/sound.rs index d85b1c9..2de7a56 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -6,13 +6,21 @@ use std::thread; use rodio::{Decoder, DeviceSinkBuilder, Player}; const YIPPEE_WAV: &[u8] = include_bytes!("../ui/assets/yippee.wav"); +const TWO_MINUTES_LEFT_WAV: &[u8] = include_bytes!("../ui/assets/two_minutes_left.wav"); +const ONE_MINUTE_LEFT_WAV: &[u8] = include_bytes!("../ui/assets/one_minute_left.wav"); -static AUDIO_TX: OnceLock> = OnceLock::new(); +enum SoundEvent { + Yippee, + TwoMinutesLeft, + OneMinuteLeft, +} + +static AUDIO_TX: OnceLock> = OnceLock::new(); -/// Initializes the audio subsystem. Must be called once at startup before `play_yippee`. +/// Initializes the audio subsystem. Must be called once at startup before any `play_*` calls. pub fn init() { AUDIO_TX.get_or_init(|| { - let (tx, rx) = mpsc::sync_channel::<()>(8); + let (tx, rx) = mpsc::sync_channel::(8); thread::spawn(move || { let handle = match DeviceSinkBuilder::open_default_sink() { @@ -25,8 +33,13 @@ pub fn init() { let mixer = handle.mixer(); - while rx.recv().is_ok() { - let source = match Decoder::try_from(Cursor::new(YIPPEE_WAV)) { + while let Ok(event) = rx.recv() { + let wav_bytes: &[u8] = match event { + SoundEvent::Yippee => YIPPEE_WAV, + SoundEvent::TwoMinutesLeft => TWO_MINUTES_LEFT_WAV, + SoundEvent::OneMinuteLeft => ONE_MINUTE_LEFT_WAV, + }; + let source = match Decoder::try_from(Cursor::new(wav_bytes)) { Ok(s) => s, Err(e) => { log::error!("Failed to decode WAV: {}", e); @@ -43,15 +56,29 @@ pub fn init() { }); } -/// Plays the yippee sound. -/// Requires `init()` to have been called at startup. -pub fn play_yippee() { +fn play_sound(event: SoundEvent) { match AUDIO_TX.get() { Some(tx) => { - if let Err(e) = tx.try_send(()) { - log::warn!("Audio busy, skipping yippee: {}", e); + if let Err(e) = tx.try_send(event) { + log::warn!("Audio busy, skipping sound: {}", e); } } None => log::error!("Audio not initialized โ€” call sound::init() at startup"), } } + +/// Plays the yippee sound. +/// Requires `init()` to have been called at startup. +pub fn play_yippee() { + play_sound(SoundEvent::Yippee); +} + +/// Plays the "2 minutes left" announcement. +pub fn play_two_minutes_left() { + play_sound(SoundEvent::TwoMinutesLeft); +} + +/// Plays the "1 minute left" announcement. +pub fn play_one_minute_left() { + play_sound(SoundEvent::OneMinuteLeft); +} diff --git a/ui/assets/one_minute_left.wav b/ui/assets/one_minute_left.wav new file mode 100644 index 0000000000000000000000000000000000000000..cc3668629218bfd35580e6d5b91384e5d9f10296 GIT binary patch literal 76950 zcmXVY1yCH@^Yz%yth2kYxH~~Yl(@Sm@5SBSU5UH9zPJ&0_dqCJPLw(-Gv|o(m*q&u9!Lx z{7$NPPFx^%5anW_@Lbq0OcBBa6aSRo&X40e^1(dL*Ki-XliXr%1lO1A&yD7$gYQ>y z>$sKNB5-ZvUU3jVfM3Kf<45zI!DpuPNjxEp71j%jg|31xxJC+h1g$t%d?zwuGiV4j z2f7Lc!w$F+L9t3~zT~$g6hDXWCrIfAxk}kum82?HwO3zJPjp$VnW%MYx9ZmFcbRE=7ZT10~OM$e;_s04GtTrmlT zVp7Zv3&Y~DmRKh&1cR|W^d`Cv9gQZS@u&_hL{1~a5DD@Zz6vja6JQGZ0BwLeLo`^S z6=Ixd6dntkg+78pNak1a&3PmDnmf*|25TS7HL~y7W9({n20M#g$|kbA*rV)mb}ze` z-O65KE7;cDA?^#8!rkC@a!0sqt|$MR_Y!&w?F6;Z$jgP9Lb)(S%o969`=HNIB@_g2 zgxet<(Z$#e$#xtiRuVsm+0r|*p$fU`y85_Fm5ZxpvZh#5thMVNyN-4H>Nd;mgKMqs zmiB=rMsv(X;j&syDPPFjNry|`Azk4f&>%5H&~q{LYNwAq!Wz(YzLB@AwtO=mFs(Iy zZ18AMHJoecVhl6&H)ED*mSdJAOIYK|rdBrAe$=^(EFt5mGgLcz0CSxE%6;Gm3J1Yz z)Ch6nanS`j2D!th;98i53*k5LH&~18LA2-=^fmeky^Wqj@1qnt6Z?a?OIk=;Nn*j* zfs*l(rIJL+KFKc0YRPa(w8V@($F^e=u@)GIK0=p*c)Ua=AZp|-yc7OJNVQBiInu!aQMCGToT~M#o4P4Qpt4kn4e1B>gxZTz;Ul|;TI)!$o^0G{v6u&#-nRPxzWA7ey!UxSA}ag-C)fP z)ol44d=Yv89s=pb?fh#7BDdJqH|ovV#u($UhHmw(4SQ={YCNk~R_(0nQT?|1M~%Kt zsM}(wG{n?5)}J(1m=l`1*>>3d9TyzKo%_hS~Y?AbsbeAlVyaO>HB`K2SV3iv&Gq~zNeCA_OSOt0k z9ft;@CXhc9kQju4-@;qrzOV=U8M+Paf#yRaq1KQDDi(i;cf}2M!Yq&YQMwl%m39;f7NR32b196FTylkSpkK(%Wt9p>u z={n7w@C@==<-Nschwpp8T>no2xq(-Mnt~<-c?SmjPxFO*?s;ADyy5Y$p4D1Zy=2jn zsmLT~vEahZqTbnNTi!P?b@OW7Yf`GFRDLYKTdFA;SnO3ip!iV9iqi3AN#$=UGAcV) zkF6=KZC!6R9=0g0Gs*#v5f56H{2LOtJ#U&CdvgFz*U zVr*bV?t^u?Ll@D0OgrWsGmy2hceqJ>j6ez>#XHaecoGtcHlgRS{*oa4G>#Bmh*`uu zVk8kq3?~TUBJPS$l^nwEqD3H3V7y^_~2O%yD*du6GpJ zr`vnmm)Y~|T^zF=?v7vfWcwh;Y-bi3L$_y4%wcvm_lZ9sror>EFZdtnMR^}(jQX2q zuWK)NrPn#1-+p0%KEYE%PKVwM+ZH}J@=sK!X3}P+$bI2$LT3fP2y7cr?5FgRdGyll zR7Mj?=nu%s=P`qw>l&Lke5v6oi1Np!>BU8bsremqr)JN|+LLu7dvWf6dF%5Z6c`Kt zEv_luP~oh4RlBXerHQgkvyQb-a4w-9F}?VA;vaYcdJS79>5UH~c1tPQFhzIe8Rar% zb7idZsIs~0nW|2esQRlE6oVCC;T|yE={oYc zGs$t#{?4Yg?Y72PF{{$r&w9|>+ZJLEa*T4`Bm?QoOadqH&&929f0U3M$FaIShzOPPJFICs55>)e)>lCZx9b|T58lHlMqL<;$kW;wAx8~k533NJn*IDHl z>oC}7*uUA#)OzMx)7Wb6sQ|(K(9;sN z^sYQyRq0Zxo2QTS+~D)TzjbhGSa9UlC}XqMF~?$E;*BkKx7^mUDE>$6-RL<{wc*Rd zc7)6fNbsgy)0Hx!7dlTo&ki9UHJ&p(s614nD?F3`AvY%5nxRa4{yXhg!0+HcCsP~K z-7_a=Rb_9=Jzj9NWMD;2b)4aT!#4BDrfK$OBu`J}&IuOChOEZ2B^7uEkuS}Zy^>#0 z3|D?sT9ig*y0TOmr#hjss0^xksw>KTMJvTu`9%3|S)Ozo(I^>#JwsZ+&&1BcWiFR7 zP%^TkhQPiki~Ygx604+DQjKhx zjF%mhcT)USV9HX(N`*~+MgCphR`E#jTM?&#jd+vZ+QW9hUf~!_{-riEZMX{ly!a37 zkABBy;K@W+*(rIsLa$0t_i_o)oYgor?pmeRsWEAiHB&TYE+5tXR9_Us<$9S!T8w{? zRHNtN1>zpQ6Ss+VFcTRcdN%phamPO1{>V-ryQ-EE1grF zx1CPs0`eo(3gEy${0L|WQjTpTIO$|XmdhHqe%`MF+lK1G4@D}QQ8E9tGPjHG^rFk0 z&O6#&ZS%I(w-)&={aT5!6T-jv&en_}_M<<<5bh6o-ZZ}4o;xYc<9FzvAAdgl%Kp(h zCH~X9k2k-p`eyj!nRPQ~ex9Qst4LX%S$opd%evipg=)?`=4yrC&>*y(WImosWJu+* z1lc&*AlVh!EO~2%MtNQNOxaDjM)6&~O`a(qshF!cE&nE+hKp!B#2wBMcL}>V1Fa$# z*@s)rjmIozbC|iEslD+)!|aB-hR;UG+`}@fae31rYmTkAqa*o~@?u)Bk(`k`#zzYE z!f0>?M}afB0U84v;2`8XatVEdN$?#+pzMh}TM@6?q^@*XuMKeB>$Y1T;$Efit>5of zNjp-4xcO zuqN9+Iv$a?=vB-)rWV}Z%yWQW-!Ku}8h$8mnb_9d4p4#GYty11S8sPla8)5Xs< zczxV~_LI6N^jq7vqTAdq&%6BY@}}2`epTJ8+X@juZpVpN=w$IRJHXkj=4?h-^43>N zpUr#I^kM1;{6qMgY0rAU*!tn|_w4KopftD^8T#%0E>0s99zRHy$!mjdt51@+s>O!zJgW0~I4wta_qmmv*x5iEfN; zu9kLbuU0Bg$wa&t_680S_i$EvC5byeTDiv2mRR#*Q#aFIQ**Nput%mb+q%=?MhEiK z;Es~b#5ws{RgvaDw~Lz>q+4O5#&G3(H` zc)V9$Od+wT~;;y zhu@QwtLM+8T@E=}H_BZA<4c9zg@NpB`Y8FqzS6SDFr@N9 z$&I2O#q&zHmv^b$TQ#cYmm%Cz=E&q)q6S&Is!TJ-^``!i#|zJT&taal{+q6k%Ui_; z>1IhT5+%0h^I490z?hjgEYB?zc0)IjKG-fvXM8bW6D{$J*jl7g{KfU5$2mfp)|xID zvTGF8o2yEzsOl}Xz3XBdR$JCO8aN&sqcm#~eUpdIM;_28WLvm8VqWOifK6VkYn2K{m&%55weJexKn)%1b zqoL6CUbWgu3M)1P;@O{MYw`$HK=)?-*6}q)=?kA ze*}N@zv&D6=)Gd~Pt@!2lfrp=9esn>plgXgQWNn>s#m0_H|jR(7}a#y7<2{mpeeX! ze9qHfwq(=iMJee&u$O5;yezloR zW%U8|Nrv}zNi{dBhE^5UBpdrXo{5Rlp)THTUp!j+eDXgV#0M`5>f{&g5vA!Wvm#UZ z8s{Zzh-I<KV1OzaiB0uCdkzlP~Eab^*Uca0gu(C1e$AMG5Ew4TQ6hP3Q_-EzeV} z*G_V4=bq(W=pL${sN1Z*F1wBX%c<<6jT@_SO0c54g+h^}bXj?NWuQUc6wfZl=V?}X z-1Xk$ZS_3rvC{+dY;+&4lgl}AEfwKhO3xPEBp;->JWP2|Tjr7ApB!usTI3(^Ep<&N zel!0VI^-|?`z-nB$Lx3T>#Hv`Z|{7)o;BUFQTZ`)K%e(x^QK2G7S>7YW546<_bckVW1nt#ADGdrehi%J`8?)W+clla zI=AQ$kl@zZE4F*6#nW46V>}wi)T}N0R=m65T@hZHWH{IO){#JsWj{g;ep-pESIbJE z%Ou@6&75F9Z!R!(GVX1-XG*rI_$LIci}OAmus(QEh*!v&Al$!;C!tA~{9rmZ&aEvj zMT(3CUPT*9^Q%0K*X{cSZ)v6`)nkrt7yqe#WnTUDdsQKlKyJD1Y{TU0PUV+N(SNl^1}N#wJLWueXe5&bXOcYcahsB@HeDn3@QF8@XT=AydtVfCFH zI{1&GMn~&g=tbQ(tw~#=y{In7b=;k%KE{_OyRCpNK|+X^3Q?En^CPrH?1K1r%?HH( z7k1Qpt7;@WyRI_-_wQSuAH2VX>uhyu%;P@tkv*o&nLl*pn@vAA zE!$MKq?haW9{lyRvLEN_nh_bB zAat(i?$N!Z>7x+{MXoEKfp9)I%cX(CmcFD?x z_qGZ{X8Eo<2dVFrYG{9=&3xZBfX{t z-)y!vj*UfPV#A(#SE#QEBaI)5{nDqUkRR8*J@W#7$-Z?>{+zwU^bejJG_})`L32he zo8mtwdBx&Q?ujo}-k5s0+kt>|)pn%GdDzhTZ~vrohktI}uw~uBEx)_xS@y@Y z>=Mg9qQ8Gci^UzW?vHxbbQ{>|e7oE6EyK=uCP|gl{)Uk94SBn>24~V)s|ue~lJ(u1 zsvIYobhx*?jW)^E>2i`7FZ@TYuwS=jTK{Qej6%J}_`S)>V{E|ah>p#VwM>j38?!T%@Jy2XGg&pMxv9Uld>ZuD@748ZgI>75fBP*y zKhSz#K}4+U-gfx1agV3pnU}UQKJnqEtt)CLE4ng%CZ!q~Mvkq&_xD=T>B9@Q4&S0a z)cX9VE3=ZiJ^uA}M#fNMD0bZEQ{1-p`Q41Y(4N&@cXj%&bxG7@zkSLJtioJYzB+GG z=DxJa>HTvLloVH|8`ahyWGIBoyXz9%XS$wN+(IaJFBL{kbX;i4HjXk}F)TDYog?6p z3eNSs_rri8A?w3#hwTeF;Gg2&S?LG;v2CeqUfMB_$m*Q2JCnUF+3Z52sub5XiqEW`Y#(t|Q{Uy(N?$fl*m1WX) z1R=4CC&-27!F4a{E?VN4ub8(g&~<}X`yeKAbNuPnjV;f_b&h!DU7)FZkx{?fzUXqcSADNP-G6o6 z)4|j{Ahf&NUpT@xuEt(KWHG6G|E6Xb^25vH>IBnGn=7{uU#6MoZq=W0`GqePTeB1B zb>uzU0`ql4U|pMrGHV9cg_x&dJyQMp20slO8F4uLPjI%+E$uSNDXOjULHWS^shMGE ze^SdbxV-A}p(Z`km-yoP-G5007c;hbUaTz=4!Y&ORDPEK+vrohy>NdPla`v+H_NN= zSJi^Xy?nWRi^qcCtIh5Cdcj_0ch!R4O5t?%^ExR_ThliRFm zxi-ctw8Z^8K{?|pFJ**&oAs{4%gpDSo@PG7-`9U1R1jr1srAiz^nN~a=)^}e_b#}) z$|JF9)2J2bl!aZieuI<_cog}#e%aqsxBDIbZ%f@~=n#3DsL@;ZN*@zz*s~e30d2xi-%wn(UASFD5~aMlU9h9pVxN{m>RyL*|cb5V)WFbFK7(9Nz!Mv@O0H&bKZ3r#`fUH$>cipBjX&;WZ>x{SM)>th z;0JX1r{mZbQ@m#1Uezjb`T9ZgmJb>dG0LT@WH~q3cA!M^8a->;*>UrLeM`^Xyox4$ zd=UCPH^skHPX2bO4&~x25@vS%+#YJDO{i+wDtbrYD9s`9xAkXjdg-A;V{Tk-=fe83 z8MPZs_nTTcm+<58P3lzLMa@jve^57OEP27Xz){ll-8ijoYpt^3thGNU$NklP-HJRX z``!!a8LSAA1?~1xx}K5F6)1a*sjjA={NIxAMURW8m(Q;Cv^*p)K!|LmrkDGEuMR#t zy#IKV>kcUGm>Yl6(O`aV7**4$x=YPrLzdagN%0GCQhnPU^|J&922T%k_nYClUpGf_ z9=Sn{F)ytiQu?=OcX6+>ua(1V*EfVV9jDUalM0=i)N6uQsXj-uM|oEsB~O%oKnvIl zwn>(X#{OiL*qWH2P`Q-2e)jy~uL)Ti+#_(B-w+SR<(XucBfWZh!HkThX>But(=Vlt zNlVBaSCnF@Cy2nw?e6#MJ^012ZX<&x#4KF8Vc}ZUoKF44pa=59Xa@h4%&y|z2VFR| zr}ef2hrF-+mqgz`@ObXCOP@{o?X64YlL7`dLu2>FUW%U7EF%VuofV$%^HmwdwQ9Oo z->G^>#gnpOpm*YU?PV#)&(KGF6F7qr!&jxM=cDt+ZO#pxG3UWj<_!IeC|8dm-CwKwcCA;E>3xYM@$RK*X9@G z-7bO4z7}^b+E*~7bVTDeqF3O$c8B^c7`So3ra>{o&rW4mc3Lxf?!rNaV4PSE-xni= zf2|At=x&ZVd}=3g^!?3ek3FAHeSYcbk2f1qUFuFiKlQ(Z#s*Ih*yXptw@;udd{1z; z=RU=D2B00|F~g=hOYN5G^EJ~NE?e?!`^h|JA@q@0suI;fiYI6{&P*P2#yVTscUoo` z{;j%I@u_-}@sGWM>x=$J;EH4F5?7^nSU_3eeE;2^%eAc(l;j*N=QGIe*2$)!^-SHd z`k$sxO&Vt>CP26dAC?42KgwFk|CLQ4#$p`Qh5taK|UMrT?73d3Q6~|ZZF(8&i8%FnsM##Fk(mpqXqC&C* zbA6_|chP-xIior(`-RM8XzMFWeA6w5joB;Ah4PTCxI(^2MXF+y{lLV5lV6c;fa2^& z8`jn(G_13UOlLNlenkF9(`cSPFJeUk+pWG!MccBLvs!-buzBGAA&+}~jc=vv$_6pf zkP-(h+A=R=+xvf>4t(|PduCd6y6125^ZXB%6!)wHRg8TM-z2sdM+-S(1OAW3Mc>2i zfciYPil426`qA9O7AF-sy8S{?Q_1w0w>8|-<{lV%z zW$TN76z7)b*X?K;$>@*?(i+uq*CSrr{D%a83|*6Xa+M?M5?$@d}`Hgz%{tn;o7 zuN&2{r?Hi@B^Qp|BW5d=njyNEy6f6Tb&>p!q&4)2IqW#qlwv+*5=~g+d|Mvr$sa`q zNMEQ%>Q?Fhb6>4b(D|yeh}8(r6XdMM4~7<1eEF3M(EV)a*Rr7ahn>?g`=1KLe}0JUvJGPYeF*dr>nB ziULzF8#j<>=W3EW2d zxs$bKncFqM24`KfhMtzS_I9AtPxE!DuIKpgV zBG}E`NMQnW6={PVmF&mkh=oKq;uan*X+XCkIJ{Zp`9!V-dyO&DTj@pgV|ozy%usGH zpDgr;uEST5*62KR3AzBCk2WCJ;UsYfU(L>DYd8zf3aR21NP*15?h~nUR;AM%*Iabj ztD@x_q#pQd^geWwD<+TG(i&$pzH2hrVx16`Loepy#gni%nA_VB1kD38`#|UbcZt49 zJz;K%@%ULqbC*KxF1L@KfBf%+vCZ1XrboXGyW~4o-%WE`-Ba_}<%4`ax`SEgI8PlG z&*A6f2k{)9a$1_6TkbSTnl3cVslHeone!*>O3wNGho$4H1M1L*Cx-m`{pN4BBjh&b z1bc*TXP<97Va>Jr*maIP=X?4)vx$Eu=0p47TSx&~jg=vD5q~&EOcPECKLs~&1r!2J z6}Jc!4++J>K&TiQg0+^6l1L?cvG$lZCX?(3ef-IOo& zh+IQ1CC`xsWDIqj@~1QCt&EI~W=+gL%nf=polUy~by0Jn0ZiCW3n9Wj-oP#8%DJh+ zMQ8?4f?NO!t%vA)$zh_IbUqPH43|EZSE>4IEv}^dT<`wAt9-+J$NMDv><^e1x;wHo zW_k07G6G+UJ3#~ruy0s^1oZ21IkAbzBSNL~q$j1@fqLNwF`oz~Z1^wy zA-)52|I@%MM2|6u5{ZZRLj-hL#KmqxXE582XQwe4^gf`(X+!(bHtHEQhH4=9kdw$& z?54NT9hoGyE58yb(NcwF0?&`(-*RiXuDn|80>4A* z{-?(2g^j`+36|(U3?uTSs}-4QLYL%b@d)-=>^seu^oa*5km|raVNatPVvjd}5!W?t zTkPSOxp9-?O>qq|y`!@u&qW3|D~-qvSsmoC)5oRVP5+UN0Iu#?nNby3b*ge} z<%y~XwM4@MQ$}M~yWP2;`btT_|2&^gWPSNnJk7cDbA_wWZe$J`hps`=;NGwS`U)k$ z%Mc&zx?~YP2mb*kvS+dDSg52}at$9$`~^LvNpU@H({4D7D zhf4&Y8BBwv@K#6%Jr?_jyM<%?Y;F)ckl9a1(oU+5YNG1FTJNL$saxb|vJW{6%9b5Tpj&fcXEM*}p+IL+$!zCHzCf@F&x8o!FmL9j0JUHRk3$rkgWN#oAYIUA zl2C#oW)qe8J>sn_M>$yI=Gv%V;`Puc##iUt!iV(6{T~DuhL4PX6!$)kh`ScsE9PKK zc=IWsr}iWIK-BvPm#B78yTbYhrv}{eIqfl7cUyWHYAI6UZ)hjv!^j#R8tzqhFYj4$ zyl`jkm7IU`Cggt4YLnS2eP>!phDTOpB3Hl#g|e;|rNWt)U*1uAn<#!^(LX*hxKjPG}9MB2nliBnys)A3$TF<1~vZY9yOc%cxh>7iupBQ`5+5=QZaCCr)l4J*Y;i zg8ss6W&g7G*f@3-Q%D!mSLS63 zP0~Hmv&0%AN7_@dUj0%#*lo1O9`9VA=RO^MW_kDZ=@sxeaxKl ze+u^IPR(1IKO=We_RY-w>7z4hvQn~kgBlc+aUi2j&dGuoB`qrNS4UTOs$wcPR+ZHB ztH(^AEq=B}#|N@AwVBLw-Xagt{n&c;Bs-Ix%k3AQLiKPiOhQsO7ULn=wIOh+?5yu~( zZE8ijQzAvvb<9oHi}U9mvr2Xivyqv})^fSR9H=9xj!tMQbV5uP+6u>nXlN?Z0{a1U zb-jSrOG#XnI;9lY6KkbcK}^jYXr;a%kQ!;ABM9rPj09!14mi+L8^ zKN@Scy_q~VJ7!%oYa|_hJ*;hnBitF>A+Xx-iq~sBstLyDioDhg!B&x)*h-udSXRQXu$p6u?K|72!od*yu38k{vNvtQRr9O% zR$Z@A*8eaLw`{X6aI7NRQisSSr;>a|t!DZIt;K)L7`6w0RP=)Xg-?ThRs__P4SWw_ zh8PM19UCT6Rkyi3I^_G6bB(k1dKdwDj!OmfOvjuEtK0#E$UdU(!L1w~lz#OKx zI7_?*%6?YWWJjM zw}f($p)qJo_vp{f`b1rhY7^5vCZyS$$nD`m=$-KQ;fjz15Q|bTsrw#HIldTZ@*rq5 zEQ8lEry6h9|ExJt5mdII_-g)ue5|k}|7@;%jy&sWWcJnJaQ?3dE8H zl@Dv~){LosS5;eez9!dj&)CNDuXV7aAIXyw$*s<6=N76RnC2g2+A_sVDyI;aL$5#$ z86sX1SpFpcg?|s`tGf{jy#zGL?$}$P%dA3|V67wpxGP};d4E?nUjAABQ9eiBAX@|U zh2gRxvO}^enWwx)HcB=EXxmI2ni2 z(baj@`O8`4eBu1pS>#v_VlmxeaNKfkASY6N>3GJA&0;%q6G3h~V#l(p*i~E?p#}5| zo`SSM9>DJKU}(SCRjd=g!5T0NehIYIk&^Lv8|gAxYgsF)PC81Ku5fp;YFD`J_vq*C z=hNt|@~-oo?ERmAcCcGSZ1k9zRnd~@$|!kMVDyU^Rdk=Ivk^VRUWfIINDGYs_~^FJ zCXey1nBp3|9jHxGp!0AJA7>w699id6^|R~+=uQ33+g)&@pkrPV$cKKJ{@F}UZFW`G zf~*~x%ItpmbBdpr|EjL3c~RX|l~q+({j@Hnp^dq9(?WZuQy@Q+-+`W4NmbG?TfVoRXW(Fh`+B!okrNEZ4URHZ~rj=e|o&<Q zBwr~Hl%JOAWgn#{qz|Pw=|I^j**RH&ti9BMUzYU3RHzp+5`F?Thdu!<{{bP1zsoIQ zapnoNgM8|o=iKKkbS99?$t7eLGTYhHne5o&c;@I1^0oo!t)9?lm>Dd}4d7z9EOs1V zBOBSz+!bLRbQxygN3b_M3%VvsL_~Cl!jO(wM}VZy0~EatZz(MTr`L3%fVd!=rc88k z)$MUR;IYrk=rzM@vM27j)4Rl<4z3Qbh(enMMD2>48F4G3G>Qc%b!+&o(77Q;LT`tz z2wLyo!gr(R8@FCAtMO+*_acS5!!Mxm%(SMz4RGDKs@RILrIMoT!q&yQqGkm*^73*_ zIja2W`Tg@=_=5o;nYGB zp)S&Xz^~Ao)w1R6YyO8QgWJRRA-gzK{0uw_7lfl?Cs>Y-!D_Hy*l4U0sQW*lZ7?hL zL~;UOLUflBvg5M%veiIam>_*kY$x^+sYFY_9pwr zC=&+?gLsU)%nYGBQzt+KZj&&znz}_@r^ZuhWDD}LbA|Jja~L?Y>!=s>E@l|p$d2S@ z0UiH27AUgVVs;?Fs0W~t@I>I*m;&7s9l$X|2{WMihzvV`#bY@37HbFg$`^vh|KFb3 zBnwi~>h{{JuKnEq^H|`K;+~;z=|0|Tr=LFPUg*Pc@9^efS3)0zY!96o{x!@Jk{p~F z*gkMu(2>Aiez87IOit)5yQ%CaOJ+GVhs1teQ*Y zZh_mAyAJZf$U^)PK?h;*Kv)eQ1{vH%d?0)jK8ZVkUbZ!0m3Pnvl*R_&9DW98CDZXz zLM}h5{HuPW5p|VrL-ZwX(ZIzrUoZ7q==(lkV=xu04_+CR6u3MvH|Rug$Ds0n!~Vnk zGW`blW4_D0Zg`Zt9nfx5eZ~(#w2&fZLk7sg6*-nQ>P=2Va_#eKxH7sTpz>iw%kucL zt0fU7H%e!e-6};&o0k+8?sBN`SPFPq;rezf{IR+9;|J5xlD z0IcXJ^OYUVHRJL?9X`uX6hA|~VF^4QdMU<=zdaZWA` z#3F*jxk=n0{+^(Rl<*ih5`GNy?W;u+aO!X3V3T3=Y%9#QiQ*k zDir~$VzpKCPS?Wqna*9eS$kP`PjB$#ect$w3pnO4_$Bzg^sVE%I{(N$Y3UsrfkOf8>N(W`nz-TsE5X2jCR{M@wJ6l|`v@%Yb8K8AH)F z`V*7F{=;?V3}D}dgMLmk=ofHk^#usZOS~g&1n!+0u`9e5>4)w`C!yYG3D9IV0nYRm z9e|Z$he1E181GIDA!Ni+9LH};Hb`~=7luDR6W@aO!tYDcur%~7;B&t4QD^{Q0OjIU zu`lqtH1HCBI=7sC#KbTNa2JhcPBC>%Be;{9-OMni7qgWqWw&t>z7O9U_`-a6k$VH& zcqqWLZ`onoE9) zR_cFxx%-*?DSxe>tGC@F*?p+~m+NHRU5#85rQN6->Spus^u+>eLuQ4ghDd{725$0C z_DS>z)hJ{WB%{z`co&qxy`g&1Tlv|@dweYM4|+}PDU@?5OavL-c)xB`)!p*(rLvNK zMdu5&MP#Y5Qd4)cVVUW*xyUlX^28KiyjCA+u+;vpPOoSvla`w*+SJ@I3^P*ZWk7$s zgbCyg{Cxf^cazHiJ}MboOc|W4qn&dkd7I+sE$jgPU$Gzj6-hy7W1p}x>@udtTA*!^ z;o!;Y#r@)1u+Qf}p}@5_7Rf<+qjymnRbd4nf28O-#0bxX^Pq)LFw`Ixilx9^BZ_*+ zA9904pt_wSQo>T9njgXc1+GUe$Ff1d`B=eC;VbynLL_j}jf8eU6QOFr2j>VY_^kjt zbz?)>LF^mgp*YBQ1G}U@N@3ISX9OiR$jW8cfTD6aHW>9shoE|NHWH5XM5o}}<%`u% zfxalv*~}V(D-RKYPGIfeZA*MzqUcQL$8Eg4*3(b zFEGGg?-S+@oL|H*j7QGGzr?%j07}MO6E34`h-Y{oBwnQX-dr>0g`>&TzxH6|t+GEQ zyNd@G4gxx#9cBBfit7p*W|$DmP0KE`pXqjk!|=0iLG7<9MaBIxzHC%wSq*PEZQNq< zwRIy^;QYJ82l6MlGu%5afZNRUqqaIL98;Y8$$Y94^P7Fc=ZG)hFjR(Jz#JGZ`G{$- za5NGb1a>+Gy%t}It^oh8ha-@8NN3=_bHRpT|6*R)W3)MX9--k`a22!w3WRLHdzmXX zh*HQM)G9y7A-)zTiFLvl;UnLSKLld&p1sa~0bFi3s78srzmO*!5&fW{P!#lB^Z+OQ zczy|Yiq*4bCWJl0_U2adzG4{M0>WEZ*( zKP%s-F4XRE>*w*t+vGPr!0vAXQ=T%9Z|U z3Pa?luUZ^YRStKjNt5($|HS{u-nO|5wnMayT4ejgMy4SVMs{gG>D`Uz6Do@oE z8Ri&!STd}o&R4=Bvd|4{g_^iHLrc5;K#wAp;hl4I^^vNTMpr|Uk~F0I~O@u#ez zEUzN0W}U&um~Q^ZI>XtH`M|BYOrmgR8{oI`U=Q9v zE}|{51=v!o8}e6Em(az`xq$BbY z9t4*|7eK`t2*rZjfB^eW6CaDmfV((hfUF4NezLpSf{tNd+8Bnoq6P40@87G5eYCH%Bra7o> z?^^B_>bc2xX<&!Ygz&$i*Mdg{H4hl(JKD3a_P*?pWC8jIz6Xuv8R`l3lzR-1#-KnEZ$%gM$Ddh>JZ;ScD`uxiUJ|%p4RE=l-aAS^XoTaDbuW6Bys^1Cx ztVuO5D`%AdC{tG;)l2Kb8cvxWHtx5drPA0SzLIOjIoXz6JFYMLFWru;bo_9T0vh*xo2HfU2)*X1vC!?*=L~K8?MiJxEPWRZYm&XzBReopu_5QGL z7q7Vd>9gV&h1K~Z3*AcX6|HJh z>-QN+Q!h)kd7EjdF}r@QVPIXini-Yb%Ey=6Dx@`24OIzxyCek06Ronz297F-EFmjd2+ z@Jbj3W)DgH8h#?*kMG1sfV_Fd&ER0}G~0&##w=#~GE;%uSj+BYb>JNcmw*>#Ca8Yl zz#o2G)QPi%=e#SZzNfj*TnKQ&mI%YK%lJ7XLJ|4r|wfYCHYjrB^X^l<0&2^K$nb&l` z*r3!pBZJw%z5X|RqCGyje3tf+bV5_%kz=2)Y5pTeuZILonMVtWtZ}} za=Id+W|rYw!(j8drc;h(w4D3EwcyUP``JuTO_ zIwNU_2igiuCg&ozU?VgbN)vaB>%~-n(D%Vtk)vo2>?hVsazkPP4&{%)Kk@?`h~=Wo z(JrVAxRC1+9=t_CL@JS7WIY0b?%ze|D?ne}g_U5Ml?qNbfjtMXl?dExJ?Rvx6O~NP zCp(g%q|S*s9S+73;oRelB5TOLBt$XP7Uuuhd+WC%|YGL9!glY;eo_@s@E}f*v9d!53l~b_QETa)e4z zDnA>?T}76*rf>QS+BVu$Qw(!SAaL_ku=usE$$DH{V@|_wE8YbKhK&kc85H4<2e)eb zvVC3jw1}m?XFc}>+>4kH6BIwI!<*P|oqRee!|ej1dGn8br8TyxUiaEP3SNgzsh*ZA z`*8J>{mal#^FL4ciB)`RIA1R-zW8;>r(a)F3QH=VRGuyM2L0jGTDy5LaaO!XtjC4M z{~CJLPuGn{8F8KaD31g3Vj)i4c3m|rP=#o+tOh)Zzk?f0%k?Qu@lE&C1^ONaH(i!` zxcYDHD#IJob#t|Okh#iy!ZO%8!M4rOh34UFIHmj|!DIebZXM~zIm7EBc9WlR8|}W- z?T0*AhDm=&2y!$Uex;}80=>b~rg%q5Ox2F>j-(RKIhncF3o z{<^jDL60X_J}oH=Y-p-WD^NZ7eo=Vs+>;}@T}r9q@E?Ks%YJ^UzH1xGdBP9J)at?I z85MK1^9a4SM@XCCrT#Ma$-Ed>Pi=AYanpaCB;TM`i5}5df~Fhn8OJHF=sXNjhT(?6 zhVQzs>VKM#H2wg^&1qFz%@nOv&oz12N?e(U0t-jGGUMoJh=To@|6D3_yXJOCp^-h4 zo{^rEtx~Am+ju2-uk#{2c#2Pw38EFU;sTW9q<5Ue}9eJou7RNgs)e8dThRMdOYK z7mlL`!j2LrN1k+CQ9rMEpYhUpgUIyQReof}#o4!3KD_y0)ZG!!7Jg4|kfV{3Uz}*; z?LWtU4zKCQjt>9Rn)$GpxoVjHU)GE9uT@9R23`?I_1~sRpwr< zSOqilHc200IcEkwl=@}uZ_L+zP+wOqQa)@dt?yLxxZ-YEPDw_IsBC+Mw02D6IOSzk zfAu9zNBvRLU$)0i6|<2zAs*$mH)wF^p%5~N@n!o=^K}av(Yi49PM6H2)P&Jd#(-)W z!7C&+e4XsPhf1-Kd)eMq<*X~I6<7KEs(M%SXv33jAI}zA%l|9E@~&n-e=U9T=w|Yb zGcOlb)1v>PV`EUC5m;~Y7w1-w&_s3G#tiX_?JJ#2d#rV?D_yr|<+J&nCZ&vJ&7QDg z&#Lz;F0UA{Ofc`($eX@vO5@)ADG>=4$It8XnKLyzu3ghqsgxV9z?}U}H=(X?QK#IE zA6I`W{5GwyeZ|q*ul4Wi`c(HT$NnId=jthq&C-er#s z9t%tf?jFJm4h&r9+uzIN{*T*yMTT4>?J7AgJjXr5($Y)pB2dbOYY(X7R0+y{&6^ul zb+f89hw@|OMKS6wMto%iO`mUm50Ki(N}|9K9ojqr?ZAKd1xY_98pQBR-uUDZvMc5Bw@ zzb7xOn#Wxpw|?;YfR*d!?w-(QBD&z}>d9+vuR6VI!SZDpaRdGM*S^KRW$Jo*T}#T2 z-CzlLgda9-->@Zl%jQj&H_>~|XTr~oI5=yoc*Exn9{=__gdS+#=X?D9RqMNNwJB&e ze;t;iiv8WKV59Pd+u}~s2izO@s@I9cKJmZXbqjvvCkP%Mv%A}$9s}Y%!&myA_4@7E zBpbt?XpU+QYwQm*!+zUQ%XCd-HS!DpaxFV0=VjiH;?-5cdRc?2mRFVg=iHwaRXZ9F z={{KfsQajn9m^XD#D+pqo~T~jEbHu1>2oKbBkZ}`gE9j;`Br!)x-V7yk*||$WxJ&o z(G~tiSjS$Yr#MnAiw&!_+tp`OQL2~9BhAAblj`cK!Yfw(8S>|Mxv6SsJxlqY=7P>! z|5LYB{}y@@;cA6I)aGrG9rdmbbhe5Q+T>^Pa`!s!b0)~#`bO;S&I1yd*j3>=uVj&h zoWl86lF9g6 zA4h$sO<#S(qJu(T3Fq2FO#N6Jg2l-`*)nSat5z|Mn;D=(cs{7X7BcZEKG_z0mLU z;XUg%Z}_Lj=KXt%4zJrUJuv0ei92_{&Q&iUX7b~x9`z4@bS&I&xe@R(>DIuk{*~Qp zIu~^48aXW}*&hqr7&oMQP14kud#$>AD?L>nlO!&5q2Wp6_{Qy;8)mWnmwA+GM8%zg z&YuH6`F}0@F`%q%&7g*(4UcONR^I)yv3yv~qvlNpi|rwG7tLc|~2J)ftt#a%=g!%I>x28$YOiXnW{y=-=y~8bszhwsWqNh&!9bzbM1J z{|$%+@H`zLTjwy~Bm zgeW+n`@9kLlai;WPB}4U<(yxC_gWY*d)D|ZL&HbE{_FVsF7wheCd~Pf{&;kF%pptK z*UtI=Hf3;ir~SU8svq8q`j0v~C6jYx#=&EmV=w024Y+aq)bhjI_Rl-)IIXzw{>;mB zZ*J7T$opl~_a-X2N%WJZZN+2C2RMTK8sZ~*ZcZBCv2**9$k`!%d{e!Gf=b&BiuaAX z7qQCsg_~S)K$godXWknhsvfHr=>x3;?CF+&HTPy*b8w|DZJ zGPSgabhG4)c$#Rb;59dg2xDDGGnvuUeMf<{vza!`(l6HS)c$~V`x5mj6<29%R5Wy~ z|5I;otWsjy0=>%E(Od+aj_y`3`%G~OM_V)tyXr(RP$rYoj^hd9oyzjsaG zwXo1Oc@axnHF)+HFXIFeUL3uEE4?r2&O67HnBVC7X#c2xG|*+9Kg@ZFMPq7CH(zPG zTfM*3@;j{{>Fb6ZdH(6zH%K?HxdFK13ck|jVV}*Z^PeBPtjD?mCkC}0uyBxfswORS zRNtX7y7vBK7!)b;BPI+niF|!#6NRKlj(@iq}lfKy{l^afhlEuY>MSzH{&P z{9BW54886Dy#EKqs|WYa-7sFee{1cd@lSk)TC-UjaX9-|m5|K+tV_<8Gf;cfg!D=@J`m@Nn+gXq5IZ@T;X6XxD< zmQ-n(p_|+oUiF~tKv_WL<+@Qyoo24CK`YR_QI2o!s2rf3VT!Vgsjm!%Nm#epR|!4Q zmgI6Ca1#ZeM0!b_>>$uT<%EyUPCo$JRQfUYo2r*0{4Kv1)cjc-h0!@Tv~lS$MNztk-&p zoR#j%q{eWUc@J&9s>6YVtS;f5XLpWBith1O_q@b;al@mhby$&jsoSQc4~g@-6nEMX zecJoFvr}EqhQFLMWg&jE#Lc?+n1>N@RL zJ)-ZYNmpg61lkmX)-=*~m;R4*fVW;N4d8EJA7!8Am$|WnrnDBdOK-O>a!N#Eczo;8 zZO*pd8~!uodhkDCi`$%Sb0lm<@Vg*U;8340;xlv?!vJF?CE}Hcb`WpP#)c|yrjpr`%I{vYh=C(=54 z6P$dcBHNG!*lz3rR*(7N1L5p<5+2B^#UFwqA`Q;--ecpjQJ5N?f&PL0{I|?7P&)LZ zE2-U7JY@ui=MFd<*Z|7I-3|}OH8@}Q1;z9spp3i+rEY6mFI!JrTbsKLv+1oiYp89v zt&P3T{@8KU`M0Y*b%Uy>nkfzCOK+tE86DGzXwfok4PK7>Lzxb-RY(%^nT3%Wmvm#C@WMI7)uu0NRt^g>U7h^VtF?Kb!xQ-^_n3yeqjX z^HLmhyX5v-5u)2+yZPiYv$RY31Z>RVoB^rQYIU?E`z0>#bX@%dJyD z$+FV=+qw{#ZXF$cog-XP)Dy}CB+WLUd~c%nF*A{w=uE6TuEGzndaysTE7?=o=U8n( zclw?+l3mKaK;)Bl&PeV|&MRUIdj_;(1lg4olQ)2cwV%iEhX@3Mr-BW_DB(N7D1n*( zMCb|UF3pN2cb12j`&&1GVxa7fJk9N$V!c8qPm_(8uX4L2KO!N;I|Ung54eNbad1Ms zin)t)!6qU?M~G#jImlR|>!dX)Pc<{DD{8Uowz9J_A9SV#>hH=~&1f^yw7O|G#E9Km zEx7GI8b=r(8#Wl`8=c07#$Kiz^CasXTcG`!?UU`geW9bPLu2b_U14!ql5NZF@xV9i z;k@cR<)j?pj_dX+`zgl`P+JJ8U(|d0K4^q-bTV*pf1zS59V2j@6$^bi9{dT(;0)Qx zS;a}`%md|J2`7k~2KuiZ+>P9cToLyuN5I)YI*9E=DDi3^pCB|Be=V6_()1d5} zjeG^q$R*JEZG^En(^co3=VUoAfT}`m-(mN*p90s&1?xbon-#HA7Lm0xwA&{u2U^#| zhS*%zK-)}PHK^83JKi~Sz-3{i;^4IHG4L?wF$6^WbI^*O(2BLJZ|o@IH=EC%&Prx& zWaY7f*|}^FpcVGup5@5MAM7*iAp}7-5hI8L#4j?9o6B3t@5Qg;ON1W;zxdtw>v{9} zZ$%xX`()XQU2fAAwEVa1s^pxsOr9WLC`*)`l(duT<+-x?;z&`Fz{%ao&1H9FW>S5b zUC1KrJeuNsXX#=YVp13=U8&lnT&=mU_0-%}2dG0-4)rSSezlt_S9znEtL&$Kuc^|F zG(9%EfCxF%_|A}Lykpt}&Ym3>Z%~Hm?TPl+pzUa3+=}fht*0$9)@Qa@2L&FxiEwr` z(fP{JU|$I|&p!^KOF(_2*3wB#C6k7nN9vHa=z2JvS%MA4{{l_S9-<3*fV=}^@d&wz z+(mvNlQ=IqVW93F#tjA)-y%@-0(lkMZwL`aP@oi=&!#|eb{AJ+5!f2kh-^pVLD8|D z31E)UO_V>?7kF|%9YY-&h!_9Zr`kK%Yi;vwYS7(QS=L)RTYR7vPFNzXkFA~%Tf5oX z*gS1=I5~J|J79n9a5!=56E&W$pnHKzB!}@uGLb0YJI}(>@mH)4L~AmZTux+x&Q-xC z*hbb+_HJShoQM{2S8{OjU&5bkARoalxQneMHgTr%?(@I%hY4zheMR9yH^B|wC|;Cs zu_RcwRk6vv+^w_Q0R<&pBz05lP(;g{Ws9UIB#-1)#c}COad%NK*rye7Pokl&tCWdR zU>>Zc%q8n)v&7uW@Iu$5ktp9Ow`g4&FEy>YuH2(ss@bf`RK9GU(mcIMt}Ifogx&qO z=9^}_@i%aBw5@tY_k#N-U} z4>_B|;f~>EfOq0IXELXm+(EV@o!}eFB&HC-L&UYowy&|TwXX+?Z)cbzAK0R8*Q|qKY+kkw zu&Hb>;oM2*Af2D!gl-zl0~ehCx>A8SUP(Kd&gd#^9C#6U@Mw z4Sg(%Ji$_-Cy;mO6V^gf!8rh@r!R3c`xmDbSIe$MOPQ637kH%H*_C845Px!|=Y^99 zEkiLW>~4Z>a-QcRkMD}T(q5vcq7vBzSO;Aa#qrB|h2lH%Z?YtrpZuuIOY)tlvOH6b z&?hp-ggfMa@ukkux=pG~${Y-%~+CJRjP0P@(h|XDK z$v2i8cUv|(C^`&PBmdD$ocXo_&>dh-ntF?z#fIVeSSi{Abb8@f6E+avf_G)zVJ{?c z?f{6LBS{X?a%%dWmC3$A93(N$XYjo|VUK0`;eEh!@eB3D_F%2>efSYvio4)+ZU%Fk z-b9ztJD5p`4|)tJ;@^=hrVUMjmuM)QmX4I9g$ezKi{Xn0P%bd9fWxio4L37W_~I69Q!>o zpPEc*kh?^80WRJmG?8{>11J*rB5C+GRN}&HhwRa46S(zq*hadCqsY3?yxVxhG?D&W z?DFd#^xi#!m0|gAkz(VdQ2`|(yIS=QIO3D&eLi4IXnCtBpEq)ENr9rtKfaYI5DC$T zH-xS58Ao?0-}n2h>Y(U-c)QSQ;@<{sQP1C-i@pAIFZ;WEX~TXvzT8uNsO0wV|4JLG z{;PERlTrNf_qS4_d9h;{*^eiu2Q_E@39C4%wjve6R?=zWG+_ZRj6fKJZM{7n-M~96 z8p(gevVsqw2hob0gLQFu8s`9sdyZ{2-5zU=Mbm^W&hS<>n0GT;rHIzML~eGt9L<4Id{u)~X z)aMdx3|?Xo$&!5_w_R#A7T zeK30#I!8E;+uW?JEVTKGr41;YIL^J!u1Ai3+dY0XR^NgFz zeaD$a?jow-EwVpvt^g4|6Qzm%2r770ob}{fLdh;;cOYI9fn*tIeyyxEcqfd7%8?aJ z2(uH|q5mO|k={s8CXP0{CP1G_w_UNGvXbDG&9x1;O|mM@UM997Tvx2A)rfVY4SA-Y zmPV`HYJrpWO!IY1guShc#r#IEvh#QcCGLt?MIY%Q;X(cuox?*EN)c4*w z2_N-8_}Vw3N1>eXY4Sy`qs9WqMe)V9vwMFXx^h%(+Tan%qm!n2q+gsAG%B%wL7#0S z=S^KTZS<6gX^W;rjvm$Z8JYIud`@xGV)s4q_O>?b&UcG1?>jjr%XmU{Jm5slm?qdftckkLb$5#` zc@J~l@^=0D@@HP%gXVdvkmmpDK3COOHq^dRJ~!+Fh0{7j%JL>f(4GspN4S6UvIN`2 zO){zbNzbERBfWNcaNYLEo=9Bc9uit|N}4IXD&dHa35M`W$uf2fs}S6bZ$TsG&2$6r zt;IRdG1k`K;xelBqjf8^E43cFmpY4XtnQ6wyDGW)bz?$fa?^BWAI)n0VAEnt0{Bf< zS`%!o9EV){nJR29IZHTRvCR9U-`{>9&2}%6|4|J0QUuNnf7@**zbDn=P6jW6#t)E)6vSf3?-CPZ%;*h=6<$SIc za)N`oVP?e}q=UJueViz}&4gZKMl74KdgA`E3ny7-eaQ%zHEZ&J!!iavN;{E$V%Dsg z(`U9%Pn=XRV3Nee~cf4XpL+a2q$oX5#OeZBeA*yD4K36Dh_tvXe9^T31lS0A1D zb!7VCcUdnlT)n70yYLcre^2&+$^_?N-YoLE^r-2Q9)igg;do&mVYT2czm{7~b|jM6XIUCxwdbMbu%^AlXd%zXDc2>Z z!4c<3urIdmFy|Yu8rm4t`U1UDU!#AaH|wTqgVmwRm}YykN!0)vijU^~)>xa=R&Tv* z+vxz`E5l&>$hXj@Mz6no7yB&q9PDP6bKPcmZt?dG`_gt#^p>_{$aT-bqBX!zLU@r9 zRPnFWNOp8>&|g&jQieA4Nw3f;W^Y%O>~+*%z1NQLANO*sPa1pDpjkI&2c`4IuN%Bz;My^XGg8uWp zPxBb}q~`{4my*6;+SJ=5tk@OpG}QNx7q2Y)ukeKB#P6&}S)DJW-=F-@c)91vwnvLH zm!D3$LR{8d7<3(fvghlN1_LvjCuRL>7*|nUykC_kd>NV8by>Ijoiy!xwyh4G=NImI z)aPDUYHU--kx{dQl07ENpU80WayDsSr>#*P(5RIGD*gZh5k%UQmDYCu(4onW)7ZDlOHsFohIl*M&IcovAQ7~W9 zLA;0D?TR&4!HOYCl~jAZXjk6n{Mn_!^(UKs8jewaPmg zk5eBJ5A&b*|8%Md)9gnpIPO@bVP0*kYOP_8=tAg}81LBoZ8_nCgP;1HbPtoa^Uwv> zw61OQGS?ZfgdWqZs2t(nl&PZO@6 zpx>#zquSqmv3an%N?&OC?#Q7;hy{HP@8+Y}N$hks2ikW6cMpH5FkAFUR3)4)c)=UP zJZW#9r01{cA5>Jsw~ zoydyh?M*?g8mwFkb3wUX;$N!a`!!-#~1jmU& zsC_ruRe?4~wWI!Q)#LKW(v07|f2UTAGF;>$UbP;h`G3>P zY{9fjSQ&7%T~53pF|La|A-&tg-tT*_?s*`gXZuI(J-USUBzrME7WWWzkLVl}mchDT z+orACcepQ?EDkUQT{x{1ErK`O}t9 zGjrSh-c-}aGz_~(TtIf3-ZT|7W!dtD8o$1wS3~{{-0H{mndp8-@<+HtI?u~JaCo59 z+bk6b@ADJ+Z8>ky@s9mwyXl-2b)IpJclucQ`k&3~>l5lGHpD2GX{!wHP4%Xu#sm7U zx;R~!;jDR{eJ{Axro+3O7W;+=gIg2!KUuHYV@M9Tmpk#J`I~qXxltT1@)GeD-dmSK zjHZdML`Qai)=In>n~Al@a4Z|%TinpYpl)9cZnq=!FuEg+((kCz)D4#b+ylcL#gJ#_ z0`Nl2Fd~Q8m)OQz_gRKp&RVuw^KGpiBb*MWk4xkVa@}y9rJCsBh(8w1Dj;@pkMd&# zWB5hf+29eK&2tyFlN8H3Dz3@Zdt{|T>VRWB>|DLY%TyYx)?UzH^lKP$?rj@91-mCQvZ4LnOP>AAMc zmUt)5dLh^X^IWomRP>d%lg<{>;7ne||0S9(SuNu8BRPI#7&)6bgAZboox5y5tQTx3 zIE=eFJ36M>wB{?u7({>?}xJkI6hUdF#ojJ~0 z=Qvj=)t(;8j7MTn6Z!_*ihHxtSxZ=JK>uxF4<(;*DDGQc3GXL&AMEPou-)0M*>Bie zh+1M3!3LVp1m=TlrL(VdwsV^!%XS+)OC^@}wlr`A$V`Y~yMBlv8TLyTnm5|dQO!sd z`25O1OPoN5V2Px+;G%f1bgXQbEKfFDj=JgGF1uY;ypY@FyWBRoPXm?k3wgF|u{20j zMXpC)I7t_Ru)#-jgz0A6ZMdO5ta+&(rpj&J)ci+jRZr4nsn4tWsATFBnr!VW9i`i& z|7n3|=NTo}(w)5Z#Go;3fnL0xJ-I z3YpJv3`JKnAE}|PF;1mJ2D|Zl;eCFs(+g-Ak&a-8o1+ip$C?aLuEaH!`ay-z>u41{ zo_Pjto-yzy(h5C{(r6mQ)u-SBx`^$?R$>{z`yL1Wo8edoED)p7JoE@U9&Lk?;CA?c z01pZBqs@hHCxXN9fB*fj2L4wA|Eq!j)xiI1;D0snzZ&>o4g9YL{#OJ4f7QSlRvk8p zu#f~654kI!qg7}s{*$^zRiXQsC&)7FvJ*jO(a%wXGl=Qx3Szp0?jRapfLtdt(SgVX zb|_MZeFjoj3aW9O!n3etSgtdJX~gdWVQU&GgtxizY!wiF3`7=|2B#$!GM~&~esXqm zvsv3nDVySMBTISL$u+EeaxQNTs}WDy6JG>CuVIbUh5|m*)dze+oD&@u6hr!kJTzBazG@16{WTM?EDLb8W&DEE=$Bkzz z?bpel90UpFd&3>mIl06lv@eqh&w?P6oCLHP4@N~DmIOU|q-_Q@mv;+#X%LfzT_;=m zNE&MfrDfmZlra0C;-e zNI@lzfyg2LBD9eH4E4UDWrW&i(JIzH21jwU6|V|DQH83Y|8#Y&cNB4_LEFc(y{ScL z5;@;o4#5Yr)L}xF#F6JJhyHt=+(8|;#;Jn5%m{hz9O@aHL!fUOWFnX`Ky1L@o)5uuX zEbbm|ZR7OvN%d&)Cnfp767h$P`g7N?r0fLPE1C){rJbBmej`r6D5SWJxY_j%p9(uVJ{*585AO)Ib{S$= zCXDnT#-E-6ExQKl^BUB1CK`$1u;cXvN;sGI6V!=?(6$318m2)Mf50q)?;JvetWC~+ z5Mg(6T6%9GJ&oK(YS~rjA&6E3ky8*2-vLERK`ej>I*WS<+2o96wfuW5s{|tcFzgh5 z8DdQY+K87UeVLUo7IU2{*av$6@hP7D|9yrBM2nUY8wz*c%~i2N;d{9R0W}$ozr*XW zXeiw&xJP%Y`~Ssj7wr#3Pz2F9((HHXl>aM75ObH7vQzOx&@;@gmPon?BAO7Q*ao&8 z7}NQnwt9ltp%)7w_uVPz8IvIXM#8mIaTRMBRt^#S6sQ{_;9GXi3qd4ir&=PS2l*53 zs)7<^VX1f|d~O!qoqCQ6;X6WT1s@J%;DMN~AX3m!B#Bf(Tpfs{pwYOLEo8OKGq2&g z5l~+%A!|Z{LR7;71B7`(hBkH z>!b&GvxE=_gwVq>(KSH!3Prpjmdt{lR)rGqbU=TCzTXJ*>T~ot^qMTJWehjs8`v## zX(W_vJj}=0tXq(8unJ9syR`K0mADqh!!T&gQ}{B702vT@TAr=tCla1~7}nBH(x3(# zp+`yC`D7Nz0FIPf;TLb;29BFCCmX*kJsCfd~Y8dpbMtlvdccS51*{s)azctWa+3@L>-?x;u zW$n@O??P58o(;;zp`h2`F$l07N#IL_Gs(<&$h$s+naGRCbOx3EQ63N{*Bft|#jVMU;Wj==ljy>T!64K@TT1m0CW z5`jpV??6R)2CU?d)DCK`E8W@K+26H^x&++NgN`@$?hXr_Rz0`BvCXp|aK5GP(LVGy zY6>$F>&-qxTw@cgt-$ULCVF!;oJT6LBJA@6;+AW2#0VzpqEDi zsr4C=kF0i9IB}!{Ya6Q#lW6}7v}vV|n~s^5o`xcwhyI5?#jscRT>C>OFveI=;Q2C^ zOiPWW$tD4QO|)x`qtv$9KETCCG}uIZF}4*Gu`Yu0vJdAmv5mcoErM~jh4m8D_m?m) zRu!;y^052p8Q9-Gi+N%$(x*}2eJ4bl3o%jm-3Oh5ztn>Vga zu0^h^E+6VFr2z8R7dn~w#*9N=AvD5Aok%@W2IH;*JQvT9Q^+~w9q>cBpe?o_YNQgW zL4F{YU=`RNkswXXTR3?b2`a}>Xj4B1XPRIST+R$+=7U~%IMWeYGKooHdNaX{lP(8_ zWD2k{(vW&K7J2QmL~)Kqzovrr(W6W;En)V+HNR3WP|h>Xo75?~n(}phcHDuS?tYHj)(G<>li6akXF78oZuU(3 z0g8*ChEsWiO z<)tCbu*`}ex5<;dOb!WWoNEXNw@9!+cuZI+7%d1AuaLj@Kz(2MP4Hh4bUs)c^sjHK ze4wCS_(=9szCjqo+&4}zA;>X4DcXg;)(e%Xs$Bh4Q@(0f_0h7_lDx9Fm7}T_fk*n6 zvb(OU@r)tbu+C6wC^j#*L#|@`IO}k;(RK{|#9JrXE6(68Aw9Uqgy$ujM2T?59}1C; zM!eCE$a$mG_^xaKYE#qxMV1RD1Uw2G!J)*?) zWNMlV0j5|nwUT*>WTV%Bjy{8>VMVaxK$E=;)VoEP0c{5-ehXJdb|T zA+i0%aEsS0Nu;8u?-jpL#V(pwE!BoHE5yI$`S^bIg=(*w&CMOPpX-+wwf#GkdY zuhAvlD$dnyZJMdRqdTs%>rxGm4V}z9+XVX^`#Iq1)VRKoO|pSrTiibiGs%ve8K7Cc zD9pll+Fd5Z+QxN~nak9q zj9|zn#zpU^Q|K6&eX6Ltz-qEnhv^>73z+>7Bnn33C|Ge!gLA`R%mtC+2YLfY=ih<9 z^^-XcxJL>OlrZ@GZtrwZRoB4k?>Sso3ZV*f{B zXmouSbMKGIH3{2WfA#3^858Q(_OFmgUZhe|^T6aLdg<3j*4FT=SpP#<=Fyl`zvySh z+wqTAJbv}QKA%;3zb2{SM8nqR_Ue4C+;r2l*BECGu*TbM&Pfyt8!cSowGW7dz2u!a z@$3=Y7s6@$VC0*jT)9T$Ykf(#LnJOgi<==>@6sx_%~*#ZWyN7f`Ghr zk?D!H!FK`0@hfW)I9b+%VxcW~0KPz$;5C9Q!Fc|AZcmO0bTTg>Qfru3bS&)-t#utn znu~r4ac~p$0!WR|oKKyYD;4Hd67=1J=}@K|GNANCoWQNS0d!#%l8bJ~80>GH!56U} zvMz#SU<8^p&a!Gu@S{1ghytAYG?| z&b!prmP!Ho+-zX7#XG%$AUF~zxY<-+x|m+c_#i8g8Hfkc0CYz=P@;c8>^u*o&Y6f4 zS%E6i6_`K%1SeQ}a79kXN&Eqv^RLB@V7XWzJ_FChUjpI22vZ{iXo2%Do5ivSh?V2b znWkDJ+x(BUgQL>f=v?TCwgp)Fn8lWhw$-jH$VOH$XCeQb_>r9J(Zws*%kF{8-}6gY z$FM16SIKhs97O~F7*>s}C8vmP3AWHoV?hz?7r$&m<30US(+Be~o8I{w+sE@1KaqWw zT@)_mrSQUpPESWfb?5Lw2h-5e!a)IvgWCQbb+hxQ&OIZ3vk%pHlvkNFvha}YZcW<1 z^4EXZ@#%Cy{r9SuD{oD?6m)gZlN+Cz;*rgzrfkTy@r8qH

eIE`1J|nr%RRwhUJ5 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 z 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 EAG3H$umAu6 literal 0 HcmV?d00001 diff --git a/ui/assets/two_minutes_left.wav b/ui/assets/two_minutes_left.wav new file mode 100644 index 0000000000000000000000000000000000000000..8680d526316a5db8189ed4134c059ed22ba96f85 GIT binary patch literal 82658 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 HTY>)phH}z2 literal 0 HcmV?d00001 diff --git a/ui/main_window.slint b/ui/main_window.slint index a7879b8..4d42f2a 100644 --- a/ui/main_window.slint +++ b/ui/main_window.slint @@ -5,6 +5,7 @@ import { ConfettiOverlay } from "confetti.slint"; import { Main } from "pages/main.slint"; import { Donate } from "pages/donate.slint"; import { InsertMoney } from "pages/insert_money.slint"; +import { InsertCoins } from "pages/insert_coins.slint"; import { HomeAssistant } from "pages/home_assistant.slint"; import { Diagnostics, LogEntry } from "pages/diagnostics.slint"; @@ -14,6 +15,7 @@ enum Page { Main, Donate, InsertMoney, + InsertCoins, HomeAssistant, Diagnostics, Top, @@ -77,6 +79,20 @@ export component MainWindow inherits Window { root.confetti-started(); } + // game-automate mode + /// Game names fed from Rust config (empty โ†’ UI uses built-in list) + in-out property <[string]> game-names: []; + /// Countdown seconds remaining in the active game session (updated by Rust) + in-out property game-seconds-left: 0; + /// Guard: true while on the InsertCoins page + out property on-insert-coins-page: current-page == Page.InsertCoins; + + callback launch-game(int, string); // amount, game-name โ€” Rust starts RetroArch + callback game-time-expired(); // Rust calls when session timer fires + game-time-expired => { + root.current-page = Page.Main; + } + title: "Donation Machine"; width: 1280px; height: 1024px; @@ -92,6 +108,12 @@ export component MainWindow inherits Window { root.current-page = Page.HomeAssistant; } + play-clicked => { + root.session-amount = 0; + root.start-accepting-money(); + root.current-page = Page.InsertCoins; + } + secret-tapped => { root.current-page = Page.Diagnostics; } @@ -167,6 +189,24 @@ export component MainWindow inherits Window { root.confetti-started(); } } + if current-page == Page.InsertCoins: InsertCoins { + current-amount <=> root.session-amount; + last-added-amount <=> root.last-added-amount; + game-names: root.game-names; + + cancel-clicked => { + root.stop-accepting-money(); + root.session-amount = 0; + root.current-page = Page.Main; + } + + launch-clicked(amount, game-name) => { + root.stop-accepting-money(); + root.session-amount = 0; + root.launch-game(amount, game-name); + root.current-page = Page.Main; + } + } if current-page == Page.HomeAssistant: HomeAssistant { back-clicked => { root.hide-home-assistant(); diff --git a/ui/pages/insert_coins.slint b/ui/pages/insert_coins.slint new file mode 100644 index 0000000..8a3f07c --- /dev/null +++ b/ui/pages/insert_coins.slint @@ -0,0 +1,256 @@ +import { Button, Palette, ScrollView } from "std-widgets.slint"; + +export component InsertCoins inherits Rectangle { + // โ”€โ”€โ”€ Inputs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + in-out property current-amount: 0; + in-out property last-added-amount: 0; + /// Game names passed in from Rust (may be empty โ†’ shows built-in list) + in property <[string]> game-names: []; + + // โ”€โ”€โ”€ Callbacks โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + callback cancel-clicked(); + callback launch-clicked(int, string); // amount, game-name + + // โ”€โ”€โ”€ Internal state โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + property selected-game-index: 0; + property selected-game-name: + root.game-names.length > 0 + ? root.game-names[root.selected-game-index] + : builtin-games[root.selected-game-index]; + + // Built-in fallback game list (shown when no games are configured in TOML) + property <[string]> builtin-games: [ + "Tetris", + "DOOM", + "Pac-Man", + "Street Fighter II", + "Sonic the Hedgehog", + ]; + property game-count: + root.game-names.length > 0 + ? root.game-names.length + : root.builtin-games.length; + + // Playtime computation: 100 AMD = 5 min = 300 s + property play-seconds: root.current-amount * 3; // 100 AMD โ†’ 300 s + property play-min: root.play-seconds / 60; + property play-sec: root.play-seconds - root.play-min * 60; + + // โ”€โ”€โ”€ Toast state โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + property display-amount: 0; + property toast-active: false; + + Timer { interval: 16ms; running: root.last-added-amount != 0 && !root.toast-active; + triggered => { root.display-amount = root.last-added-amount; root.toast-active = true; } } + Timer { interval: 1100ms; running: root.last-added-amount != 0; + triggered => { root.last-added-amount = 0; } } + Timer { interval: 600ms; running: root.last-added-amount == 0 && root.toast-active; + triggered => { root.toast-active = false; } } + + background: Palette.background; + + // โ”€โ”€โ”€ Layout โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + HorizontalLayout { + padding: 24px; + spacing: 24px; + + // โ”€โ”€ LEFT PANEL: Game Selector โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + Rectangle { + width: 420px; + border-radius: 16px; + background: Palette.color-scheme == ColorScheme.dark ? #1a1a2e : #eeeef7; + + VerticalLayout { + padding: 20px; + spacing: 12px; + + Text { + text: "๐ŸŽฎ Select Game"; + font-size: 22px; + font-weight: 700; + color: Palette.foreground; + horizontal-alignment: center; + } + + Rectangle { height: 4px; } + + // Game list + for i in root.game-count: game-row := Rectangle { + height: 72px; + border-radius: 12px; + background: root.selected-game-index == i + ? #6c5ce7 + : (Palette.color-scheme == ColorScheme.dark ? #2d2d4a : #d8d8ee); + animate background { duration: 150ms; } + + Text { + text: root.game-names.length > 0 + ? root.game-names[i] + : root.builtin-games[i]; + font-size: 20px; + font-weight: root.selected-game-index == i ? 700 : 400; + color: root.selected-game-index == i ? #ffffff : Palette.foreground; + vertical-alignment: center; + horizontal-alignment: center; + width: parent.width; + height: parent.height; + animate color { duration: 150ms; } + } + + TouchArea { + clicked => { root.selected-game-index = i; } + } + } + + Rectangle { vertical-stretch: 1; } + } + } + + // โ”€โ”€ RIGHT PANEL: Coin Insertion โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + VerticalLayout { + horizontal-stretch: 1; + alignment: start; + spacing: 20px; + + // Header row (cancel button left, title center) + HorizontalLayout { + alignment: start; + spacing: 16px; + + Button { + text: "โ† Cancel"; + width: 150px; + height: 56px; + clicked => { root.cancel-clicked(); } + } + + Text { + text: "Insert Money to Play"; + font-size: 28px; + font-weight: 700; + color: Palette.foreground; + vertical-alignment: center; + horizontal-stretch: 1; + horizontal-alignment: center; + } + } + + // Rate info + Rectangle { + height: 44px; + border-radius: 10px; + background: #6c5ce7.with-alpha(0.12); + + Text { + text: "100 ึ = 5 min ยท 50 ึ = 2 min 30 sec"; + font-size: 16px; + color: #6c5ce7; + font-weight: 600; + horizontal-alignment: center; + vertical-alignment: center; + width: parent.width; + height: parent.height; + } + } + + // Amount display with toast overlay + Rectangle { + height: 140px; + clip: false; + + amount-box := Rectangle { + width: 100%; + height: 100%; + border-radius: 16px; + background: Palette.color-scheme == ColorScheme.dark ? #2a2a2a : #f5f5f5; + border-width: 3px; + border-color: root.current-amount > 0 ? #6c5ce7 : #cccccc; + animate border-color { duration: 250ms; } + + VerticalLayout { + alignment: center; + spacing: 4px; + + Text { + text: root.current-amount + " ึ"; + font-size: 62px; + font-weight: 700; + color: root.current-amount > 0 ? #6c5ce7 : Palette.foreground; + horizontal-alignment: center; + animate color { duration: 250ms; } + } + } + } + + // Rising toast + toast-text := Text { + text: "+" + root.display-amount + " ึ"; + color: #6c5ce7; + font-size: 38px; + font-weight: 700; + horizontal-alignment: center; + width: parent.width; + y: root.toast-active ? -90px : -20px; + opacity: root.last-added-amount != 0 ? 1.0 : 0.0; + animate opacity { duration: 500ms; } + animate y { duration: 1000ms; easing: ease-in-out; } + } + } + + // Playtime label + Rectangle { + height: 64px; + border-radius: 12px; + background: root.current-amount >= 50 + ? #00b894.with-alpha(0.15) + : transparent; + animate background { duration: 300ms; } + + Text { + text: root.current-amount >= 50 + ? "โฑ Play time: " + root.play-min + " min " + (root.play-sec > 0 ? root.play-sec + " sec" : "") + : "Insert money to see your play time"; + font-size: 22px; + font-weight: 600; + color: root.current-amount >= 50 ? #00b894 : Palette.foreground; + opacity: root.current-amount >= 50 ? 1.0 : 0.5; + horizontal-alignment: center; + vertical-alignment: center; + width: parent.width; + height: parent.height; + animate color { duration: 300ms; } + animate opacity { duration: 300ms; } + } + } + + Rectangle { vertical-stretch: 1; } + + // LAUNCH button + HorizontalLayout { + alignment: center; + + launch-btn := Button { + text: root.current-amount >= 50 + ? "๐Ÿš€ Launch " + root.selected-game-name + : "๐Ÿš€ Launch (insert money first)"; + primary: true; + enabled: root.current-amount >= 50; + height: 110px; + + clicked => { + root.launch-clicked(root.current-amount, root.selected-game-name); + } + } + } + + // Disabled hint + if root.current-amount < 50: Text { + text: "Minimum 50 ึ to start playing"; + font-size: 14px; + color: Palette.foreground; + opacity: 0.5; + horizontal-alignment: center; + } + } + } +} diff --git a/ui/pages/main.slint b/ui/pages/main.slint index 796f130..3c138d4 100644 --- a/ui/pages/main.slint +++ b/ui/pages/main.slint @@ -3,6 +3,7 @@ import { LineEdit, Button } from "std-widgets.slint"; export component Main inherits Rectangle { callback donate-clicked(); callback home-assistant-clicked(); + callback play-clicked(); callback secret-tapped(); // Secret: tap the logo 5 times to open diagnostics. @@ -58,7 +59,7 @@ export component Main inherits Rectangle { Button { text: "DONATE"; - width: 350px; + width: 280px; height: 120px; clicked => { @@ -66,9 +67,19 @@ export component Main inherits Rectangle { } } + Button { + text: "๐ŸŽฎ PLAY"; + width: 280px; + height: 120px; + + clicked => { + root.play-clicked(); + } + } + Button { text: "HASS"; - width: 350px; + width: 280px; height: 120px; clicked => { From 0f3b56b92669460283dafe8734dd4dc07a66bfd8 Mon Sep 17 00:00:00 2001 From: Kita Lembrik Date: Mon, 20 Apr 2026 04:37:57 +0400 Subject: [PATCH 2/4] main window renovation --- README.md | 87 +------------- src/config.rs | 12 -- src/home_assistant.rs | 49 +++++++- ui/pages/main.slint | 255 +++++++++++++++++++++++++++++++++++------- 4 files changed, 268 insertions(+), 135 deletions(-) diff --git a/README.md b/README.md index e0f49b8..8a11b1b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# dramma ๐ŸŽฎ๐Ÿ’ธ +# dramma -Donation kiosk + arcade machine for Hackerembassy. +Donation kiosk + arcade machine for Hacker Embassy. Accepts cash (bills + coins), processes donations, and now lets people insert coins to play retro games on RetroArch. --- @@ -21,7 +21,7 @@ The app starts fullscreen. Tap the logo **5 times** to open the diagnostics pane Create `.config/dramma.toml` next to the binary (or in the working directory you run from): ```toml -token = "your-bearer-token" +token = "your-bearer-token" # For Bot donates # Optional overrides (these are the defaults): home_assistant_url = "https://ha.hackem.cc/web-dramma/0?BrowserID=dramma" @@ -41,75 +41,9 @@ Pressing **PLAY** on the main screen takes the user to the coin-insertion screen When they hit **Launch**, dramma starts RetroArch fullscreen + kiosk and auto-closes it when the time runs out. The speaker will announce "2 minutes left" and "1 minute left". -### Step 1 โ€” Install RetroArch - -```bash -# NixOS -nix-env -iA nixpkgs.retroarch - -# Or add to your system configuration.nix: -environment.systemPackages = [ pkgs.retroarch ]; -``` - -Make sure `retroarch` is on `PATH`. By default dramma just calls `retroarch`. You can override this in the config: - -```toml -retroarch_command = "/run/current-system/sw/bin/retroarch" -``` - -### Step 2 โ€” Install cores (emulators) - -Each game needs a **libretro core** โ€” a `.so` plugin file that emulates a specific console. - -```bash -# Find available cores in nixpkgs: -nix search nixpkgs libretro - -# Install a core, e.g. nestopia (NES emulator): -nix-env -iA nixpkgs.libretro.nestopia - -# Or add to configuration.nix: -environment.systemPackages = with pkgs.libretro; [ - nestopia # NES (Tetris, Super Mario Bros) - fbneo # Arcade (Pac-Man, Street Fighter II) - picodrive # Sega Genesis (Sonic the Hedgehog) - dosbox # DOS (DOOM) - snes9x # SNES -]; -``` - -After install, find where the `.so` files ended up: - -```bash -find /nix/store -name "nestopia_libretro.so" 2>/dev/null -# โ†’ /nix/store/xxxx-nestopia-x.x.x/lib/retroarch/cores/nestopia_libretro.so -``` - -> **Tip:** Use a stable symlink if you don't want to update the path after every nixpkgs update: -> ```nix -> # In configuration.nix -> environment.etc."retroarch/cores".source = pkgs.symlinkJoin { -> name = "retroarch-cores"; -> paths = with pkgs.libretro; [ nestopia fbneo picodrive dosbox ]; -> } + "/lib/retroarch/cores"; -> ``` -> Then paths look like `/etc/retroarch/cores/nestopia_libretro.so`. - -### Step 3 โ€” Get your ROMs - -Put your ROM files somewhere on the machine, e.g. `/home/dramma/roms/`. - -``` -/home/dramma/roms/ -โ”œโ”€โ”€ tetris.nes -โ”œโ”€โ”€ pacman.zip -โ”œโ”€โ”€ sonic.md -โ””โ”€โ”€ doom.wad -``` - > ROMs are not included for obvious copyright reasons. You know where to find them. -### Step 4 โ€” Configure games in dramma.toml +### Configure games in dramma.toml Add a `[[games]]` block for each game. `name` is what shows up in the UI, `core` is the path to the `.so`, `rom` is the path to your ROM file. @@ -144,7 +78,7 @@ rom = "/home/dramma/roms/sf2.zip" If `[[games]]` is **not configured**, the UI shows a built-in placeholder list (same names, no actual cores/ROMs). RetroArch will still launch but will open its own menu โ€” not useful in production. -### Step 5 โ€” Test it manually first +### Test it manually first Before trusting the machine to do it, test the exact command dramma will run: @@ -154,16 +88,6 @@ retroarch --fullscreen --kiosk -L /path/to/core_libretro.so /path/to/rom If the game boots correctly, the config is right. If RetroArch opens its menu instead of loading the game, the core or ROM path is wrong. -### Common issues - -| Problem | Fix | -|---|---| -| RetroArch opens the menu instead of the game | Wrong core or ROM path. Check paths are correct and the file exists. | -| `retroarch: command not found` | RetroArch not on PATH. Set `retroarch_command` to the full path. | -| Game loads but controls don't work | Configure controller mappings inside RetroArch first, then re-enable kiosk mode. | -| DOOM launches but shows "IWAD not found" | DOOM needs the `.wad` file. Use `doom1.wad` (shareware, freely distributable) or `doom.wad`. | -| Arcade ROMs (Pac-Man, SF2) don't load | FBNeo needs the ROM in a `.zip` file with the exact internal filenames. Use a verified ROM set. | -| Session ends but RetroArch is still open | Check that dramma has permission to `kill` the RetroArch process (usually fine if running as the same user). | --- @@ -175,7 +99,6 @@ If the game boots correctly, the config is right. If RetroArch opens its menu in | 100 ึ | 5 min | | 200 ึ | 10 min | | 500 ึ | 25 min | -| 1000 ึ | 50 min | --- diff --git a/src/config.rs b/src/config.rs index 70b2cf0..c2927b1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,9 +19,7 @@ pub enum ConfigError { #[derive(Debug, Clone, Deserialize)] pub struct GameEntry { pub name: String, - /// Path to the libretro core `.so` file (e.g. `/path/to/nestopia_libretro.so`). pub core: String, - /// Path to the ROM file. pub rom: String, } @@ -32,20 +30,10 @@ pub struct Config { pub home_assistant_url: String, pub hass_api_port: u16, pub cashcode_serial_port: String, - /// Serial port for the ccTalk coin acceptor. Set to `"auto"` (the - /// default) to probe all available USB serial ports at startup and on - /// every reconnect, which handles `/dev/ttyUSBx` number changes. pub cctalk_serial_port: String, - /// Override the value for specific coin positions (channels). - /// Use this when the device has misconfigured coin IDs. - /// Format in dramma.toml: - /// cctalk_coin_overrides = [[1, 50], [3, 500]] - /// means position 1 โ†’ 50 AMD, position 3 โ†’ 500 AMD. pub cctalk_coin_overrides: Vec<[i32; 2]>, pub stats_db_path: String, - /// Command used to launch RetroArch (default: `"retroarch"`). pub retroarch_command: String, - /// List of playable games. If empty, the UI shows a built-in demo list. pub games: Vec, } diff --git a/src/home_assistant.rs b/src/home_assistant.rs index 143ab35..6d12ad7 100644 --- a/src/home_assistant.rs +++ b/src/home_assistant.rs @@ -1,5 +1,8 @@ use log::{error, info}; +use std::io::{Read, Write}; +use std::net::TcpListener; use std::process::{Child, Command}; +use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; /// Manages a Chromium subprocess for displaying Home Assistant @@ -30,7 +33,7 @@ impl ChromiumManager { // Try chromium first, then chromium-browser as fallback (different Debian versions) let command_result = Command::new("chromium") .arg("--app=".to_string() + url) - .arg("--window-size=1280,940") + .arg("--start-fullscreen") .arg("--window-position=0,0") .arg("--disable-infobars") .arg("--noerrdialogs") @@ -50,7 +53,7 @@ impl ChromiumManager { // Fallback to chromium-browser Command::new("chromium-browser") .arg("--app=".to_string() + url) - .arg("--window-size=1280,940") + .arg("--start-fullscreen") .arg("--window-position=0,0") .arg("--disable-infobars") .arg("--noerrdialogs") @@ -108,3 +111,45 @@ impl Drop for ChromiumManager { self.close(); } } + +/// Starts a simple HTTP listener for remote control from Home Assistant. +/// When a `POST /close-hass` request is received, sends a signal through `tx`. +pub fn start_close_listener(port: u16, tx: Sender<()>) { + let addr = format!("0.0.0.0:{}", port); + let listener = match TcpListener::bind(&addr) { + Ok(l) => l, + Err(e) => { + error!("Failed to bind HASS close listener on {}: {}", addr, e); + return; + } + }; + info!("๐Ÿ  Home Assistant close listener on port {}", port); + + for stream in listener.incoming() { + let Ok(mut stream) = stream else { + continue; + }; + let mut buf = [0u8; 512]; + let Ok(n) = stream.read(&mut buf) else { + continue; + }; + let request = String::from_utf8_lossy(&buf[..n]); + let first_line = request.lines().next().unwrap_or(""); + + if first_line.starts_with("POST /close-hass") { + info!("๐Ÿ  Received remote close-hass request"); + let _ = tx.send(()); + let _ = stream.write_all( + b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: 2\r\n\r\nOK", + ); + } else if first_line.starts_with("OPTIONS") { + // CORS preflight + let _ = stream.write_all( + b"HTTP/1.1 204 No Content\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: POST, OPTIONS\r\nAccess-Control-Allow-Headers: Content-Type\r\n\r\n", + ); + } else { + let _ = + stream.write_all(b"HTTP/1.1 404 Not Found\r\nContent-Length: 9\r\n\r\nNot Found"); + } + } +} diff --git a/ui/pages/main.slint b/ui/pages/main.slint index 3c138d4..fc15fc8 100644 --- a/ui/pages/main.slint +++ b/ui/pages/main.slint @@ -1,37 +1,143 @@ import { LineEdit, Button } from "std-widgets.slint"; +// โ”€โ”€โ”€ Palette โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +global Theme { + out property bg-top: #0d0d1a; + out property bg-bottom: #12122b; + out property card-bg: #1c1c3a; + out property card-border: #2e2e60; + out property accent-donate: #e05a77; + out property accent-hass: #5ab8e0; + out property accent-play: #7de05a; + out property text-primary: #f0eeff; + out property text-muted: #8888bb; + out property github-accent: #c9b8ff; +} + +// โ”€โ”€โ”€ Feature card โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +component FeatureCard inherits Rectangle { + in property accent; + in property icon; + in property label; + in property description; + callback clicked(); + + property hover-factor: 0; + + width: 340px; + height: 220px; + border-radius: 18px; + background: Theme.card-bg; + border-width: 1.5px; + border-color: accent.mix(Theme.card-border, 0.35); + drop-shadow-blur: 20px; + drop-shadow-color: accent.with-alpha(0.15); + drop-shadow-offset-y: 6px; + + animate border-color { duration: 200ms; easing: ease-out; } + animate drop-shadow-color { duration: 200ms; easing: ease-out; } + + + VerticalLayout { + padding: 28px; + spacing: 10px; + alignment: start; + + // Icon + label row + HorizontalLayout { + spacing: 12px; + alignment: start; + + Text { + text: icon; + font-size: 36px; + vertical-alignment: center; + } + + Text { + text: label; + font-size: 22px; + font-weight: 700; + color: Theme.text-primary; + vertical-alignment: center; + } + } + + // Divider + Rectangle { + width: 48px; + height: 2px; + background: accent.with-alpha(0.6); + x: 0px; + } + + Text { + text: description; + font-size: 15px; + color: Theme.text-muted; + wrap: word-wrap; + } + } + + TouchArea { + mouse-cursor: pointer; + clicked => { root.clicked(); } + pointer-event(e) => { + if e.kind == PointerEventKind.move || e.kind == PointerEventKind.up { + root.hover-factor = self.has-hover ? 1.0 : 0.0; + } + } + } +} + +// โ”€โ”€โ”€ Main page โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ export component Main inherits Rectangle { callback donate-clicked(); callback home-assistant-clicked(); callback play-clicked(); callback secret-tapped(); - // Secret: tap the logo 5 times to open diagnostics. property tap-count: 0; - // Reset the counter 3 s after the last tap if it hasn't reached 5. tap-reset := Timer { interval: 3s; running: root.tap-count > 0 && root.tap-count < 5; triggered => { root.tap-count = 0; } } + background: Theme.bg-top; + + // Subtle radial gradient overlay in center + Rectangle { + x: 0; y: 0; + width: parent.width; + height: parent.height; + background: @linear-gradient(160deg, #1a0d33 0%, #0d0d1a 40%, #0d1a2b 100%); + } + VerticalLayout { - alignment: space-between; - padding: 16px; - spacing: 8px; + alignment: center; + spacing: 0px; + padding-top: 32px; + padding-bottom: 32px; + padding-left: 48px; + padding-right: 48px; - // logo at top center โ€” tap 5ร— to open diagnostics + // โ”€โ”€ Header row: logo + title โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ HorizontalLayout { alignment: center; + spacing: 32px; + padding-bottom: 8px; + // Logo โ€” tap 5ร— for diagnostics Rectangle { - width: 233px; - height: 250px; + width: 120px; + height: 128px; Image { - width: 233px; - height: 250px; + width: 120px; + height: 128px; source: @image-url("../assets/xkem.png"); + image-fit: contain; } TouchArea { @@ -44,46 +150,117 @@ export component Main inherits Rectangle { } } } + + // Title + tagline + VerticalLayout { + alignment: center; + spacing: 6px; + + Text { + text: "Welcome to dram'ma!"; + font-size: 46px; + font-weight: 800; + color: Theme.text-primary; + } + + Text { + text: "Your friendly Hacker Embassy station"; + font-size: 18px; + color: Theme.text-muted; + font-weight: 400; + } + } } - // spacer to push button to bottom - Rectangle { - vertical-stretch: 1; - background: transparent; + // โ”€โ”€ Subtitle โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + HorizontalLayout { + alignment: center; + padding-top: 12px; + padding-bottom: 32px; + + Text { + text: "Here you can:"; + font-size: 22px; + font-weight: 600; + color: Theme.github-accent; + } } - // buttons at bottom center + // โ”€โ”€ Feature cards โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ HorizontalLayout { alignment: center; - spacing: 16px; - - Button { - text: "DONATE"; - width: 280px; - height: 120px; - - clicked => { - root.donate-clicked(); - } + spacing: 24px; + + FeatureCard { + accent: Theme.accent-donate; + icon: "๐Ÿ’ธ"; + label: "Donate"; + description: "Support Hacker Embassy directly.\nEvery coin counts!"; + clicked => { root.donate-clicked(); } } - Button { - text: "๐ŸŽฎ PLAY"; - width: 280px; - height: 120px; + FeatureCard { + accent: Theme.accent-hass; + icon: "๐Ÿ "; + label: "Control Space"; + description: "Manage lights, climate & more\nvia Home Assistant."; + clicked => { root.home-assistant-clicked(); } + } - clicked => { - root.play-clicked(); - } + FeatureCard { + accent: Theme.accent-play; + icon: "๐ŸŽฎ"; + label: "Play Games"; + description: "Insert coins and enjoy\nretro games on the machine!"; + clicked => { root.play-clicked(); } + } + } + + // โ”€โ”€ Contribute footer โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + HorizontalLayout { + alignment: center; + padding-top: 36px; + spacing: 8px; + + Text { + text: "Wanna contribute?"; + font-size: 16px; + color: Theme.text-muted; + vertical-alignment: center; } - Button { - text: "HASS"; - width: 280px; - height: 120px; - - clicked => { - root.home-assistant-clicked(); + Text { + text: "PR to"; + font-size: 16px; + color: Theme.text-muted; + vertical-alignment: center; + } + + HorizontalLayout { + padding-left: 10px; + padding-right: 10px; + padding-top: 4px; + padding-bottom: 4px; + height: 32px; + + Rectangle { + border-radius: 8px; + background: Theme.github-accent.with-alpha(0.12); + border-width: 1px; + border-color: Theme.github-accent.with-alpha(0.4); + + HorizontalLayout { + padding-left: 10px; + padding-right: 10px; + + Text { + text: "github.com/hackerembassy/dramma"; + font-size: 15px; + color: Theme.github-accent; + font-weight: 600; + vertical-alignment: center; + } + } } } } From e12dfb2e3aef94cfca3f6111a759cea36e6c3284 Mon Sep 17 00:00:00 2001 From: Kita Lembrik Date: Mon, 20 Apr 2026 04:50:27 +0400 Subject: [PATCH 3/4] clippy fix --- src/home_assistant.rs | 1 + src/retroarch.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/home_assistant.rs b/src/home_assistant.rs index 6d12ad7..b223df6 100644 --- a/src/home_assistant.rs +++ b/src/home_assistant.rs @@ -114,6 +114,7 @@ impl Drop for ChromiumManager { /// Starts a simple HTTP listener for remote control from Home Assistant. /// When a `POST /close-hass` request is received, sends a signal through `tx`. +#[allow(dead_code)] pub fn start_close_listener(port: u16, tx: Sender<()>) { let addr = format!("0.0.0.0:{}", port); let listener = match TcpListener::bind(&addr) { diff --git a/src/retroarch.rs b/src/retroarch.rs index 7e3fdc7..9854f5b 100644 --- a/src/retroarch.rs +++ b/src/retroarch.rs @@ -77,6 +77,7 @@ impl RetroArchManager { } /// Returns `true` if RetroArch is currently running. + #[allow(dead_code)] pub fn is_running(&self) -> bool { self.process.lock().unwrap().is_some() } From c9bdfd0b59dbd911a21825e21ffb30f88f6d7607 Mon Sep 17 00:00:00 2001 From: Kita Lembrik Date: Tue, 28 Apr 2026 22:04:55 +0400 Subject: [PATCH 4/4] fix: apply PR #23 suggestions, fix Slint syntax, and secure HASS listener --- src/home_assistant.rs | 2 +- src/main.rs | 6 ++++++ ui/main_window.slint | 6 +++++- ui/pages/insert_coins.slint | 2 +- ui/pages/main.slint | 1 - 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/home_assistant.rs b/src/home_assistant.rs index b223df6..145830f 100644 --- a/src/home_assistant.rs +++ b/src/home_assistant.rs @@ -116,7 +116,7 @@ impl Drop for ChromiumManager { /// When a `POST /close-hass` request is received, sends a signal through `tx`. #[allow(dead_code)] pub fn start_close_listener(port: u16, tx: Sender<()>) { - let addr = format!("0.0.0.0:{}", port); + let addr = format!("127.0.0.1:{}", port); let listener = match TcpListener::bind(&addr) { Ok(l) => l, Err(e) => { diff --git a/src/main.rs b/src/main.rs index f2014ce..792e538 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1069,6 +1069,12 @@ mod game_handler { let weak = weak.clone(); move |amount, game_name| { + // Clear any existing timers first + *session_timer.borrow_mut() = None; + *two_min_timer.borrow_mut() = None; + *one_min_timer.borrow_mut() = None; + *tick_timer.borrow_mut() = None; + // Compute session duration: 100 AMD = 300 seconds let total_secs = (amount as u64) * 3; info!( diff --git a/ui/main_window.slint b/ui/main_window.slint index cada527..4539fa1 100644 --- a/ui/main_window.slint +++ b/ui/main_window.slint @@ -90,8 +90,12 @@ export component MainWindow inherits Window { callback launch-game(int, string); // amount, game-name โ€” Rust starts RetroArch callback game-time-expired(); // Rust calls when session timer fires game-time-expired => { + root.current-page = Page.Main; + } + /// Called from Rust when HASS sends a POST /close-hass request. - public function close-hass-remote() { + callback close-hass-remote(); + close-hass-remote => { root.hide-home-assistant(); root.current-page = Page.Main; } diff --git a/ui/pages/insert_coins.slint b/ui/pages/insert_coins.slint index 8a3f07c..98f7517 100644 --- a/ui/pages/insert_coins.slint +++ b/ui/pages/insert_coins.slint @@ -1,4 +1,4 @@ -import { Button, Palette, ScrollView } from "std-widgets.slint"; +import { Button, Palette } from "std-widgets.slint"; export component InsertCoins inherits Rectangle { // โ”€โ”€โ”€ Inputs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ diff --git a/ui/pages/main.slint b/ui/pages/main.slint index fc15fc8..36b4630 100644 --- a/ui/pages/main.slint +++ b/ui/pages/main.slint @@ -1,4 +1,3 @@ -import { LineEdit, Button } from "std-widgets.slint"; // โ”€โ”€โ”€ Palette โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ global Theme {