From a1ae4efede614baa9d75cc55135225c467c8a826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayhan=20Yal=C3=A7=C4=B1nsoy?= Date: Fri, 22 May 2026 23:35:27 +0300 Subject: [PATCH] update --- .gitignore | 2 + Cargo.toml | 20 + Makefile | 217 +++++ README | 3 + README.md | 93 --- TODO.md | 76 ++ answer-example.toml | 38 + assets/budgie.png | Bin 0 -> 10125 bytes assets/cinnamon.png | Bin 0 -> 2929 bytes assets/community.png | Bin 0 -> 27317 bytes assets/file_manager.png | Bin 0 -> 2180 bytes assets/firefox.png | Bin 0 -> 32441 bytes assets/gnome.png | Bin 0 -> 3140 bytes assets/kaptan.png | 1054 +++++++++++++++++++++++++ assets/kde.png | Bin 0 -> 21706 bytes assets/lumina.png | Bin 0 -> 2847 bytes assets/lxde.png | Bin 0 -> 2133 bytes assets/lxqt.png | Bin 0 -> 10059 bytes assets/mate.png | Bin 0 -> 4377 bytes assets/pisi-logo-dark.png | Bin 0 -> 17869 bytes assets/pisi-logo-light.png | Bin 0 -> 8756 bytes assets/pisi-software-center.png | Bin 0 -> 74519 bytes assets/pisi_speed.png | Bin 0 -> 44423 bytes assets/securety.png | Bin 0 -> 25807 bytes assets/xfce.png | Bin 0 -> 3750 bytes assets/xfce_settings.png | Bin 0 -> 24000 bytes assets/yali.desktop | 12 + locales/en.toml | 331 ++++++++ locales/tr.toml | 331 ++++++++ src/autoinstall/checker.rs | 189 +++++ src/autoinstall/mod.rs | 216 +++++ src/installer.rs | 324 ++++++++ src/jobs/mod.rs | 1313 +++++++++++++++++++++++++++++++ src/main.rs | 405 ++++++++++ src/steps/execution.rs | 305 +++++++ src/steps/finish.rs | 60 ++ src/steps/keyboard.rs | 103 +++ src/steps/mod.rs | 13 + src/steps/partition.rs | 585 ++++++++++++++ src/steps/summary.rs | 111 +++ src/steps/users.rs | 186 +++++ src/ui/error_screen.rs | 165 ++++ src/ui/mod.rs | 6 + src/ui/slideshow.rs | 428 ++++++++++ src/ui/theme.rs | 276 +++++++ 45 files changed, 6769 insertions(+), 93 deletions(-) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 Makefile create mode 100644 README delete mode 100644 README.md create mode 100644 TODO.md create mode 100644 answer-example.toml create mode 100644 assets/budgie.png create mode 100644 assets/cinnamon.png create mode 100644 assets/community.png create mode 100644 assets/file_manager.png create mode 100644 assets/firefox.png create mode 100644 assets/gnome.png create mode 100644 assets/kaptan.png create mode 100644 assets/kde.png create mode 100644 assets/lumina.png create mode 100644 assets/lxde.png create mode 100644 assets/lxqt.png create mode 100644 assets/mate.png create mode 100644 assets/pisi-logo-dark.png create mode 100644 assets/pisi-logo-light.png create mode 100644 assets/pisi-software-center.png create mode 100644 assets/pisi_speed.png create mode 100644 assets/securety.png create mode 100644 assets/xfce.png create mode 100644 assets/xfce_settings.png create mode 100644 assets/yali.desktop create mode 100644 locales/en.toml create mode 100644 locales/tr.toml create mode 100644 src/autoinstall/checker.rs create mode 100644 src/autoinstall/mod.rs create mode 100644 src/installer.rs create mode 100644 src/jobs/mod.rs create mode 100644 src/main.rs create mode 100644 src/steps/execution.rs create mode 100644 src/steps/finish.rs create mode 100644 src/steps/keyboard.rs create mode 100644 src/steps/mod.rs create mode 100644 src/steps/partition.rs create mode 100644 src/steps/summary.rs create mode 100644 src/steps/users.rs create mode 100644 src/ui/error_screen.rs create mode 100644 src/ui/mod.rs create mode 100644 src/ui/slideshow.rs create mode 100644 src/ui/theme.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..869df07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4f4d213 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "yali-rs" +version = "0.2.0" +edition = "2021" + +[dependencies] +eframe = "0.27" +egui_extras = { version = "0.27", features = ["image"] } +image = { version = "0.24", features = ["png"] } +serde = { version = "1.0", features = ["derive"] } +toml = "0.8" # answer file ayrıştırma +zbus = "4.0" +tokio = { version = "1.0", features = ["full"] } +sysinfo = "0.30" +rust-i18n = "3.1" +lazy_static = "1.4" +async-trait = "0.1" + +[patch.crates-io] +# Yerel mudur veya comar-api kütüphaneleri buraya eklenebilir \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..93f6865 --- /dev/null +++ b/Makefile @@ -0,0 +1,217 @@ +# ─────────────────────────────────────────────────────────────────────────── +# Yali-RS — PisiLinux Kurulum Aracı +# Makefile (GNU Make 4.x) +# ─────────────────────────────────────────────────────────────────────────── + +BINARY := yali-rs +VERSION := 0.2.0 + +# Kurulum yolları (DESTDIR ile paket yöneticisi uyumlu) +PREFIX ?= /usr +BINDIR ?= $(PREFIX)/bin +DATADIR ?= $(PREFIX)/share/$(BINARY) +LOCALEDIR ?= $(DATADIR)/locales +ASSETSDIR ?= $(DATADIR)/assets +DESKTOPDIR ?= $(PREFIX)/share/applications +PIXMAPDIR ?= $(PREFIX)/share/pixmaps + +# Cargo hedefleri +RELEASE_BIN := target/release/$(BINARY) +DEBUG_BIN := target/debug/$(BINARY) + +# Renk çıktısı (terminal destekliyorsa) +BOLD := $(shell tput bold 2>/dev/null) +GREEN := $(shell tput setaf 2 2>/dev/null) +YELLOW := $(shell tput setaf 3 2>/dev/null) +RESET := $(shell tput sgr0 2>/dev/null) + +.PHONY: all build release debug run demo auto check fmt lint test \ + install uninstall clean distclean help + +# ── Varsayılan hedef ──────────────────────────────────────────────────────── +all: release + +# ── Derleme ───────────────────────────────────────────────────────────────── + +## Üretim ikili dosyasını derle (release modu, LTO etkin) +release: + @echo "$(BOLD)$(GREEN)▶ Derleniyor: release$(RESET)" + cargo build --release + +## Geliştirme ikili dosyasını derle (debug modu, hızlı derleme) +debug: + @echo "$(BOLD)$(YELLOW)▶ Derleniyor: debug$(RESET)" + cargo build + +## 'build' takma adı → debug derleme +build: debug + +# ── Çalıştırma ─────────────────────────────────────────────────────────────── + +## Grafik arayüzü başlat (release) +run: release + @echo "$(BOLD)$(GREEN)▶ Başlatılıyor: GUI modu$(RESET)" + ./$(RELEASE_BIN) + +## Grafik arayüzü debug modda başlat +run-debug: debug + ./$(DEBUG_BIN) + +## Demo modu: gerçek komutlar çalıştırılmaz; UI akışını test etmek için kullanılır. +## Kurulum ekranında slaytlar arasında 5 sn beklenir. +demo: release + @echo "$(BOLD)$(GREEN)▶ Başlatılıyor: Demo modu (--demo)$(RESET)" + ./$(RELEASE_BIN) --demo + +## Demo modu (debug derlemesiyle — daha hızlı başlar, geliştirme için) +demo-debug: debug + ./$(DEBUG_BIN) --demo + +## Otomatik kurulum modu: answer-example.toml kullanılır (DİKKAT: gerçek disk!) +auto: release + @echo "$(BOLD)$(YELLOW)▶ Başlatılıyor: Otomatik kurulum modu$(RESET)" + @echo "$(YELLOW)UYARI: answer-example.toml içindeki diski kontrol edin!$(RESET)" + ./$(RELEASE_BIN) --auto-install answer-example.toml + +## Otomatik kurulum — yalnızca demo; gerçek komutlar çalışmaz +auto-demo: release + ./$(RELEASE_BIN) --auto-install answer-example.toml --demo + +# ── Kalite Kontrol ─────────────────────────────────────────────────────────── + +## Kod derleme kontrolü (ikili üretmez) +check: + @echo "$(BOLD)▶ Kontrol ediliyor$(RESET)" + cargo check + +## Kod formatlama (yerinde düzenler) +fmt: + @echo "$(BOLD)▶ Formatlanıyor$(RESET)" + cargo fmt --all + +## Formatlama kontrolü (CI için; değişiklik yapılmaz) +fmt-check: + cargo fmt --all -- --check + +## Clippy lint (uyarıları hata say) +lint: + @echo "$(BOLD)▶ Lint: clippy$(RESET)" + cargo clippy -- -D warnings + +## Birim testler +test: + @echo "$(BOLD)▶ Testler çalıştırılıyor$(RESET)" + cargo test + +## Tam CI kontrolü: fmt-check + clippy + test +ci: fmt-check lint test + @echo "$(BOLD)$(GREEN)✓ CI geçti$(RESET)" + +# ── Kurulum ────────────────────────────────────────────────────────────────── + +## Sisteme kur (sudo gerekebilir; DESTDIR ile paket kurulumu desteklenir) +install: release + @echo "$(BOLD)$(GREEN)▶ Kuruluyor: $(DESTDIR)$(BINDIR)/$(BINARY)$(RESET)" + + # İkili dosya + install -Dm755 $(RELEASE_BIN) $(DESTDIR)$(BINDIR)/$(BINARY) + + # Varlıklar (görüntüler, SVG'ler) + install -dm755 $(DESTDIR)$(ASSETSDIR) + cp -r assets/* $(DESTDIR)$(ASSETSDIR)/ + + # Dil dosyaları + install -dm755 $(DESTDIR)$(LOCALEDIR) + install -m644 locales/*.toml $(DESTDIR)$(LOCALEDIR)/ + + # .desktop girdisi + install -dm755 $(DESTDIR)$(DESKTOPDIR) + @printf '[Desktop Entry]\nName=YALI Installer\nComment=PisiLinux Kurulum Aracı\nExec=$(BINDIR)/$(BINARY)\nIcon=yali-installer\nType=Application\nCategories=System;\nTerminal=false\n' \ + > $(DESTDIR)$(DESKTOPDIR)/$(BINARY).desktop + chmod 644 $(DESTDIR)$(DESKTOPDIR)/$(BINARY).desktop + + # Logo (pixmap) + install -dm755 $(DESTDIR)$(PIXMAPDIR) + install -m644 assets/pisi-logo-light.png $(DESTDIR)$(PIXMAPDIR)/yali-installer.png + + @echo "$(BOLD)$(GREEN)✓ Kurulum tamamlandı$(RESET)" + +## Sistemden kaldır +uninstall: + @echo "$(BOLD)$(YELLOW)▶ Kaldırılıyor$(RESET)" + rm -f $(DESTDIR)$(BINDIR)/$(BINARY) + rm -rf $(DESTDIR)$(DATADIR) + rm -f $(DESTDIR)$(DESKTOPDIR)/$(BINARY).desktop + rm -f $(DESTDIR)$(PIXMAPDIR)/yali-installer.png + @echo "$(BOLD)$(GREEN)✓ Kaldırıldı$(RESET)" + +# ── Temizlik ───────────────────────────────────────────────────────────────── + +## Derleme çıktılarını temizle (Cargo önbelleği korunur) +clean: + cargo clean + +## Derin temizlik: derleme çıktıları + Cargo registry önbelleği +distclean: clean + rm -rf ~/.cargo/registry/cache + +# ── Paketleme ──────────────────────────────────────────────────────────────── + +## Kaynak arşivi oluştur (git archive veya tar) +dist: + @echo "$(BOLD)▶ Arşiv oluşturuluyor: $(BINARY)-$(VERSION).tar.gz$(RESET)" + @if git rev-parse --git-dir > /dev/null 2>&1; then \ + git archive --format=tar.gz --prefix=$(BINARY)-$(VERSION)/ HEAD \ + -o $(BINARY)-$(VERSION).tar.gz; \ + else \ + tar -czf $(BINARY)-$(VERSION).tar.gz \ + --transform 's|^|$(BINARY)-$(VERSION)/|' \ + --exclude='.git' --exclude='target' \ + .; \ + fi + @echo "✓ $(BINARY)-$(VERSION).tar.gz" + +## Sürüm bilgisini yazdır +version: + @echo "$(BINARY) $(VERSION)" + @cargo --version + @rustc --version + +# ── Yardım ─────────────────────────────────────────────────────────────────── + +## Bu yardım metnini göster +help: + @echo "" + @echo "$(BOLD)Yali-RS $(VERSION) — PisiLinux Kurulum Aracı$(RESET)" + @echo "" + @echo "$(BOLD)Derleme:$(RESET)" + @echo " make release Üretim ikili dosyasını derle (varsayılan)" + @echo " make debug Debug modda derle" + @echo " make check Derleme kontrolü (ikili üretmez)" + @echo "" + @echo "$(BOLD)Çalıştırma:$(RESET)" + @echo " make run GUI başlat (release)" + @echo " make demo Demo modu — gerçek komutlar çalışmaz" + @echo " make demo-debug Demo modu — debug derlemesiyle" + @echo " make auto Otomatik kurulum (answer-example.toml)" + @echo " make auto-demo Otomatik kurulum demo modu" + @echo "" + @echo "$(BOLD)Kalite Kontrol:$(RESET)" + @echo " make fmt Kodu formatla" + @echo " make fmt-check Formatlama kontrolü (CI)" + @echo " make lint Clippy lint" + @echo " make test Testleri çalıştır" + @echo " make ci Tam CI: fmt-check + lint + test" + @echo "" + @echo "$(BOLD)Kurulum:$(RESET)" + @echo " make install Sisteme kur (DESTDIR destekler)" + @echo " make uninstall Sistemden kaldır" + @echo "" + @echo "$(BOLD)Paketleme:$(RESET)" + @echo " make dist Kaynak arşivi oluştur" + @echo " make version Sürüm bilgisini göster" + @echo "" + @echo "$(BOLD)Örnekler:$(RESET)" + @echo " make install DESTDIR=/tmp/pkg PREFIX=/usr" + @echo " make auto # answer-example.toml diskini kontrol edin!" + @echo "" diff --git a/README b/README new file mode 100644 index 0000000..88820d4 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +# YALI (Yet Another Linux Installer) Rewrite + +Rust and egui based YALI which written python and qt originally. It is the installer that sets up the system by installing packages from the installation media (eg. CD, network, Internet) and carrying out the basic configuration. YALI is intended to be smooth in operation and fast in performance. diff --git a/README.md b/README.md deleted file mode 100644 index 10ecf1c..0000000 --- a/README.md +++ /dev/null @@ -1,93 +0,0 @@ -# yali-rs - - - -## Getting started - -To make it easy for you to get started with GitLab, here's a list of recommended next steps. - -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! - -## Add your files - -* [Create](https://docs.gitlab.com/user/project/repository/web_editor/#create-a-file) or [upload](https://docs.gitlab.com/user/project/repository/web_editor/#upload-a-file) files -* [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command: - -``` -cd existing_repo -git remote add origin https://gitlab.com/ayhanyalcinsoy/yali-rs.git -git branch -M main -git push -uf origin main -``` - -## Integrate with your tools - -* [Set up project integrations](https://gitlab.com/ayhanyalcinsoy/yali-rs/-/settings/integrations) - -## Collaborate with your team - -* [Invite team members and collaborators](https://docs.gitlab.com/user/project/members/) -* [Create a new merge request](https://docs.gitlab.com/user/project/merge_requests/creating_merge_requests/) -* [Automatically close issues from merge requests](https://docs.gitlab.com/user/project/issues/managing_issues/#closing-issues-automatically) -* [Enable merge request approvals](https://docs.gitlab.com/user/project/merge_requests/approvals/) -* [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/) - -## Test and Deploy - -Use the built-in continuous integration in GitLab. - -* [Get started with GitLab CI/CD](https://docs.gitlab.com/ci/quick_start/) -* [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/user/application_security/sast/) -* [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/topics/autodevops/requirements/) -* [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/user/clusters/agent/) -* [Set up protected environments](https://docs.gitlab.com/ci/environments/protected_environments/) - -*** - -# Editing this README - -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. - -## Suggestions for a good README - -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. - -## Name -Choose a self-explaining name for your project. - -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. - -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. - -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. - -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. - -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. - -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. - -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. - -## Contributing -State if you are open to contributions and what your requirements are for accepting them. - -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. - -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. - -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. - -## License -For open source projects, say how it is licensed. - -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..c008114 --- /dev/null +++ b/TODO.md @@ -0,0 +1,76 @@ +# 🛠 Yali-RS (Rust Installer) Yol Haritası + +Bu dosya, PisiLinux için geliştirilen yeni Rust tabanlı yükleyicinin (Yali) gelişim sürecini takip eder. + +## 1. Temel Altyapı +- [x] Proje iskeletinin oluşturulması (egui + eframe) +- [x] `InstallerStep` trait yapısının kurulması +- [x] Global State yönetimi (Dil, kullanıcı, disk bilgileri) +- [x] **i18n (Çoklu Dil) desteğinin entegre edilmesi** +- [x] Navigasyon sistemi (Geri/İleri/İptal butonları yönetimi) + +## 2. Kurulum Modülleri (Calamares Benzeri) +- [x] **Hoşgeldiniz (Welcome):** Sistem gereksinim kontrolü ve dil seçimi. +- [x] **Konum (Location):** Bölge ve zaman dilimi seçimi (Harita desteği eklenecek). +- [x] **Klavye (Keyboard):** Klavye düzeni seçimi ve test alanı. +- [x] **Bölümleme (Partition):** + - [x] Disklerin listelenmesi (sysinfo/block-utils). + - [x] Otomatik bölümleme (Tüm diski sil). + - [x] Manuel bölümleme (GParted/KPMCore benzeri yapı). + - [x] Mevcut bölümleri tablo olarak göster. + - [x] Bölüm silme / oluşturma (diyalog penceresi). + - [x] Bağlama noktası (mountpoint) ve dosya sistemi seçimi. + - [x] EFI, swap, kök (/) bölümlerinin manuel atanması. + - [x] Değişiklik planı gösterimi (özet tablo). + - [x] GlobalState'e `custom_partitions: Vec` eklenmesi. + - [ ] Yeniden boyutlandırma (mevcut bölümleri koruyarak) — gelecek. +- [x] **Kullanıcılar (Users):** Kullanıcı adı, parola ve hostname ayarları. +- [x] **Özet (Summary):** Yapılacak işlemlerin son kontrolü. +- [x] **Kurulum (Execution):** Gerçek işlemlerin (rsync, chroot, grub) yapıldığı ekran. +- [x] **Sonuç (Finish):** Yeniden başlatma veya masaüstüne dönme. + +## 3. Sistem Arka Plan İşlemleri (Job Queue) +- [x] Disklerin formatlanması (mkfs.ext4, mkswap vb.). +- [x] Sistem dosyalarının kopyalanması (`rsync` veya `squashfs` açma). +- [x] Chroot içine girerek yapılandırma yapılması. +- [x] Bootloader (GRUB) kurulumu. +- [x] COMAR üzerinden servislerin ve tetikleyicilerin çalıştırılması. + +## 4. Görsel ve Kullanıcı Deneyimi (UX/UI) +- [x] PisiLinux temasına uygun egui stillerinin uygulanması. +- [x] Kurulum sırasında slayt gösterisi (Slideshow). +- [x] Slayt gösterisi öncelikle ortak slaytları göstermeli, sonra masaüstü ortamına özel slaytları göstermeli. +- [x] ISO hangi masaüstü ortamını içeriyorsa onun slaytı gösterilmeli. +- [x] Hata yakalama ve kullanıcıya bildirme ekranları. + +## 5. Test ve Dağıtım +- [x] --demo parameteresi ile komutlar aktif çalışmadan sadece görsel arayüzde başlangıçtan bitişe kadar gezinme, slaytlar arasında 5 sn kadar bekleme süresi. Böylece arayüz testi yapılmış olur. +- [ ] ISO ortamında çalışma testleri. +- [ ] Farklı disk yapılarında (UEFI/Legacy, NVMe/SATA) testler. +- [x] Otomatik kurulum (Auto-install/Answer file) desteği. + +## 6. Kritik Düzeltmeler (Gerçek Kurulum İçin Zorunlu) +> Bu bölüm, gerçek Live ortamda başarılı kurulum için düzeltilmesi gereken kritik sorunları içerir. + +- [x] **[KRİTİK] `arch-chroot` bağımlılığını kaldır:** + - [x] `MountBindJob` eklendi: `/proc`, `/sys`, `/dev`, `/dev/pts` bind mount'ları yapılıyor. + - [x] `UnmountBindJob` eklendi: kurulum sonunda bind mount'lar temizleniyor. + - [x] Tüm `run_cmd("arch-chroot", ...)` çağrıları `run_chroot(...)` helper ile değiştirildi. + - [x] Job Queue'ya `MountBindJob` başına, `UnmountBindJob` sonuna eklendi. +- [x] **[KRİTİK] initramfs oluşturma adımı:** + - [x] `GenerateInitramfsJob` eklendi: önce `dracut`, hata olursa `mkinitcpio` deneniyor. + - [x] GRUB kurulumundan önce Job Queue'ya eklendi. +- [x] **[ÖNEMLİ] Kaynak dizin hardcode — dinamik hale getirildi:** + - [x] `detect_source_dir()` fonksiyonu yazıldı (birden fazla aday dizin deneniyor). + - [x] `build_full_job_queue()` içinde otomatik kullanılıyor. +- [x] **[ÖNEMLİ] GRUB kurulumu chroot içine taşındı:** + - [x] `grub-install` artık chroot içinde çalışıyor (hem UEFI hem BIOS modu). + - [x] `grub-mkconfig` de chroot içinde çalışıyor. +- [x] **[ÖNEMLİ] Lokalizasyon anahtarları güncellendi:** + - [x] Yeni job isimleri (mount_bind, umount_bind, initramfs, bootloader) eklendi. + - [x] Manuel bölümleme UI anahtarları eklendi (en.toml + tr.toml). +- [x] **[ÖNEMLİ] Manuel bölümleme için Job desteği — state hazır:** + - [x] `CustomPartition`, `FsType` tipleri `installer.rs`'e eklendi. + - [x] `GlobalState`'e `custom_partitions: Vec` eklendi. + - [ ] `CustomPartitionJob`: kullanıcının seçtiği planı uygulayan Job — gelecek. + - [ ] `build_custom_job_queue()` fabrika fonksiyonu — gelecek. \ No newline at end of file diff --git a/answer-example.toml b/answer-example.toml new file mode 100644 index 0000000..c63364d --- /dev/null +++ b/answer-example.toml @@ -0,0 +1,38 @@ +# Yali-RS Otomatik Kurulum — Örnek Answer File +# Kullanım: yali-rs --auto-install answer-example.toml + +[install] +# Hedef disk aygıtı (zorunlu) +# Örnekler: "/dev/sda" "/dev/nvme0n1" "/dev/vda" +disk = "/dev/sda" + +# Zaman dilimi (varsayılan: Europe/Istanbul) +timezone = "Europe/Istanbul" + +# Sistem locale (varsayılan: tr_TR.UTF-8) +locale = "tr_TR.UTF-8" + +# Klavye düzeni (varsayılan: tr) +keyboard = "tr" + +# Klavye varyantı — isteğe bağlı +# "f" → Türkçe F | "" → Q (varsayılan) +keyboard_variant = "" + +# Kaynak dizin — canlı sistem (genellikle değiştirilmez) +source = "/run/livecd/squashfs-root/" + +# Bağlama noktası (genellikle değiştirilmez) +mount = "/mnt" + + +[user] +# Kullanıcı adı: küçük harf, rakam, - ve _ ; max 32 karakter +username = "pisi" + +# Şifre: minimum 6 karakter +# UYARI: Bu dosyayı güvenli tutun; şifre düz metin olarak saklanır. +password = "changeme123" + +# Bilgisayar adı: harf, rakam ve - ; tire ile başlayamaz/bitemez +hostname = "pisilinux" diff --git a/assets/budgie.png b/assets/budgie.png new file mode 100644 index 0000000000000000000000000000000000000000..c2909dae3c6841ab0dd5bb8a678f64d6f459952c GIT binary patch literal 10125 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 NC@W~l*UJGz{|8Gmtx*5~ literal 0 HcmV?d00001 diff --git a/assets/cinnamon.png b/assets/cinnamon.png new file mode 100644 index 0000000000000000000000000000000000000000..3c01f67bbe4a1b6fec9e908677199b296fca46f2 GIT binary patch literal 2929 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 literal 0 HcmV?d00001 diff --git a/assets/community.png b/assets/community.png new file mode 100644 index 0000000000000000000000000000000000000000..b5293c9dfc4b32b1310040d67a1d38df3301696d GIT binary patch literal 27317 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 Of~>TXRONprU;YQlKZk_? literal 0 HcmV?d00001 diff --git a/assets/file_manager.png b/assets/file_manager.png new file mode 100644 index 0000000000000000000000000000000000000000..a958a5823e746c7a0c354202138ad9a71802135f GIT binary patch literal 2180 zcmah~c|4R`AAe?=VJLc{8J7u<~r_9=R^1&*2FXosE(Zvb7LhQw#+E@6Sz3D-vLiYw?th?x` z{lkufC%{Oy37Zq$GHUKWTH}YU-9L)<&&{@ZtuELo!1)s}Y{zId$DTIF-&aS67Ievi zY8r+|7H-|{t0xP#OZw`Vlj(eeJ~H`IJPO9}udPXL;4i%1ZstKP=DRUbhfnXq(Hj|w zRX%Ou+SZwqeoMo`Z;sm19j_9!EAwBH-(S|Z7B-ISp0|GXJVv;Hch1%GGuCt;;OR%^ zc0Yc9`IMI4kZyiMiG>uAwppkY^Hi^u!yRm%v&gs{zLojbOWTJ|JyW7h`o+#NbI8H8 zfa5vZ?lV~Q?)0YeSKk91tFiu%GqumXwdZBPF@C)X?c^1%kqvIupx7Y_*S#+hVZy6; z9ItwG6Z48pHk&aS{wUT=>@$pQXb+PRxL07h!FqcazS&fM5j~25HGKIsq?{fzK;4t zx!qNdQl|2;?ipTu_sE#R{ZF-TL`79xwYLP>SNi@!-r%1%8wKa7B&=7OcXdv%K zhIRgnC&?u#y`_;td-E7beeNWy%u8kb!;s^2%e!Ca9F}-eBr(R35SQihJ?^$iFy0ed8t)Nuc!- z6%h!;T-S*R7HekJrOE|@bg_{v7VCIKHnXC6?@|xcL_@ZOfMDXd$}{oyd;hnZAY%Ax zW>)6Y7)(JZ6|Dj_Ws@;*sLs&C@R;+?Bmhf}k5|FjP}{o%>(`g3g9Yvwsf{9CId9cR}9ekSUB;RD;Wg6PN(TP(VgH!2D4{a`vvbmE zl-JZo1arFuvDVLSI3Y@zoD8hb*KlsqA$n&rOji&RH^n-CO0d60K^n!RTxUz&7gzmb z0g~@aVin+WWrnF~RFHy}2o<|v`eI!^Qj#4QJ8zU1gxgIA2^cZ$cooAL`AAmwvZTzi zZHL_xD3XPGBbR?p9D%q%v+Orz)+)2*Q3yKdK(%-FtQ%5=ukj8`UiB!PA43ejrw&AC zEk_#Z*tHXT>+Y~T5*e($zF0rBZu=Tm7&F7a+4T!OepKeH)EL!?BD(yR<@y?aF zgqKkQ1Vg8F>XRBZQZX3BTv6C@xcZXITfZ}lWBwj(x`!+NhR9*lDT`6T-k?1-&>OU- z*q@_FHy&8~Tc%M1r!RqUZQim?&pu1C6&wuLTh@;#38z(8lQE{uXJRqUlX@XPpZZqm zVlywF^KUp!U3?Rw=w$vw1I+XsqZ0y}ujtA*5EpPJ1dvz+h;@tdqO4sI{*9?u(f@+_e+PfXIp$ zMTOPawtf#M22FTJGqsb1g^P0OHp7h%pQ>Zn`&<85T)+*jo2cjz9jVTe46jz{=p1%- z2hRF|JSv6XEgt6UQPC7|vqq&r13RjO~6*^*U!VP0eywKyr{@eXMd?-N=3W*9;+J>XWN7_gG|1! z(!=pOU-E~aY#vXm66x3e*zzunn^E8{>pfBlQ_d}51%DoC{5E=R7w7y+jl&sVi;>q+ z!~w0^Vw(VQSsnQCnf7eH>mBrC6+L$}0oyhnx}4nYCE9Wgv|?Cd!u?GL-yYkX)l89y zw%YdBue_tt^UBRVQ{YBD6F3{CyqPrh0W!9|?Thc3k2_ss?DXu;)^U|rhTDtj{-**fX=z+S%y?8JpKU zPCTtA9#*{6!@sJfV^~x1i9}r5$e4%|C|2IOUPr)hanlba5xJe&N^zROJ)hrI^X(X! sj}~dJ`6UB$S41B;$}xKX`e!~^+pDBL;FpTOuC`-qWo~O$YQkXu58nO1^#A|> literal 0 HcmV?d00001 diff --git a/assets/firefox.png b/assets/firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..ddc9d4db1f14aed47c3391a3cc8805fb4c9e6e97 GIT binary patch literal 32441 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

q3EG!9bk4E+iS+MFA}Hs~Jn&6r^e> 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%0D%Z^L{x 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 IM6N<$g8r`E;s5{u literal 0 HcmV?d00001 diff --git a/assets/gnome.png b/assets/gnome.png new file mode 100644 index 0000000000000000000000000000000000000000..c3d1f5e5bfb34dc3741a3bb263b2a997e4078bfd GIT binary patch literal 3140 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + yali-branding-pisilinux-xfce/slideshow/kaptan.png at master · erkanisik1/yali-branding-pisilinux-xfce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+
+ + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + +
+ Open in github.dev + Open in a new github.dev tab + Open in codespace + + + + + + + + + + + + + + + + + + +

Files

Latest commit

 

History

History
14.6 KB

File metadata and controls

14.6 KB
kaptan.png
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2026 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/assets/kde.png b/assets/kde.png new file mode 100644 index 0000000000000000000000000000000000000000..0cc1094d69c36ae70dd0804eb701e7513400cf8c GIT binary patch literal 21706 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 literal 0 HcmV?d00001 diff --git a/assets/lxde.png b/assets/lxde.png new file mode 100644 index 0000000000000000000000000000000000000000..a23c3f8bfab16beb54c3afc7cf56e69777a178e1 GIT binary patch literal 2133 zcmV-b2&(sqP)@QIrUZ1_gmAm6uAuh$P}8!GKW|Ar?hL zAWA?1iJ&PO5eO6;K=B<3O(e8v49Y_VDe{t5lwyH$@5ev(Oz!Eq=ggg%^SX1(_wRky z{;f4<_St)_bxsH`5wH!8#*MhLX+2X0?20q-50MA(vZi$nJvbOY!H6-Q#@bK)*w5FTvWhe->L#oq=DY=>_&?Z>18`{DM2f$eZ?)Ba2v zu${QhzF1OlVH3`5+PB8RQaoH@VAEWVR?~jg4tBxy6$UoRB~ANV8<>VO@Jvm??Ql-h zzE=+3h&yWzY==?2ujv?60%qe|`a6YH!4p`}bUaE$OvpUcaA1?%)^tot0dsMM{7hGq z9ADJGMzgd8FA%w-PR%^qc2DU0uOwV8^ToXdLIZWQ*h7h%#Rm4E; zcQB3%AzT_l*s1Qh2jtlh!lG8I_2eKI*LDYEK5hshTo;BXxFLivD}->ypcmJ22jip= z!X+VuVXfG12qEmzYPFu~_rgl=VC;+=LkL%g;SFvGAb0_cd%Hx`B4br`p|rEpAI3c3L*SH#J_nFb_pRIRaj9Ga3mgW;zW?* zPdEzG656JT?NRp@u=|^)0=qq~EFPCqxCq;J(K-_s8Z6&2iaqL#ZNMQWM-E{Wr}v@z z!v?EBpIv1@6NJph-4jNlE@K>to*g%b2q>@isVDEN^FV4?d4w`n3D~0)g%Di4y(X z3b*tz_g-a8x);`D7+)to;NCKz-8abpOOD`bTr+`#*B5qhysjPa&mIFjcp4Ked>a2t z7~F)FI0n-T*q$c8p!qP~CO!mLcX94P6}9?{{TIFPyFn+Ihno|I?!#v>uOtV)lq2{q z?LwpYbnSw1g0r$lem&j@j)o^Tcgk9+kH_ zwKe>whamU%+JU(Jx)_g$y{z$1w8*)}Cxh1Eb*XXP{*qs7Nc&b|>a!ciG@&gia(PP73phA6 zW}*C~%N-JV-3IiZFhPJXZ%SJb_snTNo-uA^j`;O>RTJ71+P2m`Nq=8c!WQ6PDKX>v zZ}EXH;*V}Zdm5b7MI*eT2~jtvMEpYPuZ}tLyVftQU33oO1Grl$?1;JreIzB|uh=1D z+&6Os{{b^<6+HnsyGwwV)hT3w%@gU*V4sX}`^wJHZNTE%1ow#8Pq#5Az_->ZWJO}) zQ5h|u;`V1%j@XaZCbmy-RgUI$>Ue?1_@&{zoN;-{oNFr=Spf0Wn|IROv+Btgw13GC zx5+qqi%o!8$(#qUeWfBx0Kd)&@Cj8Ot8HYKdY5w6W(4}#3TW)Px&{h z=wV4Lkizl_#vNq*vGR+BCZB{D-ym~f5o1fllFuq#x_jE|(>BQ1qK65blJNJ5K@2SKWo;2(lS*>yR9tt{h;6UWCH(Ha2r8C# zCVas}d?_Z`V6wKaiH02UgU=m$--_z-P=K#)N$YMJd??}nsbw4A)8+-iE$&Nt?SF9R z6J+Hk-)-Ilaf>0#@0NwJ*B*XerqTB&g8R^xwC<)cmcCtEmcbdu$|oBQNnNcfFiWg# z6wgVt4SqRs_kOGdjYAJ^XvgENMGd{uSj*`ZCFvV_j1_=SE^4T=@4Fi_OVT&=hz*S! zabXc7hqi;ePTk*67y{b6s#^xVc$%1SAHiWIYnu{?WwM6`z4+Aj-CNIxDTWa2DCW)Q zOgwt?3ulRq$T!&nk~l>Wd)W5xH%O<45FQU9oY-o$Mk~-Yl~@r%=)Dm|{CM(eOy-Yy zP8zT~mi2Q7FAO0pZM9mDRHSK2(Q38UhWOpKm#7LH(zJ#t4R-!N8t?Lj4yBqh00000 LNkvXXu0mjfHggGc literal 0 HcmV?d00001 diff --git a/assets/lxqt.png b/assets/lxqt.png new file mode 100644 index 0000000000000000000000000000000000000000..7bb1eb73c6e3bf0fac283c0e4b36d3797e1eed13 GIT binary patch literal 10059 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 literal 0 HcmV?d00001 diff --git a/assets/pisi-logo-light.png b/assets/pisi-logo-light.png new file mode 100644 index 0000000000000000000000000000000000000000..b4119529cdcf1adea536994a480a8da4065aa4b4 GIT binary patch literal 8756 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
1J_qk?wes8?0V3Cowf9J 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 literal 0 HcmV?d00001 diff --git a/assets/pisi_speed.png b/assets/pisi_speed.png new file mode 100644 index 0000000000000000000000000000000000000000..a9855a706a804481dc79f3cae724ef1cc66ded26 GIT binary patch literal 44423 zcmYIQ1yCGKnB83#g1bX-5AG7&6I=rc?oM!b3Be(_y9IZ52u^~#ySu~9e^pmETT?Kz zwL9HkcYpHU>kU&K$*9PKKpr$8kY5l8^a$MY+XsQ1SwWyfeGrI083e+!Pj6BF z2)qGj_*q&4^!DE?yS*qLxPxFXqvZ$!F;o6`g53&)U4WbKoMh!C-yOmt<1mttohB>- z4*|(ah^o0Q9%s0^5zovF_;S>$_cJ6K%T~nMELT^{v(WHjZ-K~Z^vUqWh2RVE4Q1fT z{juT4l2a$;=yHN|14{gpOkb)45nFQ`>i!?hu-DW&=C>a^Nh)A{of}2+2 zXOv#L1gesGRyv5(Crn*XSvJod%I_VYm2-JLwT(HHe-dSg@DOzLeTdsdKVAlh1fK?ysIaSS?eEVq(vy_CPATKc=$Tya82xjY1SU?HZ?>kdRC=4 zrQbdC&zy$0OU#q;)JT4QQT#@ct+QP`BG=h|WFW9V&H3$;T`L?i{^SJfFBPrX-rGBs z-fV1q3RxA6FHN5?aD*&#*&=T7_L-<-N4N`FN~h{&b6sKodl=JdVSk#7n{1pIp&$&k ztjZ{50q=%oswKZ>c4Pi2PidPTONlG-yVQL*uqX&3DE(j4)aH7%z53)hu=8~{jCwz{ z8GISzlo}5HZWe*)0{33vt%lZn*;f#(S`SCm}Asp);|h*vR*0KSX&;dR5t?snlivw97ItY0I-+^K>@*D6r+= zr4rXJ0v`Fu@jRW?!Yh?mQzGPGPx)Y=GxkY&HQ^sUZWcc! zN?l6hl;+>Nd*lKTos5@ZZjQg(1Yln$Fw^RF7+RX8pFxPI)M&WkvkwE*!xFGnjErhP zN3#(M%o4mvoQeUx{QDGqC3QQxB^QFsQX8q%4((xuuSVAl%aKKu{vYx28CNNQ5zx^N ze-omm6p#M9i6GfXNF7Hd8v-V$CYe-SXIOZF^%#r^j-7=5LZpysK<#CPlv3FtSzTEj z?0lg#*|X(lhr6ee=8jqU4aWkkmuxHZ3+1ePnZ%(D{rtc*`fpHb{nuW_AmBtz!KA$owjD`acx>q)7M_ zN0QgCN+FvA7PyEl7t3}{7qPQiu?aT72cuXh)^9Jg%YU+)x6U828XD65tP!T@vRLm9 z{;yY(UA`Mbqoa%smKVx4tN36QZO2kAtH7+F6`>hOy9w1lZ8S2NQbK#%rAUjkHO4!K z7ZHVS4L2z)uY!8cFQm$Z<3ZX5kgjK^ zZA21CP3Cl$afl*EvrERzaI6#97iH7%(9xljhC!+bX%JodU~>v~$9M-r*t{DPyiBh5 z^pjs%_LuT(fdOFnH_I?q?P)Z5@)gHkK%+GCx?XhRT-zj~Y77Y;vj54HuvLGsflTJw zoZeq)|KnJD(K`+2U}b->dSpwTRnqS7FIeZ$xe}5&kFkvQ#WQ+!Y72PQZ9n(C-~!p~ zRt%9gT)WzSG&uTJ3xgC(tVs0zmFZC|HD@Eu@{RdMN#~hzHNk&qVAsdH?z#?>)I7!b z#WwV0psW0!!_g`?ERjLP@<@Mgufl-tjv!u});~C`DAzNuBQm1px6YQG9&?E*%67#B z+31R7bHJ08_P2h*fju%L`;HXQ_taCQfRDtXI2bQ;I7D4Kc81DuQ>Io~J(`tRt?amC zht%>kWzgWx_VGVc1>v$J1?V!2IFwYVB8HfV#uVn#1&f^JKm-j|;H2d9m`|##t}2e} zOU+`k3hUg-f5Ac*gF(4S0TT81RoS$rqUcz0V;`rU1IWa(N%tY`B@SbgcN#}gCxzT+ zVdhs$>YAHseGmxby*LPl7?Y@#9lDb4-|8Z)+a+L0=J-g|s%+6}I z(?MO-=2E>>H6b$j5|U&Zo?QXza=lb*Y)|5-Z%G?t_QP7tT8B&v)-@D2qNPFKHPf?a zkd5r>D>w_rqH!yK`HApwf%|i5ip?rZ$vxHOuaJy9jfav>atkY^nMq>`r%}#jI=~h+ znMW%5LL@^eCsdSU{+y~8Ha?EKPc+l z!Ty;dprM{3qRbVckFDO?-HqyF@scc|YBO^m67F0+p}_pxZt>TZJvmB<5KG$JKZ$EQ zK&2eW&p31mf^Y_bs;_ze3PN`w#H0z%a58-V!Li6E9ewsqV{KDi= zkExv&TTUplyJPbyonB?jGcZf)dd?2onb!$7dy_0f{Q-Peki$zgG7oqK`{JhE( zdA;_p_^xR9Qe1suPk0!SvGZs?&QOb89;3$=twmJ5oF-+_Ych`ot!YXFO0oF-r|(h| zUjIK|vV#1!q#<~^t*MzPC~Ptxx2ijMpUI9vE-=X3O-OnWT=)Q! zDS8t^5toDj4^Mm#1u2~(?Pgp)4yS*OCO*H|eq9($rO7#^o=hwK%F{D6LX2Ytlex}6 zv!ji1j{6&pSCYXH{NFPRvw!^}!nH|r`u6?C)s>hdTPAjY3J2C>(+EX8Wu-5 z4QN}1bE$x5r9k@clTorts*`)8v+;gK9>2LsJfY^TAJ%; zVd(O~2X(tOc6kdA0}OI&Sbof>2GKLa7@VAU@KgbKf50xcyb#b7)%BF?+}`rX>hrCk zmzpRxWb7j%0}&E6+EXvZQC$_b!LY{?1ljB`g1slX-gmA=8|>5l44f&`WYg~gjlcgjFy+Y^QRV7j zg`sA!bol4=VJ~Y!@NPM9?aXW}l?(XZUy|Xt)#iUGG%9r?D`;g7HR|zJpNg7q2;ikN z5QI}v-Cq`$X&^Q|-@7EcCj4~AP?6enX%y1`C`-TZkCi4F>V8K$+T{-uYm!1P9#Un{ z8*-k5l~y+RSMX_ZKL)Su>JVoi6@PC{LE)6QnX=_l4=6+Jyg zNl89fz;v}1q^(m=btkz?v&ju_=rnT4Ait#()8qN-i1z}CDI8|04jrXGf#zPUdY)YX z*>|na%j5myt+oH$X)q6opEyl#7+z2EmPGoeL2{UTSbIL!!jeF2$&Ejh(Z<8S=;bm$ zrd(_dZaMK|kq8*{KtF)x=7quVOo}4e{d75~@>BE8j_(Kv4(`2uuq6#d-d?x&_G%sH zY^VK5K?n$qyH-zQV_Cwy0OuN0bz~mkb>qT}{0Z zZDi}h8_uMgyLc`wQCfX40yzYQC^7vq?+BUcecz1cw}F`?z2QQ6BKOk=Jono*mMV`i z?WYZa+3pWl3Lqbl?Ym5n+TSgDQPOpfbrrI4;V+3M3h7>uJ$d0YjtSntQQZ_%6&P7K z@n{;}c{FezE*R;*5+)zL6$OnsDZVF{qO^>Gfd86IHDz|p-A|wO$J7CpfB=#BT=Tr@ z1Y1h|a@)#C9Guw^bBnvl_EFRKt(YBCXh4NO38yd$iqpz7C-SGCNKF@uAO1VP+z;(N z8@7<9u( z-eG@RWUWUa9)i4)R@u4PdX}i7tSc%n&xL}5(zIgx><{urd}Ou0XMMamnlMkwdiurh zb1P2s6i}XwzDiJi!fq;uMPnoguZ`}+l?g=_tRu)_bqm~z#viD=p(&fL!N z6%x16$*3PN=(6f6B9HI?iE4ZJnv9hn3dv&&%=j6{TM3>A{e~tQ!AW@&Q2dDMbMMj- z`F@Nh{x0df)ynkyYTeXDla8rDHc5;e1m5Z`ju_`Pt{3?_zBg^9SCE!Aw8Q(U#{22k z{_lCA?I?LrvY*IN)l~e%)Ms3dz3pCnHV15?xk{tGah?5^kdYm+II2TStCF&EldE0% z2tvV-UQ~gI&EK3Pj3s+`M;yvuFTZJ=`VTDrIX&O#-Qx0*=Ys7l41xNxegd^5fSj%h zs=jqLxze~k`*6?cvBf{_3HN$O3(2cHN8TU~Le?O6Am73iP#$*=f*eF)@YlmQ#Pp`=|I2E+@JdhK**js-M8Y@Au;KXx3OOJtg*Aj1L5YNN zvIZzaCY?p1BS2!9v=nX*QyI?(se0^BxsFX&q>2t_d2coL@m&)Hlvcr_;2 z`WUakT%0=ATOgoz>&KA=vs=%zzCNwJg|K)k6{}E!!T4hEH)JyS*B6?sY)#>T5e&mC z&A+EP9#)n86u*bVS&|(CneqONc6KBQgyc`;-@0@jAlpTs?1(&AkgLetddv=Z znt=wJr7!IsTpu)kS6TK}^WrCm@-4h*?>}kUGq26jO}nVZ~R1(y=&?^ z4QJ8iTj`g_rh$o7H+6qm`jNQ)D znWn?_-$7PJ9YeX)fw)Ji+F!>%7vHA-{o7w_#8=BIk%WU`qeB0Y@(w=Dw=U*ojll_d z37%~B^kb79iJhPi9!qCyOqpFKu#7Pz7lJL8gfN<7XuhGORSP{6Pf?m$Gdvj`PM17y z(+XE7oGjFa1|#9s*l&of`aIb**sc(IrXumu)_KD%L)zwgK9k}R%FbiTlDPIkNnV%E z@Y$L=7tl&4*y-)4x8^%yu+aU2p*?*S=C_Z?fd=p1V|&{5Vqy3(>aJx{JQLl=JL1eK z@C9Vso?p;r)#!Iaa2daJwV)6sJMFuj5?~rjY`OgXauO8WK30d6#%+_^P=Q)GH^OrD zm6f!a!?HqXKRf4-2Pi;DH5=-k&8^*_q%}$Ui2T0jF}HK6Am7; zf_=MVX%D+;c1^F3NA%3h3TpjqU9HLStMPGd$JXnVW#_JZ8Os+>3(sc{@9>pXjIBn@ z-|kZn!Uyghr{}kr(h62L#6KIJvE+1Ck@=AXT*0h4-d1DX`^;E&JRDk4Ws?bKU0-u1 zGU*H_=`oxBS?_-CseLyzDH&J~|Xo61VCIsz0z%E_tQ z#6$n(SswniFv!=aZ4%*;e4mzQWvmQsWw^KTg`{%Ol${YVB}l<;mox(9{gw5fpkL@) zgVAQQzqQg`7A@#0K}0aJnEwT5Al)zn;ymM*DnEMFLb86^KLRvPofGk0frIR`t$0mn zpEbsFsA2A(>mQzP;~Zn0XO08yeYxoW+==&92a#OUlHpwOzdUZoW@ctW!9h}FE0$R1 z7#>dyDQu-bE-w)^%D>4fE0gP1;>l0N#QYf@1@cvO>xG(x5~ELlG>#ajW|=(<^v zUCvg6DMqeuMD#QHBzSO<{y>MzW28RJ)f5GA`!+T z57x3-Y~$-d;_sHyi$3+kXNMXZ+oQca-5HI{mgk%0=N%BHR^-qjGA9v5&js4zAFtM? zjYi19@tk5u&g$lY6zxF6!^7~Fgg<+`a|lGkUmC;84U;T{Q4K`C8?=EYAr}GNG<{5+ z7Kw^XF2d+5jZq*&8GU0}y$&}Up`r|4dJW1B(t9IwVe8Z8fWoWUr7Gtmjp31zgQ+6L zscKaDt`nE|l$3>*JL7GcOt(!0jdJaNAR#6tGM@X8f8ZOLV#tT$hQ-^92xY9WOm+u;0**T8T1#G&6D)xP@bZIgqEfY*c>-=%|1fEpI)!G|BW zK{inybHK@!(=L>O;w;)x0zZjfhZ>qnLWq(`1P{m6V7)5$eXZmAK=ntV#eNG(7(TI@ z%FhW>5e_GIXT2+NCN@MXuG=ODwwU6wvb^eQjHD^qYE}7lSj<2N0s1=@<|?G*Y!e7C zzRWsYDj6!-LfGIrRZVVxM%t;v8(6(3}nuY*o3|yFDg{B0hDPa5mfnmh7DO`!PkOcRF8Ogh>#zM1@Yd~lFWi=SGYZjK z3N1Lfxef8FtoCeaP#H`O68yhG6&3CO2sz4DLU?}#tf3$`jXA=t}!rv zZD14wxvqJ;wkG@DhW4Tfr&o5qrkZ8ChwwS>D(ULl)~8DZ`Bsi1ue$G^5p&soi8ybJ z5vdh*H_%jS1vPpa2M2YMP(b=OMSo2uXmTe6(K(3Iv^+wglNo9)r)563@~Ze5JKO8T zs(+%#UD#`qup0k4h#o0ZjUS)w6uq=Rd)vJ4d~Jx+$C6hqI&@pM{rU5!jN;Yi-4lIT zapCW_h-^ZtPO_}$03l;jQx#3kk&+aY`*f6#O)NTePbYraRC!1I&d$!pW+qdEDSgBu z$lz<1VVZ@sd*{`f;bTj zx;V(7J6?k9i^LM=b@61FYR~9a(py!m(L{>8ypH#$Me~Ik6TcM9hyA?hU0}?Qu_5qz zRaG(n4ZFou;l+sFYaHNtWIngu-iAgzTsYyj--A+Y`4&mLMZC08nTUVkog$UpuBqwK zk&DfaDT{nN_H*t-f6s+|J0A5y1X~Ryqw!w?6*00gj12L?Ox-UvF|K|TijFkHR(5vL z!_8O@l}4S|_!-EathR28w_(?x0?Y&hr%lPATQ`rZ(ao7_CT7DfKhgYxf~}jvzw`6( zaS{dwY$VZ1&ceTUS_?h{iJZiobH$O4WGdqT=mfTNBAQB;_*kA|$H(Ru=+eQFQM-fs zMmz`_@Ryy49(p`DNP@M1hEO_RY&iDl>GW2ACv4JlkTihsR-#%Imyxkj+Mrc$iQ}*I z7>1?zv07D51Yxa~W5O7)6S4R8--gQsVe9;}zrtoGk7M%r+e%w`^*7ljnT5?ARhesY zZ~fQGx-L@3Cxh}a@DOtt4LK&`9Yw^4JGS;_12q-Oj z?{77!;&_W2J~C`O)aET3e-W9ldy#-p;O7Moz>^E&*V^GIfju)4x9r@vVGDJ-8MHG3w5w4=qa-%lm9Hld|6Lp(L=tlLafa%oCS6R_DMguFi&UAjoP+kS_WWIeKTuo-_rz&_IPgqk!G*1NI(>l%ihCOaIq zMkYw*JJokP=fBgp?T#M(@WI(S_ZrE*Uv-p?1LEb|(; zM{|{=S>Cq08h5_bId)-_xCtaLLE3nM)Wuj1Zkx)2ubSvt733369I6&~%N!J#KlS zmc^`LoKn(@W|SQ&@BFHX;~nl;lk4KmG&?{l$NE4dm#scv+uhe-d6aLm?<%g!cc|%l ze%NDY)5!aMQv#PocND+_av@TQDZ;)&wvDYbP_hwr+H`xdBnm&)Lb;TlT*+`crpN&; zf{^Y6SK$#-5_duW6=AUQ5rUL1!c%UEPs1;ZziZ2=DWlh%M<=_t`jCBsoIyV36md@; z;qOP9%hs;DRkY=Pghe`^@A*A>Lkz0y&UArJcqr{OS;rDm>_D^WWXM_2C<*XP^f+&P zLguh2p^VI#+~C+^#`!)wZ9}lhJYGB-XF@M?YbZun>GZBZ4i(&tf;_wt~Pw>tpIv7a{xT^P1|ne+U{e;4dVAusb!_F9s+yz#F@Ct*#_ zRn-4!0X)8WA6V!fG4->E(*J6LLECctde&S!mmnUvne+QMvLqV}&!Fc_g^luoXNDN&g4jgKo&_tNT@tfRY+ z7i!%P3X%XM(dx3f9)KEi?+n zS(26DOX{_IL-oyXpI^U2L=?|kZNp&TC9^~HP$`L_rV^To|MKE-L|4{h%1DiNcH0|b zN88-5ns!sIZatrD8`DBbeUi7Lg@u|i(3I5G`)A9)67brSy*%FhhnxP^sx4e_RKY-4 z)&?S8rspZ&e^m<%ngq;drk5|hsQQkcW1;rt?I81nMc6Kv*lD^{F-v|-xfEK`;B^V{ zq2t28!IlTXF)NOCcPw-f*T7Xoi&f|RPOxpy zg8Yq_j{~Vg9F>2p);RZyQ7|P;yK>&&J@G^w_5v~py;lG=tfU6KW%ndUb=Dro#}s@5 zaFbEMkJNdJ9$}63zDguwd0~C`0V-Ae63ZA2O~IiM9d+)Fw=Nho`+givs+Z1afm2@Q zmVJuXhY8;Xa}xdaE`JOTB}ZT?Bl7X_Wh^%S%(Vv?+4zKnex}A{OnTp4-w(0WfkhSk z^wTU-0k2)Fc(amgC#@H-fhn5M#ER_n69(*?vxL0kggU6NK<%D)QS$4v7WYSbZ^I}&%laQYAM?&qZq7p!U;o`r z;f2AshP_6dJWYPrjV@cj0GM&qF4qJwiH_!Al8KMy%&dIztCf*pY38y_VG;)yP5Yv@ zBiJFdBKAn8P{Ckb(Ip;-Kr4<783qO>bUI*&1*Y}3qw}nxX8xl{;uz~Dbg0_bEoElu zgLRMZ>+{1mkAs48k3t7W#}pnr-Eb+80kQA%1#gCYw5`C%>l!xT3Of7ceT1J^9el2? z_gqA6zGf}_z}md+_%!Jo_9#?$!jjQ&4mqqMIB3u*qsXpqph>0z|Dk`dGjNrh;v_TO zSLK7mm^cz7+Y?1QJf#VAzfx(b@=`sMwD#%CX%Wj(;fe^i9_iqgFW6wcDhfRq_YHQ| z^PaU`Z6;dFnL=YyQid?3iT~QbgVv)2PS+Q$D(e%*yp8D5I%<3Vy?z0*Ko-L%oXvkC zeYcGm<#SaZB17=OPDam4@!!-cI3(K-@1B&gsSjiY{PXESlCknwp7)YAqC`Yex#=IJ zus%tv{*?KB&T1{ZcK)o{cAKy=a|K}WI{`?{GO|b?@7Dv3jg61*n&i{Cm34G7ei0OZ zzyx(IH#=_844VmG@Y%7fn4U~S0|X1vA|<>RpEVLB;=N*s|2Z zQk{jzjRF4gWBfG0*bGfuU;;h-$1Mv2qRb7vNa9Yh_blrz2c)X8v*HLLh~EXwBI|M$ zi%ogHg-gtKx2D$-KC;VFqjLsyf8Eaa>Fe;ymZ^k}S8hvy>oKYi2HWy6C9j&D{+M_3BH z{ts7sjg~g6FWnpV=K${^0YOa*aHja8jGcyl!VCqiJ2bn!+{_UOdN?`NovQNPH&*5m zu;qbDQeJ;9H8!1pa)~Rps&bE+x%&p$AN7~{S&{VHRk2y`^N_Eqy5qR$)XmEqnm?`} zdJQ9GC^U;|Br$9yD5rNla&e^Wh|n-dWRyJ$VFW0~v<-$Y(@bUL?qAaGXUsJw5U^;@ z2Z-#}9qO~t&ilf!?yR(HqClw}FwV{p(4XPq%`u*}y5=6+%Hq9WOKXjH3FW>$RJIF) zkMv)II;{m*Xe3>oKZ41kIb#5xep;gv2{P;`x-wjVe|F-QF)_^ipsz3vk#gT z5pI9^)~X&c)bmjBV_yvC;Oe{K$&NH)tUb@7Fgg@E37$=Gx% zbV!>jNjdm0jW8@G_Ua|P|Bh?Uh7$9S9<+@PMrW@)nFDaKx(Lu=9*g@I{XWDSc+nt@ z8$`S6y&*(j9}{|{&S+-711ElWKoLjJz;GC|3&iLxAUXAn?|gdknXS+vS|I)CR>kyW zil31Jms`MlT-ED#SW;wNSf8f*oX9eJ_IWvUR$k+nGI-v5gzL< zIqSaK=3YL&v8FAT!XBLU_Pl4q4&$7JAp)T0&bW@dqhY0CA>CoVIwIwY;YUUHuU4fK zdERbh%x=9mOr(pZ`|tGu*fCH7l4 zBk-s`xj8yKlj`NHl5*jZc%65Dy!=C%G0Pkr94z0GHh|f+Jrr-VD!#C=Fjg40UkZf1 zw&%+cZpS6pwA=41s#&z?uLzIxE&U(geRWCb*R}l&f$WFWb_p6^HvK6(pN|Dh4LMC%_;;X_f71A9@`9Gn?#{KC~1Qy0uXs7@@C^9%q1Uym&Bq~IBwX@`m*Wycu-^$#C;ZN z_odE7F~VLm*SnZE&)e?gYd^ukQ+ewhwKxc(1GbgijQNJg@rk3!(F-*zOQmnt;^n@R zJVka+x$Lm5xt-1A&N#?>nytlv(;n{@(lc6SgaXGA@xs`eVy0(db#%(!T4=W-CMI;L z^L;_a@a2@y*5?-Mt2dh9wNg*mOq7)BXPLyLq*|lFD4H>ml@t)@KOor=SYuyT1(O}F zkf2TrVwcq~)}(*?8Ng|cXVto5FfQ;AnUYC!ot1vw6jD6*CJ#3nMbeBxo+4aj?{QF~ z9Mf(|-qrnBF=N!Q>y~*A%Im56%ycPXiG%udfOZhPwo}JnoQ8^zKTulzQxCG8#d+dg zxLg&^d>T4d+l=(uM3fi_^}nScVdI4yuiqbKiPcK{7*FTpu%#{=mjK$!&4aPLf&dy- zpQ2IBBwnbrIOlk|)wF&wvqgXx^2e-lP8!?pgi-Qj2G@m7%3$Wz>U?x?BhgD&ksG`A zKjyUpkv=!Yc%q$*!4?q6?Vk*k*U1mA?oA~(meLd?a{G4KA<_ZqEV68$W&Y?h3~Hz$ zO;9`)viF;X=g^tmRsW06%B~yu><0#>Mh?cK%`A*vbspm(GT^Fuyzf@#sDllTG2^PQ zK++`cRP7!&{Q5wwGRgEfq+gP_x5}#AEU%oU-JetH6!?~?==pFbY+a|(Nx#9>e>DG! zpLDeOFOZ#&Vokn~<3`>Vfbd5l&HmnNhMUCu2q~@0eKU-fLagp{iiG%Q8SOB(L{Pc{?cjUYWw1C1 z1kjN?r>$oV3G#0vo#xZ|_?Y$sF|Am{e>+h3F+XU$=$D&@k@>-3`)Xo>1_ez8g&fTQ$&+e0NJ z7=AY2%v0<{wz$t3I|ws>HW2me?Jdzl1ve@km z6yVT1-dW#vYK>uG1_Y_XFK|O9;{@o-@qR@`9>4CL+-(MTP8ngLJ7#%BMlR)st-_%a z{{f=rlkJ@D-I}kkg@pxB@)k)8(*Ad)rS(^2((LUD;{*5c56reH7=_9cf-m*997H@e z4H{QIsy70CW%Cb{$Q+@*!Fp!VibkI^hIb#yz8(hrE>nJJ=us4}s)bgf-hMgv%~h4N{1 zbaea56Q2wW$bBEDvhHsxeQi1-L%JtSU;Lf3-e?Di{t%=f`&?z98J4-L0&2X?5pSQ} z^3q%(^Ytm@QuU01Y|*?zRgB3JRHrdcq}hb7ka`+%zxAjfd^#?&&vD*{)C&!SJOsKO zOYDelSr~J=MnhmyYQI_^u5dr<=+_0atg-15)mEF<8&06SQrFb!2PhsKHsA8Kw#d*d z&%hDpj;^>@@K^7BdP(-Ya1{&pD`U(@3h*BQKPw4^MyM8f9ipGJ&`|acHcCGb73zx&_e6>+C z5b`BmogA0H55E5ob-UH`pyuqZTwA5^l~y!{@a z60uCo2x!1TOO$P0u8ktE@MV2lTlydgN4vKVFh7@aO%(Zde$n75W8L{v{g{eNrjJ20@qkA+LC>bURnI(@Mn<0Io=(ueJ0~-foqJ>}QwV#QrNkg-4*&D64{-a*87n1Ug}+0fD(#UUlzm-(2uBm+vtDi-{Ax6 zXaLZh;Vb}Dv>=|YTh0yo`=$>mEr1${DyW$dAF4j}4P!bWS6PMTSsY6C*}O#|cy-u5 z9m`C_*1*_xZ#*OROt-S}E0rgf`Fq>W7nh}1jgfrebL_GES0tdLpTuFq1_q?CB}GLC z|Kci=vC$&K$%Oa|#91z-!?0?9&6+|od*wH9oJipaeSLWffA;|DuO1{>Qd81{IUh7W z!tmFB&xW>)0;?W*9J&1#OBMDpRJ3Di-_RnyMX#6t??L7LC@)A-R9*eEN0WxNbQS_- zR8{>aQBlzzY8+Tp#$}f!n^^01++~q~dS6&@UHCe$eXx47;jWL;4B1bLP+aD}7%2v- ztSyjq1?g!dnW;sk6ewkM1CEa8NxhCk0*n8&;b=13^Cn*B52n`+YUgV*2s$64Hf3=@ z=})SmAr@_lm|yPlh&zyfPLcAKMBjebkug5I8uRe*Bx%)}hDn{0HysqF+4EXE%5++h zgPpj_ZGF?ur4D3@MY%RB=I5wovdi(QxPn4X3h`np4mc-6$jT@5f-m=fyro)IkaKXT zayp@PuXhL9SiymW;i51pLH^tZm3ep!?3N;uiPT-$BIqJ%8?iSs$bM9^#ogR)ng@h! z?;~#xX3Fq1b=?chw@E^TpEuB|9l>+Jh?rvq#0B^V`C|;j(8hraAaPVVbf2g&zA2$p z>Drn2yt2H(cydd-m`!BLD=0+$_u*Jd=>ZRD23&+}6sRQ)R)#L;Jt9-F0X~0-!8%6d znkjNDk=SBq1h}~L=VGcUmy_Gm-#@kh*-&dXfs3*nC=J#Sgqb3ei2y;h(Xx)=sr@;) z<_uQJdQv)V(!|+gOklOx^x7BwqR3^LDy@dzRT=5zSDKEcO8WS8xS4y>p$Z(c0turv z6F(6?1t8pKcivRW_e3ny`IPvuLKfTkeeUq5ZH8jrGKIsy8=Z0=$;-iaZ*lo14)L zfu#SmuO2s+fQTvax*0f#eeO4&pZA2#7V9il_yvJoG>qDHKmKD0|C9H)oGj+&Z8Mh>6--hSV=p}uu; zU+!3qosBb4giORkiYB#U>ho*~wx~h5SV;bc5;5J+0LGDf81SKmKZ5y?Z;o~7iDdK; zOuR$iZ?+{%;H%I7!&HF49`#@71$guzl_*yoMy;A4B$l=qKu1#ed%WIiuHnfW4-e0A zfWYkha)c!`+z0Xtl;*(-{t*_K*h8BV9lCbLvj;*B?ADEB^2y<;gM+Oh4HfUk(9RZI zN2^k|5?#$i%L?ytA zN@76AgVnfPFtNAQa#XQ3!qT~|_x6ZK5?%E9b_Qr#*Jug{8^+S{K*v9&~9lA%gFb4rm^_3JBX))iTRX_(#J-A~?-t=DXq0LXao&dP-y zIq)5+S4^61M_B1_Y0%(*Ai}+ukgoTQdb)yH(qR!m_Jv(d2n(-DYW_TorOonUNBej# zq7r@zbUF=~2q0kj05%&uacMmA<$b;10${y5=W7SHT`@NB(f1k|81hMMwIPGT5Ael7 z(npk2Dx95vVFJ4zhrz~@137g2sROHi3VAtHuCIHQOR1H4Dne(g?Mn@7m3p0~(P&Ue zy7R2oXr^EqgB}hs7Q0XoY%#1|`wcG7s+&=g$8Hjf-gpE72j-xeo1c+C_&<1$)pnT| zp!M3;_yL1iQA&r0Dzt6_W8HYV3;zE3N0Y3aK=b>oLlZrIl>!|o4u%E?SztC=-2tLEr!B1w*qT%#)g57PShxp*FD zA%oA+G<3yLTs+W5`1mLj-mde7Tk+!s^cr>?<{zVQ6cUDiuMj3Ha^6UOwcF(otyYJZ z`!kx6za!Y{-z-Acfs&5;Sf$TRndwoaPF7BJb+!1bqJ{>p@WYVeZ%I{gN`DewAmZUL zP)DcKh|I;9q#&1YeEZh=ru0dSR`nl%F!2(jLi|AqV5a6Pymnj*gwWn@K)JMLz;t%^ zWb*{nJn|%-BTS9SJugL6nL5Pik4#e0U)$W+vb-*3_Xy#U1DhT92HsdFv9A%RcX%C* z&jH>3IbcmLEm!L_ScpIBlOBiZXw_+ppQ8sI7~WICssV8*(f}VCD2gqa)2Z4|?d*hl zaT@Jk6YW$4BN-b@9R_T0z~u@XQuGZxcqQl=qRm>)i7f~lr3$NZ+*9ayzWj`j%$fAd ziIbJ0qp96{>n;@FE2vg?)ZxbcO!2G*mY=KKmix$Ou}UeEGzE8lsT#^FarD89WW&;s z;f2@&;&x)xcg#-4vVGt>?BF=zI`jxE$;68XuVXnHl)kyMR4VkIU_9OVoV)i{9Y44b zf-iuek`iE}&&UB%gh2z@fqdiyTCnYe5F1RK>$v{|m?K!yLEDfI{?h)wpsc=qDwwgi z8snijnxiPL2Tn7o&s@M0fu&kezt5`QLuTTU7 zI3>`bx6p7T6>eZ-vM=Vm)6#n_ty|+bK!}VG9sX-@xPiw%QiQJx`yO)&QE=Ypi=-s% z=OpHny4MGwQce5PdIwV(^23_t9OKrWp~&J3LaRHCn7ezkO=q5}VPCR;7drtXUM8B zRd0R&xsv+#>ps_Jz5MPy^E}sYE$uMu{~0v+9tfnSmZ9@be6;#4isPV)?sRxK8FYmz z%b8MzgEZ%(S*@$xWcWc>*&NSKKurC}qG6Z)-VbavK&2bdSXelaC{n4ICG_4Bg199u z{HT1~`2omgs`U2bxcY9#28gLs5?gOqTi#U4b?ZOCC_0H%QtMY59 zq(xai9z891EV|ZdyrjZDUPaG?Xu{8vEv+9Vbp8mMO1f=KPK}y!He0}{tUK#0W3B+`j0l+0X zWrc4)RJQ#aVuXLIg!zkRa~=dUO)=c4q+S_eohR@e>gbzu=l1wo=s z()Ot9=(RIvo|C;-9x#jF)W-J3Lp1F-j-|b;i_LJB#bE`3lRDHlUzWCWG3&n{T!78} z<_h9*|0bQ^bK!Sw*vI5SFMiO{T3jm!V4RR<=Z;GU7gD)i#ufz<3*MF#WgebC0VHpW z&D-o(J9&IGK=|?BPY#4e2tyM=Xht5dLGogjGWH#iXQXcmtpcKE&He+rjX>>pE?Bs< z*T{C)3G4RWjgUAs@V^B+R7V^w^jK`8#^JF2KQvusP?lTQrdvQ7B&9(*q#L9~x=TR1 z1u5z7?(UNA?rxBlMp{xp>f6ux<~=ja9Q}cJ?0fCCuG+&(BTMK#;NcptKS66!BZ-h( z%o8X&D-8X)+Og+hMI+cp4hxcTf!jP!$L?mP6;;Tu_*BTYEYZFU&$=Bld?v@zA)%+I z7yRo5$T+OS5rMq@>voCOxLUW+!!-w_=}KT2xPHn;d_-=>{f43my+a%EdxSQtKJ(b| zYm~Rv$=8qkr<^|kI8V%l?nL#u}h^W8Z(@D;xr?xt{!^eI<}vgXvI#615{zXTJ^%*Ut&V~;Ry zN=~8(Q#PvIHCu}k6;WjHqqKAj;1qwRAEqWJfjHtvP2xHrLjie#h#dV9@Jhajq=s{Y z3TpsDhFpYv8fR$yN1;@!s*WVk+g?sAZuGZ^n|=A>D*Mtu$OjZt`;(btpfQHvH7VRS zMDa8V#=t}cX$Qdi&BkR^x4+v8rmd*T&GmJf5?tJWF#ufJmZ&Ebq)D-!>8j*67W7dR zOA|L!jRJZ=fr!bkY&1g?JuRe{f}gfnkFVAR+KbBO{w#cHzFXEiKBB2Gpsg= zp@pY&Jj(s*Lo&axP*c$vShe0Czg5_lv!bhMa<sjuTvq{jmm4B^4FB6?K!_ z00?SG+yE>SN#~scXqKmhU)mcEK07^9OF?B8zcS;~a$XU!{6gHXQH){yTob6v!H_&M zaLB!d!OB@~6`)%hC)PldUsiUAOvM=Cg6MAer@_-WUK<=x}AV~2gkTiY$i{*$CMQLI?7 zk*NUaYuTJh26B~7klwZz#*upllO>M@&K*j?lpP;yl{boE3vB70OP!uKt-I*x#?|~C z%nc?Tt(y`G&y&E#?PL9RkQ+=#Prn7aW-E53cZ4tp6$9Id=)~q%+sn-kpJ&e+g|ed| z?Ws&Wjl(E?alho#^L4SXDPRvtp0ha>cEA$4bz@=NNlj-bYOc7l9+pkGK?vk)I)yG0C~c3_8P@h6cU{DaI`5k2J&_ zuY|r~vC@vN1u~(v|6Q@laQ)@hIC8MEqJ7r+U<>*Acl&1wU~)qTGx_xN z^c0MY;T09{05!3AW;$0V^2 z#aWvIoZ+|WdIr#|p%=1NVu_&&wUS@|VvccQ$Xx?bDSsetgW_8;=UAB1oH38u6K|T%8 z>b9ycCZ?y4*)**WQYY&gqvjpcm6VNwKF6BL5)NyB6_17-v@oJalB@)1)PWpaOP}<& zP*#Zl$$r1oV`omrF76WrD^$2Xkktug>%4^Ne$}qaCNW0=URF-d4fq1w&RTveziqzy zZ!A9p1OIzl-Sp!F0M~%BWwze>6(WbpeESH!Kb1WND3D4?3@B63IcP^BjL0ZVcmLrK z^aW1JY7TOuBEkq~E-4xxQ<=QR#-v2cH+62$&fLv;PDt<9>|wz)p81yy_)>L~z)S)5 z;89R|*N)_qOEJ4MMWKLUlI-c=gTVE)xb;S7=EGTA^xE2*;saS^WaOIrapliEhRvv= zC|76xxe!gfW+&2j#MVD&2?$t|k(_ym(Okk4FelP*GhQ|8lIk+!r~Rm_Q7>E@w$v$H z_S)=Et==^1M&oG(zqJM6Uwk)Rq)y{(#Nfw=H}v1lqCuU-91XYanzWi4E?5w;GRL5t zTwYxrf+7P^nH@~$W?DW&^Zd?mN?|pEDOayF9s@kpYGWh`zl#z8H$rj#x_1Cw3}luE z@&W>0N2*{Fmy`*PvN{KF%S-ZF-I*eia{#L`t*NT9O4V#U(Dy5oRZ??k(Zw0%Dj4It zaW6xNLqu=mXC*jPcW80na%lnTc~6z}yceFmxR`~ zAdxCE-1xA171{vvtD3)d0{=$7ySGt+Z$&ZLKPU(xiK}23c03b7xPzfqM?+(%VNsuv zvxqdR{6}lp5wI1`Fo}3wg@uU(8v}G^CJ8r?d$Fvd;<_epcIpy^jFIuNq7pslNbe*0 zS$8-~4iLQ$Ulvh}U?K9V{Y3tl!xQ1m4HPQ&ZF<9T@-{Y1Z{~3j{*rjnJpS3JUKl^V zdAyq9uvy^*P%sTq7veS$_=Zi)wnoqhcpD?-v{~r8H>u-Q-Ff0y+5RxH%O4z-C0p=4 zi&rVuy;LTlio@#7+OX(Qb&JYdV>HVfl@s3N|3}@tNL*&W)m9lwV%+{lDHwnIv zZP8u|mlfU+smD8bc=$Y6cT7u5OYk>I4brgRLsPqOj9`vrGYgN}8(Wg5ZaJM90k2}o zlqu3J4`u~Epop{U3jaFiv*j%FrGgfim$ zcDson+Mb|}+Q%XiS^VNX(+qReI+b*~Jz2rdE6AI00Ls9F|V5aWuctL{* zs8%S)HIyNoB8S6s;xqo*m?=dviHY$ooZ_z?^{;h?yUCC+kpdjo#;_;{R-ll_g>BnO zF$fU&87%K;Vtxs&MD!tZJfkI&#|LOXiN?zlpa&l`PyE_O;25KqXU3WtM- z{v<-pT+4hwB%%TDjbOj1C#i?K6K3IXs|TC&qd5#EB!^sDDb8es5LrAUquA;8;ls_f z^X)b3ItR&@vs<^L)Y4V8^(I@j%s+x#S)Ut?xl?BjU(w;9xLZzGGpK~8qn6mSir9&j zD@c?t7_+A@>mPIS}k5-6)$?6+XFw6q8!2N}4+RFsvaWo3av8IRNIX9Vb!W-E2xx4QmOT>POobA03Q zlA%?pe%5}aczM+!_P7E69c|x(2ot(LNWn<89Bv=omQ*79^BA77_#k0=oVq%yV+(Pi zvdqUy&DXlVq@#|?4Gi_#OqLB{Yiqhc6C`|yy>F3-ml3|8!&HBnB89La5M7-u+EfN_ zUvD6)7GOmn-oI+r<}?BzRKdZ+`?uhiAWIEl;{P32eYrlE(e-}1ak$SAyy(XU4d+0e z#hY{0>J3VH5g5^(7$)fOWxqb75BW3G+NP9R%nSk0y7^2Wj@e&^P1u=naB5a@e6^Zo zVKJVtu^7VB$J5_OyIt)MtP|}2{(S|q#x9<2HxQW~tunfotgY8u69Gun*Q9E^W(ZX2 zor#^7zN@}DUyL1HUH1N^$LW#x^VlpJHm1~Q7f9o`pt&Cf;N|r6kn6RqLR)jEFUS4K z$v{fIn@#WYxBGSv3-;Sj-~r=l?0maf(BJ?{%xW4Hu+$&iu4g{%oDu4Pn+N+!gUr+=UR>PWAs zs3;LMK*S(5dAz$wnb6N&tb!f0ddTdBqr&8rr&}`PHe^qa857C>G^b!AN@2CM!>+62 zr(XV*U*8EejMq5S&&jhN*8Ya|)>cswy=l!c+^*uAggh?*(@g;a-VQi9(d?I5IhKnd z;b*o2FU!RrB;oihf6I!k8?>$7S-5TYBLn7J8c?d5UEjU>?GC{LB?OxbC|Fq&sJ>l` zdmix6Nb@Mc6@2nE94>7nky3IhiT>Q9tY(OjC3%Nv?sEOIcA3j#k9GVT^1k9)<$ucO z5bQUEb8J4|o&&%u=ryI(om6DNt2UR@JTQy{r2$N&lsI70$_0PgHeFSDKZW-NV|X-- znXn7}JD~j0vY!@n4SKFn)3K!3*sYGY4?u&O0~R2NnW$fJx^Wk*)Na_GEtEqe6UunM z;mNUC8~auA)2G(}?Arz)f7Zks-J)zh-i>~-YICG0pNEr(Wt%2J!q0BJcy)x4QvS-N z1;IawrE>9B%?5kYu;Lmlo%u-kB7*?g`x8gffh1T8G5QHHt>KoPB7&H=b_FXa7edAo z3VdTN{+L|^KGjDco>+7Ho%ua_0*pz(vT6nd;gFd~O=$7Z+4JGFsUCb9ieAceI1sC+ z?Ru-){X5V?0!77OG}#m=bdPD}Y47bOqe%EucpTnxr$>U}KF(ohFmO%gG#rpH5X#md z_=aLrJ!jHI1H|jx(OMS&%HIn46trwDRT`78UQSr_o?F^R+Bg2qSJMM$zH4_9^y2u8 zN6*I8S2L$66!4_kl)S-uOPyZ);K5u@5D^m1<&5+LwtN@}&)A3}*S_sUo~*URL&GB6 z34RAER|p;qAeG#?!#m()+P-ZDtW=Hjp)y*~O7w5=U!Rpm40-Vh(_b5E1|+ zbvRsX4=@Z-)6iT3An;-YBHB%yw{-0OVd&Z%{JWs^j5643|Lrbs|U8Z7b8{z2sRHiP{yDc{T`joZi)iL0QsOU5et9M zfQ+^P6`(6MBE2>jHk09)7@nZ6muC<6o1+1+5Tq3q z&A_8<2kvJ&9JM|JIXStOohbekzOM{;;emkX0_hAcz-3uRIVNp1-sSxuosvwQb7+4J_TbDY|2ogz=bRLYlrp z^$L-p+Cy~_HKfSXn6MLSS0*(Qy-~nxfF%QYuVbVddi@{COR8_c3wV<#I{=CmsA^VAUEbb_pK(#(!GqcbQxY{b zb)bRwQz8hU0XH|AGy#H7MoI=5r{k-&ta!}dHT?~BoPJS zc+84tOpB#awI%U&5IY(IEHZ+iOIs$k)_nyRO}}jyM_L~?nRuP7D2Q4d8jhuejA5{? zzxiFy3hXvIEA%^vD%Hop#t#frog4j5xOE5of7;_`XO&szWNdQP%e8i_%c(YaCi{&y5Z>u~bQP=V&B=0nd%FO5H3Oic+4ERN%{udC3cNgCt$lwu zO-T0W;D7M-?H;l3=(=q7ytNGccH()m5y62@;+OQ zSXx?Iq-s$`Rki<7j(xmFs7lrb=A$Q!O{)j;5fHv-0Gz;xU5!kS=gTB9M6U(Xe9RZh zaNlrSZvtTI+~Wk$6Oi=jE z@n=xYu1{B!D|MRGdH*IGe9zUW(toGlzI2zuBh#ro~Zn zuLjWn^xH4R4$l~K(8ME0Y6pV54f!RJ*Z!T)pJP|uR*^L}CPqZr7zXMKvsq0u6`K%? z`8k>4zu*{6`suN;F*mS;4}l>POx`;Ht^s59Ij{|>9=9_wFhIc=|D)x z>Nv;r4uu5M$2U}^iD;$86uI7A zujQ`>D|}EG>a7-|Afxu2!uxwcuiLYA$nH!nmy|POo+9Yc=wYPhB_3G$0+xNr%+Kts ztjRE3Mo3#5J7NON=@EKuW%E`qWcIkqpOQnw!1I!>o{1Ct{s~z<96nPqT&jGlu|RqL z=AF2?s~WF(d?ghPO@cl;@i_Da}@6KjS4N!rnGF=9%jT zXEc{1Q5ygItZ2VkK+Ic?f|HPxn5#-BEzLSD!L(zkz&h#@dD*wj1A-5GOW|3QCJA(3Qnc0YuVLdPSTqoZT!H*3gSJe)bKU&~U}wj-_G zIKDhgDXF&ng=vbun)VOH_TPbNfsiNjB?|2r>Kub)*C!}j=eT20`HXH6YpycO* z9^3g~x`*+03KYh&i6?ADDk>^NRswSXDyjzk==~||xGUXM*=4o(!}(}FbV}%9{PtXT z(`a+U2Q3Am0y+&D1~bHJmv`YY;W($goj6fDu*Wc`?w2T;&Eo@%Hog2>k}(yyq}^RA zRaxrfTINf2b-`+f^ijh}gRSHD-M0Sv;#;Xzc(5KmzkSc{R5KaC>IIGJ@SY>Y^$N;| zLAiuYu1}94IW2AR3Jy-Jh_*HnpmIa`;cmd*-Rb5_-2FvFW78{nvunr{q4gKnPjS%f z_j4sB(8MNZNB5b<&r%*ZucfL+gxxU_RrU77kMNpM5rIyHhK<7a(GRAR@AGc6!kdlv zCu^U+-JmaZAnc+L2cOPqA%A@&3?KV(gVmMwF8d%Hw8s7r15 z^_yO&-w;~BW~ILLhxXE^92RA0{3)D@7uX--vRBgtn(zX9vuJN6pn4x!FvT+L36@g6 z6jrpOMM_DEiNRACxB4U_P0a*A7EM`Lg+a_T>|NQX~_b46b@i-fsi8lidAz)=@$TI5JTK8S z<)>>{1UjHrZp+RhM47P%>)XyNKG!q(jZQDH>!E`RaU;)swoC5~F|Q4NzHP98zoS4(x}-y+QOr6CS1w(gF_R}1Y`y`uM`P!#z8 zV2lRX(xdF^GH{ZUaz2&I$jcX`>JRA21hPFUsjj=1%DK^1hRpApD61$-vmT60j%;<& zj`3J7^wWyt>jt%V$__`_k`kEGpT3F#fmw&UDoJFiS>Js{_}{Tr~|ur?WGK-bc$8M|#mn#}a#+PJeX^e z`ru_6j;`u|g>JV$#A)Z><4#8ILwF?l*7uv5=p^kz{heVg6j@8-ukLJJ4uh%yQK|gc zy|Lsv&lVijc>p{C*5i*NFF-G%V`w5!;RXfqXbRiK- za3{0TuZ^#hr`@PO9MX1!Ri`M`UfkhF=miG8p1>9Sg96=Ah*t$SHOHkfcVAo_>%mPy zLBaHj<=(FXF(EqH@R8;m@UB=2bO9~_1H>mFwgS>axX{FFOj-_q?O$e8QAZ*Zh7JB6 z`?relm8&4)k!5}LDdT2%a*wqEnl#N2t+~GR0R5VFuw+YDFb}=$J)5Ar9Pmy2XzxfNQ`zofyv|q z05brRKul;NqxbvGzloZxb>dhj3$J|f*Mhk&3j1!vbXF_49^LR=HEi>QWKmXi%lHQ! zJ*v6IuP1ul(O@PtCgnC6pOh(bnx$T8vQSV~ehWspPmKbKT4DDTgLq0@E)$Qd#WXQl zSyJxqM6!W?fND*zQ~Ly)8J2fE{SsvO)759$0Un7$zhn7_z4V&Mvp4Bm`X3yCiKbrKsj{ zgRvOvOD;A^?8S&DiguDt_Dw>3=y8YC06Z9y7)L0<{aJL+i%P3;d ztKd2juZ2$e3Kl9=eC&KM^y>7c2puWn^d1-sHsilDD;Q%c6PQHS`GNrltOkO=AAWKj z|3Y~5*}eOL%z$62;G(DU72^hOQ*yJ~ihBd&j<^|lB-mb%HF5NO289?Np*gCh&s69r zeAkH{99Mujr)eo)IFw3kJ9j9ppfHe>6t-^k+v1DRlv!b{MKm)q+8oY>p(R_SavX4C zQZq5VD%530e#w{WWD2L;vg7JYe(^ErO#Iu1;pbrhFV3}SZ;j~52^)4rHFPe>k$bDK zSz(NAv5yr($Tb`v`s0)*k=t>DGZj7Ar*il^{f993!{0SuUj^VCLGi~`KBasxXuLl> z-kTnx4tNQvk13}a_Wk19CMYjU>HAxERZv=S8(EbJR_o|rX14Br{*3f%NpJhuP#{av z^yh?j=Gn@=FLf43AK=nvk_koTA$9>AXBE%YorfY{D)(2q?+kPW!zXL;F=Gm)=yCDX z9^RH=I9pEpCtAOF%yw62O}1%#$oaANpK&M2lFcsPucPje!l&vw!g)j{kFm91zsN*w z71>Y^+0Ql3e)$zl`?k=}TxSN7Kmas63;?O6!fZxX5ZS7(lh%0qMozN&_Pp+#sodp1^wv zRKzbA$;{fmIM5uJBOj{KN3uHkpsr+ntyZxIVr`(&oNOpd23?V~5gwIlN1@6wF^8}=4xor#Gqt@0uU&Ep@OV)AN99b@&n zV=gXl(?z&hZAqO!&zQ-E`<+zHDgK5I(>!>F)tgQA5Fhi2vbkRtolMj|#(m|glzRUK zkx@@u&sVlEFQ+=@@eu|^PWGN|svBcZ#wZf~D2LslIM=6BCMG3C+R>4HWJHF*nJ+9X zeA(qvfF*Om{;fW7Cp!NlE57=8EDdU9tMuRJYsN=1@4u|$_iuLHc!KQO=cX8UJhMNz z3x_3C?MLHI@MT7kc|XRA`Xk&w{bSN;WCbVy2m`hn9kWW1{GuyS{j-odBkIyzJtgno z+vT-jihDukaDZVtEb6(kfoId|TGje((X7q^*n-`Yyz5&!ZwrL?pzrYGK9eMm{El8Q zS46?MiX|SYc?`DfY~q8tW1d9H(Zm$V$j=`g=O?Lfw(){zNKDJy#zH|w1qp>_I=TKW z1Bbfx!Q6Q5`Lp9T$dbD0=9HpUv}|m#1ymOC6qF!W)s)uJ?LEJ*z!ze*zbg&0wOg>d z!mppt1E`jsj8<>Y2N>hB$s6be?hxur2ie}e_IZ65uCoGwV;~vVvFm6Uw8h24gTysL zZWS=dA?u_{ZqvF{9)HmdyX3@qeCwCq&6{sy^=9gNKeUdsK;M&qabyrg;@my`@t&H_ z75_xX%%Ts`;Uv(jw5P>n>@OH$DgRUwoMku;mHs6Ce9m8>97iu*T4)EvaY*DvGx`?$ z*{4j-whP1^`X9C2cmo3^f&T52rrGWT7Kxl37QN%oU$UhGiYyJWpO6c$Gt9r|d<<0EFpROs80*T{{UsqeJ2}Gw5&3RwYE8jR@+Q~Mv2K?BJ`W9*QdEJqa zkbz(-W!<_RlVm8HqZJ~`K(oeNypf-+E~ld@Y@eHNe(JOUQHQ^*w@r;EXxU%^@bmRO z#k~wW%a>1LmznkAVQ8}Amo|4^g)!RE{VTA$~*xP&16|;dkUi-I8sszoIxyCC}H)s|k#*#aXwZM`UzKTz>d{ z%yQXwZpCm1gEPd+f4r6m9wi7g8wGDuv(7BC>t8dQKOpSb0df_DK{g3sJqr-CmD%|R zOepVxIQh!j9r0UU(44X_Mhx*TOTa%OcxZ`KD3oy*bleo46uWID-%vf?y^|3xWy`PA zn1(USsd38P0WKq)Rpc?AUtmzR)sS}Ol_`NW`6U0S$0Auo5~m@EaGpXgRW zIMMKkIt=4whrMJl;Rfn_|UGh|&QFX#4@(QR{JQ3p^ihzaxTY zeE{V60HMhTkR=4i0@+)E>du6b^|tFP91{{0aq%thv_EE%`yhQ5!G?uRJ6cZuV(gt2 zTfsMRe*E!!{xPSiyp8Qn+5TZcVNsqE16w*1fdY*@4W)WHZuvscgjt_uLu+7{F7pTG zw>yP3$ABArA|P=3emUrtP(n-H}r}>CY0i{-o5r!FPAJ;&5IdZw+ol2 z>HANCU%hM%t|u%!oL9wUcTwz3SJLp3rDDz!g{^l39aBKlAO91Mvm&6Zi~|8L3-r+G zKHl;fJh4DN=+6C0RC^lNAtbT;W-1NqmdvqP9{6Cafx4WAN0!;e}>SeEl}DR z-(T*5d4a~qb(Eqo6|;GqfVam8R&sA84kXo2w>W)?BIZ?|;e<|6Txf+d3U2m*aX@^- zK0Z0Bfb^n`QpBPk)FIrGuF8N5%Gvf&c@_Ezzx;qw65>9)g=DSBp7op=!spis`#zPH z2b~`*kz#5~6(giR?(u|F)fR2r;Fl!+qvftTeYiCmo0SzMPX@HLr)}$DQFpMK4OAQM zICWeO;{?1)Xg$xwa<{5&Fl>bsE1sAPdIG-mgCZhb83O4VkbiZ?s@+NjL%{`XmfWWM z;BzzkCH`vo@XP&}37B|>|Lve8CR@M;zj|k?l*RJe55U5EHyZraIz74!7NUjAvk@DX zaRJ}qO&tHQIp%_-LqLnp)|Cp+qL_+8)liPZ!yOU+wezX^;>PuKYUjNJY&=edSyW1zes0e$#rCs<@~*6gX6dqJLnc00$#UHh32RUiSd%Ic^k@rGZsrI^yB6 zj*DDVrMgF#)pK!j3gsM&3R)gEa=j^)NL$DMBD4R_N$WH~SQ<{_6(CshrQE2`+lWe~ zsv)O#DJg6dJ*vmRzqp}|hOhU{0$3Pgd!0YRr0P*QX35rNR@$=Skn8=aN%vaJ0WV=s z&Wy?_RRYbWyeYCneJViZA8EP_*55sNW?GjhlV3ISqMHvW-uHX>Vo@LJN!uN~oua zN!?!K$UlMk*l4Z^xcJn;BI2cZBx zIA#e6H;XTs@P%cXpa;kpjX=Jt(D=Gsl8gYGDnMsb0v=0eOR{YQF*H)RzmLdMkFUac zqO0x;5Ic?mojXzL#$t#Vf5}(T50dMEz0GRVfYCsD1+IYHK7)5x`#_CQ91>rA1(=-= zKQLq?H|7yvg+uw#_T-9}YkCDq?79s6M&j@D^t{ed8MR0*$o-m^hE^GemKi6-M@^_r zJz@#ZS4dnbCRL{1`n6DVAgNfoN-p5YAwgXB4-z)6fZXs3syzo`dHwt0(%x*_HUN-shQ{GHi{S6E*EuD3w1R<(2*h=WC>j)#ld(;M+dhw9Qi zdN9Hw-cOrC76&Cj^Ud=$FHg(jdO}9V_-G=d#X^}{f&#@WB~+!w3Fu!{2Erd1>LVhUi&Wj)I+sg)}{)>Ew%tJ6hXeN4A~Cd+E=DMO_owN(N@27TO+1_HnJ#$Fc>G?fhq|E));BNT0}Nm5 z0v5+B{Rf(B6FhVPCU|ez8*5SNI@F;(m`G$%XFe=1TMO5tj8&`_vjt1X?dR``#25^W=V^+>)s^6( z<#d~R$NKL68Zqo4)QJpwHmA<<(LzVY-*QX|tHem0P)jzm3>z7BXGPpLD-tX}h3V+? z6X6Q;N&mq(=PulNEh77%=^t<8O>V^7)z;89Wq7$s{oPM;Vx1bk zc#9oq)<&>yIfw~cA{lX0R8Hh`21~Ox?#S@?&FFF;>2MFA+<7%kNK+lU|ilCuF z9_<_(H4pCek^SY>J=V`mCNt2SdA00iFg1i+;GRc+&Fvdf z8-9AII>W7+rU`mv)TuY$iiUDQg$bF_+BhYdgAw{^;(A`yp*8+1eqf*$p;=y^{2TES zlHAMb0;k7cYpG~bl5Ci|cU9ll@DugftpW+YbNUo*wWH-i&%dVBrbTqlnAzVPr2eqv zQYw#@CSus^j3VUGQ;zfx$RjXY<|lK5#HcM`)Kxq;@KXh>qfY1N89MuS?e)XRefV-r z{rEO_ZLZMw=V7;4uwF@`4Y-{@JC~NUp+ZDRe?U{~X^>3w+S+WJ?@l5f>hc^;iH4dQ z872gOYk`9LJit~?5f2HP0h6EtFXfgBN7wQF*TdOB5F1TY$UbSH)gs0Y@|K+03qX1? zb8o=z?yfne52k#B@*-!LPqbiy9S$rFCIMataxq4;D+fC}L}K%Z9L$p``lj3Rn%!pL zmGhR~fyIBV_>%Qm%yRW}jwX^iVu1y0b|h|^jd3@e}?%7wi6M=S__X5IKQ4242TB;}M(=)CZvdy2~!>-A&1wbWMlf6?sIs1XJ zvLNziz=$EU{^-5(XwZ9Tx?XqGettqisuCO=-JclbOSwJ9H^uhW#UAgOm?A+BnYUnh z{L*k7m&5r!hznOzQ~gmN-K=ie>V1XDT(z0$%$U$Jy_!n#AIm(A8D=eUCx0TNZ)G2N zoRHMLRC(7`=z!W48qhvA1dA*hgN@>v_`Gu;1J9c@+d1=;!7_4dB+goH5DXc3hs{?| zbE-UXTdNQkM0)7nT6}zvnp>>X8ufQX`+9UVc-q9Znz1c{x(k=}w+J^iUMwp!vk_bG zi~jZK=?hRRIe_r0_Z1G)1l?vZA0h;YEWIQYgrN!x)l4L0Qjp1i$z#;aZETan{n^oY zPrYIN`6AS_cFcxzmfj+@q{yj^>Yxq$i&;NtW%TMsK9=9aN7I>CDhcxE}hjn6cXx?9{IiihuH;1w0>qJ%*bQEzHx}^Om11?H*EXYCiZ> z(40qJb3Lh&3k!FJr64m-g}$%(OUF78G|G_N6D+=1>lU^v6@UL#oMVr?VwSi-FO5+Lw5g zp7$74s>2X-u0k5;>pyX{&LeRoLUEuCO2)!%>!Jk$s$+hx*F+-Ylb1gC!Jn;OkCkwj z8fS`B7!T+UmuGCP18E&V-?Sp+a7%Fl8=%wr4=hMYc^r2`Kq|eF0TPXw)z{vYI!S9D zGJb6l4*xL4Qa%a^<5&2K-9c4rZSEaeVCTK3dB(Cw-3^Gr*R8^1(9?8!T=a#C3d*$V zdF_pc`8nXcJ1t(c5*g`zYY`|iyzicx60U{<@eMp<0qqv*P&$KyV@4S$hWnTJ#rG{g z|LS|RYkN4P9N!d|-jJO@8Yw10W$_=`n=xv(d-k2NCzqSyLrn@lk+xpTEpoc-tbX-{QK@3t)C`cq}=$TnkW(6Y}o5E~Ttz)$O za%JfbECt(L^`8rJW@W!VN2`zK z`AwZdS@^7g7e^WmGraL;q^)DX1^s>zL9!u5yjz#OPJt2LwaqoRT3>5`sSeg4oOHFtHcD)KFn?d++>GkdZM0!dByEG3ZqJ zw1H%NX$i~&-qzieu)B)^mafO`799~dJYN~OO`qmbl1=lJvJf;SdYHCPl4j}Tqvpn^ zzYR;Tmj!@Oyr8Hk%mJAYc~~@?fj2M{THeK(o(=zE2f2J<^oL$s`yIJ*oMM3QAaWYf zJRMBE-cKBD22800{Jx|@pnSP@hIlmwsfno!r2}g{?e(S9E#oQmf3j%;^$}|R%)xR! zwQ?6zp3gQMHh&?a=SdArK0$TK;iX*p_;Y+*Tz_+bq&q#eLJl8x5Y6lPnru8EEoQiU z#s{iL+xm|`+3UOw3#q1(wRxC0eGa;9uWFx;Z`^@~;_V=HhEhp)jQT=LxlD+qQL^FY z4pbvFKS&EAhqblI9%N~{C6~lbX|P>ie#>S*(|gvSlmcYke>xweKYqmD!9vEG_K>(M zc{Nk@4liQ%;1ueYcnWHdhgbz{2wMp*yL-W#<{}Fi6%Wp>GO3;k<4zt1l)hlJp4Lci z<_api)Ce#ts74qSa6yN&wIlC}MW_@jI$Y#w{PZz+d;j17tiamssjpq25bvD$3Nx|@ z5!~OiO&8br{))st$jbddU8Se_^U#>1{3HHCJX8)(TZqa7c^!ND4luP1lx;|h|A=7R z!uWprq62>0C;~R~0dQAZ;y7y4S{x*l<$n%KilXP^E0Xorp|Ok!W`(tQ56TF3$ zNT~i&sd4ZdD645@1ySaaz;XdtR>vLrtQY1d5r?P>N5=O|Lc;^>;RF%pMh{`5go(-{ zKN>?q+)b#5L=s6s9V25w53ID6jinwID2trj}!CT=ez~D7nmkwYL!9 z`x0FoSE=nj{TRmf5n0QfxBOk1`PpGIb<;OJ&DJgzLHb|Q=_H5u{M>dTg+akFUt=Lhu z9N$I<4mr}}mS%naebM5q%nscGNxYc1Y#?CtB{Hg8UTSl#`ZD*!{92se%)f@xU@|F% zH_dKW(>K=NZSQ29!N^XL5U;ISxQ6#(W3z!DC}i1aV4$}E)Za-c;vFd^EFoEqnKQ0k zNAl~)K2FVS%epjB&J=GlF{MS-cF!a?G#@^08b45X8x4^GnVf>c7pNR%z}1SJkGzoC zyb{S_KDfOnH4zC@m#Nhb)u!m%w>PfkXI&vqv7R;Xbq{!yvwv>(a0Olv^9F4;V5FzO zd+Q@o0gF`X_sOu

?Uh28NP0Twa&1LCLTddCP$1>$gADkG+rB*$_J@kf4WfLz__W zf>WQ7kosvl9;}BLX|2H^0CHa>(Nu`HfsJ$j1d1S9yv4tq8EKn%*tbYI82Kk zibkF_&rSPoJCC(C01pFQjikVtLlBUDUIM?LVbdy56MKMvCv^Ca8ORONK1#gw?ji@X zb_Dzp^&~06=fY|NA^w+v?(I+EANOcLRAsEC6CfD%winkyySaT00$|G8&|U_Q==h zAn5UT7u>=QhWDNL`1QI8J0xM)5!ge@;sy>)E_X*Du0Q~vvMUq$aQq_zQpjdG^2x1g z54C3^fp7Nynol|)h98{Jqg88y3{Eqi{GS#8sG17e+uH}7K;X*|5VI0+n4!IZ@OL0A zRhzGZpmrQUf_Z7p0P`1S5f(5$Y+z-9ULsHtKMUuN5S%?8UFgqmoWx`zX#cR_w=t6y zeH+*xEMK0Vj!z5qo9%rej_!23&QuVnX%9S!=fFb>NA)NO@$}3AWCG$s&X_#tKoWjD zhb8-dm-{6i_YT&c(LOKl0-$q1)yiT0bj}7%61Fdh_eliCFV%l}(%tG9yyWs^*F9ho z%m>~JfyeVch=RF%L3=&7*yq-_&G(l`o)z~~TwKumNW8>5@ z37=Y(-^Nr8Pk_~}k)ZbW&3~>o5H(}I3#PIy z8lS$I_Aa2$!9>DYPF2Q;68APfvNwhtnZ^3NJFdjb9p zSnFrrC#VGOqVmA4$xNVzMZqp^#XbN@NC3cW9WIQ&g&S$T)5pDL)=-?c$VMLcP3-{>b?nSw#MsGCCwGRmD1YrIrC%q*8qjbQ}mnzTo^^i2Jzx-%GuOW<@Okxn55EwhzOr#Tia%`EgnssvnUUk38s=MxbzNxxNf_jv| z0SwH!6n012R;3Ezst`$`E)4>ex{~@qB21omFuJk4F3^pW3BNpY0FS~I7b;;)o;S0` zyL;1uKvO6Pj0e)J0@9)KjA1VGp)%wJ>yV_y?X%v&P4`>Ocgzm6!+n5g}oyi~1f+;AFS9FYRr3nkW&_Kks=b(8i&X zR5{x(M;RaQcA_ax)1xuS@#IC+H`~d55Q1Drw4dL%qAqgFT~+rH!{cJ-6W$VnE^4*e1Q9w3p9BE!`U;`@VW2avo+`~n zn14b^;8ne{9rD@dLiL79t%j1sW$go3T;FlHm(8x4=)OJ@wP-VrLcQXUIZl7VSiSJot>M5oIT^%lAPj(M{im$ z+;cqH=X9|xxzWoM%MR^UqgWzM$H9Re+_$yt%z$?mI}Jtj_Dd+!U1bG3t-P_Z@lu)O z!h6sXB>=DRcsPDcT;F}4*i>e=_cJdM+$OwM$Vv5gWxWh=$N^?xsfcHfiJtXpXSxvxazEO0tL=J`6i}8*e@cY*0 zvjxa1Me-NcmS}65k%Z<}1CyZ2h#C7gt)6x!c3b;miIi~qfS{oP5aHDS&M^Xy4T((} zDl|0ISilcrAUjy)Y)unipL+%jHP}n=v0%<^P_EaMUW>T6Gy-K&w_y$c-E)(G(2~jq zp6@^nHi&G@oNlnvSZTC*g98l(x^~7gILxxQe?eHD+P-Uzy+J}Ei<#F4Yu%mFx7e^% zCGRR6T8I06*VzC5PN-!mPJnGOC7xgzI>K!Hk>V$l;&T)RcG*j?p{SiSBBa4|HomTk z)A~M33)XipSl=^HvKMqBWUxT2MK4hMk6?p%jG}F=7yQ1kac(xc3n-mJUd8f-u!|CS zAOYN8ogc-3)|GIaEfbdn!Qx1Nr48CJpm+O61z*Eq8sX?zzvIoKM0gvug}um(N$yz| z3SBQTN^pdXs2pO#?*n+=0CCumX6&V4s9G=?=;{wQlL`c@r1<5*6ss^myZvP~$wX*V zi;y7!33{j-MMp_0*+0mA=u&)oVX|43K#5a*t5#m1)9U-<5TVtS;9!n3Rv&cm0(NhH z%Z?lSyoD|&R6GluLnOb#%;4WPy~Qu#_f+ro`@lv(rdwjRPwW7L6o_D0w+x(Sx5`Lx z&=Q_f_;1$DvvQ0~+Bn@gWpg}&e6u3kRYXuFFbA=~bdPSG5YV+i%$7Ti`3X?Kg{9za zhWAvcGvbBAH)!h}Z@ijC#Jo%g{~gPH_k()NIPrNXg1tPjfy+`O zag;4=n|<#G6tMC7V)DG$0P@ zEfIpYzCJ14g`_Xk_Qc46Gg9jRm2}o&O}&2~-^Qe4gmi;QNh942(g+G)Is~Moo6+4M z-Hieg5+X>4bT^Fd?tYHHXMgWnoa=1&eZS-NVT5%p*asdC7$0t{t@*7Lsr8XKE9=NE z&xYdiUFFGbztw0#E|D51CdbAUjLrZ(44S=wv;jT3a-J88AQy=^25Ju|Dz!zXQU@BV zn%@_1B36%vd6H+|7QrvqwtO644vf-y&eDtp|La&`dNshc^K*kRN$Xk?1F8yorKOLA z_&Ucsh}bU&&q7|o)l%UPu+)G5>_76pqqg4T92n?r(nafbAO0a5H1#8uTKOiZU1h%J zj0>-OwZnT98;lIYgYc6w(H!)exe1U-(!Uc2a--0WfWgj_+eoz?3hN3j=2T&0#t{); zlnOnb$|vuViIFYp_S~0HH949apgtxO3<@Avqj7@(m{V97w4N={{J9Koj@xGR{loUp z=k>o=I?$6>D(n-gFVKjc(+A2fAiPFEBdxVKbty&QKU`}Xa%d2md@gA_Z1=b<)gOH_ ziub%|2x+%0e9-q);;8ko2hp=IvSkHfW@95<*T;aIv>(Z%uMP~Iv0r~=d?zkjpbirU zsP3@B%d6JPR3x&Na>sd=jZ3ux)r5bCSb$d6NUW) z=+%E)4pnEyqElVK;juFEB`i$n;X>x+s^7|C=Uk(i_DRP|ETZb>kCkjqZ{BcRA)}@I zZ0i!s_JS4lGgs(q_akD=kYCEz--g$Mk<}DHr`q@$;%&i!8OE1>E$PKeVqasIvqNMl zHVzhZ5ZANm7Va~k6U`01TvA{fyVFjbPWrQ~`5T)P7lzAgq|} zNO-@{6sNCt$Rvq`8Uymqu;%Zsu#?GqD4w_$m|jGiwG=$7bOCp%1F3flo*(f+RXtE2yV^AX}jz0^ql?SG9)6mio6aX_$>i zQFUvogyF^I%h1>y^EIhjeupmAijO|D7fmlbG5ra30=5Uo&qE72t ztgKAkXT3uj#Hpz+uLX_V^hI4gjy_z`Nqh9#+9^XLtEWV`UAIcAhmUk*Zpd=%TssU| zs_mCQ2VAfe{xz0YL3DI<2yT|y!=Z5)FOHUy&!1-%xrrf_|96OYsTW?-$$BD`7xXW|DksfxbjO4NHgfo63H9^Q-flV237G*vYg+WegZi6I|N+Z!q zTZR0|;*eogyR6d8m~FORC~Du5q8jtu#7iCx zz(JgFcxj4##za2=?%tVmhVtWoM}`60X?kxE&;h505!9$OKOfHhRBrq7d_1hTwdAmG z8utOER`TB9$gj4x*2i@5#ecI6_BqGayYIo->7-yRYNMCUtr_qQPCkK3E2l7eM=b2O z7#lk1iEI>l$j-XH#%SNBpLOR(Yq*_B)EZiy8|Oc}0h_e7C#c2KM-oIC4IlV+J!rst zE4idsl`;qMvbWr-bL#&OLQUI6w1;fYhqKJN6Vvtr@TDWpzs}n~%8P_+28bRAnUW?Kq@bV>fAmYISVb&NI4~r~rWmc-F$W6n!pOvOXF0EIo2v1U z6_={Nj#K>=;;J*%!mfx__l*b1cCk^NKIB}&%8Cg9EneBoizArgT7pa&9lodLR_d@;`+nxKJm zU!jW=0h1ANYZ=~e2G~^Gr+?ksVhuNXjTi>=ra=MHeY_yCnK)vWYvw0Zakg)p-XHj* z)(NqX2b&bljf^J^cJs1m-nCaM!Brj?n*sRDwf-qHYAzm;f8ftC(1mBqAJ|`DZ8QV+ zlnM&rqaYLLEj_P+>bFUt)>FiFL;!L_eqXNuGd$9FdF(96$=+ zvBl_790bh`LBrK+lQu#UK){av8xI6(8HWJwa#_ZNGjkZ&8{11Sto2 zV+%zVbf|aF7@1=Iv8#JmIJ{E;rNoJLmhAK(>`GY76P<8k;bkasv@DRbszCPp<~=B; zl7bAITylLbm!A5(ofac(yEa=gV7ye2ru( z7T(<(e5~6QB`&H7Pcfa|{k}LwtV>H|k;};Kvhg;VbUeM;&tqk^&Eia_-d@5nzn3-> z|Bv=LSxh8<7DhYg%jTvxBQcgEwGHpq(&C-i=pMj|a6jz>0FH19uw8g(U#|f=&;L}D zUCj1{<|QZsSdl750T!I0(|9APS&rV`_U2|V{Yqjip~I^LVY z^wfTvDTZ7WjBv16HKTFe)?%$c66UTE7>P;k2-DR%U zVXn&zeqFOQ$XY+6oa>AWFVABk#x6rVO8EmF%`+LfFlw7kwd0AUg?LFc>HN%o{JI}| zYmBWPcQyrQ{I=|{@m6Y}%fUy^lj{fyfXYi3E4-$M(vXJ-f@8ZA^CJsWRmot7zvCPt-|1vw=8d($@3nk9!Fm}m(!j?()`OWhvLhy zX+}9lJDN}K_prPmf`@K=hLL|KzGiy36LWtGNtfJ)9DR2JRHt=7Vf*aRu=7s`130{e zdJT3@qT0U(&Cfr_30Yi=Svd9GP1k->J!)LX9x0Y>>%DP9^}-cr)bRN?$Mm1gGbQsj z8sZ9~+v5ZGCEZ&s8?zr)9YwQMD^(2Pyp)cg=5G*fl?Ny#_%Ak753!;DSuSXvy=XjH zzgq%lP4m;Gjdk98zP&^W32Jn6Mc~dDf((3b&Fk$~mUHdKTxRrpfkB-74hRsC8D5L# zTSi2%RGx?&P$JUAQQOS8g6sSMpj@$)W|hLTJYq~9CJrPn-2v^iZ*b7;>R`_KczNj> zhV%oqUrcQTRlJyAyr5oaXY?CNNYb|l^mC*72&W8WE93|Xg4FLeqB?z9VS4lewuUxkDm>NGEjfHD(s*Z88$tC_Nc&qdfC-38 zPM)H+*8wD?n}wC9p8mww9>BykZz;|kaJo!7h?Lj53vgBs7E(Tnf6kF&4^9U$1MQKH zi`|L2KYn6B9=ZTv%eK;=9N$TSxKu_2oDN(o5kXu+NTSxNQXW#LK#4;IA{^W)ABY^4#^mdBv)&{dDnJ z{8MaWHO`}#m-6=zkXuk*0eh2{NB{iA^McU%4#Tih^s{Wurt()E))Po-xAj zYxen;a?VNA5o8XtM3hQ7kPPkgUva707T6{?`N)#K&=N&Ppvc{MDu9D zjH?<*5WAdD1SWyHNbx2_E&f}!Oc>9Mi)99461%vcC5bNxa~;n3mqM@29HE#z)_Uzlw6`%_T(; zIAOWC6rZ;R%BORI{?W4lUI6B2JdU(?07gM+&bc`y_Ll|+1-9IW4PHQW`UhfJG<|s@ zVs9YcxG(aLUqnFAXr(j+YUL4!B2a_de?>8wi>9`9`zrWcco52j~ThMd8Zy9*LJ9Qk_Sc+&L zLG~pH@oS*^P-%7sbV@Zod;kh^13y|e@EID122~)mEwEAy;KXk%@D&&Y@sCB)8r+`(*_eOyOBvL7K`1a)-tys?N(sta3()QE{<~;( z(MHNo?kVkt4UBOd%Y+2h(N(`|vtm@9$6shBD*rwoD4BE|R|V~NI+!mf_$|mlgj^4d z0IS=W+nP^M3y%bXP~a}mYC8SriLmz4q6P@Q;lXa)^u%ogrUp-LZ^!sIGW?>BjtM4S z7nSv+Nx&`G261Lbd%&leXXi@kWL1&JLHV zSg}QUT4?%GRv(|Ta`A`l*vH9kbNe&Zd%h}&K}Uo9hg^4M2Cz=p8DJ*?Sd!#_m?L^T zq(HQ>u@>eg5A;7-;_)h8z@X9}6eEWX*AbG@*U}&g3JT-vMPNanC{fjUyR_9Uh0Y0v zPDbJ{gmWI59w@(+jmZc!AUd8ReStrIns$HOT`osDj;!}~bo5+WT0vFLnN{wf|0~uL z-v^>D+{D(JG@`y^p$`X8tYe5mm0X>Cfs zhc5ujlIhJGink46p=S|Ul%mtf-dl^aKs;Xlbr2KK&;4$vF+A?5Nv>r@9{d83iT(}| zw|SeogYsvUwFY~mvd3ctys!gAt5-N5#G4yheZ~5Py#v3^^de?{VYUus56lNRPZP2l zA3hjeI74J!p0I4oYDNaTu-l(bT&EEJxfv@Eempb?XN-gw$m??Eb-guWD8IP^uu8zm zYBT(GHZcszsby?#ZeZDqrE%YJS65eew%%6nLriaAPizg5dZqU|An_ZEiIuZ5A@?Bd zkcmild%xQ%l$DLn2^OUtDri3*F{@O=M5mL~?HLNof0K(zclfgH((%6+r|bxKY`tr( z139@SOyB2A=YV$4Hr}iA@%;tiE5oWc)e06&AW>FOMJbLhHL zSJal{0MZfA0!cnNu=zL497sZb;Sbruba+oJa}Wr6$`zIa05_;gjW&RGvsXM3aj7XP zO6GX5(4gA13xJLy)eyTYl;SXpa+`v{uu{5I?g`GWD75V(B&)0NiBMIeV`y4 zh1d}BUpIt>a~0jQHr<&IOK9~rO=GMR%mhe{0_$A-t?RGWObUD+cv1MtD>uEUd^!q7 z9!Qmr)4FqL&Ci2$CycWX+M}*7EC7lGfQJK=lz$k_n%dgXE{gYn;{-^-Ss6dwiA<4Z zVhI`&1^|cmB+*{E zK0TiJ`1t)pL*_v32$(n*5fz0A zX*(jwN9nPFtEz$b7yum8fc4=YA<3Hk6F5Q9vJnlT91e26TQ9We!L!XIe^(+>r|;qC zr*U~NGA*kZn+BV#Y?cL4(i&w^Q_5|CXuBtK7DfhED5BP+@Z-7U*2EQ$y|zaSZLj)kDrnQ;&>nkd-GKNB?tS|2#K|ip{ zIFt-$S#yZQ)7yS}oLd0a0bw038{q5ft=tjj`0f=m=wU2I51A66`6jKSxu|3mxm80s}dIUqOHPz>>I2{#SbQ??RRQgIXy_~ z3Z=f9uctd<%Ks2WP1!YG9gC%;8+t-A3t@G&OIgc++KEumFjUS3*RSzJ>yu6Y%YpCx}bd3?_w@>3qY zW;M!q!9S<}p7h7)=VP&pjw2qE{4Kazn1PObReE+u8-)r-bImo6`}K*_Z$cFo3u5t$Dj!k>9t=z6S1xRa*MH zP90}VX{gIm$r5;LC|yzXMVV-3eftd564mb#W-jH+g8tgosN2=%rDo)EMd&-?Os3UO zF!;4*e74RS9@AtwniFoVZ{F}p%2kZK#AR53dea3V?-bfRsNMh!7Wo>Q^-c$URoZA2 zAFfdx<(1bHyA-)B($uKOZ8OUq(hTOWUd?*hIlYEw=E;M${Y|93IJ2&nz>3V6GW2v< zi}o&Tx%;sSceH*%jQZj+$w; zLu5gRl|F(Mf655NIa9?=BRk^4usodOHKm1)JxNiY^`4dykT!o?v+PQ z+J5hXgZ+PdpyecM*WAY5yI0*nqbo#Fq+|qyol(oQ+c@W>epsb28x^uhn!3>`&vMgE z%^b#l@xWK8DGK!Va}=D8gRRO}}cU+U}C8^|>qmb3<7bN8IaU z@v&*!L*toM%?GP(G||~>fr>-l*fKZjDVS(XlDadY0<^+{*pNGseEM%vr*6UK=7+hR z*kr8FjVGT9b+J1YbD5m=&z=|g2q~^MBrN_u~|sFG)l2%y=EWTAazs5IxccBk3=zP5%9KPhqp7ng2BZry!1a43+wW@RKzZpF#Dtx>lh$6>_;Qx$13}NPOV5nkh;5=K_gD1UezET$IvZ+|_~YWXwR`68gGe(2e>vD9 z>M@w?C{|a!Wjw7S6KA4pjNK}G`xj2nTmw3QV&H%*3<~_P(^9k8T6&5Sx!D3UzwDaD zzQrdQbF+L(c567#n);(%96XJ*ej?0Yi7P((K_^pLdP4-Y<3H#Y4eF_}7Mkbr*wTErFYPS{NM^y1T zYV^={^{CD-1$(=gM2jfDqZM7-38)6NXzahD8;<~Y{pd}OCQI}9DGqn&o$U@R{T2A zPKCzF488gbC-shaN#fT42U`(nY16p)^rT#}L7Pw;S2PG2o$NYFYINiUI&M&txbulz z(VfY9av;z2AUOvF*6j+z_Aej~YR@m>&NPxOpX612?Abs|`|fo`L%7WS5?meY5J&8A zyyBIy=hHM~=ccwWEBoGuC54PtOW$@=BQQ7}8Dr|wmZ#oj%&dBR(XQy{`rS9T)V2Ju z$hSsOoN-1`47{8%xZ$!I_|b(7B%CE(1N*0i4Bd%eO=y|g8OaZ)_q4o_QOK(^qVVD@;FlXAZ zUffOpg}aFMa^MS4gJS!P^9*Qhni6GeJ-caJ-}(u9X2G-?dzUnK7BF^N*zDIO&K7^h zd>dMYS=Bp_0iU;jT&A{LQLZ7n(oP{Szn?bvxkAKM@VhH4w`eH>mAmI8O5$k0Px*Dvpji&@LXnI%@M8X_pAN_?{|Sfc*^{mtHukP| z-$aT={n?2<)k%bR>_jp{PA(cT_FPueB`(b_?&-l)Ju6eDI`QI$25>P03Dnd1v@#Er=X*JNr7$S?k?u1 zcT#wadOL?reHmOK_H5ZhGh0i;Ve|znfh|vo@bOupMV8Gx2C%mmXqnQ@PZ*y28;oPS z2UE*65GVF}E*aM5bXw)+X%O6u{z20psbdM{NL9Po<~K<=f-FI(sU-Rw@4b>saEvL} z-&B_D?pmtR5`Dn(#!|R1A_8E=+-D3wPAc`>5tYI{pNg+=x6rz7ggmeBL_&N5E zB~+B~+97lIKvXmjbnq?jTZFj-KXm6{Z)@rL>SR%MrMOJyBXTMq+#aVSL!UU|`R^`8 z7%OONRM#(xcpZ~3@EC?etLvtDVH9m~&g0(p0l`@aUjHsiVrqhnaXh#_Y$dRG+HGTk zg)7SK6F_`K^Ej#zW8RLv!cK5AtQpJs@*yk7_cFp_fd>kr7=O2B zPs=26Rn|*IlJ`mXhoGhAnP$KJm=gWT;r8kT*||Gma#PQ<2e@FndGBZW~!r!(!$`umcvxp4~k1s577 z3+nuNg+$5>Jm+Zz;y{S@FRu;_!aTCF)O)7Fd=_9D z3<>=gVXXgMfwwzw_P=H)=7qmn1>F0Y(Fsqh)l*FhJN0w=gn4B@2R12q^aQKtWORjo?bOWg9Ml`{{unoP z8=ah&&ouN7xkt5D+2bvAxllZABAN8eNv9u_yDaYn*i&y?w^jKQZMwykrIxc-WUEt)`^Q) z;!jD5M@Lxd&i#98E-sVNUBwblG04#%9^kI9Aa2yQ;0*c9^ewyGSHR5lFzEdl(s5h^FYwX; e#|KO5#WPN@vTX4&ofZNFJQQS9q$?$j0{#zS>p}wn literal 0 HcmV?d00001 diff --git a/assets/securety.png b/assets/securety.png new file mode 100644 index 0000000000000000000000000000000000000000..ea713c057c6028538fbcd3bd43ac4437f7f3286d GIT binary patch literal 25807 zcmZ5{2|Uza_y3H+C~IZSz9qZJo;}MXi3nrQzVG`sgG@-4LRmtM3fZy~MiSW@``AX3 zUG{zXe@5T$^E|)*tCvsX+;h)8=Y6(&?|j7Gzo$ug@#;ko2t*0fx~&faK{yCMWTXIP z+>_K1_z&!(uc-wrMP*FYddGzfGEkPr(X zke?U`v}6SW$-M-D7(BD;^=<(Jq>r>UZ-dSV|8g7OKL;omJhe=GKp+ur!VfqwU&$XJ zLVaO6>d++;ItF3}fkWL=U=a}Pwu(U@Ze=o{(n7uQY-10mtEEbo)K3IeUC=Vp8-x%W z5T~xGKP92ay&k+1H^d)*7Q><{jcRf~gcIqD4Ug!4#*fb0 zeDP=HB)nLXJUzfXs5jK%k3+=kF^Pdl9+*ot+j=;D6|;tU*A@X4V-2LQWv->%x7nD6 zrSQP?Q7hnM@JnhTCx=XGGx+h@9e{|1yO|Rwwy~123D&e>>@Z{v4+zx4kC3O}-~OC| zA15rJ--woRjQ}+T1V`v$wj?P4-gM*x#F~E%Kr}E9A*va^0dTI7?v{`9!cx%AW5kS5 zA!n<7<0c(Ybr}U=@wy$Z#)~`f=aKE3ZcJ=I5 z_@oVx6Na82j|BNv_k7t>BZ!ZYB@X-;*)KMVQFkU`;o{u18&zu4AKEf z!_GYG)R5af421zcjsOR&YlZB140FF`Hvn%=B>_+jC+#t^7%nwcH5@y_jm00}Da`Og z4j{&2BHsxaoRO5pw%!Mbb|dkX*JjkCln2IL@xE3`t@;Gw0Hw_3zzOJ?r`uIefwh+e zr=&1mm{^Vqmy);N@$3Lx&#&nLc3*E%Y}gfZsxEBf6asiyT%l&fLc7+A%e&H6mZ%Cq z(>FK@MopaEcj*3RWh};>$^+0%y`0TSI$u`tV|umlwH{};RZqYs{fcd(dti$VaHIID zA695YgDL`GmF&a{`{isSKYwzgcN%sv7li`EA#HL`MzQZuPtzaoh%7M@w}EvGY`Brl zM;JF#H5ysEh1q-{I?yGf47F|06*?Rj-Uu_+7E!I6R`njCOQg`~3(Oe2m-NRiM&0?|21bgf zZC7TDhS;u0J^_{xus7aFy48pJDP1{k;+3uG;08VZero2%&i>QxI$%*aa|%^b=CYb6 z3W%#=Ev%r{?gsO?FgkmfV6S)-%!SEfE3Za-`IcM}pOevt^p!t`)v*{0i+6y62h0Yy z%$k?f)&xd^vM4FstQ3Z!;c?4q4~OWVSBFbI(MsX5a|A8gE*XWEncFphN2_9Y#_0P@ zOvZ~$+$_EU5;iDFn_?x{id+)GD3Zbv6^z=jUDYbwie1zNz&3E0uhDsqiMGgnKubb3 zjA*!o*=gg*XV@u0f@>`U2pC!nsrvfM8MP&W@ldQRAG7`au5fiN@7+!gz%{f|f%|3k zha^1=U{gD|DYdwnPs0#lV31L}Z{y{v+Jf`A8)p2@{bjd!8ao}M={4T$k5fO3RRCD4 zV;FA@<4#R(Jx%K|MP?TNxjKGAdI?YoN17)V3i_q0x*cJ&ZhpFp zqu$S)wJ%}fM46_F~(Na)Gn*eBSax`t{LtU zSmd+U3InICV~Ql(J_}kYX#26pl~KLRidj`flNVP0lwEkAT6t=pY*T6Orm+##`i>xH z@cL1b1^ebYX159jYq)VB66PwOJUlC7FJJxm4;6vKfVvTp2tHeHDVlVKN+c{9Wc9ls~^9}7A(*-2U^0LuD$*s0P?^T%_PnAo>Zx^lI zN8Pvc<6d>$EgOmA`>36Qu41MLWeOZd#Lr;?pN8=-E|uY|+z_E6F?sx2ZL_y}~pdaLeeu;Tmto zg6!ZF3zyJ|<@XO%&baVy1TmX~?2MGRensiLr+V1%Fj4~$a$#Wp;0e8FEhu=bl;&nMrJk1&hGZ1+UEy_Ox8dqA1*vp`E;+zQ)Y*mhx2 zf=C5i=f6*LK*L6gOWhS%x3Q{iB_#ax6Fm%395 z7PIa5Jg}u)9pnv+0lSdgq&-86%@x#haq-Kwt;;pqtFL~Z*5wi8NSX#a<~Er4754~4 zwtu7Iw{vC32ba!gu(-=$XMi0|94Yuce(}4xn?yXmJX!4yFFDth&rJ;z*XZ`fPO11| z`l+jwS(i(3YF?fw~Lc zAx*VP4eB*K{2`M_HAL(_?zS*aNvlFrfd!6jrsV7)zPHErW3D=>a>|~k|7Sn29kMmv zP{zaNs+?-*RC=LAPCLVpra04pkwS&r8BVM#0E_w%YfXP~`_ULmrV>rHsFT5;wW5H& z=El}ly}6@F1JfsKMLa;hKYmj(=Jf3fLR!8OEwZQqw>rt)OU=fPS<$ykC0g(ft|bv$6O>c12u59r`-5Dgx&hNyaMQ-|w*`E3iEus;L!}!8 zXj4mWqn_ic-g`lXVfqO>yp6hH6_%BfZUb5(#jErkr3gE}E| zA&W-E=_ikhokAijE4t;VZWJs^eG?8{{_$G4NeRyS2uLm_<&4#r3k;4unA%;EDLoc7aFV;?ZIJ1foMZOBR9zO2cyNG9{y1`ElR29%(&{<(n2-Ut+SwidG zltPyWSpT@h!#3meu&wsz7BugWW?_1>T%7_T1ce-B(YRJt$L4HnsN%SQi ztM{LyLl5E%Z7jGwt?LYgPmn(_+*6R{U=LOu9E)-at(g+O6>Y9bf57{&=J8y5GX0u% zVF?=sg=h}3{AikaAq(<3-uF!-5C0Q-?4$1$NTZW4h06>xeTYj`vM|9QsOOEc{t!EJ zOTQD+*TP&dojJjW3G(+{D8xoN`J9B)*jyKa8xDI_r&WX1i<;H$r7U^Sc(QmZG(9r> zvulL+oOq?K-(C#KBD=e30Uz1Dx=2@?JXOS7P#yfd`Z^1B_b&PS5;sLB?T#9`6`r9E z#kR1vk&2~={+ZD?&AhPe{^Hu$XCxMz@%d{&+1gFal-uSR`aawiW?#QIQC|Z?8_mSX zukbjn`U|;dBp#7qll(;&6@E5RDFB5c$=ALA`BW5h@X}!nK!Dp<{QMnQV@XSCijhHX z_m=TUYD;66tF9p1rZSl~<5r2WV>)bC1q)J0>7-Sf1Fw!)@HS$Hm)4)tc9&pete)*H z#Z)q({Zdi*pMEgj5va`N+RyvE-$aq$Dp5$?8UKWopUgy|bT5B4Hdq7Q#oWpPm4p7Y zaN#q1bw^>qG~hQ)TlXv&AYfQ(!6+)xh6E;vZU^@K>`ESzn&av^(ZE^vP7%JhS`znC3^c;xjwTwXwlb@q z4_~8FgC(oBZ%yT9dK0b5;B~0fVRRKx5xB>&NL&rAwJkR)4{aa)Z2mKobpFZn?PqJj zRGKh4X>=`n@H;J^)(#rf8+7mq?k0WUaHjhMoN8M3R=g-mmW8*#yjo-}Q}l=xTPY@3iEpd|!!nA8ce@Di|CV zbg!R9zM4Az!opaas`ely<55T!U9A7Yj6an&e*|+1JyHksJ0yx+a(o7fOredc;M(}o zv4|dNo!rsuye+tR(rFq8weYa_^8bXx&hW$X+)(n4>dv|;!ynevaMv~UIU17QiTv5K zr*kf!OvM~|@d?5@b(HWnnBwr9$4h7-%a4##Gz{&7EwLSQchE1`=5uR5^ufL!KD~UYrtxAH<>wx2LDx*<&J&eup90A5tEfTcJ)apN7a&(a!3S*?YM*0_6~ z-UY3-j9r3gSuN8eXBE&Aa<`ydO?>hFUhW$?hB=}W!tu*CoK6j2Bfx!uYUu{n9>S3w zdKiud?#g*Y5uymWthMZy{|+9WIdLHK_*Iw4!`b*UM^I^_BIX9>F=kM5(E93PYIGvq z%)dx5MaU zN~Oj)(e&4-XFg84KV`*I_x!D@8Ppc4UvA6w@?*YHjlE+Yiaz|~QlpK9S0xRXJ>$(b zpOLsdAw@nCV=%mnt|0qN^QanyxPcj_8WJM~iQaS)@~t`IEtsrN?k!*>|GXff-mxoQ zmaSF=Kb#r%*HddBLAtTL;S8&bwV72~35PAcut4vmG?UmLe!S#9-`hm>V`(25rFb`_ zaR0GAJIc;+(rIlbQ`&?Gw)9C6{d@%I#*j@}^uek;RhRSVC1X6o!#U*YKIghU%0>$3 zcnZ%I7K-8->aNFVB8$RAoSjV(rH>51h_bHeI1R*Eno+gv9r$cFf@~H7yEtHeH(pkL z?;y6y>l32%IGd*ts-e`H*OVD$9 zZ#MM<$If*6RqKYg1tarR%7S9V3#50Uuff;o@^baqNOoPlBX0dpN<#NraJt==Xd>fg z2R#F6q}UHs*)JzkJu!%_%=lB_{2RAA7I5L61QEK_Rg>g@bwMg8RhEgb^M|{>}w3_$ioeQ?`dNZJKK{IZ#8BI1E9ZY*Ah~l6P;9D05_{ z;tU--8~8#^Gv$tlU}4yL9{4LL#m$s>!tgkwEXt1BCIEjIOVp_GG>U&PybG6yZu9CH zWuA0n0qS&cn|Z&7fFBfh%$AY|rXpa`EiB8kEmmXA>Z;i>BX+L0Iuk*-PBwyl% z%^jYy>c~@Mu;7k}A~nkuEjWk8a$m5l7$)x;tgvNou;5ok zQ5pahwjTmc7vY$m5PvM0x$w8V_U(KgA5XDBuIBtdK!NQ|EN{y>(R!!TRf|)&i_>@L&;T# zzQ;EVenLtE(VE0DrEyhS2#qg!NX_BQXU8cQnkTiO^omVseVf6TjPLP>rvf)KCf}|q zU(Epx8T+h6dcqNnF!IjCcc0^Prm={K_D1z17BS+{s{Q#x3=!7lVIt_c7V7GqltEXY zRU*if!RwijGcb$hsxD=sV_?)-*aM^st9=U3chDOF=DQhlGHExL_3}yj)P$RPVB!d^ zoe^f4CzVHSDri48!&Sn?CFF?#RJ(6khF<0(brocUaJLJPd>SC^0;;I-vEl{w2IUkU zCS`QVcpe!GJ5hC&{6m)%a}HPv1&97Tg(y+`4@|GWX2XON18{!_XcXS6CBdo*2^nK$ z^{@KNhs`JkvVNbejJ>}{Wbws!jJbc*xjG&<8D(B<#|>M0jIU)QdR z#MAi4RE+6wsV-uCE9P#4D#3OGDQ>L_78E1|Brwd2fxSB=}5Bgb9=I_J6I)~1NW7HESvpWMw!79$Eyr4fbRhyPXuP6F^TV9 zg3XAZLe|RV&uukax5oSUtF;Q5-#=x>dz;-CAxteyYQZF~#KZ)?ygBYA;^b9#&YQZW zWA$Y6zO*Q~8S?GY;zEm)~>0$<~!DvStlxhIaep6xl+=l&s< z7qhCqP)qjGJ^g$_<(t;kNRg0?O1HIA#CL)bfUAp!sYfT>7hV{_pd`Yqz0Du79 zrHrA!%iXc&F-8(S@VylDdyE&j04AlWn!e_*(r}y&M9m)r!z$Hzyvnr~2N-!Q2C*`L z5^=2Oe14Ol1}l;W2y$R6mqUQq7NqA^HA-?9TEZiIt(nc(^{-NBc!p{8vn@o?Mw0U1 z*tgNvz1GaQ4-xD7YmHV_ihm}H`vUlU2XUzpAfe#EZhiwf zK>Eh$07Hg=jJbcs{L%hjK>!6<{=ZKO4#MaEecFNm7XZc*o`C27|0k0&f%5kWtO$Jm z`vi~$KL4L5pf^DI`}{wP{#C&F9g2|M8Lo_C#Eit-kYO+>5zy%|6juH}?1>&A(pRO< zMOR+SB>F?-PpknNr#)L4i9IV`#Qb`rKr}%;VRpQCu6w~7q>W{6F&Ufb$a+MG0=`Gx z)cM9b$kXP>>75LPOfI4{V1i_wUe}U@y!E~_aMnE|I2ukaG zz;hg21F-}JKm6rk!N91UacQiBlY`(IeVeC5YeZ89Kbj*Vuv|M3){Ezw59vnWYtWO$ z!v%qs6yQ^e&?w(`PtJW@n3spKL{g8_oei@xs>#6`OD8$c1-ZGxu5){$fbVc;7%ZUx?Yw7m@^w)2ZtgEB|P%mlm z61Uj@ zsDZLBp0+^+4&=yvlX)U`Cv0`hMhK+6U^HGARtp#%eV2Wr>2DF0!bcFjy;5uINs%H$3ydu04bW zKrjAo8ZV}w*nFUYrMi}a?tPqSX4wFz$Qq4STqZq^d|7H;M2OQzo$SN zO1iL|^c;Q9h5OG)i3W73D_ct`T75BRoMmce|6&>iN6R+1Fw3#5C!bUK;ijdy?sNZ} zOpp~F+(o?<+x;iMDwV@-Ht)Nq0vpmtpc@F^emUT-UOd#6MlmhiL4o~4slU$$W@XPy z^@G+Gt3ZRijo_qN&u-mlrF(uPC>RQYaitFp)d;!NDK!g za%Z%F6wD2b!`PD&_f_Nmr^~mD?AShsxZg9alrM^>=eS;Oq_`AE_dZ~4!K)on&0i-YN zlKPWvny_u9=%va+03=6bwvthz&_kib;IR*#=c;WHRD*huQc-OOg_3Be{-yv*e@x;h zrR6N9g;(=Icz#j#b09VMafXUbcQe4TKd*_h8)gH=B4zM~8z3=0favVXiUhEE4C)0c z>0o$o=r0>6Ui|0Ds53}!?tJB=%9(CWkr>DbC@LzfBpr$R{KCMGz+LGNaKELir5Y8& zI~>{QQJO%XMJC{-gk^9 zM?SWAm=fO)+`y#*h4Xd%4EojMp2&#a=@1iGEWs(o9VGJyj=XD;TXU1t6Knar1e@T7 z`|DLjpGzKet-^ErvQF z8OtRSyqV|?Cv}1yh27^1B$CW`9YtWwL?sAzV6p2nE=C8@iCGp6M77K^?Ok^X(PX1+s(X0tn6rAKA+Na`?)$n>eZllP`)Tnru4 z78VpnmTcVlfTieo!;$m0VWf^n@-cbu){i^k0L$>=K3DX0cD?YV(r*7A!;2i`tiMtW z7XML!#j=5DU*(dw9gv8O${--R2-t~*4)&R2j2b5>ICuje7T-k~@f*qkp^`8V{J!C0cYIXqOy=DKoz)L_kjS`OzV1b#6D=B$g?~>3yjvFH;LO^ zw3rypoD?Yode+GL4T+AErnhc4)(b8U719NY55R@N_qMzR6Q-d|4_?z5>BmDTO2~zy z&ikebD$#Pk%vgW{%J_g>SS?7HObjDZMR5)@qay7$JMg!mTV3}pwumUo1c4hVLa&XX zetd%yGn!$?)amjN0rt-MXG9R&r6S$=*0-GvksK!rYDNADFH`b%8uBcS_6q z{EmdtYK=|=7DEk8Q1dclx5{dCWa?ag41%m^02f(*>DCjpRv#4{0Qwj}zxO|MI;+n* zICqg0{pQ5^54B6wzgJHG3RHB080&tpMz(;f1mM^6o379 z@fRasK@itx{}uBa${1l}60=!@e6qsHccD7@SF)SIsU)!&o*^rI5Xin_l^8y+#sBd4Hn{Y(&4;IUxkT zN8DSeRU8A62DOTx96J!br}cXvsb1IDU84VRpy%nj+4#NAItkr zR^C6@NZ7dC`o#v^(*Uro_mj?BLqV|#mA{>@+ZxeRp2oP%d)O5XVG2Q9c-KilJmLsp ziZsaJ{P1_gd>;5sn};J*nwlCUen#Dd&g7G{FN6cQqMns!7p7XRA~BIQaEQS4k-4al|Q>tovVT>-wKz7v|UR%qE>vh^_bd; z`qE_rg{JKxXO!EOEAS{OK+VSz?1hnkpiHF=rg58BFWDw#yYb)g0C|S16JF-KXC;V2 zJZ$+#WZ}$+%D0uYv^Sqgp-i^v@HqYP>`JLeu*c&R`0J=hLMpYQA{)3mYFQomJByeX zzs}oJe_|F^cS<1oZEy=v@!QNj6GBm?V2@k=4Vv{w&Q>1-N#sav9D`l7xaG<$H#O=G z9S(RxU?E5&%AmDcX##Re^h?o=K6s4&BBhyYzp+gS&1iStqjT^m*f0Km44Mr{vAftS8DBRB9>v=4|>e@+5P(I ztG8YlnEE8TH|~>4ryyz4W=NY#sfdNdJQ#|ji=p{jkeHO6t>8m)Q%p&}y-0axO-oK%^lfc~ z+_RVI8{x8{wL|WTGp)t``G!X}NnTB_@~<~vNA*rv^M5L{+`v4NaWu;WzOv&6wvuY3 zN+x;mppM*1`-t||f+6Kg;dPmhn7%9{`LgA&yqS~TN=|&3b&xdtyN*MtzJQC3QVdUj zzeiF=_CPlZ!Fl^{fz2OeHDtYphyIQxx5dMq!E>tkLUq)Y`v!}Yh4Z;svUc$wn} zj7M@rxl3zb8ukd?572o60;<7RNp}6CRXW>=9MiVm(j`IVK9W1raSqH@FD7YXP;^qd zOjJy_8n~*Q+tf(&pFR0R^2f(;B^2@`%F<(7-7M!y!hG~izRz9!RhV`UU;+^4i=!nsOu=XBvQ);t0UvQF>VSq$ zzR=q7)IrHTlDdGMYT6-j1q>!+N<4b=Jw;P3yGW$Iu)QcXNAD|{7@Bh=IVG`!ppjPX zw7g)pi<@mg8bz0Z*Msq*t0w4I@vr^%#}i3kOa8}Zfk)XtPk*eq{8ZG|Q@9c}kyKMd z%NZ)Lp1#XtHBU-hCMXeJw()hlcO!ZWC|Vch^@~?%f7S0-%ccm>))KzK{iz~&@7LH{C8znHVW@zS3CZ~_Y7s%G5C-k{hNmD*n%0orrHRW zvP25b^C$-P8=oA(_Rxct^7nHe-d&eIpcGOcSh>6qe`NRQbFdxRjq|!0L!COLp;D60 zC#3GDJ{CMgQqkjMn=AU~M$3`F-s44&0{p&zOAt_@TIvSLJjlI!%pCX&m!(xmXHbB+ zP~Hy4m(&#BbDOg+eAi?K_S;`xQ5SeAviz!-E$UQXc(|dmZ=2Ltp1&9Mj_J}bA2Z0^ zp4{dp>QK%BI5p8V{e)LZK-;~!M$-j{6J=3knJ0(b7hFv5w|*6V>Ln!qK&4aV#p7vR zc-)fQFs)gToGF zCm2QXEfF3U!_0`@RT73p$X&q(o*zYk2(yDbvu6*9cZw7Jm@dm(Qe7qiUz%jdI2 z%IWc?_58a^NA;MYUy@g_4?};SGVShN#uMY`>FP!(_*QF2G8X5RuE<=d!5N-bQ*X)& zG?SEqiLXHqSjJ7_VluD%^4S*F%L%@xWkV<*@Qp0s$n)uqrto8p%QkZEpYk1R>8-30 zI7{O%O@2CBCzUf9iDp2C$IZoZj10>QKbE>6&d5L%CZyTgNT0hKA?h?;e+|8BMktzQ zTb$}xYGc}8hq!+4CqJ#ZzaS>Y^lwg7d>wsO8Ui~Sd6k6wH;mgVOp}(E?X>gq*T}@L zCsxx^?s+ER{#g7}l==tsg0W{8yb~sE`OTu62GJZjHX+(SJkKs}%4($5CN}FfHP}!R zmAHA6IdQu&yk3sn0%}s^)(nR7R|Ed|u9;`aX58k}owEFXeZBC!#(w>qbL7&htA7fV zEgP<(XaA$GKP<^*)hA6=8`uTiSG3~4x>kW?1Nlp?9LWuP3f`KcR7>wen@_c+<@kuYVw6;fBL0*R6YbL?wBKAifeMx!#%U^VVZt6-ZZ?tvD=4hqxEnA~x&6Rv)J(n6K;{9MvH|vY&NWAwW$u|=Ebj4$q8Qc|R)4Tf{8~IZ`o$K(_zl@D z&eXm+m6E<`V}OMrl45wCP!VsuMNz3e={eukXcf`hfe#&o9}nA~DO(C;nm&8SNcQ;= z*#*J*k@C=00XAS))ag{DJhCV+gc`PQ{7EkJ1)+fRzS%P`9zy1I?d$Ju&33{%BR7z1 zMayuiD$N&?Af;+rodHN7hUU>fHC#Wfm(08PUNxGk-uwK7_rD$5vZ-WZxppjmNV zSflW6w6NtLw3sFncbuPX`qATG&iVCUSU+wHzs}<_tFSC*0j5JoguuJiEIN`;eP3pA z@<=hfYrub2F!K~KY*j>-j6;M_I2SQ5`Zs6q=N#*~#lwuxm24O94b>XDWG8>3UJEj3 z-6m_2|6tcE4mkL40K9mt9ck8ZRz|z@0cgWh{Apa#ikOoantx05myl~6J0aEi_cgN_ z7swqYx-NaWhjCTYqBpzpGlSZ*2W6n139XMwtYBICU`|Ad=N8grM1jaDI88i((542; z>XNKLzu)Jmx%--aPzy?NghG;7+N?zQha3MEobGR=b)%m5Fu233i>UJ*8Y{QOH$EUHe}y53<+@uq)Oo%3CLs= z)RfAv?H5PXLAbUx8KB-dM6jZrM2?Z2)-+XfNwyJW$A4XG%Y1phIMouEGz3F7eWa>j zA;8A@m2kk_Ce+cV27rhgj z7bHvIb+rFyrQ2#xDo$rryYk=%cXLI{T7^-BN#`NPb26@nEZKQ3gmSifuM9c5+eJ{_ zK=B;hl(d7O+~qJRFwu##ae%?v>TJN9fL$upU-;-0VwRN*^wWtCRmVI3j{E~GT>_bJ z&snechv9qQ_Q-)P$-g~0MQhntw~VE*N^4nJq=sO!R=z4>>&59bR6^mq>fs`5;F3Iy z>?R5}y$qO*zWf)FO6Nx8E0vOyc_Gx&+)rgo?;{f+89CA0{|pC1iR({A0m13I(5nm6 zRp*im&cl$?sVAIqflUnO{lUVY;%5J!zsoxPGq}oj(U+akTGl{R7(@Qm*i##BQz-qQHXTsV{)9l;9x{6lAkGYPlAG7|AG0{g>cUobN3tFl*7UgR_=z7 zELg(;;F8{rG42a5Ru%N_j&WJBlr<4xDKHNPNkmRi(-TDr$6lT3Rkn=&Q^t}{!8y;U z`stI)rQ5%Kb93xd-mTUY8Cx`{iCLDO0RS6{H<@Fe!U=BcnQ zqb^Qt+qTGCOH*rQyU-+1(KWt{1FlQH-13M3b>kuIJ4Fq+G>!m-Bd4JHW zhYS!=o@NWj0>MK#EU6VDCW$7QEd-k0=f~7t?S$h)0DoPW)89dUgu|E{n$yy1&a;gt~~oO(f-F}AmhFiLW~kF573w4&4I%k z9FB$-qE^AV@iWHSK-ixjOq1>`*dW&!1`up%w|jiUbIE@``mc_67B-dlp85!(GFCq* zGkm?9oAW;kexeeS?+=^3ul>e;nYx?OSC7Ss;Jkm7VY#xrLUG&Q}aRKC{TB*RragoG#5(E?)9%gZ{?6HP9w-=H;)Zm|CTZ+Z@4+aZ%m z^hC_Ym({&pa>;EY|3{#wUv5YTWt!TLQ2u_BO}Rx38=>r-8*b)y|JK0my2Q}llyW=msouib6a{4=zRXl_v zJSV>zGhLs!-Ws2cQ0$vvpEA*DUDL}TFBH{8Zjc9RLK4bC0HP7zxMz9q4#zwU-7&miM|= zZoK^`%Z|S*UlB$dy?!%c%2v(O*>*;H^eDXH-xUIl%8t55gkrtR&CBBFg|xW{K&FVV zFI(-sTm=MeD(A+}8v=g&s}Zso@|k{t&8LP}&;8W0Omqn_=6vakD{ouYBrHGiboM;_ zic?*?`i~@{2F3m``y2hvuorLTA?8}~2cqQl^_qaOaW+jTf0HX#?v{eY~`OD?@U$p+V0;m%pqn%c`w@p1L}GsUdu6> z4(vk!YY1mUH0X`ns80#6p2=tV(KgBNqW=FVpfjwBvR%QS9q~rbSXBgOF<~ z@yKG~_|Ao0E6aV$O2D!gTmTw8bH4>!*3_g;E~gH~wun@>ubXQ!sd`fbYQpNAz}KJ+ z46F_&1`n50dS{;awj@*viAUQq18AjqZ@;$Mdn4N>kzoLDruP3~?g}$#wX6&W8WWJx zJjHExEo+*yfJSSLEh6jN1WAE)!ZE&)i3LG2zj$#jZ4U!}1&J!DZy@#Dtj(06DS%5Lo0{57U&kxoa1$DA?gVUWAFbnVX{l zt^lCB^Yf$C-iIJe48Y~DQWozmRn}yu$La?Of4J;xmN*8ut zJ%fhZISnFcHU;rEyayrnMADEmj@7K4N0&t4h*OLPI=k4P_k?JqlqX{ERa=;AtQs8a zeUGE~Li{gVyhEDCol?(ko~d2mNuh+R9KZ#Jp$E{PDg`EE112yo7-em4VIO-8G`>|h zo`O>ffc2h?0A69aJxv|{gUm{=jC|)Fpfa$1=PbCgcG15NPE1iFgk?5oTIaM;`ga6E zMHV<+-~CDJz^rVWPjgI&QKnt;!#}6MD^+Z1>V*Bbn!fxB-TKrHVo$`W zN0Dj$OJo0eVyu&!>C2m4UO(Nr(ZyA4azvX`|L?m1miT-thBZ|zR}fI&_mj{=Ocu8! zZr4XNl5LmY#Nx8)*TKJp2&&Aer3~X&5PM~3=etA^OJFZj&rHGQwRYL6OByDMhxKf3AKFRW#ddijzCqfT79_n8T0^L>9khg%ToVhwlFmTW`Z#I5Amr<~}vx zDD7cO?k7QO?Gds7`&F`TvcPgnD<|6iJd9cEH)fnGK8%XmiNp=_SBzn8I=pd-nDv z#JsP^hI<0qZ*zxve~bDhxHHU(MqxYaAvHJm;m2AR4p(uAz1lk9y?v*G@KezRNNr$rY=ev!XAV=S}m51H&^>D3RTBtPWXk)G&%P`>)`=|Ew0 zA~RxDsG;)CxL&jRyo-zF_sTvvVjMEH{2QDpi_Slcmm}X)(SA$Oq^t=RO_K?{Wptcy z%E3_#PrP=_3}hA-Iw)8PIceiQ5hs$gP2cR_yyLQ+ z3L05%kXWu*!|-ICBngNv33ap!Cy0xG4s`4b3hM~9x>c4i_hQ&Nw;sPw66jlY5?ai9Y8Khv{Zqoj`2g*|2%ez(b=WBQHhfuaRrg8hP_NO{ z8T#52KxJO-w|6PQ_ej{tSZ=KmDe4~FdziMg>VhnpHThL>Z@D>YioDNLOS|WipKyl@ zMk7u0)%Ybw$SpQ}Muuv}>gdoXt?W;N8&g+1tmUUT(O15iA8|U7=sBo_yE_?Np48$y z3kSahbvt5qw!}S|7AX?VJv9Xj1P_U*NseE4&wvkwvQF-^?&qg9TVrg07B?8*mJ66+ zPt)QZXk;As09TV}B+(;0^p2+98>~u8;KH za|^>`2B#x4*v^IpUKgAbKu@<9GXmM0l*Ax`sZ8iGYnYDIQ^xU&C54Ucn_4LuR%-Zz z-01{el0OZ5B&#)Jz+b4l@jqiHZZx_3rS$^vZF>NTS3pIBjA!!>h>Zg0G3{@xUH%dJ z`SNy*SIS&6k7WOauZr#S50FP|5-LZoa_&kZkGF?%r4tH%l~3mK@JEcN44bJ_vXjR) z7@lxozXbL%J|A>n28j|kdWH4@8Z3R3_PQtEx3N>iPO@6zU{aljLL(Gew}0PYAMGWK zJG!o~m%sEaxqn+e$$u_x)Z;BHPTy4l*&aEid=1V9)6Zss-@u=k%dD<#E59h)Z?*3&k((=gJ%l}rH@8C*3cBm~nuP$X-uMNz=9 z?dKZ(wF1^&>d*(L2mnPtRbBjViZ7bK%uA`rCp_k5zUCiCaAvS>lWx(9Xr=S`P3TIH zvG;+aqINAU@v*rlQmD$JSLp6Aat5?^O6SZ=iZAV#@lnX5b$R5`Dl?T=0m~sn^Vi#- ze+Ys6%Yk=x`~$CeIqal+G*eBW$f&7PA#78*E#PX#m3CpR zsgk>nY2r@8` z^j5O+%u*^X?$n6K3cSQp;^9WzT;S^>aaS(tpE1RrNe7)j?XeItyGNb!{A#SwxOz0R zq0?S|!`30^;%}YBqrv-EI~D`WEnU!KloONWXilH^w{Un_u06l<&^`xPbss@$`&)$` z<#RAfK`GzuExiDWxM+dP%4TDnh&rsLYz%`agOIV=2|65wbD=rHgbz;!fTQMWGy1hE zN^N!8EKAqc_Mf|~X&xq6x{wm;GK6fT>6Ci7@P#bA;1Y|h*dQT|%H&dXaBZpBF6}3v zr(i8L{wl);_EiE3_i2JVB2UAl`VCL3ZsN5iMn)N;qwhA(<*NddZhG`TMW$jGwsjtb z_Nn5p$Qf-vjUW4|;J1xyc7K4mAIJE?ielf1M7=^VRI$|U*@K=)MHC7-7jmTBOq9U} zsYRovLnAvR6HMX;STd21h8dhVy*Fxcb8lmXjn>oNM}K;wP$qd3I}Q^j$6)f1QvX%M zCZepdZ1B?WeatS2jdo+~xDl}f^irdNG*JsEf@`7 zRKO9kWE%AZkO{=ZbSws)t;u)RN54BKj1k?-0Nf#goEmbhN1{<4C3`qkpN&oJRrcAyqsX;gWN8pgI}pywV% z6-*Bkt*NAh?(qr{aMp|g2*r>6aJYapif;D~?{1NyCVX!6e&ru{=8U*hWOUnCe~~g5 zc{arhF#~`(?egi>%nf^`pdw~;yDQtZ+*~pXa`ZbdB`CQl?NBbk40qT6%-ROFAk94P z4QT5D9BmJ!ZtF#XW ze9jEFU-^jFBydb_=M44r<{8pC;}0$S zQa)|}^nRbX6yrl|5qvr-O6!`AEB8xXJMe=EaU|EM*Fy^{VRdU<-PeJhp?H7YDma{> z?DzNhk%fh@()Fwzw%lx~`3qu3IO5 z0K-Rn;%XDjaW2D5PCOwSK!{d0)oEwieSp<;W?I5DrgMJQgXPzFQpFzO7^Dn(o*JkN zr@?PtU<3QJp{rMG9Zi!Z%xGCDh-^G=60z$(JkW#2RO^Qx6^d-_JGVT-KTd!Gzs$U^ zDmmfI?)qT-0Rb~gIv`LhvK6WKrZSh4?BRx|Idk~3XX0;?<3hqk=VLul9DGrMUl|1k4s|oP?KLrzwe1N-=SpJ&M9vLm;?Wb32;}g~=;ZU6))+?i zgSZYRMMmCpl{0#rr7^q|TP?}4PJ*?NpqQA@1a9HpsO>nlu2DbE0B=I`PGP4cRtSkyoo z>bu>=kSTLBSAnl;#83L6QQ{Ie0H_aw@tECPv4{ns;)~<=xESaTFGy>LIKnCpOc%mr zh&n{mmM2I*@?h8g^CNRN!k~;48wbjj<#m8A?d+=0J?22J+EkWRPk;|(sTHS@#%T*| zxcbn5-@hbHW>YONs~1=vG~rk))DN8k3wi-kEBQjcqFYbTptb^;hF^5hsH~U|*sYTi z%+`|oL)-||l6WQc)&Hg!t*IvGG1kW2pFDL>;@2qSv0q_a$ZMhF(?j z#ohHqtW8>|2{)eEP~J=;-gLXoSHw{D-x-|veMKWc6Kk<@3{( z7o|C(CLwI_iba_<(nsW|Q(dl?3_f?-L_iZYt;lDe{*6YBeJKCfghK{w2FruhO*}%D z#ri_E*?rxbo@RYB$Endg(CjHrYQie<-M4tx5;38KQ{+K;B1P)@OH7{LR5-J7+4IAzOtaNfl(Hvk!hLbY54&IUHECc9V`u!4sI4)ELk$W(NY_(3 zqj$;MO~-e~Y+i~Y3>gyRVW`~bD>Olt1tmZl*;TZj;Q!`ZXf_u0(WnM)?e{mcv7s>n zo~=N@6M#+$2eR)q18Pd1wvv_x#cxYIp_?11M>$SpBg=ThU@urT@(&Y%bm|mPiFT+l zEY+w>>%Xhu7V=YMnY{~RC6h*3)Zj2`e3H+5$YUc2R{K4<$f_UVZt_ncZ^oo`vz3c- zBf+Y7!YJQYx6O2^Z|E(oa>I%;9d;fi-LPOFxvhdI%qqFw)gCd!`kYgnwFq%@$Ln9K z?>@t>G8TI4`t0JDTD5j*?w10c)_9|&y{BV`fcG1OfcT%%{Q2B-7hf5rzDA>7$E;Ge zVs8#Nx3ltk?_}WZjX@vQ%^%~tn^pd3gzzY;MNFF<{Z*>aOhn-z6OcUN5Qwr?PFCV= za8HpdSZq4#B3>Kh>(`ipCx^k0g+fI4>wacl77z@ax+LJu>au$F#jR z!>44OmBjNUTxIg{ep&0Ox)z6^N8KE*J-$TI2fF9{{1-ZdK#-f}g}H)q}CCz`ExWF>|zp2r|6zX#IZjUc~{A%C152 zqb9Z?TkMA=A)K|4CBFLfb;)-{neP`(rQ4#J)M6?@GdTtXR!9{>JGIDbEFJ&%4!G)+ z_I+o|-Wsv8T^hH?R0MC{bA#vxNIOD1#x&X|O4K=! z7Qx(R2obe`byi9GE<}7yq;BXCbHdb7qy%5aL%B8N&c(p=TUlz}+G{}+$Dh(&rxRx&4IzZ+Ohj#9E3pDR)|MiBX#`!pUVgZ5f5jN(v%=B4$qCqwscKAW(Qo zuqCU=uzxtYKc%@CJGNa{MCnzia}7Rw$NA_kONZkL`` zJ)XRYt=<~{so!OUNGYCBEuU28}FN;CsuYF4$zaa{@zl5cCvEO%VASkdKIJ6HjQSZmICaukRMMwoH%2H63~3jm4nfDPA@ErY)wb- z@0hg~u%XaDmkkf8_E#a*s#(2Xvfx`KDev~59oB3_0D%mOC_#R;{PL#Hj8X_>=S66b zyo?!%%TL{(dq)iR*9AC%LlRvV3B4VO{8MRzstkmCcSE7SfriK9{4Prq!@r!wSNv72 z0Hq8YB)po0pV1qr`lr)y*~IKAU$inIC+m($vPYD`{?OTk*Nzj|MHOC!q7LTYI6S=I zN;COfG@2lw;vtoj$xI3#yvR8{A$u(TFz7FeGzQ>4`TgxM*WsCq>=eb$GLbgt^qAm} zugLg^agxfs!orf(cE80@e7tPhc^$|})~Jy{X{-P<$txz{f*Ku(358SVI*C>ZH*nTh zCZRiCisQD}4HS=Y$?Io!>23GkzOui{tSFXQyLKKEe?A+@HU8sQ(2tLc_x3Lsmd8iF z6gm18X1J~_7FVId2VI4A^P^E{21iJ+az1udaylp@nKlGl5Np54sgP$H)Ml|&f5=7d zPB+7e@>%ZRzL=P_dxv5V6!fu5PT(I+B!>fp1ZM2B-Y5T~6SbxHRr^-Wi*8U8SlnC0^D; zjpFrXY0P71b6nO#Zpx=85(^LFrV$nVz6dG55V3<#=ftZ{3cpDHG=?>uQaM54l)p1P zFZ||lBpdkpmd(Qf-#|T$GW^zY+OOc*;>((YV;^PWK&TLZ0HAJfuX-}|wviC${!vy<~rGg*BhOsG}JQx+PpdO(V;(sfi&U|23?jpR7Ch+v~TrX0H z<}gRU_4}3W)(8Psp#ZE7j$slMep~IE0y6q%2K_chPa*GwX~`bf{2Za3KAsn%uK2?r zIM|eukU0h$suFYX%)73m3Uz(6olld87-!*GuflD;)VPn}!q>8qcOJsQxt?n4cGx0t zF`}CO$NO&Zok-oa1l-8@Dav0&Pm#=eXfO(=R>rq$mXHD*sh&x&3msvKiVq1WR_7Ve z)7SiA1JA^^-_}^^Cx#~jFu?}43_DsrQw=Wbx=Hz4Zi*>I8#8FUKYACVwqUe0hOV;k zzY+KQ%j)iL6W@Ita%-xVsQmZ9<}YK`Z*4-dmtu`h4Nr~anlx#>=RF_zP_c7;-hskf z037}&G&1g$EWAq}{9TaZdiM#`w5R``fSr)|IY|JQ7+uGrDAW1*vev?rZGA)8(a#{X zXR|6_s${UzKou~5Q+={YbQSNsCs6a@e9r!81SQ9!C*74=YXuBKM$8L1-&E$u^Z1k< z+}+hqVzNa~YPDUDF>rt`%}TUA@l$i})i|XD`|>0?)77cID1=T@8{XxpjYXbj=#Kjj;#tjfdII`Psc9re^wbY>fy&|&PNvBq$f#GtT8s- zRN|$GaVKDf@4jA*G8Oj466pI5k@?PF)CvA2nr|#s0Rl7E7!qSZOUbyiYhF5ncy7_Q z5ZdCRHamOG9A_Qnj-B;vy-)@U2R{(Fn>|v2VvC?n^#s5h)JAZ~&q~3w#0OJFJbmr=>Lf&+@uHm zAKTKWY&1>1z9jP9gN<%I+neY=xGT93ofek>*xE|qvo||#FP~u+^lakl|4ED%|5Ich z$HCHwM9l-NvA&ixLv7_XQEaLC2T=m7DB`7nS#0FnT2n7=n{Te)zsIA9K=gTBdR&kWA=5MIqs2A4?P6NZ)cL468LY!4dc?M@y2#3!MPILhZKn zno|s?VHK^ZE6d%H;VL&EPZA7v>xIGt}q`dT7hmW zZvq&Wx5l8{Z0~Q@U~bSV(cOXGB0+H`e!^|NGOut4xD4oO%kw3*a^FSiVH6R=YL^L~ zrjH)co_wAk0Z4*so#AO7>q5K$r`bMot|n%EYr4CnWlmlx zg3tJK0NjYD4LS=-?aIgOtqGgr-U0;%+ui9aT9vYQ9NW3b-#h_`L-OmSO?ptikmG|p z4%eNZN6L!pb)tCsi{$Q1`ZK>l}2>WHn2C!T$FFoG;`<}U*$DC1-LxnT6$AjYbaysmT%cqB( ze!we438-=Au~y#u+2oRM)O^K{R>>1uLLz+Lu61#MK8GSc*akp7ISC8Et*dNiLEJ4%4wb~0a=+inG0jU!k8gWj9D9C;_Y57K>41sztMpLe;j<+eo4!%i&Faz})-D(AQGl~wXC zvzG4PKd@FDv#3v@OfC}@rNoU zTSD@vgMP)dGf+W|Zm3>Z?Zo0ewly2dDbmCAXw|y?ldVzuNn_|#%RQLl;EJ3S5AAer zRxNHi#Wv)+0-oC-uas#I5?dbxHz;$MeH2dbAjG=5kf> zjOr#6egJ=b?g5vSU%*>tXXeiq6QQ!{wcP)Trt@>J_H~UXjf**zGL#5H>|dHQ3tdjI!c74u$>$~oHSo=6FL9EYz3&VsP$ekF6i?E185B+c_{&5y zh8#c-Z2LSgPESwxn6cw{yBRNlMAKIpiMscHAi^6D9!w)WHWk(YZ4i$(;A5z>IcXe% w_+Z~+KNCesErL7X9ncOAO*6wW5Ko{t#aWQ>QW00+#t;z7$m&YfWla440Dm+@H~;_u literal 0 HcmV?d00001 diff --git a/assets/xfce.png b/assets/xfce.png new file mode 100644 index 0000000000000000000000000000000000000000..732c1056c95d7ada3d2fdaf5bef2b0dcc09fab18 GIT binary patch literal 3750 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 hSpQ$IpkI#|H72lmz1U, msg: impl Into) -> Self { + Self { name: name.into(), status: CheckStatus::Pass, message: msg.into() } + } + fn warn(name: impl Into, msg: impl Into) -> Self { + Self { name: name.into(), status: CheckStatus::Warn, message: msg.into() } + } + fn fail(name: impl Into, msg: impl Into) -> Self { + Self { name: name.into(), status: CheckStatus::Fail, message: msg.into() } + } +} + +// ───────────────────────────────────────────── +// TÜM KONTROLLERİ ÇALIŞTIR +// ───────────────────────────────────────────── + +pub fn run_all() -> Vec { + vec![ + check_ram(), + check_disk_space(), + check_internet(), + check_boot_mode(), + check_cpu_arch(), + check_live_env(), + check_nvme_support(), + ] +} + +/// Tüm kontroller geçti mi? (Fail yoksa true) +pub fn all_passed(results: &[CheckResult]) -> bool { + results.iter().all(|r| r.status != CheckStatus::Fail) +} + +// ───────────────────────────────────────────── +// BİREYSEL KONTROLLER +// ───────────────────────────────────────────── + +/// RAM kontrolü. Minimum 1 GB, önerilen 2 GB. +fn check_ram() -> CheckResult { + let mut sys = System::new(); + sys.refresh_memory(); + let mb = sys.total_memory() / 1024 / 1024; + + if mb < 1024 { + CheckResult::fail( + t!("check_ram"), + t!("check_ram_fail", mb = mb) + ) + } else if mb < 2048 { + CheckResult::warn( + t!("check_ram"), + t!("check_ram_warn", mb = mb) + ) + } else { + CheckResult::pass(t!("check_ram"), t!("check_ram_pass", mb = mb)) + } +} + +/// En az 10 GB boş disk alanı kontrolü. +fn check_disk_space() -> CheckResult { + use sysinfo::Disks; + let disks = Disks::new_with_refreshed_list(); + let max_gb = disks.iter() + .map(|d| d.total_space() / 1024 / 1024 / 1024) + .max() + .unwrap_or(0); + + if max_gb < 10 { + CheckResult::fail( + t!("check_disk_space"), + t!("check_disk_fail", size = max_gb), + ) + } else if max_gb < 20 { + CheckResult::warn( + t!("check_disk_space"), + t!("check_disk_warn", size = max_gb), + ) + } else { + CheckResult::pass(t!("check_disk_space"), t!("check_disk_pass", size = max_gb)) + } +} + +/// İnternet bağlantısı kontrolü (isteğe bağlı). +fn check_internet() -> CheckResult { + // DNS çözümlemesi ile basit kontrol + let connected = std::net::TcpStream::connect_timeout( + &"8.8.8.8:53".parse().unwrap(), + std::time::Duration::from_secs(3), + ).is_ok(); + + if connected { + CheckResult::pass(t!("check_internet"), t!("check_net_pass")) + } else { + CheckResult::warn( + t!("check_internet"), + t!("check_net_warn"), + ) + } +} + +/// UEFI mi BIOS mu? +fn check_boot_mode() -> CheckResult { + if Path::new("/sys/firmware/efi").exists() { + CheckResult::pass(t!("check_boot_mode"), t!("check_uefi_pass")) + } else { + CheckResult::pass(t!("check_boot_mode"), t!("check_bios_pass")) + } +} + +/// CPU mimarisi kontrolü (yalnızca x86_64 destekleniyor). +fn check_cpu_arch() -> CheckResult { + let arch = std::env::consts::ARCH; + if arch == "x86_64" { + // CPU özelliklerini de kontrol et + let cpuinfo = std::fs::read_to_string("/proc/cpuinfo").unwrap_or_default(); + let has_sse2 = cpuinfo.contains("sse2"); + if has_sse2 { + CheckResult::pass(t!("check_cpu"), t!("check_cpu_pass")) + } else { + CheckResult::warn(t!("check_cpu"), t!("check_cpu_warn")) + } + } else { + CheckResult::fail( + t!("check_cpu"), + t!("check_cpu_fail", arch = arch) + ) + } +} + +/// Canlı sistem ortamı kontrolü. +fn check_live_env() -> CheckResult { + let source = "/run/livecd/squashfs-root"; + if !Path::new(source).exists() { + CheckResult::fail( + t!("check_live_sys"), + t!("check_live_fail"), + ) + } else { + CheckResult::pass( + t!("check_live_sys"), + t!("check_live_pass"), + ) + } +} + +/// NVMe ve diğer modern disk arayüzlerinin çekirdek desteğini kontrol eder. +fn check_nvme_support() -> CheckResult { + // /dev/nvme* cihazları var mı? + let has_nvme_dev = std::fs::read_dir("/dev") + .map(|dir| dir.flatten().any(|e| e.file_name().to_string_lossy().starts_with("nvme"))) + .unwrap_or(false); + + // Çekirdek modülü yüklü mü? + let modules = std::fs::read_to_string("/proc/modules").unwrap_or_default(); + let nvme_loaded = modules.contains("nvme "); + + if has_nvme_dev { + CheckResult::pass(t!("check_nvme"), t!("check_nvme_pass1")) + } else if nvme_loaded { + CheckResult::pass(t!("check_nvme"), t!("check_nvme_pass2")) + } else { + // NVMe yoksa bu bir sorun değil; SATA/virtio kullanılıyor olabilir + CheckResult::pass(t!("check_nvme"), t!("check_nvme_pass3")) + } +} + diff --git a/src/autoinstall/mod.rs b/src/autoinstall/mod.rs new file mode 100644 index 0000000..2677286 --- /dev/null +++ b/src/autoinstall/mod.rs @@ -0,0 +1,216 @@ +//! Otomatik kurulum (answer file) desteği. +//! +//! Kullanım: +//! yali-rs --auto-install /path/to/answer.toml +//! +//! Answer file formatı (TOML): +//! +//! [install] +//! disk = "/dev/sda" +//! timezone = "Europe/Istanbul" +//! locale = "tr_TR.UTF-8" +//! keyboard = "tr" +//! +//! [user] +//! username = "pisi" +//! password = "changeme" +//! hostname = "pisilinux" + +use serde::Deserialize; +use std::path::Path; + +pub mod checker; + +// ───────────────────────────────────────────── +// ANSWER FILE YAPISI +// ───────────────────────────────────────────── + +#[derive(Debug, Deserialize)] +pub struct AnswerFile { + pub install: InstallConfig, + pub user: UserConfig, +} + +#[derive(Debug, Deserialize)] +pub struct InstallConfig { + /// Hedef disk aygıtı. Örn: "/dev/sda", "/dev/nvme0n1" + pub disk: String, + + /// Zaman dilimi. Örn: "Europe/Istanbul" + #[serde(default = "default_timezone")] + pub timezone: String, + + /// Sistem locale. Örn: "tr_TR.UTF-8" + #[serde(default = "default_locale")] + pub locale: String, + + /// Klavye düzeni. Örn: "tr" + #[serde(default = "default_keyboard")] + pub keyboard: String, + + /// Klavye varyantı. Örn: "f" (Türkçe F için) + #[serde(default)] + pub keyboard_variant: String, + + /// Kaynak dizin (canlı sistem). Varsayılan: /run/livecd/squashfs-root/ + #[serde(default = "default_source")] + pub source: String, + + /// Hedef bağlama noktası. Varsayılan: /mnt + #[serde(default = "default_mount")] + pub mount: String, +} + +#[derive(Debug, Deserialize)] +pub struct UserConfig { + pub username: String, + pub password: String, + pub hostname: String, +} + +fn default_timezone() -> String { "Europe/Istanbul".into() } +fn default_locale() -> String { "tr_TR.UTF-8".into() } +fn default_keyboard() -> String { "tr".into() } +fn default_source() -> String { "/run/livecd/squashfs-root/".into() } +fn default_mount() -> String { "/mnt".into() } + +// ───────────────────────────────────────────── +// DOĞRULAMA +// ───────────────────────────────────────────── + +#[derive(Debug)] +pub enum AnswerError { + Io(std::io::Error), + Parse(toml::de::Error), + Validation(Vec), +} + +impl std::fmt::Display for AnswerError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AnswerError::Io(e) => write!(f, "Dosya okuma hatası: {}", e), + AnswerError::Parse(e) => write!(f, "TOML ayrıştırma hatası: {}", e), + AnswerError::Validation(v) => write!(f, "Doğrulama hataları:\n{}", v.join("\n")), + } + } +} + +/// Answer dosyasını okuyup ayrıştırır ve doğrular. +pub fn load(path: &Path) -> Result { + let content = std::fs::read_to_string(path) + .map_err(AnswerError::Io)?; + + let af: AnswerFile = toml::from_str(&content) + .map_err(AnswerError::Parse)?; + + validate(&af)?; + Ok(af) +} + +fn validate(af: &AnswerFile) -> Result<(), AnswerError> { + let mut errors: Vec = Vec::new(); + + // Disk kontrolü + if !af.install.disk.starts_with("/dev/") { + errors.push(format!( + "Geçersiz disk yolu '{}'. '/dev/' ile başlamalı.", + af.install.disk + )); + } + if !Path::new(&af.install.disk).exists() { + errors.push(format!( + "Disk '{}' bulunamadı. Mevcut diskler için 'lsblk' komutunu çalıştırın.", + af.install.disk + )); + } + + // Kullanıcı adı doğrulaması (UsersStep ile aynı kural) + let un = &af.user.username; + if un.is_empty() || un.len() > 32 { + errors.push("Kullanıcı adı 1–32 karakter arasında olmalı.".into()); + } else { + let valid = un.chars().next().map(|c| c.is_ascii_lowercase() || c == '_').unwrap_or(false) + && un.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-'); + if !valid { + errors.push(format!( + "Geçersiz kullanıcı adı '{}'. Yalnızca küçük harf, rakam, - ve _ kullanılabilir.", + un + )); + } + } + + // Şifre uzunluğu + if af.user.password.len() < 6 { + errors.push("Şifre en az 6 karakter olmalı.".into()); + } + + // Hostname + let hn = &af.user.hostname; + if hn.is_empty() || hn.len() > 63 || hn.starts_with('-') || hn.ends_with('-') + || !hn.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') + { + errors.push(format!("Geçersiz hostname '{}'.", hn)); + } + + if errors.is_empty() { Ok(()) } else { Err(AnswerError::Validation(errors)) } +} + +// ───────────────────────────────────────────── +// GLOBALSTATE'E UYGULA +// ───────────────────────────────────────────── + +use crate::installer::GlobalState; +use crate::steps::partition::PartitionStep; +use crate::installer::InstallerStep; + +/// Answer file verilerini `GlobalState`'e yazar. +/// Bu işlemden sonra `PartitionStep::on_enter()` çağrılarak +/// disk listesi yenilenebilir ve plan oluşturulabilir. +pub fn apply_to_state(af: &AnswerFile, state: &mut GlobalState) { + state.timezone = af.install.timezone.clone(); + state.keyboard_layout = af.install.keyboard.clone(); + state.keyboard_variant = af.install.keyboard_variant.clone(); + state.selected_disk = Some(af.install.disk.clone()); + state.erase_disk = true; + state.username = af.user.username.clone(); + state.password = af.user.password.clone(); + state.password_confirm = af.user.password.clone(); + state.hostname = af.user.hostname.clone(); + + // Locale'den dil kodunu çıkar: "tr_TR.UTF-8" → "tr" + state.language = af.install.locale + .split('_') + .next() + .unwrap_or("tr") + .to_string(); + + // Bölümleme planını hesapla + let is_uefi = Path::new("/sys/firmware/efi").exists(); + let mut ps = PartitionStep::default(); + ps.on_enter(state); + + // Seçili diski bul ve plan oluştur + if let Some(disk) = state.available_disks.iter().find(|d| d.name == af.install.disk).cloned() { + use crate::installer::{PartitionPlan, PartitionTableType}; + let total_mb = disk.size_bytes / 1024 / 1024; + let efi_mb = if is_uefi { 512 } else { 0 }; + let swap_mb = recommended_swap_mb(); + let root_mb = total_mb.saturating_sub(efi_mb + swap_mb + 512); + state.partition_plan = Some(PartitionPlan { + disk: disk.name.clone(), + table_type: if is_uefi { PartitionTableType::Gpt } else { PartitionTableType::Mbr }, + efi_mb, + swap_mb, + root_mb, + }); + } +} + +fn recommended_swap_mb() -> u64 { + use sysinfo::System; + let mut sys = System::new(); + sys.refresh_memory(); + let ram_mb = sys.total_memory() / 1024 / 1024; + let swap = if ram_mb <= 2048 { ram_mb } else if ram_mb <= 8192 { ram_mb / 2 } else { 4096 }; + swap.clamp(512, 8192) +} diff --git a/src/installer.rs b/src/installer.rs new file mode 100644 index 0000000..25d8a16 --- /dev/null +++ b/src/installer.rs @@ -0,0 +1,324 @@ +use eframe::egui; +use rust_i18n::t; + +/// Disk adı ve bölüm numarasından tam aygıt yolunu oluşturur. +/// +/// - SATA/SCSI: `/dev/sda` + 1 → `/dev/sda1` +/// - NVMe: `/dev/nvme0n1` + 1 → `/dev/nvme0n1p1` +/// - MMC: `/dev/mmcblk0` + 1 → `/dev/mmcblk0p1` +pub fn part_path(disk: &str, num: u32) -> String { + let needs_p = disk.contains("nvme") || disk.contains("mmcblk") || disk.contains("loop"); + if needs_p { + format!("{}p{}", disk, num) + } else { + format!("{}{}", disk, num) + } +} + + +/// Calamares'in "ViewStep" yapısına benzer bir Trait. +pub trait InstallerStep { + fn name(&self) -> String; + fn on_enter(&mut self, _state: &mut GlobalState) {} + fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState); + fn is_complete(&self, state: &GlobalState) -> bool; +} + +// ───────────────────────────────────────────── +// VERİ YAPILARI +// ───────────────────────────────────────────── + +#[derive(Clone, Debug)] +pub struct DiskInfo { + pub name: String, // ör. "/dev/sda" + pub model: String, + pub size_gb: u64, + pub size_bytes: u64, +} + +/// Otomatik bölümleme planı. +/// Disk seçimi yapılınca hesaplanır; Özet ekranında gösterilir. +#[derive(Clone, Debug, Default)] +pub struct PartitionPlan { + pub disk: String, + pub table_type: PartitionTableType, // GPT veya MBR + pub efi_mb: u64, // 0 → BIOS, >0 → UEFI + pub swap_mb: u64, + pub root_mb: u64, // kalan alan +} + +#[derive(Clone, Debug, Default, PartialEq)] +pub enum PartitionTableType { + #[default] + Gpt, + Mbr, +} + +impl std::fmt::Display for PartitionTableType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PartitionTableType::Gpt => write!(f, "GPT"), + PartitionTableType::Mbr => write!(f, "MBR"), + } + } +} + +/// Manuel bölümleme için desteklenen dosya sistemleri. +#[derive(Clone, Debug, PartialEq)] +pub enum FsType { + Ext4, + Btrfs, + Xfs, + Fat32, // EFI bölümü için + Swap, +} + +impl FsType { + pub fn label(&self) -> &'static str { + match self { + FsType::Ext4 => "ext4", + FsType::Btrfs => "btrfs", + FsType::Xfs => "xfs", + FsType::Fat32 => "FAT32 (EFI)", + FsType::Swap => "swap", + } + } + +} + +impl std::fmt::Display for FsType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.label()) + } +} + +/// Kullanıcının manuel olarak tanımladığı tek bir bölüm. +#[derive(Clone, Debug)] +pub struct CustomPartition { + /// Bölüm aygit adı; oluşturulacak (ör. "/dev/sda1") + pub device: String, + /// Boyut MB cinsinden; 0 = "kalan alan" + pub size_mb: u64, + /// Dosya sistemi + pub fstype: FsType, + /// Bağlama noktası; swap için "swap" + pub mountpoint: String, +} + +/// Kurulum boyunca toplanan tüm veriler. +pub struct GlobalState { + pub language: String, + pub timezone: String, + pub selected_disk: Option, + pub erase_disk: bool, + pub partition_plan: Option, + /// Manuel bölümleme modu için kullanıcının tanımladığı bölümler. + pub custom_partitions: Vec, + pub keyboard_layout: String, + pub keyboard_variant: String, + pub username: String, + pub password: String, + pub password_confirm: String, + pub hostname: String, + pub current_step: usize, + pub available_disks: Vec, + pub install_progress: f32, + pub install_log: Vec, + pub demo_mode: bool, + pub is_dark: bool, +} + +impl Default for GlobalState { + fn default() -> Self { + Self { + language: "tr".to_string(), + timezone: "Europe/Istanbul".to_string(), + selected_disk: None, + erase_disk: true, + partition_plan: None, + custom_partitions: Vec::new(), + keyboard_layout: "tr".to_string(), + keyboard_variant: String::new(), + username: String::new(), + password: String::new(), + password_confirm: String::new(), + hostname: String::new(), + current_step: 0, + available_disks: Vec::new(), + install_progress: 0.0, + install_log: Vec::new(), + demo_mode: false, + is_dark: true, + } + } +} + +// ───────────────────────────────────────────── +// WELCOME STEP (sistem gereksinimleri + dil seçimi) +// ───────────────────────────────────────────── + +use crate::autoinstall::checker::{CheckResult, CheckStatus, run_all, all_passed}; + +pub struct WelcomeStep { + checks: Vec, + checked: bool, + last_language: String, +} + +impl Default for WelcomeStep { + fn default() -> Self { + Self { checks: Vec::new(), checked: false, last_language: String::new() } + } +} + +impl InstallerStep for WelcomeStep { + fn name(&self) -> String { t!("welcome").to_string() } + + fn on_enter(&mut self, state: &mut GlobalState) { + if !self.checked || self.last_language != state.language { + rust_i18n::set_locale(&state.language); + self.checks = run_all(); + self.checked = true; + self.last_language = state.language.clone(); + } + } + + fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) { + use crate::ui::theme; + + if self.last_language != state.language { + rust_i18n::set_locale(&state.language); + self.checks = run_all(); + self.last_language = state.language.clone(); + } + + theme::section_heading(ui, &t!("welcome_title")); + ui.label( + egui::RichText::new(t!("welcome_description")) + .color(theme::c_text_dim()) + .size(13.0), + ); + + ui.add_space(12.0); + + // Dil seçimi (Açılır Liste / ComboBox) + ui.horizontal(|ui| { + ui.label(t!("select_language")); + let current_lang_label = if state.language == "tr" { "🇹🇷 Türkçe" } else { "🇺🇸 English" }; + egui::ComboBox::from_id_source("language_select") + .selected_text(current_lang_label) + .show_ui(ui, |ui| { + ui.selectable_value(&mut state.language, "tr".to_string(), "🇹🇷 Türkçe"); + ui.selectable_value(&mut state.language, "en".to_string(), "🇺🇸 English"); + }); + }); + + ui.add_space(14.0); + ui.separator(); + ui.add_space(10.0); + + ui.label( + egui::RichText::new(t!("system_checks_title")) + .size(15.0) + .strong() + .color(theme::c_text()), + ); + ui.add_space(6.0); + + // Kontrol tablosu + egui::Grid::new("checks_grid") + .num_columns(3) + .spacing([10.0, 6.0]) + .striped(true) + .show(ui, |ui| { + for check in &self.checks { + // Durum simgesi + renk + let (icon, color) = match check.status { + CheckStatus::Pass => ("✅", theme::c_success()), + CheckStatus::Warn => ("⚠️", theme::c_warning()), + CheckStatus::Fail => ("❌", theme::c_error()), + }; + ui.colored_label(color, icon); + ui.strong(&check.name); + ui.label( + egui::RichText::new(&check.message) + .size(12.0) + .color(theme::c_text_dim()), + ); + ui.end_row(); + } + }); + + // Hata varsa uyarı + ui.add_space(10.0); + let has_fail = self.checks.iter().any(|c| c.status == CheckStatus::Fail); + if has_fail { + theme::error_box(ui, &t!("check_fail_warning")); + } else if self.checks.iter().any(|c| c.status == CheckStatus::Warn) { + theme::warning_box(ui, &t!("check_warn_notice")); + } else if !self.checks.is_empty() { + theme::success_box(ui, &t!("check_all_pass")); + } + + // Yeniden tara butonu + ui.add_space(8.0); + if ui.add(theme::secondary_button(&t!("recheck"))).clicked() { + self.checked = false; + self.on_enter(state); + } + } + + fn is_complete(&self, state: &GlobalState) -> bool { + // Demo modunda her zaman ileri gitmeye izin ver + if state.demo_mode { + return true; + } + // Fail varsa ilerleyemez; kontroller bitmemişse de bekle + !self.checks.is_empty() && all_passed(&self.checks) + } +} + +// ───────────────────────────────────────────── +// LOCATION STEP +// ───────────────────────────────────────────── + +pub struct LocationStep { + search_query: String, + timezones: Vec, +} + +impl Default for LocationStep { + fn default() -> Self { + let tz_list = vec![ + "Africa/Cairo", "America/Argentina/Buenos_Aires", "America/New_York", + "America/Sao_Paulo", "Asia/Baku", "Asia/Dubai", "Asia/Istanbul", + "Asia/Tokyo", "Australia/Sydney", "Europe/Berlin", "Europe/Istanbul", + "Europe/London", "Europe/Moscow", "Europe/Paris", "Europe/Rome", + "Pacific/Auckland", + ].iter().map(|s| s.to_string()).collect(); + Self { search_query: String::new(), timezones: tz_list } + } +} + +impl InstallerStep for LocationStep { + fn name(&self) -> String { t!("location").to_string() } + + fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) { + ui.heading(t!("location_title")); + ui.label(t!("location_description")); + ui.add_space(10.0); + ui.label(t!("search_timezone")); + ui.text_edit_singleline(&mut self.search_query); + ui.add_space(5.0); + egui::ScrollArea::vertical().max_height(300.0).show(ui, |ui| { + for tz in &self.timezones { + if tz.to_lowercase().contains(&self.search_query.to_lowercase()) { + ui.selectable_value(&mut state.timezone, tz.clone(), tz); + } + } + }); + } + + fn is_complete(&self, state: &GlobalState) -> bool { !state.timezone.is_empty() } +} + diff --git a/src/jobs/mod.rs b/src/jobs/mod.rs new file mode 100644 index 0000000..8d88b52 --- /dev/null +++ b/src/jobs/mod.rs @@ -0,0 +1,1313 @@ +//! Kurulum iş kuyruğu. +//! +//! Mimari: +//! egui (ana iş parçacığı) +//! └─► std::thread::spawn +//! └─► tokio::runtime::Runtime::block_on +//! └─► JobQueue::run_all ─► std::sync::mpsc::Sender +//! +//! egui her frame'de `Receiver::try_recv` ile kuyruktan mesaj okur. +//! `egui::Context::request_repaint()` arka plan iş parçacığından çağrılarak +//! UI'nin hemen güncellenmesi sağlanır. + + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc; +use tokio::process::Command; +use rust_i18n::t; + +// ───────────────────────────────────────────── +// MESAJ TİPİ +// ───────────────────────────────────────────── + +/// Arka plan iş parçacığından UI'ye gönderilen mesajlar. +#[derive(Debug)] +pub enum InstallMessage { + /// Bir log satırı. + Log(String), + /// Genel ilerleme; 0.0–1.0 arasında. + Progress(f32), + /// Tüm işler başarıyla tamamlandı. + Done, + /// Bir iş başarısız oldu; kurulum durdu. + Error(String), +} + +/// `mpsc::Sender` ile `egui::Context` birlikte taşır. +/// Her mesaj gönderiminde `request_repaint()` çağrısı UI'yi uyandırır. +#[derive(Clone)] +pub struct UiSender { + tx: mpsc::Sender, + ctx: eframe::egui::Context, +} + +impl UiSender { + pub fn new(tx: mpsc::Sender, ctx: eframe::egui::Context) -> Self { + Self { tx, ctx } + } + + pub fn send(&self, msg: InstallMessage) { + let _ = self.tx.send(msg); + self.ctx.request_repaint(); + } + + pub fn log(&self, s: impl Into) { + self.send(InstallMessage::Log(s.into())); + } +} + +// ───────────────────────────────────────────── +// JOB TRAIT +// ───────────────────────────────────────────── + +#[async_trait::async_trait] +pub trait Job: Send + Sync { + fn name(&self) -> &str; + /// İşi asenkron olarak çalıştırır. + /// Hata durumunda `Err(açıklama)` döner; kuyruk durur. + async fn run(&self, ui: &UiSender) -> Result<(), String>; +} + +// ───────────────────────────────────────────── +// JOB QUEUE +// ───────────────────────────────────────────── + +pub struct JobQueue { + jobs: Vec>, +} + +impl JobQueue { + pub fn new(jobs: Vec>) -> Self { + Self { jobs } + } + + /// Tüm işleri sırayla çalıştırır. + /// İlerleme ve loglar `ui` üzerinden UI'ye iletilir. + pub async fn run_all(&mut self, ui: UiSender) { + let total = self.jobs.len(); + + for (i, job) in self.jobs.iter().enumerate() { + let localized_name = t!(job.name()); + ui.log(format!("▶ {} başlatıldı…", localized_name)); + + match job.run(&ui).await { + Ok(()) => { + ui.log(format!("✓ {} tamamlandı.", localized_name)); + } + Err(e) => { + let msg = format!("✗ {} başarısız: {}", localized_name, e); + ui.log(msg.clone()); + ui.send(InstallMessage::Error(msg)); + return; + } + } + + let progress = (i + 1) as f32 / total as f32; + ui.send(InstallMessage::Progress(progress)); + } + + ui.send(InstallMessage::Done); + } +} + +// ───────────────────────────────────────────── +// SOMUT JOB'LAR +// ───────────────────────────────────────────── + +/// Sistem dosyalarını kopyala (rsync). +pub struct CopyFilesJob { + /// Canlı sistemin kök dizini; ör. "/run/livecd/squashfs-root/" + pub source: String, + /// Hedef bağlama noktası; ör. "/mnt" + pub target: String, +} + +#[async_trait::async_trait] +impl Job for CopyFilesJob { + fn name(&self) -> &str { "job_copy_files" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + ui.log(format!("rsync {} → {}", self.source, self.target)); + + // --info=progress2 ham çıktı verir; gerçek uygulamada + // satır satır parse edilerek ilerleme güncellenebilir. + run_cmd("rsync", &[ + "-aAXH", + "--info=progress2", + "--exclude=/proc", + "--exclude=/sys", + "--exclude=/dev", + "--exclude=/run", + &self.source, + &self.target, + ]).await?; + + Ok(()) + } +} + +/// /proc, /sys, /dev, /dev/pts dizinlerini chroot hedefine bind-mount yapar. +/// Standart `chroot` için gereklidir; kurulum başında çağrılmalıdır. +pub struct MountBindJob { + pub mount: String, // ör. "/mnt" +} + +#[async_trait::async_trait] +impl Job for MountBindJob { + fn name(&self) -> &str { "job_mount_bind" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + let mt = &self.mount; + // (kaynak, hedef) — kaynak sistem üzerindeki gerçek path + let bind_dirs = [ + ("/proc", format!("{}/proc", mt)), + ("/sys", format!("{}/sys", mt)), + ("/dev", format!("{}/dev", mt)), + ("/dev/pts", format!("{}/dev/pts", mt)), + ("/run", format!("{}/run", mt)), // COMAR/dbus için gerekli + ]; + for (src, target) in &bind_dirs { + run_cmd("mkdir", &["-p", target]).await?; + ui.log(format!("mount --bind {} {}", src, target)); + run_cmd("mount", &["--bind", src, target]).await?; + } + + // efivarfs — UEFI kurulumunda grub-install için zorunlu + let efivarfs_target = format!("{}/sys/firmware/efi/efivars", mt); + if std::path::Path::new("/sys/firmware/efi/efivars").exists() { + run_cmd("mkdir", &["-p", &efivarfs_target]).await?; + ui.log(format!("mount --bind /sys/firmware/efi/efivars {}", efivarfs_target)); + run_cmd("mount", &["--bind", "/sys/firmware/efi/efivars", &efivarfs_target]).await?; + } + Ok(()) + } +} + +/// Bind-mount'ları temizler (kurulum sonunda çağrılır). +pub struct UnmountBindJob { + pub mount: String, +} + +#[async_trait::async_trait] +impl Job for UnmountBindJob { + fn name(&self) -> &str { "job_umount_bind" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + let mt = &self.mount; + // Ters sırada umount — en derin path önce + let subdirs = [ + "sys/firmware/efi/efivars", + "dev/pts", + "dev", + "run", + "sys", + "proc", + ]; + for subdir in &subdirs { + let target = format!("{}/{}", mt, subdir); + ui.log(format!("umount {}", target)); + // Hata görmezden gel; bazıları zaten unmount olmuş olabilir + let _ = tokio::process::Command::new("umount") + .arg("-lf").arg(&target).status().await; + } + Ok(()) + } +} + +/// initramfs yeniler (GRUB öncesi zorunlu). +/// PisiLinux `dracut` kullanıyorsa `dracut -f --regenerate-all`, +/// mkinitcpio kullanıyorsa `mkinitcpio -P`. +pub struct GenerateInitramfsJob { + pub mount: String, +} + +#[async_trait::async_trait] +impl Job for GenerateInitramfsJob { + fn name(&self) -> &str { "job_initramfs" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + ui.log("initramfs oluşturuluyor (dracut)…"); + // Önce dracut'u dene (PisiLinux), hata verirse mkinitcpio dene + let dracut = run_chroot(&self.mount, &[ + "dracut", "-f", "--regenerate-all", + ]).await; + if dracut.is_err() { + ui.log("dracut başarısız, mkinitcpio deneniyor…"); + run_chroot(&self.mount, &["mkinitcpio", "-P"]).await?; + } + Ok(()) + } +} + + + +/// GRUB bootloader kurulumu (UEFI veya BIOS). +pub struct InstallGrubJob { + pub disk: String, + pub mount: String, + pub is_uefi: bool, +} + +#[async_trait::async_trait] +impl Job for InstallGrubJob { + fn name(&self) -> &str { "job_bootloader" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + // Chroot içinde grub2-install çalıştır (UEFI veya BIOS) + let mut grub_args = vec!["grub2-install"]; + let efi_dir_arg; + let disk_arg; + + if self.is_uefi { + ui.log("GRUB UEFI modu kuruluyor (chroot içinde)…"); + efi_dir_arg = "--efi-directory=/boot/efi".to_string(); + grub_args.extend_from_slice(&[ + "--target=x86_64-efi", + &efi_dir_arg, + "--bootloader-id=PisiLinux", + "--recheck", + ]); + } else { + ui.log(format!("GRUB BIOS modu {} diskine kuruluyor (chroot içinde)…", self.disk)); + disk_arg = self.disk.clone(); + grub_args.extend_from_slice(&[ + "--target=i386-pc", + &disk_arg, + "--recheck", + ]); + } + + run_chroot(&self.mount, &grub_args).await?; + + ui.log("grub2-mkconfig çalıştırılıyor…"); + run_chroot(&self.mount, &[ + "grub2-mkconfig", "-o", "/boot/grub2/grub.cfg", + ]).await?; + + Ok(()) + } +} + +// ───────────────────────────────────────────── +// YARDIMCI: KOMUT ÇALIŞTIRICI +// ───────────────────────────────────────────── + +static DEMO_MODE: AtomicBool = AtomicBool::new(false); + +/// Disk adı ve bölüm numarasından tam aygıt yolunu oluşturur. +/// +/// - SATA/SCSI: `/dev/sda` + 1 → `/dev/sda1` +/// - NVMe: `/dev/nvme0n1` + 1 → `/dev/nvme0n1p1` +/// - MMC: `/dev/mmcblk0` + 1 → `/dev/mmcblk0p1` +fn part_path(disk: &str, num: u32) -> String { + crate::installer::part_path(disk, num) +} + + +/// Başarısızlık durumunda stderr'i hata mesajı olarak döner. +async fn run_cmd(program: &str, args: &[&str]) -> Result<(), String> { + if DEMO_MODE.load(Ordering::Relaxed) { + tokio::time::sleep(std::time::Duration::from_millis(3000)).await; + return Ok(()); + } + + let output = Command::new(program) + .args(args) + .output() + .await + .map_err(|e| format!("{} çalıştırılamadı: {}", program, e))?; + + if output.status.success() { + Ok(()) + } else { + let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); + let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string(); + Err(if stderr.is_empty() { stdout } else { stderr }) + } +} + +/// Standart `chroot` ile verilen komutu hedef dizinde çalıştırır. +/// Bind-mount'ların önceden yapılmış olduğu varsayılır (MountBindJob). +async fn run_chroot(mount: &str, cmd: &[&str]) -> Result<(), String> { + if DEMO_MODE.load(Ordering::Relaxed) { + tokio::time::sleep(std::time::Duration::from_millis(2000)).await; + return Ok(()); + } + + // chroot [cmd[1..]...] + let mut args = vec![mount]; + args.extend_from_slice(cmd); + + let output = Command::new("chroot") + .args(&args) + .output() + .await + .map_err(|e| format!("chroot çalıştırılamadı: {}", e))?; + + if output.status.success() { + Ok(()) + } else { + let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); + let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string(); + Err(if stderr.is_empty() { stdout } else { stderr }) + } +} + +/// ISO ortamında canlı sistemin kaynak dizinini otomatik tespit eder. +/// Bulunamazsa varsayılan yolu döner. +pub fn detect_source_dir() -> String { + let candidates = [ + "/mnt/sqfs", //Pisilinux default + "/run/livecd/squashfs-root", + "/run/live/medium", + "/lib/live/mount/rootfs", + "/mnt/livecd", + ]; + for path in &candidates { + if std::path::Path::new(path).exists() { + return format!("{}/", path); + } + } + "/run/livecd/squashfs-root/".to_string() +} + +// ───────────────────────────────────────────── +// FABRİKA: STANDART KURULUM KUYRUĞU +// ───────────────────────────────────────────── + +/// `GlobalState`'ten derlenen standart kurulum kuyruğu. +/// +/// # Parametreler +/// - `disk` — hedef disk aygıtı (ör. "/dev/sda") +/// - `mount` — bağlama noktası (ör. "/mnt") +/// - `source` — canlı sistem kök dizini (ör. "/run/livecd/squashfs-root/") +/// - `is_uefi` — UEFI mi BIOS mu? +/// - `locale` — sistem yerel ayarı (ör. "tr_TR.UTF-8") +/// - `timezone`— zaman dilimi (ör. "Europe/Istanbul") + +// ───────────────────────────────────────────── +// PARTITION JOB (otomatik bölümleme) +// ───────────────────────────────────────────── + +use crate::installer::{PartitionPlan, PartitionTableType}; + +/// `parted` ve `mkfs` araçlarını kullanarak diski otomatik bölümlendirir. +/// Plan, PartitionStep'te hesaplanmış ve GlobalState'te saklanmıştır. +pub struct PartitionJob { + pub plan: PartitionPlan, +} + +#[async_trait::async_trait] +impl Job for PartitionJob { + fn name(&self) -> &str { "job_partition" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + let disk = &self.plan.disk; + let is_gpt = self.plan.table_type == PartitionTableType::Gpt; + + // 1. Bölüm tablosu oluştur + let table_label = if is_gpt { "gpt" } else { "msdos" }; + ui.log(format!("parted {} mktable {}", disk, table_label)); + run_cmd("parted", &["-s", disk, "mktable", table_label]).await?; + + let mut next_mb: u64 = 1; // İlk MB'ı boot kayıtları için bırak + + // 2. EFI bölümü (yalnızca GPT/UEFI) + if self.plan.efi_mb > 0 { + let end_mb = next_mb + self.plan.efi_mb; + ui.log(format!("EFI bölümü oluşturuluyor: {}–{} MB", next_mb, end_mb)); + run_cmd("parted", &[ + "-s", disk, "mkpart", "primary", "fat32", + &format!("{}MB", next_mb), &format!("{}MB", end_mb), + ]).await?; + run_cmd("parted", &["-s", disk, "set", "1", "esp", "on"]).await?; + next_mb = end_mb; + } + + // 3. Swap bölümü + let swap_end = next_mb + self.plan.swap_mb; + let swap_num: u32 = if self.plan.efi_mb > 0 { 2 } else { 1 }; + ui.log(format!("Swap bölümü oluşturuluyor: {}–{} MB", next_mb, swap_end)); + run_cmd("parted", &[ + "-s", disk, "mkpart", "primary", "linux-swap", + &format!("{}MB", next_mb), &format!("{}MB", swap_end), + ]).await?; + next_mb = swap_end; + + // 4. Kök bölümü (kalan alan) + let root_num: u32 = if self.plan.efi_mb > 0 { 3 } else { 2 }; + ui.log(format!("Kök bölümü oluşturuluyor: {}MB – disk sonu", next_mb)); + run_cmd("parted", &[ + "-s", disk, "mkpart", "primary", "ext4", + &format!("{}MB", next_mb), "100%", + ]).await?; + + // 5. Biçimlendirme + let efi_part = part_path(disk, 1); + let swap_part = part_path(disk, swap_num); + let root_part = part_path(disk, root_num); + + if self.plan.efi_mb > 0 { + ui.log(format!("mkfs.fat -F32 {}", efi_part)); + run_cmd("mkfs.fat", &["-F32", &efi_part]).await?; + } + + ui.log(format!("mkswap {}", swap_part)); + run_cmd("mkswap", &[&swap_part]).await?; + + ui.log(format!("swapon {}", swap_part)); + run_cmd("swapon", &[&swap_part]).await?; + + ui.log(format!("mkfs.ext4 -F {}", root_part)); + run_cmd("mkfs.ext4", &["-F", &root_part]).await?; + + Ok(()) + } +} + +/// Bölüm yolunu bağla. +pub struct MountPartitionsJob { + pub plan: PartitionPlan, + pub mount: String, +} + +#[async_trait::async_trait] +impl Job for MountPartitionsJob { + fn name(&self) -> &str { "job_mount" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + let disk = &self.plan.disk; + let mount = &self.mount; + let root_num: u32 = if self.plan.efi_mb > 0 { 3 } else { 2 }; + let root_part = part_path(disk, root_num); + + ui.log(format!("mount {} {}", root_part, mount)); + run_cmd("mount", &[&root_part, mount]).await?; + + if self.plan.efi_mb > 0 { + let efi_dir = format!("{}/boot/efi", mount); + ui.log(format!("mkdir -p {}", efi_dir)); + run_cmd("mkdir", &["-p", &efi_dir]).await?; + let efi_part = part_path(disk, 1); + ui.log(format!("mount {} {}", efi_part, efi_dir)); + run_cmd("mount", &[&efi_part, &efi_dir]).await?; + } + + Ok(()) + } +} + +/// Tam kurulum iş kuyruğu. +/// +/// Sıra: +/// 1. Disk bölümlendirme (parted + mkfs) +/// 2. Bölümleri bağlama +/// 3. /proc /sys /dev bind-mount (chroot hazırlığı) +/// 4. Sistem dosyalarını kopyalama (rsync) +/// 5. UUID'leri oku → fstab yaz +/// 6. Hostname + /etc/hosts +/// 7. Locale yapılandırması + locale-gen +/// 8. Zaman dilimi + hwclock +/// 9. Klavye (vconsole + X11) +/// 10. Kullanıcı oluşturma + şifre (chpasswd) +/// 11. initramfs yenile (dracut / mkinitcpio) +/// 12. GRUB kurulumu (chroot içinde) +/// 13. COMAR / pisi configure-pending +/// 14. Bind-mount'ları temizle +pub fn build_full_job_queue( + plan: PartitionPlan, + mount: &str, + source: &str, + locale: &str, + timezone: &str, + username: &str, + password: &str, + hostname: &str, + kb_layout: &str, + kb_variant: &str, + demo_mode: bool, +) -> JobQueue { + DEMO_MODE.store(demo_mode, std::sync::atomic::Ordering::Relaxed); + + let is_uefi = plan.efi_mb > 0; + let disk = plan.disk.clone(); + let mt = mount.to_string(); + let plan2 = plan.clone(); + let plan3 = plan.clone(); + + // Kaynak dizini: parametre boşsa otomatik tespit et + let src = if source.is_empty() { detect_source_dir() } else { source.to_string() }; + + let jobs: Vec> = vec![ + // 1. Bölümlendir + Box::new(PartitionJob { plan }), + + // 2. Bağla + Box::new(MountPartitionsJob { plan: plan2, mount: mt.clone() }), + + // 3. /proc /sys /dev bind-mount + Box::new(MountBindJob { mount: mt.clone() }), + + // 4. Kopyala + Box::new(CopyFilesJob { source: src, target: mt.clone() }), + + // 5. UUID oku + fstab yaz + Box::new(FstabFromBlkidJob { plan: plan3, mount: mt.clone() }), + + // 6. Hostname + Box::new(ConfigureHostnameJob { + mount: mt.clone(), + hostname: hostname.to_string(), + }), + + // 7. Locale + Box::new(ConfigureLocaleJob { + mount: mt.clone(), + locale: locale.to_string(), + }), + + // 8. Zaman dilimi + Box::new(ConfigureTimezoneJob { + mount: mt.clone(), + timezone: timezone.to_string(), + }), + + // 9. Klavye + Box::new(ConfigureKeyboardJob { + mount: mt.clone(), + layout: kb_layout.to_string(), + variant: kb_variant.to_string(), + }), + + // 10. Kullanıcı + Box::new(CreateUserJob { + mount: mt.clone(), + username: username.to_string(), + password: password.to_string(), + }), + + // 11. initramfs + Box::new(GenerateInitramfsJob { mount: mt.clone() }), + + // 12. GRUB + Box::new(InstallGrubJob { disk, mount: mt.clone(), is_uefi }), + + // 13. COMAR + Box::new(RunComarJob { mount: mt.clone() }), + + // 14. Bind-mount temizle + Box::new(UnmountBindJob { mount: mt.clone() }), + ]; + + JobQueue::new(jobs) +} + +/// COMAR servislerini ve tetikleyicilerini yapılandırır. +pub struct RunComarJob { + pub mount: String, +} + +#[async_trait::async_trait] +impl Job for RunComarJob { + fn name(&self) -> &str { "job_comar" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + // pisi configure-pending: paket post-install scriptlerini çalıştırır. + // Yapılandırılacak paket yoksa çıkış kodu sıfır dışı olabilir — fatal değil. + ui.log("pisi configure-pending çalıştırılıyor (COMAR)…"); + match run_chroot(&self.mount, &["pisi", "configure-pending"]).await { + Ok(_) => { + ui.log("✓ pisi configure-pending tamamlandı"); + } + Err(e) => { + // "no packages to configure" gibi durumlar hata değil + if e.contains("no packages") || e.contains("Nothing to do") { + ui.log("⚠ configure-pending: yapılandırılacak paket yok, atlanıyor"); + } else { + // Gerçek hata — uyar ama kurulumu durdurma + ui.log(format!("⚠ pisi configure-pending uyarısı: {}", e)); + ui.log("⚠ Bu uyarı kritik değilse kurulum devam edecek."); + } + } + } + Ok(()) + } +} + +/// blkid ile UUID okuyup fstab'ı doğrudan yazan job. +/// (async closure Rust'ta trait object olarak kullanılamaz; +/// bu nedenle ayrı bir Job struct'ı gerekli.) +struct FstabFromBlkidJob { + plan: PartitionPlan, + mount: String, +} + +#[async_trait::async_trait] +impl Job for FstabFromBlkidJob { + fn name(&self) -> &str { "job_fstab" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + ui.log("blkid ile UUID'ler okunuyor…"); + let (root_uuid, efi_uuid, swap_uuid) = read_partition_uuids(&self.plan).await?; + ui.log(format!("Kök UUID: {}", root_uuid)); + + let job = GenerateFstabJob { + mount: self.mount.clone(), + root_uuid, + efi_uuid, + swap_uuid, + }; + job.run(ui).await + } +} + +// ───────────────────────────────────────────── +// CHROOT YAPILANDIRMA JOB'LARI +// ───────────────────────────────────────────── + +/// /etc/hostname ve /etc/hosts dosyalarını yazar. +pub struct ConfigureHostnameJob { + pub mount: String, + pub hostname: String, +} + +#[async_trait::async_trait] +impl Job for ConfigureHostnameJob { + fn name(&self) -> &str { "job_hostname" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + // /etc/hostname + let hostname_path = format!("{}/etc/hostname", self.mount); + ui.log(format!("Yazılıyor: {}", hostname_path)); + tokio::fs::write(&hostname_path, format!("{}\n", self.hostname)) + .await + .map_err(|e| format!("/etc/hostname yazılamadı: {}", e))?; + + // /etc/hosts + let hosts_path = format!("{}/etc/hosts", self.mount); + let hosts_content = format!( + "127.0.0.1\tlocalhost\n\ + ::1\t\tlocalhost\n\ + 127.0.1.1\t{hostname}\n", + hostname = self.hostname + ); + ui.log(format!("Yazılıyor: {}", hosts_path)); + tokio::fs::write(&hosts_path, hosts_content) + .await + .map_err(|e| format!("/etc/hosts yazılamadı: {}", e))?; + + Ok(()) + } +} + +/// /etc/locale.conf ve /etc/locale.gen'i yazar, sonra locale-gen çalıştırır. +pub struct ConfigureLocaleJob { + pub mount: String, + pub locale: String, // ör. "tr_TR.UTF-8" +} + +#[async_trait::async_trait] +impl Job for ConfigureLocaleJob { + fn name(&self) -> &str { "job_locale" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + // /etc/locale.conf + let conf_path = format!("{}/etc/locale.conf", self.mount); + let conf = format!( + "LANG={locale}\nLC_ALL={locale}\n", + locale = self.locale + ); + ui.log(format!("Yazılıyor: {}", conf_path)); + tokio::fs::write(&conf_path, conf) + .await + .map_err(|e| format!("/etc/locale.conf yazılamadı: {}", e))?; + + // /etc/locale.gen — satırın başındaki # kaldırılır + let gen_path = format!("{}/etc/locale.gen", self.mount); + ui.log(format!("Güncelleniyor: {}", gen_path)); + let content = tokio::fs::read_to_string(&gen_path).await.unwrap_or_default(); + let updated = content + .lines() + .map(|line| { + let stripped = line.trim_start_matches('#').trim_start(); + if stripped.starts_with(&self.locale) { + stripped.to_string() // yorumu kaldır + } else { + line.to_string() + } + }) + .collect::>() + .join("\n"); + tokio::fs::write(&gen_path, updated + "\n") + .await + .map_err(|e| format!("/etc/locale.gen yazılamadı: {}", e))?; + + // locale-gen çalıştır + ui.log("locale-gen çalıştırılıyor…"); + run_chroot(&self.mount, &["locale-gen"]).await?; + + Ok(()) + } +} + +/// Zaman dilimini ayarlar ve hwclock'u senkronize eder. +pub struct ConfigureTimezoneJob { + pub mount: String, + pub timezone: String, // ör. "Europe/Istanbul" +} + +#[async_trait::async_trait] +impl Job for ConfigureTimezoneJob { + fn name(&self) -> &str { "job_timezone" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + // Sembolik link: /etc/localtime → /usr/share/zoneinfo/ + let link_target = format!("/usr/share/zoneinfo/{}", self.timezone); + let link_path = format!("{}/etc/localtime", self.mount); + + ui.log(format!("ln -sf {} {}", link_target, link_path)); + // Önce varsa eski linki sil + let _ = tokio::fs::remove_file(&link_path).await; + // tokio'da Unix symlink için spawn_blocking kullan + let lt = link_target.clone(); + let lp = link_path.clone(); + tokio::task::spawn_blocking(move || { + std::os::unix::fs::symlink(<, &lp) + }).await + .map_err(|e| format!("symlink spawn hatası: {}", e))? + .map_err(|e| format!("localtime symlink: {}", e))?; + + // hwclock --systohc + ui.log("hwclock --systohc çalıştırılıyor…"); + // Hata kritik değil, uyar ve devam et + match run_chroot(&self.mount, &["hwclock", "--systohc"]).await { + Ok(_) => ui.log("hwclock senkronize edildi."), + Err(e) => ui.log(format!("⚠ hwclock uyarısı (kritik değil): {}", e)), + } + + Ok(()) + } +} + +/// Klavye düzenini /etc/vconsole.conf ve X11 yapılandırmasına yazar. +pub struct ConfigureKeyboardJob { + pub mount: String, + pub layout: String, // ör. "tr" + pub variant: String, // ör. "f" veya "" +} + +#[async_trait::async_trait] +impl Job for ConfigureKeyboardJob { + fn name(&self) -> &str { "job_keyboard" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + // /etc/vconsole.conf (TTY için) + let vconsole_path = format!("{}/etc/vconsole.conf", self.mount); + let keymap = if self.variant.is_empty() { + self.layout.clone() + } else { + format!("{}-{}", self.layout, self.variant) + }; + let vconsole = format!("KEYMAP={}\nFONT=ter-v16n\n", keymap); + ui.log(format!("Yazılıyor: {}", vconsole_path)); + tokio::fs::write(&vconsole_path, vconsole) + .await + .map_err(|e| format!("/etc/vconsole.conf yazılamadı: {}", e))?; + + // /etc/X11/xorg.conf.d/00-keyboard.conf (X11 için) + let x11_dir = format!("{}/etc/X11/xorg.conf.d", self.mount); + let x11_path = format!("{}/00-keyboard.conf", x11_dir); + run_cmd("mkdir", &["-p", &x11_dir]).await?; + + let options_line = if self.variant.is_empty() { + String::new() + } else { + format!("\n\t\tOption \"XkbVariant\" \"{}\"", self.variant) + }; + + let x11_conf = format!( + "Section \"InputClass\"\n\ + \tIdentifier \"system-keyboard\"\n\ + \tMatchIsKeyboard \"on\"\n\ + \tOption \"XkbLayout\" \"{layout}\"{options}\n\ + EndSection\n", + layout = self.layout, + options = options_line, + ); + ui.log(format!("Yazılıyor: {}", x11_path)); + tokio::fs::write(&x11_path, x11_conf) + .await + .map_err(|e| format!("xorg keyboard conf yazılamadı: {}", e))?; + + Ok(()) + } +} + +/// Kullanıcı hesabı oluşturur ve şifresini ayarlar. +pub struct CreateUserJob { + pub mount: String, + pub username: String, + pub password: String, +} + +#[async_trait::async_trait] +impl Job for CreateUserJob { + fn name(&self) -> &str { "job_user" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + // wheel grubunun varlığını garantile (PisiLinux'ta olmayabilir) + let group_file = format!("{}/etc/group", self.mount); + let group_content = tokio::fs::read_to_string(&group_file) + .await.unwrap_or_default(); + if !group_content.lines().any(|l| l.starts_with("wheel:")) { + ui.log("wheel grubu oluşturuluyor…"); + run_chroot(&self.mount, &["groupadd", "-r", "wheel"]).await + .unwrap_or_default(); // hata olsa bile devam et + } + + // useradd: kullanıcıyı temel gruplarla oluştur + // PisiLinux'ta "storage" grubu yoksa useradd hata verir; -M flag ile grub yoksa atla + // Güvenli yöntem: önce her grubu tek tek ekle + let groups = ["audio", "video", "wheel", "cdrom", "plugdev", "storage", "lp", "scanner"]; + for grp in &groups { + if group_content.lines().any(|l| l.starts_with(&format!("{}:", grp))) { + // grup zaten var + } else { + // grup yoksa oluşturma (hata görmezden gel) + let _ = run_chroot(&self.mount, &["groupadd", grp]).await; + } + } + + // Kullanıcıyı oluştur + let groups_str = groups.join(","); + ui.log(format!("useradd -m -G {} -s /bin/bash {}", groups_str, self.username)); + run_chroot(&self.mount, &[ + "useradd", + "-m", + "-G", &groups_str, + "-s", "/bin/bash", + &self.username, + ]).await?; + + // chpasswd ile şifre ayarla (stdin üzerinden güvenli) + ui.log(format!("Şifre ayarlanıyor: {}", self.username)); + let chpasswd_input = format!("{}:{}", self.username, self.password); + set_password_via_chpasswd(&self.mount, &chpasswd_input).await?; + + // Root şifresini de kilitle (güvenlik: root doğrudan giriş yapmasın) + ui.log("Root hesabı kilitleniyor…"); + run_chroot(&self.mount, &["passwd", "-l", "root"]).await?; + + // sudoers: wheel grubu sudo yetkisi alsın + let sudoers_path = format!("{}/etc/sudoers.d/wheel", self.mount); + ui.log(format!("Yazılıyor: {}", sudoers_path)); + tokio::fs::write(&sudoers_path, "%wheel ALL=(ALL:ALL) ALL\n") + .await + .map_err(|e| format!("sudoers yazılamadı: {}", e))?; + + // Dosya izinleri: sudoers 440 olmalı + run_cmd("chmod", &["440", &sudoers_path]).await?; + + Ok(()) + } +} + +/// `chpasswd` komutuna stdin üzerinden kullanıcı:şifre gönderir. +async fn set_password_via_chpasswd(mount: &str, input: &str) -> Result<(), String> { + if DEMO_MODE.load(std::sync::atomic::Ordering::Relaxed) { + tokio::time::sleep(std::time::Duration::from_millis(2500)).await; + return Ok(()); + } + + use tokio::io::AsyncWriteExt; + use tokio::process::Command; + + let mut child = Command::new("chroot") + .args([mount, "chpasswd"]) + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::piped()) + .spawn() + .map_err(|e| format!("chpasswd başlatılamadı: {}", e))?; + + if let Some(mut stdin) = child.stdin.take() { + stdin.write_all(input.as_bytes()).await + .map_err(|e| format!("chpasswd stdin yazma hatası: {}", e))?; + } + + let output = child.wait_with_output().await + .map_err(|e| format!("chpasswd bekleme hatası: {}", e))?; + + if output.status.success() { + Ok(()) + } else { + Err(String::from_utf8_lossy(&output.stderr).trim().to_string()) + } +} + +/// fstab'ı doğrudan dosyaya yazar (genfstab yerine; ISO ortamında daha güvenilir). +pub struct GenerateFstabJob { + pub mount: String, + pub root_uuid: String, // blkid ile alınır + pub efi_uuid: Option, + pub swap_uuid: String, +} + +#[async_trait::async_trait] +impl Job for GenerateFstabJob { + fn name(&self) -> &str { "job_fstab" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + let fstab_path = format!("{}/etc/fstab", self.mount); + ui.log(format!("Yazılıyor: {}", fstab_path)); + + let mut fstab = String::from( + "# /etc/fstab — Yali tarafından otomatik oluşturuldu\n\ + # \n\n" + ); + + // Kök bölümü + fstab.push_str(&format!( + "UUID={} / ext4 defaults,noatime 0 1\n", + self.root_uuid + )); + + // EFI bölümü + if let Some(ref efi) = self.efi_uuid { + fstab.push_str(&format!( + "UUID={} /boot/efi vfat umask=0077 0 2\n", + efi + )); + } + + // Swap + fstab.push_str(&format!( + "UUID={} none swap sw 0 0\n", + self.swap_uuid + )); + + tokio::fs::write(&fstab_path, fstab) + .await + .map_err(|e| format!("fstab yazılamadı: {}", e))?; + + Ok(()) + } +} + +/// Disk bölümlerinin UUID'lerini `blkid` ile okur. +pub async fn read_partition_uuids( + plan: &PartitionPlan, +) -> Result<(String, Option, String), String> { + let (root_num, swap_num): (u32, u32) = if plan.efi_mb > 0 { (3, 2) } else { (2, 1) }; + + let root_part = part_path(&plan.disk, root_num); + let swap_part = part_path(&plan.disk, swap_num); + + let root_uuid = blkid_uuid(&root_part).await?; + let swap_uuid = blkid_uuid(&swap_part).await?; + let efi_uuid = if plan.efi_mb > 0 { + Some(blkid_uuid(&part_path(&plan.disk, 1)).await?) + } else { + None + }; + + Ok((root_uuid, efi_uuid, swap_uuid)) +} + +async fn blkid_uuid(device: &str) -> Result { + if DEMO_MODE.load(std::sync::atomic::Ordering::Relaxed) { + tokio::time::sleep(std::time::Duration::from_millis(1500)).await; + return Ok(format!("demo-uuid-{}", device.replace("/", "-"))); + } + + let output = tokio::process::Command::new("blkid") + .args(["-s", "UUID", "-o", "value", device]) + .output() + .await + .map_err(|e| format!("blkid çalıştırılamadı: {}", e))?; + + let uuid = String::from_utf8_lossy(&output.stdout).trim().to_string(); + if uuid.is_empty() { + Err(format!("{} için UUID bulunamadı", device)) + } else { + Ok(uuid) + } +} + +// ───────────────────────────────────────────── +// MANUEL BÖLÜMLEME İÇİN DESTEKLEYİCİ JOB'LAR +// ───────────────────────────────────────────── + +use crate::installer::{CustomPartition, FsType}; + +/// Manuel bölümleme ayarlarını disk üzerinde uygulayan ve biçimlendiren Job. +pub struct CustomPartitionJob { + pub disk: String, + pub custom_partitions: Vec, +} + +#[async_trait::async_trait] +impl Job for CustomPartitionJob { + fn name(&self) -> &str { "job_custom_partition" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + let is_uefi = std::path::Path::new("/sys/firmware/efi").exists(); + + // 1. Bölüm tablosu oluştur + let table_label = if is_uefi { "gpt" } else { "msdos" }; + ui.log(format!("parted {} mktable {}", self.disk, table_label)); + run_cmd("parted", &["-s", &self.disk, "mktable", table_label]).await?; + + let mut next_mb: u64 = 1; // İlk MB boot sektörü + + // 2. Bölümleri parted ile oluştur + for (i, part) in self.custom_partitions.iter().enumerate() { + let part_num = (i + 1) as u32; + let end_str = if part.size_mb == 0 { + "100%".to_string() + } else { + format!("{}MB", next_mb + part.size_mb) + }; + let start_str = format!("{}MB", next_mb); + + let fs_label = match part.fstype { + FsType::Fat32 => "fat32", + FsType::Swap => "linux-swap", + FsType::Ext4 => "ext4", + FsType::Btrfs => "btrfs", + FsType::Xfs => "xfs", + }; + + ui.log(format!( + "Bölüm {} oluşturuluyor: {} - {} ({})", + part_num, start_str, end_str, fs_label + )); + run_cmd("parted", &[ + "-s", &self.disk, "mkpart", "primary", fs_label, + &start_str, &end_str + ]).await?; + + if part.mountpoint == "/boot/efi" || part.fstype == FsType::Fat32 { + run_cmd("parted", &["-s", &self.disk, "set", &part_num.to_string(), "esp", "on"]).await?; + } + + if part.size_mb > 0 { + next_mb += part.size_mb; + } + } + + // 3. Biçimlendir + for part in &self.custom_partitions { + let path = &part.device; + + match part.fstype { + FsType::Fat32 => { + ui.log(format!("mkfs.fat -F32 {}", path)); + run_cmd("mkfs.fat", &["-F32", path]).await?; + } + FsType::Swap => { + ui.log(format!("mkswap {}", path)); + run_cmd("mkswap", &[path]).await?; + ui.log(format!("swapon {}", path)); + run_cmd("swapon", &[path]).await?; + } + FsType::Ext4 => { + ui.log(format!("mkfs.ext4 -F {}", path)); + run_cmd("mkfs.ext4", &["-F", path]).await?; + } + FsType::Btrfs => { + ui.log(format!("mkfs.btrfs -f {}", path)); + run_cmd("mkfs.btrfs", &["-f", path]).await?; + } + FsType::Xfs => { + ui.log(format!("mkfs.xfs -f {}", path)); + run_cmd("mkfs.xfs", &["-f", path]).await?; + } + } + } + + Ok(()) + } +} + +/// Manuel bölümleri kök dizinden başlayarak hiyerarşik olarak hedef yola bağlayan Job. +pub struct MountCustomPartitionsJob { + pub custom_partitions: Vec, + pub mount: String, +} + +#[async_trait::async_trait] +impl Job for MountCustomPartitionsJob { + fn name(&self) -> &str { "job_mount_custom" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + // 1. Kök (/) bölümünü bul ve bağla + let root_part = self.custom_partitions.iter() + .find(|p| p.mountpoint == "/") + .ok_or_else(|| "Kök (/) bölümü manuel listede bulunamadı.".to_string())?; + + ui.log(format!("Kök dizin bağlanıyor: {} ➔ {}", root_part.device, self.mount)); + run_cmd("mount", &[&root_part.device, &self.mount]).await?; + + // 2. Diğer bölümleri sırala ve bağla (derinliğe göre artan sırada) + let mut other_parts: Vec<_> = self.custom_partitions.iter() + .filter(|p| p.mountpoint != "/" && p.fstype != FsType::Swap && !p.mountpoint.is_empty()) + .collect(); + other_parts.sort_by_key(|p| p.mountpoint.len()); + + for part in other_parts { + let target_path = format!("{}{}", self.mount, part.mountpoint); + ui.log(format!("Bağlama noktası dizini oluşturuluyor: {}", target_path)); + run_cmd("mkdir", &["-p", &target_path]).await?; + ui.log(format!("Bağlanıyor: {} ➔ {}", part.device, target_path)); + run_cmd("mount", &[&part.device, &target_path]).await?; + } + + Ok(()) + } +} + +/// Manuel bölümleme planına göre fstab dosyası üreten Job. +pub struct FstabFromCustomPartitionsJob { + pub custom_partitions: Vec, + pub mount: String, +} + +#[async_trait::async_trait] +impl Job for FstabFromCustomPartitionsJob { + fn name(&self) -> &str { "job_fstab" } + + async fn run(&self, ui: &UiSender) -> Result<(), String> { + let fstab_path = format!("{}/etc/fstab", self.mount); + ui.log(format!("Yazılıyor: {}", fstab_path)); + + let mut fstab = String::from( + "# /etc/fstab — Yali tarafından otomatik (manuel mod) oluşturuldu\n\ + # \n\n" + ); + + for part in &self.custom_partitions { + if part.mountpoint.is_empty() { continue; } + + ui.log(format!("{} için UUID okunuyor…", part.device)); + let uuid = blkid_uuid(&part.device).await?; + + let (mp, options, dump, pass) = match part.fstype { + FsType::Swap => ("none", "sw", "0", "0"), + FsType::Fat32 => ("/boot/efi", "umask=0077", "0", "2"), + FsType::Ext4 if part.mountpoint == "/" => ("/", "defaults,noatime", "0", "1"), + _ => { + let pass_val = if part.mountpoint == "/" { "1" } else { "2" }; + (part.mountpoint.as_str(), "defaults,noatime", "0", pass_val) + } + }; + + let fs_name = match part.fstype { + FsType::Ext4 => "ext4", + FsType::Btrfs => "btrfs", + FsType::Xfs => "xfs", + FsType::Fat32 => "vfat", + FsType::Swap => "swap", + }; + + fstab.push_str(&format!( + "UUID={:<36} {:<12} {:<6} {:<18} {} {}\n", + uuid, mp, fs_name, options, dump, pass + )); + } + + tokio::fs::write(&fstab_path, fstab) + .await + .map_err(|e| format!("fstab yazılamadı: {}", e))?; + + Ok(()) + } +} + +/// Manuel bölümleme kullanıldığında derlenecek kurulum iş kuyruğu. +pub fn build_custom_job_queue( + disk: String, + custom_partitions: Vec, + mount: &str, + source: &str, + locale: &str, + timezone: &str, + username: &str, + password: &str, + hostname: &str, + kb_layout: &str, + kb_variant: &str, + demo_mode: bool, +) -> JobQueue { + DEMO_MODE.store(demo_mode, std::sync::atomic::Ordering::Relaxed); + + let is_uefi = std::path::Path::new("/sys/firmware/efi").exists(); + let mt = mount.to_string(); + + // Kaynak dizini: parametre boşsa otomatik tespit et + let src = if source.is_empty() { detect_source_dir() } else { source.to_string() }; + + let jobs: Vec> = vec![ + // 1. Bölümlendir ve Biçimlendir + Box::new(CustomPartitionJob { disk: disk.clone(), custom_partitions: custom_partitions.clone() }), + + // 2. Bağla + Box::new(MountCustomPartitionsJob { custom_partitions: custom_partitions.clone(), mount: mt.clone() }), + + // 3. /proc /sys /dev bind-mount + Box::new(MountBindJob { mount: mt.clone() }), + + // 4. Kopyala + Box::new(CopyFilesJob { source: src, target: mt.clone() }), + + // 5. UUID oku + fstab yaz + Box::new(FstabFromCustomPartitionsJob { custom_partitions: custom_partitions.clone(), mount: mt.clone() }), + + // 6. Hostname + Box::new(ConfigureHostnameJob { + mount: mt.clone(), + hostname: hostname.to_string(), + }), + + // 7. Locale + Box::new(ConfigureLocaleJob { + mount: mt.clone(), + locale: locale.to_string(), + }), + + // 8. Zaman dilimi + Box::new(ConfigureTimezoneJob { + mount: mt.clone(), + timezone: timezone.to_string(), + }), + + // 9. Klavye + Box::new(ConfigureKeyboardJob { + mount: mt.clone(), + layout: kb_layout.to_string(), + variant: kb_variant.to_string(), + }), + + // 10. Kullanıcı + Box::new(CreateUserJob { + mount: mt.clone(), + username: username.to_string(), + password: password.to_string(), + }), + + // 11. initramfs + Box::new(GenerateInitramfsJob { mount: mt.clone() }), + + // 12. GRUB + Box::new(InstallGrubJob { disk, mount: mt.clone(), is_uefi }), + + // 13. COMAR + Box::new(RunComarJob { mount: mt.clone() }), + + // 14. Bind-mount temizle + Box::new(UnmountBindJob { mount: mt.clone() }), + ]; + + JobQueue::new(jobs) +} + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..224516e --- /dev/null +++ b/src/main.rs @@ -0,0 +1,405 @@ +mod installer; +mod steps; +mod jobs; +mod ui; +mod autoinstall; + +use installer::{GlobalState, InstallerStep, WelcomeStep, LocationStep}; +use steps::{KeyboardStep, UsersStep, SummaryStep, ExecutionStep, FinishStep, PartitionStep}; +use eframe::egui; +use rust_i18n::t; + +rust_i18n::i18n!("locales"); + +fn main() -> eframe::Result<()> { + // ── CLI: otomatik kurulum modu ─────────────────────── + let args: Vec = std::env::args().collect(); + let demo_mode = args.contains(&"--demo".to_string()); + + if let Some(pos) = args.iter().position(|a| a == "--auto-install") { + if let Some(path) = args.get(pos + 1) { + return run_auto_install(path, demo_mode); + } else { + eprintln!("Hata: --auto-install şeklinde kullanın."); + std::process::exit(1); + } + } + + run_gui(demo_mode) +} + +/// Grafik arayüzü başlatır (normal mod). +fn run_gui(demo_mode: bool) -> eframe::Result<()> { + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default() + .with_inner_size([1100.0, 760.0]) + .with_min_inner_size([900.0, 650.0]) + .with_title(t!("installer").to_string()), + ..Default::default() + }; + + eframe::run_native( + &t!("installer").to_string(), + options, + Box::new(move |cc| { + // Görsel yükleyicileri etkinleştir (PNG desteği) + egui_extras::install_image_loaders(&cc.egui_ctx); + + ui::theme::apply(&cc.egui_ctx, true); + let mut app = YaliApp::default(); + app.state.demo_mode = demo_mode; + Box::new(app) + }), + ) +} + +/// Answer file ile tam otomatik, UI-siz kurulum. +fn run_auto_install(path: &str, demo_mode: bool) -> eframe::Result<()> { + use autoinstall::{load, apply_to_state}; + use std::path::Path; + + println!("=== Yali-RS Otomatik Kurulum ==="); + println!("{}: {}", t!("answer_file"), path); + + // Dosyayı yükle ve doğrula + let af = match load(Path::new(path)) { + Ok(af) => af, + Err(e) => { + eprintln!("{}: {}", t!("error"), e); + std::process::exit(1); + } + }; + + println!("{}: {}", t!("disk"), af.install.disk); + println!("{}: {}", t!("timezone"), af.install.timezone); + println!("{}: {}", t!("username"), af.user.username); + println!("{}: {}", t!("hostname"), af.user.hostname); + + // Sistem kontrollerini çalıştır + println!("\n--- {} ---", t!("system_checks")); + let checks = autoinstall::checker::run_all(); + for c in &checks { + let sym = match c.status { + autoinstall::checker::CheckStatus::Pass => "✓", + autoinstall::checker::CheckStatus::Warn => "⚠", + autoinstall::checker::CheckStatus::Fail => "✗", + }; + println!("[{}] {}: {}", sym, c.name, c.message); + } + + if !autoinstall::checker::all_passed(&checks) { + eprintln!("{}: {}", t!("error"), "Critical check error. Installation stopped."); + std::process::exit(2); + } + + // State'i hazırla + let mut state = GlobalState::default(); + state.demo_mode = demo_mode; + apply_to_state(&af, &mut state); + + if state.partition_plan.is_none() { + eprintln!("{}: {}", t!("error"), format!("{}: {}", t!("partition_plan_could_not_be_created"), af.install.disk)); + std::process::exit(3); + } + + println!("\n--- {} ---", t!("installation_started")); + + // JobQueue'yu oluştur ve tokio'da çalıştır + let locale = af.install.locale.clone(); + let timezone = af.install.timezone.clone(); + let username = af.user.username.clone(); + let password = af.user.password.clone(); + let hostname = af.user.hostname.clone(); + let kb_layout = af.install.keyboard.clone(); + let kb_variant = af.install.keyboard_variant.clone(); + let source = af.install.source.clone(); + let mount = af.install.mount.clone(); + let plan = state.partition_plan.unwrap(); + + let rt = tokio::runtime::Runtime::new().expect("tokio runtime"); + rt.block_on(async { + use std::sync::mpsc; + use jobs::{InstallMessage, UiSender}; + + // CLI modunda egui Context yok; basit bir mpsc kanal kullanıyoruz. + // UiSender'a dummy bir context gerekeceğinden terminal çıktısı için + // doğrudan kanalı dinliyoruz. + let (tx, rx) = mpsc::channel::(); + + // Arka plan iş parçacığı — gerçek job kuyruğunu çalıştırır. + // egui::Context::default() CLI modunda request_repaint()'i no-op yapar; + // mesajlar mpsc kanalı üzerinden terminale aktarılır. + let cli_ctx = eframe::egui::Context::default(); + let ui_sender = UiSender::new(tx, cli_ctx); + + let plan_c = plan.clone(); + let locale_c = locale.clone(); + let timezone_c = timezone.clone(); + let username_c = username.clone(); + let password_c = password.clone(); + let hostname_c = hostname.clone(); + let kb_layout_c = kb_layout.clone(); + let kb_variant_c= kb_variant.clone(); + let source_c = source.clone(); + let mount_c = mount.clone(); + + std::thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().expect("tokio runtime"); + let mut queue = jobs::build_full_job_queue( + plan_c, + &mount_c, + &source_c, + &locale_c, + &timezone_c, + &username_c, + &password_c, + &hostname_c, + &kb_layout_c, + &kb_variant_c, + demo_mode, + ); + rt.block_on(queue.run_all(ui_sender)); + }); + + // Kanalı oku ve terminale yaz + loop { + match rx.recv() { + Ok(InstallMessage::Log(line)) => println!(" {}", line), + Ok(InstallMessage::Progress(p)) => { + print!("\r {}: [{:50}] {:.0}%", t!("progress"), "=".repeat((p * 50.0) as usize), p * 100.0); + let _ = std::io::Write::flush(&mut std::io::stdout()); + } + Ok(InstallMessage::Done) => { + println!("\n\n{}: {}", t!("installation_done"), t!("installation_done_description")); + break; + } + Ok(InstallMessage::Error(e)) => { + eprintln!("\n{}: {}", t!("error"), e); + std::process::exit(4); + } + Err(_) => break, + } + } + }); + + // eframe::Result döndürmek için Ok + Ok(()) +} + +struct YaliApp { + state: GlobalState, + steps: Vec>, + last_step: usize, +} + +impl Default for YaliApp { + fn default() -> Self { + let mut app = Self { + state: GlobalState::default(), + steps: vec![ + Box::new(WelcomeStep::default()), + Box::new(LocationStep::default()), + Box::new(KeyboardStep::default()), + Box::new(PartitionStep::default()), + Box::new(UsersStep::default()), + Box::new(SummaryStep), + Box::new(ExecutionStep::default()), + Box::new(FinishStep), + ], + last_step: usize::MAX, + }; + app.steps[0].on_enter(&mut app.state); + app.last_step = 0; + app + } +} + +impl eframe::App for YaliApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + rust_i18n::set_locale(&self.state.language); + + let cur = self.state.current_step; + let n_steps = self.steps.len(); + let is_exec = cur == n_steps - 2; + let is_finish = cur == n_steps - 1; + + // Adım değişmişse on_enter çağır + if cur != self.last_step { + if let Some(step) = self.steps.get_mut(cur) { + step.on_enter(&mut self.state); + } + self.last_step = cur; + } + + // ── Sol panel: adım listesi ────────────────────────── + egui::SidePanel::left("sidebar") + .exact_width(195.0) + .frame(egui::Frame::none().fill(ui::theme::c_sidebar())) + .show(ctx, |ui| { + ui.add_space(20.0); + + // PisiLinux logo + ui.vertical_centered(|ui| { + let logo = if self.state.is_dark { + egui::include_image!("../assets/pisi-logo-dark.png") + } else { + egui::include_image!("../assets/pisi-logo-light.png") + }; + ui.add( + egui::Image::new(logo) + .max_width(120.0) + .rounding(egui::Rounding::same(8.0)), + ); + ui.add_space(8.0); + ui.label( + egui::RichText::new(t!("os_name")) + .size(11.0) + .color(ui::theme::c_text_dim()), + ); + // get desktop environment + let desktop = std::env::var("XDG_CURRENT_DESKTOP").unwrap_or_default(); + ui.label( + egui::RichText::new(&format!("{} Desktop", desktop)) + .size(11.0) + .color(ui::theme::c_text_dim()), + ); + }); + + ui.add_space(16.0); + ui.separator(); + ui.add_space(12.0); + + // Adım listesi + for (i, step) in self.steps.iter().enumerate() { + let label = format!("{}. {}", i + 1, step.name()); + + egui::Frame::none() + .fill(if i == cur { + egui::Color32::from_rgba_unmultiplied(0x21, 0x96, 0xF3, 30) + } else { + egui::Color32::TRANSPARENT + }) + .rounding(egui::Rounding::same(6.0)) + .inner_margin(egui::Margin::symmetric(10.0, 5.0)) + .show(ui, |ui| { + ui.set_width(175.0); + if i == cur { + ui.horizontal(|ui| { + ui.colored_label(ui::theme::c_accent(), "▶"); + ui.colored_label(ui::theme::c_text(), label); + }); + } else if i < cur { + ui.horizontal(|ui| { + ui.colored_label(ui::theme::c_success(), "✓"); + ui.colored_label(ui::theme::c_text_dim(), label); + }); + } else { + ui.colored_label( + egui::Color32::from_rgb(80, 80, 100), + format!(" {}", label), + ); + } + }); + + ui.add_space(2.0); + } + + // Alt kısım: tema değiştirme + sürüm bilgisi + ui.with_layout(egui::Layout::bottom_up(egui::Align::Center), |ui| { + ui.add_space(12.0); + ui.colored_label( + egui::Color32::from_rgb(60, 60, 90), + "Yali-RS v0.2.0", + ); + ui.add_space(6.0); + // Tema değiştirme butonu + let theme_icon = if self.state.is_dark { "☀" } else { "🌙" }; + let theme_label = if self.state.is_dark { "Light" } else { "Dark" }; + if ui.add( + egui::Button::new( + egui::RichText::new(format!("{} {}", theme_icon, theme_label)) + .size(12.0) + ) + .rounding(egui::Rounding::same(6.0)) + .min_size(egui::Vec2::new(100.0, 28.0)) + ).clicked() { + self.state.is_dark = !self.state.is_dark; + ui::theme::set_theme_mode(self.state.is_dark); + ui::theme::apply(ctx, self.state.is_dark); + } + }); + }); + + // ── Alt panel: navigasyon ──────────────────────────── + egui::TopBottomPanel::bottom("footer") + .frame(egui::Frame::none() + .fill(ui::theme::c_bg_panel()) + .stroke(egui::Stroke::new(1.0, ui::theme::c_border()))) + .show(ctx, |ui| { + ui.add_space(10.0); + ui.horizontal(|ui| { + ui.add_space(8.0); + + // İptal — kurulum ve bitiş ekranında gizle + if !is_exec && !is_finish { + if ui.add(ui::theme::secondary_button(&t!("cancel"))).clicked() { + ctx.send_viewport_cmd(egui::ViewportCommand::Close); + } + } + + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + ui.add_space(8.0); + + let is_valid = self.steps + .get(cur) + .map(|s| s.is_complete(&self.state)) + .unwrap_or(false); + + if !is_finish { + // İleri / Tamamlandı butonu + if !is_exec || is_valid { + let next_label = if is_exec { + t!("finish_next") + } else { + t!("next") + }; + let btn = if is_valid { + ui::theme::primary_button(&next_label) + } else { + // Devre dışı görünüm için secondary kullan + ui::theme::secondary_button(&next_label) + }; + if ui.add_enabled(is_valid, btn).clicked() { + self.state.current_step += 1; + } + } + + // Geri — kurulum ekranında gizle + if cur > 0 && !is_exec { + ui.add_space(8.0); + if ui.add(ui::theme::secondary_button(&t!("back"))).clicked() { + self.state.current_step -= 1; + } + } + } + }); + }); + ui.add_space(10.0); + }); + + // ── Merkez panel ───────────────────────────────────── + egui::CentralPanel::default() + .frame(egui::Frame::none() + .fill(ui::theme::c_bg_dark()) + .inner_margin(egui::Margin::same(20.0))) + .show(ctx, |ui| { + egui::ScrollArea::vertical() + .id_source("main_scroll") + .show(ui, |ui| { + if let Some(step) = self.steps.get_mut(cur) { + step.show(ui, &mut self.state); + } + }); + }); + } +} diff --git a/src/steps/execution.rs b/src/steps/execution.rs new file mode 100644 index 0000000..c02b411 --- /dev/null +++ b/src/steps/execution.rs @@ -0,0 +1,305 @@ +//! Kurulumun gerçek olarak yürütüldüğü ekran. +//! +//! Sol yarı : Slayt gösterisi (Slideshow) +//! Sağ yarı : İlerleme çubuğu + renkli log terminali +//! +//! Hata olursa tüm panel ErrorScreen ile kaplanır. + +use std::sync::mpsc; +use std::thread; +use eframe::egui; +use rust_i18n::t; + +use crate::installer::{GlobalState, InstallerStep}; +use crate::jobs::{self, InstallMessage, UiSender}; +use crate::ui::{ErrorScreen, Slideshow}; +use crate::ui::theme; + +pub struct ExecutionStep { + rx: Option>, + tx: Option>, + finished: bool, + error_screen: Option, + slideshow: Option, +} + +impl Default for ExecutionStep { + fn default() -> Self { + Self { + rx: None, + tx: None, + finished: false, + error_screen: None, + slideshow: None, + } + } +} + +impl InstallerStep for ExecutionStep { + fn name(&self) -> String { t!("execution").to_string() } + + fn on_enter(&mut self, state: &mut GlobalState) { + let (tx, rx) = mpsc::channel::(); + self.rx = Some(rx); + self.tx = Some(tx); + self.finished = false; + self.error_screen = None; + + let desktop = std::env::var("XDG_CURRENT_DESKTOP") + .unwrap_or_else(|_| "default".to_string()) + .to_lowercase(); + self.slideshow = Some(Slideshow::new(&desktop)); + + state.install_progress = 0.0; + state.install_log.clear(); + state.install_log.push(t!("install_starting").to_string()); + } + + fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) { + // ── İş parçacığını ilk show()'da başlat ─────────────── + if let Some(tx) = self.tx.take() { + let timezone = state.timezone.clone(); + let language = state.language.clone(); + let plan = state.partition_plan.clone(); + let username = state.username.clone(); + let password = state.password.clone(); + let hostname = state.hostname.clone(); + let kb_layout = state.keyboard_layout.clone(); + let kb_variant = state.keyboard_variant.clone(); + let demo_mode = state.demo_mode; + let ctx = ui.ctx().clone(); + let erase_disk = state.erase_disk; + let custom_partitions = state.custom_partitions.clone(); + let selected_disk = state.selected_disk.clone(); + + let ui_sender = UiSender::new(tx, ctx); + + thread::spawn(move || { + let locale = if language == "tr" { + "tr_TR.UTF-8".to_string() + } else { + "en_US.UTF-8".to_string() + }; + let rt = tokio::runtime::Runtime::new().expect("tokio runtime"); + let src = jobs::detect_source_dir(); + + if erase_disk { + if let Some(p) = plan { + let mut queue = jobs::build_full_job_queue( + p, "/mnt", &src, + &locale, &timezone, + &username, &password, &hostname, + &kb_layout, &kb_variant, + demo_mode, + ); + rt.block_on(queue.run_all(ui_sender)); + } else { + ui_sender.send(InstallMessage::Error( + t!("error_partition_plan_not_found").to_string() + )); + } + } else { + if let Some(disk) = selected_disk { + let mut queue = jobs::build_custom_job_queue( + disk, custom_partitions, "/mnt", &src, + &locale, &timezone, + &username, &password, &hostname, + &kb_layout, &kb_variant, + demo_mode, + ); + rt.block_on(queue.run_all(ui_sender)); + } else { + ui_sender.send(InstallMessage::Error( + t!("error_target_disk_not_selected").to_string() + )); + } + } + }); + } + + // ── Kanaldaki mesajları tüket ────────────────────────── + if let Some(ref rx) = self.rx { + loop { + match rx.try_recv() { + Ok(InstallMessage::Log(line)) => { + state.install_log.push(line); + } + Ok(InstallMessage::Progress(p)) => { + state.install_progress = p; + } + Ok(InstallMessage::Done) => { + state.install_progress = 1.0; + self.finished = true; + } + Ok(InstallMessage::Error(e)) => { + self.error_screen = Some(ErrorScreen::new( + t!("install_failed"), + e, + state.install_log.clone(), + )); + } + Err(mpsc::TryRecvError::Empty) => break, + Err(mpsc::TryRecvError::Disconnected) => { + if !self.finished && self.error_screen.is_none() { + self.error_screen = Some(ErrorScreen::new( + t!("install_failed"), + t!("error_thread_unexpectedly_terminated").to_string(), + state.install_log.clone(), + )); + } + break; + } + } + } + } + + // ── Hata ekranı ──────────────────────────────────────── + if let Some(ref mut err) = self.error_screen { + let mut retry = false; + let mut quit = false; + err.show(ui, || retry = true, || quit = true); + if retry { self.on_enter(state); } + if quit { ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); } + return; + } + + // ── Normal kurulum görünümü ──────────────────────────── + // Üst: Slayt gösterisi | Alt: ilerleme + log + let available_w = ui.available_width(); + let available_h = ui.available_height(); + + ui.vertical(|ui| { + // Üst kısım — slayt gösterisi + let slide_h = (available_h * 0.45).max(280.0); + ui.allocate_ui(egui::vec2(available_w, slide_h), |ui| { + ui.vertical(|ui| { + ui.add_space(8.0); + theme::section_heading(ui, &t!("execution_title")); + ui.label( + egui::RichText::new(t!("execution_description")) + .color(theme::c_text_dim()) + .size(13.0), + ); + ui.add_space(16.0); + + if let Some(ref mut ss) = self.slideshow { + ss.show(ui); + ui.add_space(10.0); + // Manuel ileri/geri butonları + ui.horizontal(|ui| { + if ui.small_button("‹").clicked() { ss.previous(); } + if ui.small_button("›").clicked() { ss.advance(); } + }); + } + }); + }); + + ui.add_space(16.0); + ui.separator(); + ui.add_space(16.0); + + // Alt kısım — ilerleme + log + let log_h = available_h - slide_h - 50.0; + ui.allocate_ui(egui::vec2(available_w, log_h), |ui| { + ui.vertical(|ui| { + ui.add_space(8.0); + + // İlerleme çubuğu + let running = !self.finished + && self.error_screen.is_none() + && state.install_progress > 0.0; + + egui::Frame::none() + .fill(theme::c_bg_widget()) + .rounding(egui::Rounding::same(8.0)) + .inner_margin(egui::Margin::same(12.0)) + .show(ui, |ui| { + ui.set_width(available_w - 4.0); + + // Yüzde + adım etiketi + let step_label = state.install_log.last() + .cloned() + .unwrap_or_default(); + ui.horizontal(|ui| { + ui.label( + egui::RichText::new( + format!("{:.0}%", state.install_progress * 100.0) + ) + .strong() + .color(theme::c_accent()), + ); + ui.label( + egui::RichText::new(&step_label) + .size(12.0) + .color(theme::c_text_dim()), + ); + }); + + ui.add_space(4.0); + ui.add( + egui::ProgressBar::new(state.install_progress) + .animate(running) + .desired_height(10.0), + ); + }); + + // Durum etiketi + ui.add_space(8.0); + if self.finished { + theme::success_box(ui, &t!("install_done")); + } else if running { + ui.horizontal(|ui| { + ui.spinner(); + ui.colored_label(theme::c_text_dim(), t!("install_in_progress")); + }); + } + + ui.add_space(8.0); + + // Log terminali + let terminal_h = if self.finished { log_h - 60.0 } else { log_h - 80.0 }; + egui::ScrollArea::vertical() + .max_height(terminal_h.max(100.0)) + .stick_to_bottom(true) + .id_source("exec_log") + .show(ui, |ui| { + egui::Frame::none() + .fill(egui::Color32::from_rgb(12, 12, 20)) + .rounding(egui::Rounding::same(6.0)) + .inner_margin(egui::Margin::same(10.0)) + .show(ui, |ui| { + ui.set_width(available_w - 8.0); + for line in &state.install_log { + let color = log_color(line); + ui.colored_label(color, line); + } + }); + }); + }); + }); + }); + + // Kurulum devam ediyorsa sürekli yeniden çiz + if !self.finished && self.error_screen.is_none() { + ui.ctx().request_repaint(); + } + } + + fn is_complete(&self, _state: &GlobalState) -> bool { + self.finished && self.error_screen.is_none() + } +} + +fn log_color(line: &str) -> egui::Color32 { + if line.starts_with('✗') { + theme::c_error() + } else if line.starts_with('✓') { + theme::c_success() + } else if line.starts_with('▶') { + theme::c_accent() + } else if line.starts_with('⚠') { + theme::c_warning() + } else { + egui::Color32::from_rgb(185, 185, 205) + } +} diff --git a/src/steps/finish.rs b/src/steps/finish.rs new file mode 100644 index 0000000..2004d89 --- /dev/null +++ b/src/steps/finish.rs @@ -0,0 +1,60 @@ +use eframe::egui; +use rust_i18n::t; +use crate::installer::{GlobalState, InstallerStep}; +use crate::ui::theme; + +pub struct FinishStep; + +impl InstallerStep for FinishStep { + fn name(&self) -> String { t!("finish").to_string() } + + fn show(&mut self, ui: &mut egui::Ui, _state: &mut GlobalState) { + ui.add_space(32.0); + ui.vertical_centered(|ui| { + // Büyük onay simgesi + ui.label( + egui::RichText::new("✔") + .size(72.0) + .color(theme::c_success()), + ); + ui.add_space(16.0); + + ui.label( + egui::RichText::new(t!("finish_title")) + .size(24.0) + .strong() + .color(theme::c_text()), + ); + ui.add_space(8.0); + ui.label( + egui::RichText::new(t!("finish_description")) + .size(14.0) + .color(theme::c_text_dim()), + ); + + ui.add_space(32.0); + + // Yeniden Başlat — ana eylem butonu + if ui.add( + theme::primary_button(&t!("finish_restart")) + .min_size(egui::vec2(200.0, 44.0)), + ).clicked() { + let _ = std::process::Command::new("systemctl") + .arg("reboot") + .spawn(); + } + + ui.add_space(12.0); + + // Canlı masaüstüne dön — ikincil eylem + if ui.add( + theme::secondary_button(&t!("finish_live")) + .min_size(egui::vec2(200.0, 36.0)), + ).clicked() { + ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); + } + }); + } + + fn is_complete(&self, _state: &GlobalState) -> bool { true } +} diff --git a/src/steps/keyboard.rs b/src/steps/keyboard.rs new file mode 100644 index 0000000..0fe71cb --- /dev/null +++ b/src/steps/keyboard.rs @@ -0,0 +1,103 @@ +use eframe::egui; +use rust_i18n::t; +use crate::installer::{GlobalState, InstallerStep}; + +/// Klavye düzeni ve varyantı seçimi. +/// Gerçek uygulamada mevcut düzenler `localectl list-keymaps` +/// veya `/usr/share/X11/xkb/rules/evdev.lst` dosyasından okunabilir. +pub struct KeyboardStep { + test_input: String, + layouts: Vec<(&'static str, &'static str)>, // (kod, gösterim adı) +} + +impl Default for KeyboardStep { + fn default() -> Self { + Self { + test_input: String::new(), + layouts: vec![ + ("tr", "Türkçe (Q)"), + ("tr:f", "Türkçe (F)"), + ("us", "İngilizce (US)"), + ("de", "Almanca"), + ("fr", "Fransızca"), + ("es", "İspanyolca"), + ("ru", "Rusça"), + ("ar", "Arapça"), + ], + } + } +} + +impl InstallerStep for KeyboardStep { + fn name(&self) -> String { + t!("keyboard").to_string() + } + + fn on_enter(&mut self, state: &mut GlobalState) { + // Varsayılan düzen sistemi diline göre seçilir + if state.keyboard_layout.is_empty() { + state.keyboard_layout = if state.language == "tr" { + "tr".to_string() + } else { + "us".to_string() + }; + } + } + + fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) { + ui.heading(t!("keyboard_title")); + ui.label(t!("keyboard_description")); + + ui.add_space(12.0); + + ui.columns(2, |cols| { + // Sol: Düzen listesi + cols[0].label(t!("keyboard_layout_label")); + egui::ScrollArea::vertical() + .id_source("kbd_layouts") + .max_height(260.0) + .show(&mut cols[0], |ui| { + // &(code, display) pattern ile code: &str, display: &str olur + for &(code, display) in &self.layouts { + // tr:f kodunu layout+variant olarak ayır + let (layout, variant) = if let Some(pos) = code.find(':') { + (&code[..pos], &code[pos + 1..]) + } else { + (code, "") + }; + + let is_selected = state.keyboard_layout == layout + && state.keyboard_variant == variant; + + if ui.selectable_label(is_selected, display).clicked() { + state.keyboard_layout = layout.to_string(); + state.keyboard_variant = variant.to_string(); + } + } + }); + + // Sağ: Test alanı + cols[1].label(t!("keyboard_test_label")); + cols[1].add_space(4.0); + cols[1].add( + egui::TextEdit::multiline(&mut self.test_input) + .desired_rows(5) + .hint_text(t!("keyboard_test_hint")), + ); + + cols[1].add_space(8.0); + cols[1].label(format!("{}: {}", t!("keyboard_selected"), { + let variant_part = if state.keyboard_variant.is_empty() { + String::new() + } else { + format!(" ({})", state.keyboard_variant) + }; + format!("{}{}", state.keyboard_layout, variant_part) + })); + }); + } + + fn is_complete(&self, state: &GlobalState) -> bool { + !state.keyboard_layout.is_empty() + } +} diff --git a/src/steps/mod.rs b/src/steps/mod.rs new file mode 100644 index 0000000..0a36d04 --- /dev/null +++ b/src/steps/mod.rs @@ -0,0 +1,13 @@ +pub mod keyboard; +pub mod users; +pub mod summary; +pub mod execution; +pub mod finish; +pub mod partition; + +pub use keyboard::KeyboardStep; +pub use users::UsersStep; +pub use summary::SummaryStep; +pub use execution::ExecutionStep; +pub use finish::FinishStep; +pub use partition::PartitionStep; diff --git a/src/steps/partition.rs b/src/steps/partition.rs new file mode 100644 index 0000000..d89c7c4 --- /dev/null +++ b/src/steps/partition.rs @@ -0,0 +1,585 @@ +//! Disk bölümleme adımı — Otomatik ve Manuel mod destekli. + +use eframe::egui; +use rust_i18n::t; +// sysinfo::Disks mount point başına bir kayıt döndürür (partition'lar), +// ham disk listesi için lsblk kullanıyoruz. + +/// `/sys/block` altındaki gerçek blok aygıtlarını (partition değil) listeler. +/// lsblk'dan JSON çıktısı ayrıştırılır; başarısız olursa /sys/block fallback. +fn list_block_devices() -> Vec { + // lsblk -d: sadece diskler (partition'lar hariç) + // -o NAME,SIZE,MODEL,TYPE -b: byte cinsinden boyut + let out = std::process::Command::new("lsblk") + .args(["-d", "-o", "NAME,SIZE,MODEL", "-b", "--noheadings"]) + .output(); + + let mut disks = Vec::new(); + + if let Ok(o) = out { + let text = String::from_utf8_lossy(&o.stdout); + for line in text.lines() { + let cols: Vec<&str> = line.splitn(3, char::is_whitespace) + .filter(|s| !s.is_empty()) + .collect(); + if cols.len() < 2 { continue; } + + let name_raw = cols[0]; // örn. "sda" veya "nvme0n1" + // loop, ram, sr aygıtlarını atla + if name_raw.starts_with("loop") + || name_raw.starts_with("ram") + || name_raw.starts_with("sr") + { continue; } + + let size_bytes: u64 = cols[1].trim().parse().unwrap_or(0); + let model = if cols.len() >= 3 { cols[2].trim() } else { "" }; + + disks.push(crate::installer::DiskInfo { + name: format!("/dev/{}", name_raw), + model: model.to_string(), + size_gb: size_bytes / 1_073_741_824, + size_bytes, + }); + } + } + + // lsblk başarısız olduysa /sys/block fallback + if disks.is_empty() { + if let Ok(rd) = std::fs::read_dir("/sys/block") { + for entry in rd.flatten() { + let name = entry.file_name().to_string_lossy().to_string(); + if name.starts_with("loop") || name.starts_with("ram") { continue; } + + let size_path = format!("/sys/block/{}/size", name); + let size_sectors: u64 = std::fs::read_to_string(&size_path) + .unwrap_or_default().trim().parse().unwrap_or(0); + let size_bytes = size_sectors * 512; + + let model_path = format!("/sys/block/{}/device/model", name); + let model = std::fs::read_to_string(&model_path) + .unwrap_or_default().trim().to_string(); + + disks.push(crate::installer::DiskInfo { + name: format!("/dev/{}", name), + model, + size_gb: size_bytes / 1_073_741_824, + size_bytes, + }); + } + } + } + + disks +} + +use crate::installer::{ + CustomPartition, DiskInfo, FsType, GlobalState, InstallerStep, + PartitionPlan, PartitionTableType, +}; + +const MIN_DISK_GB: u64 = 10; +const EFI_MB: u64 = 512; +const SWAP_MB_MIN: u64 = 512; +const SWAP_MB_MAX: u64 = 8 * 1024; + +// ───────────────────────────────────────────── +// Manuel bölümleme için yerel durum +// ───────────────────────────────────────────── + +#[derive(Default)] +struct ManualState { + /// "Bölüm Ekle" diyaloğu açık mı? + adding: bool, + /// Diyalog: seçili dosya sistemi + add_fstype: usize, // FsType listesindeki indeks + /// Diyalog: boyut alanı (MB, metin girişi) + add_size_str: String, + /// Diyalog: bağlama noktası + add_mountpoint: String, + /// Silinmek istenen bölüm indeksi (onay isteği) + delete_idx: Option, + /// Genel hata mesajı + error: Option, +} + +const FS_OPTIONS: &[(&str, FsType)] = &[ + ("ext4", FsType::Ext4), + ("btrfs", FsType::Btrfs), + ("xfs", FsType::Xfs), + ("FAT32 (EFI)", FsType::Fat32), + ("swap", FsType::Swap), +]; + +// ───────────────────────────────────────────── +// PartitionStep +// ───────────────────────────────────────────── + +pub struct PartitionStep { + scanned: bool, + is_uefi: bool, + manual: ManualState, +} + +impl Default for PartitionStep { + fn default() -> Self { + Self { + scanned: false, + is_uefi: std::path::Path::new("/sys/firmware/efi").exists(), + manual: ManualState::default(), + } + } +} + +/// RAM miktarına göre önerilen swap alanı (MB). +fn recommended_swap_mb() -> u64 { + use sysinfo::System; + let mut sys = System::new(); + sys.refresh_memory(); + let ram_mb = sys.total_memory() / 1024 / 1024; + let swap = if ram_mb <= 2048 { + ram_mb + } else if ram_mb <= 8192 { + ram_mb / 2 + } else { + 4096 + }; + swap.clamp(SWAP_MB_MIN, SWAP_MB_MAX) +} + +/// Seçili disk için otomatik bölümleme planı hesapla. +fn make_plan(disk: &DiskInfo, is_uefi: bool) -> Option { + if disk.size_gb < MIN_DISK_GB { + return None; + } + let total_mb = disk.size_bytes / 1024 / 1024; + let efi_mb = if is_uefi { EFI_MB } else { 0 }; + let swap_mb = recommended_swap_mb(); + let overhead = efi_mb + swap_mb + 512; + let root_mb = total_mb.saturating_sub(overhead); + if root_mb < 6144 { return None; } + Some(PartitionPlan { + disk: disk.name.clone(), + table_type: if is_uefi { PartitionTableType::Gpt } else { PartitionTableType::Mbr }, + efi_mb, + swap_mb, + root_mb, + }) +} + +/// Manuel listedeki bölümlerin geçerliliğini kontrol eder. +fn validate_manual(parts: &[CustomPartition], is_uefi: bool) -> Option { + let has_root = parts.iter().any(|p| p.mountpoint == "/"); + let has_efi = parts.iter().any(|p| p.mountpoint == "/boot/efi" || p.fstype == FsType::Fat32); + + if !has_root { + return Some(t!("mp_no_root").to_string()); + } + if is_uefi && !has_efi { + return Some(t!("mp_no_efi").to_string()); + } + None +} + +impl InstallerStep for PartitionStep { + fn name(&self) -> String { t!("partition").to_string() } + + fn on_enter(&mut self, state: &mut GlobalState) { + if !self.scanned { + state.available_disks = list_block_devices(); + state.available_disks.retain(|d| d.size_gb >= 4); + self.scanned = true; + } + } + + fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) { + ui.heading(t!("partition_title")); + ui.label(t!("partition_description")); + ui.add_space(10.0); + + if state.available_disks.is_empty() { + ui.colored_label(egui::Color32::RED, t!("no_disks_found")); + if ui.button(t!("rescan_disks")).clicked() { + self.scanned = false; + self.on_enter(state); + } + return; + } + + // ── Mod seçimi ───────────────────────────────────────── + ui.horizontal(|ui| { + ui.selectable_value(&mut state.erase_disk, true, t!("erase_disk_label")); + ui.selectable_value(&mut state.erase_disk, false, t!("manual_partition_label")); + }); + ui.add_space(10.0); + + if state.erase_disk { + self.show_auto_mode(ui, state); + } else { + self.show_manual_mode(ui, state); + } + } + + fn is_complete(&self, state: &GlobalState) -> bool { + if state.erase_disk { + state.partition_plan.is_some() + } else { + !state.custom_partitions.is_empty() + && validate_manual(&state.custom_partitions, self.is_uefi).is_none() + } + } +} + +// ───────────────────────────────────────────── +// Otomatik mod +// ───────────────────────────────────────────── + +impl PartitionStep { + fn show_auto_mode(&self, ui: &mut egui::Ui, state: &mut GlobalState) { + ui.group(|ui| { + ui.label(t!("select_disk_label")); + ui.add_space(4.0); + let disks = state.available_disks.clone(); + for disk in &disks { + let too_small = disk.size_gb < MIN_DISK_GB; + let label = format!("{} — {} GB ({})", disk.name, disk.size_gb, disk.model); + ui.add_enabled_ui(!too_small, |ui| { + let selected = state.selected_disk.as_deref() == Some(&disk.name); + if ui.radio(selected, &label).clicked() { + state.selected_disk = Some(disk.name.clone()); + state.partition_plan = make_plan(disk, self.is_uefi); + } + }); + if too_small { + ui.small(t!("disk_min_required", err = t!("disk_too_small"), n = MIN_DISK_GB.to_string())); + } + } + }); + + if let Some(ref plan) = state.partition_plan { + ui.add_space(12.0); + ui.separator(); + ui.add_space(8.0); + ui.strong(t!("partition_plan_title")); + ui.add_space(6.0); + partition_bar(ui, plan); + ui.add_space(8.0); + + egui::Grid::new("plan_grid") + .num_columns(3) + .spacing([20.0, 6.0]) + .striped(true) + .show(ui, |ui| { + ui.strong(t!("plan_col_part")); + ui.strong(t!("plan_col_fs")); + ui.strong(t!("plan_col_size")); + ui.end_row(); + + if plan.efi_mb > 0 { + ui.label(format!("{}1 (EFI)", plan.disk)); + ui.label("FAT32"); + ui.label(format!("{} MB", plan.efi_mb)); + ui.end_row(); + } + let swap_part = if plan.efi_mb > 0 { 2 } else { 1 }; + ui.label(format!("{}{} (swap)", plan.disk, swap_part)); + ui.label("swap"); + ui.label(format!("{} MB", plan.swap_mb)); + ui.end_row(); + + let root_part = swap_part + 1; + ui.label(format!("{}{}{}", plan.disk, root_part, t!("plan_root_suffix"))); + ui.label("ext4"); + ui.label(format!("{:.1} GB", plan.root_mb as f64 / 1024.0)); + ui.end_row(); + }); + + ui.add_space(8.0); + ui.label(format!("{}: {}", t!("partition_table_type"), plan.table_type)); + + ui.add_space(10.0); + egui::Frame::none() + .fill(egui::Color32::from_rgba_unmultiplied(200, 60, 40, 25)) + .rounding(5.0) + .inner_margin(egui::Margin::same(8.0)) + .show(ui, |ui| { + ui.colored_label( + egui::Color32::from_rgb(210, 80, 60), + format!("⚠ {}: {}", t!("erase_warning"), plan.disk), + ); + }); + } + } +} + +// ───────────────────────────────────────────── +// Manuel mod +// ───────────────────────────────────────────── + +impl PartitionStep { + fn show_manual_mode(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) { + let accent = crate::ui::theme::c_accent(); + + // ── Disk seçimi (hedef disk) ──────────────────────────── + ui.group(|ui| { + ui.label(t!("select_disk_label")); + ui.add_space(4.0); + let disks = state.available_disks.clone(); + for disk in &disks { + let selected = state.selected_disk.as_deref() == Some(&disk.name); + let label = format!("{} — {} GB ({})", disk.name, disk.size_gb, disk.model); + if ui.radio(selected, &label).clicked() { + state.selected_disk = Some(disk.name.clone()); + // Disk değişince listeyi sıfırla + state.custom_partitions.clear(); + self.manual.error = None; + } + } + }); + + ui.add_space(8.0); + + let disk = match &state.selected_disk { + Some(d) => d.clone(), + None => { + ui.label(t!("mp_select_disk_first")); + return; + } + }; + + // ── Mevcut bölüm listesi tablosu ─────────────────────── + ui.strong(t!("mp_plan_title")); + ui.add_space(4.0); + + let mut delete_idx: Option = None; + + egui::Grid::new("manual_parts_grid") + .num_columns(5) + .spacing([12.0, 6.0]) + .striped(true) + .show(ui, |ui| { + // Başlık + ui.strong(t!("mp_device")); + ui.strong(t!("mp_size")); + ui.strong(t!("mp_fstype")); + ui.strong(t!("mp_mountpoint")); + ui.strong(t!("mp_action")); + ui.end_row(); + + for (i, part) in state.custom_partitions.iter().enumerate() { + let size_str = if part.size_mb == 0 { + t!("mp_size_remaining").to_string() + } else if part.size_mb >= 1024 { + format!("{:.1} GB", part.size_mb as f64 / 1024.0) + } else { + format!("{} MB", part.size_mb) + }; + + ui.label(&part.device); + ui.label(&size_str); + ui.label(part.fstype.label()); + ui.label(&part.mountpoint); + if ui.small_button("🗑").on_hover_text(t!("mp_delete")).clicked() { + delete_idx = Some(i); + } + ui.end_row(); + } + }); + + // Silme onayı + if let Some(idx) = delete_idx { + self.manual.delete_idx = Some(idx); + } + if let Some(idx) = self.manual.delete_idx { + let dev = state.custom_partitions.get(idx) + .map(|p| p.device.clone()) + .unwrap_or_default(); + egui::Window::new(t!("mp_delete_confirm_title")) + .collapsible(false) + .resizable(false) + .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0]) + .show(ui.ctx(), |ui| { + ui.label(t!("mp_confirm_delete", dev = dev)); + ui.add_space(8.0); + ui.horizontal(|ui| { + if ui.button(t!("mp_delete_confirm_yes")).clicked() { + if idx < state.custom_partitions.len() { + state.custom_partitions.remove(idx); + } + self.manual.delete_idx = None; + } + if ui.button(t!("cancel")).clicked() { + self.manual.delete_idx = None; + } + }); + }); + } + + ui.add_space(8.0); + + // ── "Bölüm Ekle" butonu ──────────────────────────────── + let btn = egui::Button::new(format!("➕ {}", t!("mp_add"))) + .fill(accent.gamma_multiply(0.15)); + if ui.add(btn).clicked() { + self.manual.adding = true; + let next_num = state.custom_partitions.len() + 1; + self.manual.add_size_str.clear(); + self.manual.add_mountpoint.clear(); + self.manual.add_fstype = 0; + // Akıllı varsayılan bağlama noktası + self.manual.add_mountpoint = match next_num { + 1 if self.is_uefi => "/boot/efi".to_string(), + 1 => "/".to_string(), + 2 if self.is_uefi => "swap".to_string(), + 2 => "swap".to_string(), + 3 => "/".to_string(), + _ => String::new(), + }; + } + + // ── "Bölüm Ekle" diyaloğu ────────────────────────────── + if self.manual.adding { + egui::Window::new(t!("mp_add")) + .collapsible(false) + .resizable(false) + .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0]) + .show(ui.ctx(), |ui| { + egui::Grid::new("add_part_grid") + .num_columns(2) + .spacing([12.0, 8.0]) + .show(ui, |ui| { + + // Dosya sistemi + ui.label(t!("mp_fstype")); + egui::ComboBox::from_id_source("fs_combo") + .selected_text(FS_OPTIONS[self.manual.add_fstype].0) + .show_ui(ui, |ui| { + for (i, (label, _)) in FS_OPTIONS.iter().enumerate() { + ui.selectable_value( + &mut self.manual.add_fstype, i, *label + ); + } + }); + ui.end_row(); + + // Boyut + ui.label(t!("mp_size_hint")); + ui.text_edit_singleline(&mut self.manual.add_size_str); + ui.end_row(); + + // Bağlama noktası + ui.label(t!("mp_mountpoint")); + let mp_field = egui::TextEdit::singleline(&mut self.manual.add_mountpoint) + .hint_text(t!("mp_add_dialog_hint")); + ui.add(mp_field); + ui.end_row(); + }); + + ui.add_space(8.0); + ui.horizontal(|ui| { + let ok_btn = egui::Button::new(t!("mp_add_btn")).fill(accent.gamma_multiply(0.2)); + if ui.add(ok_btn).clicked() { + let size_mb: u64 = self.manual.add_size_str + .trim().parse().unwrap_or(0); + let mp = self.manual.add_mountpoint.trim().to_string(); + let fstype = FS_OPTIONS[self.manual.add_fstype].1.clone(); + let part_num = state.custom_partitions.len() + 1; + let device = crate::installer::part_path(&disk, part_num as u32); + + if mp.is_empty() { + self.manual.error = Some(t!("mp_error_empty_mountpoint").to_string()); + } else { + state.custom_partitions.push(CustomPartition { + device, + size_mb, + fstype, + mountpoint: mp, + }); + self.manual.error = None; + self.manual.adding = false; + } + } + if ui.button(t!("cancel")).clicked() { + self.manual.adding = false; + } + }); + }); + } + + // ── Doğrulama mesajları ───────────────────────────────── + ui.add_space(6.0); + if let Some(ref err) = self.manual.error { + ui.colored_label(egui::Color32::from_rgb(217, 0, 91), err); + } + if !state.custom_partitions.is_empty() { + if let Some(warn) = validate_manual(&state.custom_partitions, self.is_uefi) { + ui.colored_label(egui::Color32::from_rgb(220, 160, 40), warn); + } else { + ui.colored_label( + egui::Color32::from_rgb(60, 180, 90), + t!("mp_plan_valid"), + ); + } + } + } +} + +// ───────────────────────────────────────────── +// Yardımcı: renkli bölüm şeridi +// ───────────────────────────────────────────── + +fn partition_bar(ui: &mut egui::Ui, plan: &PartitionPlan) { + let total = (plan.efi_mb + plan.swap_mb + plan.root_mb) as f32; + let bar_height = 28.0; + let (rect, _) = ui.allocate_exact_size( + egui::vec2(ui.available_width(), bar_height), + egui::Sense::hover(), + ); + let painter = ui.painter(); + + struct Seg<'a> { frac: f32, color: egui::Color32, label: &'a str } + let mut segments: Vec = Vec::new(); + + if plan.efi_mb > 0 { + segments.push(Seg { + frac: plan.efi_mb as f32 / total, + color: egui::Color32::from_rgb(80, 160, 220), + label: "EFI", + }); + } + segments.push(Seg { + frac: plan.swap_mb as f32 / total, + color: egui::Color32::from_rgb(220, 160, 40), + label: "swap", + }); + segments.push(Seg { + frac: plan.root_mb as f32 / total, + color: egui::Color32::from_rgb(80, 190, 100), + label: "/", + }); + + let mut x = rect.left(); + let rounding = egui::Rounding::same(4.0); + for (i, seg) in segments.iter().enumerate() { + let w = seg.frac * rect.width(); + let seg_rect = egui::Rect::from_min_size( + egui::pos2(x, rect.top()), + egui::vec2(w - 1.0, bar_height), + ); + let seg_rounding = if i == 0 { + egui::Rounding { nw: rounding.nw, sw: rounding.sw, ne: 0.0, se: 0.0 } + } else if i == segments.len() - 1 { + egui::Rounding { nw: 0.0, sw: 0.0, ne: rounding.ne, se: rounding.se } + } else { + egui::Rounding::ZERO + }; + painter.rect_filled(seg_rect, seg_rounding, seg.color); + painter.text( + seg_rect.center(), + egui::Align2::CENTER_CENTER, + seg.label, + egui::FontId::proportional(12.0), + egui::Color32::WHITE, + ); + x += w; + } +} diff --git a/src/steps/summary.rs b/src/steps/summary.rs new file mode 100644 index 0000000..eee9efd --- /dev/null +++ b/src/steps/summary.rs @@ -0,0 +1,111 @@ +use eframe::egui; +use rust_i18n::t; +use crate::installer::{GlobalState, InstallerStep}; + +/// Kurulumdan önce kullanıcının tüm seçimlerini gösteren özet ekranı. +/// Calamares'in Summary modülüne karşılık gelir. +pub struct SummaryStep; + +impl InstallerStep for SummaryStep { + fn name(&self) -> String { + t!("summary").to_string() + } + + fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) { + ui.heading(t!("summary_title")); + ui.label(t!("summary_description")); + + ui.add_space(12.0); + + egui::Frame::group(ui.style()).show(ui, |ui| { + ui.set_width(ui.available_width()); + + egui::Grid::new("summary_grid") + .num_columns(2) + .spacing([20.0, 8.0]) + .striped(true) + .show(ui, |ui| { + summary_row(ui, t!("summary_language"), &state.language); + summary_row(ui, t!("summary_timezone"), &state.timezone); + + let kb = if state.keyboard_variant.is_empty() { + state.keyboard_layout.clone() + } else { + format!("{} ({})", state.keyboard_layout, state.keyboard_variant) + }; + summary_row(ui, t!("summary_keyboard"), &kb); + + let disk_str = match &state.selected_disk { + Some(d) => { + if state.erase_disk { + format!("{} — {}", d, t!("summary_erase_mode")) + } else { + format!("{} — {}", d, t!("summary_manual_mode")) + } + } + None => t!("summary_not_selected").to_string(), + }; + summary_row(ui, t!("summary_disk"), &disk_str); + + // Bölüm planı detayları + if state.erase_disk { + if let Some(ref plan) = state.partition_plan { + let plan_str = if plan.efi_mb > 0 { + format!("EFI {}MB | swap {}MB | / {:.1}GB ({})", + plan.efi_mb, plan.swap_mb, + plan.root_mb as f64 / 1024.0, + plan.table_type) + } else { + format!("swap {}MB | / {:.1}GB ({})", + plan.swap_mb, + plan.root_mb as f64 / 1024.0, + plan.table_type) + }; + summary_row(ui, t!("summary_partition_plan"), &plan_str); + } + } else if !state.custom_partitions.is_empty() { + let mut plan_lines = Vec::new(); + for part in &state.custom_partitions { + let size_str = if part.size_mb == 0 { + t!("mp_size_remaining").to_string() + } else if part.size_mb >= 1024 { + format!("{:.1} GB", part.size_mb as f64 / 1024.0) + } else { + format!("{} MB", part.size_mb) + }; + plan_lines.push(format!("{} ➔ {} ({}, {})", part.device, part.mountpoint, part.fstype, size_str)); + } + summary_row(ui, t!("summary_custom_partitions"), &plan_lines.join("\n")); + } + + summary_row(ui, t!("summary_username"), &state.username); + summary_row(ui, t!("summary_hostname"), &state.hostname); + }); + }); + + ui.add_space(16.0); + + // Uyarı kutusu + egui::Frame::none() + .fill(egui::Color32::from_rgba_unmultiplied(200, 60, 40, 30)) + .rounding(6.0) + .inner_margin(egui::Margin::same(10.0)) + .show(ui, |ui| { + ui.colored_label( + egui::Color32::from_rgb(180, 60, 40), + t!("summary_warning"), + ); + }); + } + + fn is_complete(&self, _state: &GlobalState) -> bool { + // Özet her zaman geçerlidir; önceki adımlar bunu garantiler. + true + } +} + +fn summary_row(ui: &mut egui::Ui, label: impl Into, value: &str) { + ui.strong(label.into()); + ui.label(value); + ui.end_row(); +} diff --git a/src/steps/users.rs b/src/steps/users.rs new file mode 100644 index 0000000..57406cb --- /dev/null +++ b/src/steps/users.rs @@ -0,0 +1,186 @@ +use eframe::egui; +use rust_i18n::t; +use crate::installer::{GlobalState, InstallerStep}; + +/// Kullanıcı adı, şifre ve hostname ayarları adımı. +/// Calamares'in Users modülüne karşılık gelir. +pub struct UsersStep { + show_password: bool, + show_password_confirm: bool, +} + +impl Default for UsersStep { + fn default() -> Self { + Self { + show_password: false, + show_password_confirm: false, + } + } +} + +/// Kullanıcı adının geçerliliğini kontrol eder. +/// Linux kuralları: küçük harf veya alt çizgi ile başlamalı, +/// en fazla 32 karakter, yalnızca [a-z0-9_-] içermeli. +fn is_valid_username(s: &str) -> bool { + if s.is_empty() || s.len() > 32 { + return false; + } + let mut chars = s.chars(); + // İlk karakter küçük harf veya alt çizgi olmalı + match chars.next() { + Some(c) if c.is_ascii_lowercase() || c == '_' => {} + _ => return false, + } + chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-') +} + +/// Hostname kuralları: 1-63 karakter, yalnızca [a-zA-Z0-9-], tire ile başlayamaz/bitemez. +fn is_valid_hostname(s: &str) -> bool { + if s.is_empty() || s.len() > 63 { + return false; + } + if s.starts_with('-') || s.ends_with('-') { + return false; + } + s.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') +} + +fn password_strength(p: &str) -> (String, egui::Color32) { + let len = p.len(); + let has_upper = p.chars().any(|c| c.is_uppercase()); + let has_digit = p.chars().any(|c| c.is_ascii_digit()); + let has_special = p.chars().any(|c| "!@#$%^&*()_+-=[]{}|;':\",./<>?".contains(c)); + let score = (len >= 8) as u8 + + (len >= 12) as u8 + + has_upper as u8 + + has_digit as u8 + + has_special as u8; + match score { + 0..=1 => (t!("pwd_very_weak").to_string(), egui::Color32::from_rgb(200, 60, 40)), + 2 => (t!("pwd_weak").to_string(), egui::Color32::from_rgb(220, 140, 40)), + 3 => (t!("pwd_medium").to_string(), egui::Color32::from_rgb(200, 180, 40)), + 4 => (t!("pwd_strong").to_string(), egui::Color32::from_rgb(80, 170, 80)), + _ => (t!("pwd_very_strong").to_string(), egui::Color32::from_rgb(40, 140, 60)), + } +} + +impl InstallerStep for UsersStep { + fn name(&self) -> String { + t!("users").to_string() + } + + fn on_enter(&mut self, state: &mut GlobalState) { + // Hostname boşsa username'den öner + if state.hostname.is_empty() && !state.username.is_empty() { + state.hostname = format!("{}-pc", state.username); + } + } + + fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) { + ui.heading(t!("users_title")); + ui.label(t!("users_description")); + ui.add_space(12.0); + + egui::Grid::new("users_grid") + .num_columns(2) + .spacing([12.0, 10.0]) + .show(ui, |ui| { + // Kullanıcı adı + ui.label(t!("username_label")); + ui.horizontal(|ui| { + ui.text_edit_singleline(&mut state.username); + if !state.username.is_empty() { + if is_valid_username(&state.username) { + ui.colored_label(egui::Color32::from_rgb(80, 170, 80), "✓"); + } else { + ui.colored_label(egui::Color32::from_rgb(200, 60, 40), "✗"); + } + } + }); + ui.end_row(); + + // Şifre + ui.label(t!("password_label")); + ui.horizontal(|ui| { + if self.show_password { + ui.text_edit_singleline(&mut state.password); + } else { + ui.add(egui::TextEdit::singleline(&mut state.password).password(true)); + } + if ui.small_button(if self.show_password { "🙈" } else { "👁" }).clicked() { + self.show_password = !self.show_password; + } + }); + ui.end_row(); + + // Şifre gücü göstergesi + ui.label(""); + if !state.password.is_empty() { + let (label, color) = password_strength(&state.password); + ui.colored_label(color, label); + } + ui.end_row(); + + // Şifre doğrulama + ui.label(t!("password_confirm_label")); + ui.horizontal(|ui| { + if self.show_password_confirm { + ui.text_edit_singleline(&mut state.password_confirm); + } else { + ui.add(egui::TextEdit::singleline(&mut state.password_confirm).password(true)); + } + if ui.small_button(if self.show_password_confirm { "🙈" } else { "👁" }).clicked() { + self.show_password_confirm = !self.show_password_confirm; + } + if !state.password_confirm.is_empty() { + if state.password == state.password_confirm { + ui.colored_label(egui::Color32::from_rgb(80, 170, 80), "✓"); + } else { + ui.colored_label(egui::Color32::from_rgb(200, 60, 40), t!("passwords_no_match")); + } + } + }); + ui.end_row(); + + // Hostname + ui.label(t!("hostname_label")); + ui.horizontal(|ui| { + // Username değişince hostname otomatik güncellenir (boşsa) + if state.hostname.is_empty() && !state.username.is_empty() { + state.hostname = format!("{}-pc", state.username); + } + ui.text_edit_singleline(&mut state.hostname); + if !state.hostname.is_empty() { + if is_valid_hostname(&state.hostname) { + ui.colored_label(egui::Color32::from_rgb(80, 170, 80), "✓"); + } else { + ui.colored_label(egui::Color32::from_rgb(200, 60, 40), "✗"); + } + } + }); + ui.end_row(); + }); + + // Hata mesajları + ui.add_space(8.0); + if !state.username.is_empty() && !is_valid_username(&state.username) { + ui.colored_label( + egui::Color32::from_rgb(200, 60, 40), + t!("username_invalid"), + ); + } + if !state.hostname.is_empty() && !is_valid_hostname(&state.hostname) { + ui.colored_label( + egui::Color32::from_rgb(200, 60, 40), + t!("hostname_invalid"), + ); + } + } + + fn is_complete(&self, state: &GlobalState) -> bool { + is_valid_username(&state.username) + && is_valid_hostname(&state.hostname) + && !state.password.is_empty() + && state.password == state.password_confirm + } +} diff --git a/src/ui/error_screen.rs b/src/ui/error_screen.rs new file mode 100644 index 0000000..8be4dc3 --- /dev/null +++ b/src/ui/error_screen.rs @@ -0,0 +1,165 @@ +//! Hata yakalama ve kullanıcıya bildirme ekranı. +//! +//! Kurulum sırasında kritik bir hata oluştuğunda +//! bu ekran tüm merkez paneli kaplar. +//! Log detayları açılıp kapanabilir; kullanıcı +//! hata raporunu panoya kopyalayabilir. + +use eframe::egui; +use rust_i18n::t; +use crate::ui::theme; + +pub struct ErrorScreen { + pub title: String, + pub message: String, + pub log_lines: Vec, + log_expanded: bool, + copied: bool, + copied_timer: u8, // frame sayacı; 0 olunca "Kopyalandı" etiketi kaybolur +} + +impl ErrorScreen { + pub fn new(title: impl Into, message: impl Into, log: Vec) -> Self { + Self { + title: title.into(), + message: message.into(), + log_lines: log, + log_expanded: false, + copied: false, + copied_timer: 0, + } + } + + /// Ekranı çizer. `on_retry` ve `on_quit` kapanışları buton basımlarında çağrılır. + pub fn show( + &mut self, + ui: &mut egui::Ui, + on_retry: impl FnOnce(), + on_quit: impl FnOnce(), + ) { + // "Kopyalandı" zamanlayıcısını azalt + if self.copied && self.copied_timer > 0 { + self.copied_timer -= 1; + if self.copied_timer == 0 { + self.copied = false; + } + ui.ctx().request_repaint(); + } + + ui.add_space(24.0); + ui.vertical_centered(|ui| { + // ── Büyük hata simgesi ───────────────────────── + ui.label( + egui::RichText::new("✗") + .size(56.0) + .color(theme::c_error()), + ); + ui.add_space(10.0); + + // ── Başlık ──────────────────────────────────── + ui.label( + egui::RichText::new(&self.title) + .size(22.0) + .strong() + .color(theme::c_text()), + ); + ui.add_space(6.0); + + // ── Hata mesajı ─────────────────────────────── + egui::Frame::none() + .fill(egui::Color32::from_rgba_unmultiplied(0xF4, 0x43, 0x36, 18)) + .stroke(egui::Stroke::new(1.0, theme::c_error())) + .rounding(egui::Rounding::same(8.0)) + .inner_margin(egui::Margin::same(12.0)) + .show(ui, |ui| { + ui.set_width(ui.available_width().min(560.0)); + ui.colored_label(theme::c_error(), &self.message); + }); + + ui.add_space(16.0); + + // ── Log bölümü (aç/kapat) ───────────────────── + let log_label = if self.log_expanded { + t!("error_hide_log") + } else { + t!("error_show_log") + }; + + if ui.button(log_label).clicked() { + self.log_expanded = !self.log_expanded; + } + + if self.log_expanded { + ui.add_space(6.0); + egui::ScrollArea::vertical() + .max_height(180.0) + .id_source("error_log") + .show(ui, |ui| { + egui::Frame::none() + .fill(egui::Color32::from_rgb(14, 14, 22)) + .rounding(egui::Rounding::same(6.0)) + .inner_margin(egui::Margin::same(10.0)) + .show(ui, |ui| { + ui.set_width(ui.available_width().min(560.0)); + for line in &self.log_lines { + let color = log_line_color(line); + ui.colored_label(color, line); + } + }); + }); + + ui.add_space(6.0); + + // Panoya kopyala + let copy_label = if self.copied { + t!("error_copied") + } else { + t!("error_copy_log") + }; + + if ui.small_button(copy_label).clicked() && !self.copied { + let full_log = self.log_lines.join("\n"); + ui.ctx().copy_text(full_log); + self.copied = true; + self.copied_timer = 120; // ~2 saniye (60fps varsayımı) + } + } + + ui.add_space(20.0); + + // ── Eylem butonları ─────────────────────────── + ui.horizontal(|ui| { + // Ortalamak için boş genişlik hesapla + let btn_w = 140.0; + let gap = 16.0; + let total = btn_w * 2.0 + gap; + let side = (ui.available_width() - total) / 2.0; + ui.add_space(side.max(0.0)); + + if ui.add(theme::danger_button(&t!("error_quit"))).clicked() { + on_quit(); + } + + ui.add_space(gap); + + if ui.add(theme::primary_button(&t!("error_retry"))).clicked() { + on_retry(); + } + }); + }); + } +} + +fn log_line_color(line: &str) -> egui::Color32 { + if line.starts_with('✗') || line.to_lowercase().contains("hata") || line.to_lowercase().contains("error") { + theme::c_error() + } else if line.starts_with('✓') { + theme::c_success() + } else if line.starts_with('▶') { + theme::c_accent() + } else if line.starts_with('⚠') { + theme::c_warning() + } else { + egui::Color32::from_rgb(180, 180, 200) + } +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs new file mode 100644 index 0000000..63895a4 --- /dev/null +++ b/src/ui/mod.rs @@ -0,0 +1,6 @@ +pub mod theme; +pub mod slideshow; +pub mod error_screen; + +pub use error_screen::ErrorScreen; +pub use slideshow::Slideshow; diff --git a/src/ui/slideshow.rs b/src/ui/slideshow.rs new file mode 100644 index 0000000..5a6e4f5 --- /dev/null +++ b/src/ui/slideshow.rs @@ -0,0 +1,428 @@ +//! Kurulum sırasında gösterilen slayt gösterisi. +//! +//! Her slayt: başlık, açıklama metni ve isteğe bağlı bir simge karakteri. +//! Slaytlar otomatik olarak 6 saniyede bir değişir. +//! Masaüstü ortamına göre farklı slayt setleri yüklenebilir. + +use eframe::egui; +use std::time::{Duration, Instant}; +use rust_i18n::t; +use std::borrow::Cow; + +const SLIDE_INTERVAL: Duration = Duration::from_secs(6); + +pub struct Slide { + pub icon: &'static str, + pub title: Cow<'static, str>, + pub description: Cow<'static, str>, +} + +/// Masaüstü ortamına göre slayt seti döner. +/// ISO meta verisi ileride `/etc/livecd-desktop` gibi bir dosyadan okunabilir. +pub fn slides_for_desktop(desktop: &str) -> Vec { + let mut slides = default_slides(); + let specific_slides = match desktop { + "budgie" => budgie_slides(), + "cinnamon" => cinnamon_slides(), + "gnome" => gnome_slides(), + "kde" | "plasma" => kde_slides(), + "lxde" => lxde_slides(), + "lxqt" => lxqt_slides(), + "lumina" => lumina_slides(), + "mate" => mate_slides(), + "xfce" => xfce_slides(), + _ => vec![], + }; + slides.extend(specific_slides); + slides +} + +fn default_slides() -> Vec { + vec![ + Slide { + icon: "pisilogo", + title: t!("welcome_slide_title"), + description: t!("welcome_slide_description"), + }, + Slide { + icon: "pisi", + title: t!("package_manager_title"), + description: t!("package_manager_description"), + }, + Slide { + icon: "community", + title: t!("community_title"), + description: t!("community_description"), + }, + Slide { + icon: "pisi_speed", + title: t!("speed_title"), + description: t!("speed_description"), + }, + Slide { + icon: "securety", + title: t!("security_title"), + description: t!("security_description"), + }, + Slide { + icon: "customization", + title: t!("customization_title"), + description: t!("customization_description"), + }, + ] +} + +fn budgie_slides() -> Vec { + vec![ + Slide { + icon: "budgie", + title: t!("budgie_title"), + description: t!("budgie_description"), + }, + Slide { + icon: "budgie_applets", + title: t!("budgie_applets_title"), + description: t!("budgie_applets_description"), + }, + Slide { + icon: "budgie_raven", + title: t!("budgie_raven_title"), + description: t!("budgie_raven_description"), + }, + Slide { + icon: "budgie_gtk_theme", + title: t!("budgie_gtk_theme_title"), + description: t!("budgie_gtk_theme_description"), + }, + ] +} + +fn cinnamon_slides() -> Vec { + vec![ + Slide { + icon: "cinnamon", + title: t!("cinnamon_title"), + description: t!("cinnamon_description"), + }, + Slide { + icon: "cinnamon_panel", + title: t!("cinnamon_panel_title"), + description: t!("cinnamon_panel_description"), + }, + Slide { + icon: "cinnamon_settings", + title: t!("cinnamon_settings_title"), + description: t!("cinnamon_settings_description"), + }, + Slide { + icon: "cinnamon_desklets", + title: t!("cinnamon_desklets_title"), + description: t!("cinnamon_desklets_description"), + }, + ] +} + +fn gnome_slides() -> Vec { + vec![ + Slide { + icon: "gnome", + title: t!("gnome_title"), + description: t!("gnome_description"), + }, + Slide { + icon: "gnome_search", + title: t!("gnome_search_title"), + description: t!("gnome_search_description"), + }, + Slide { + icon: "gnome_extensions", + title: t!("gnome_extensions_title"), + description: t!("gnome_extensions_description"), + }, + ] +} + +fn kde_slides() -> Vec { + vec![ + Slide { + icon: "kde", + title: t!("kde_title"), + description: t!("kde_description"), + }, + Slide { + icon: "file_manager", + title: t!("dolphin_title"), + description: t!("dolphin_description"), + }, + Slide { + icon: "kde_connect", + title: t!("kde_connect_title"), + description: t!("kde_connect_description"), + }, + Slide { + icon: "discover", + title: t!("discover_title"), + description: t!("discover_description"), + }, + ] +} + +fn lxde_slides() -> Vec { + vec![ + Slide { + icon: "lxde", + title: t!("lxde_title"), + description: t!("lxde_description"), + }, + Slide { + icon: "lxde_openbox_title", + title: t!("lxde_openbox_title"), + description: t!("lxde_openbox_description"), + }, + Slide { + icon: "file_manager", + title: t!("lxde_pcmanfm_title"), + description: t!("lxde_pcmanfm_description"), + }, + Slide { + icon: "lxde_lxpanel_title", + title: t!("lxde_lxpanel_title"), + description: t!("lxde_lxpanel_description"), + }, + ] +} + +fn lxqt_slides() -> Vec { + vec![ + Slide { + icon: "lxqt", + title: t!("lxqt_title"), + description: t!("lxqt_description"), + }, + Slide { + icon: "lxqt_panel_title", + title: t!("lxqt_panel_title"), + description: t!("lxqt_panel_description"), + }, + Slide { + icon: "file_manager", + title: t!("lxqt_pcmanfm_qt_title"), + description: t!("lxqt_pcmanfm_qt_description"), + }, + ] +} + +fn lumina_slides() -> Vec { + vec![ + Slide { + icon: "lumina", + title: t!("lumina_title"), + description: t!("lumina_description"), + }, + Slide { + icon: "lumina_applications_title", + title: t!("lumina_applications_title"), + description: t!("lumina_applications_description"), + }, + Slide { + icon: "lumina_theme_title", + title: t!("lumina_theme_title"), + description: t!("lumina_theme_description"), + }, + Slide { + icon: "lumina_panel_title", + title: t!("lumina_panel_title"), + description: t!("lumina_panel_description"), + }, + ] +} + +fn mate_slides() -> Vec { + vec![ + Slide { + icon: "mate", + title: t!("mate_title"), + description: t!("mate_description"), + }, + Slide { + icon: "file_manager", + title: t!("mate_caja_title"), + description: t!("mate_caja_description"), + }, + Slide { + icon: "mate_settings_title", + title: t!("mate_settings_title"), + description: t!("mate_settings_description"), + }, + Slide { + icon: "mate_applications_title", + title: t!("mate_applications_title"), + description: t!("mate_applications_description"), + }, + ] +} + +fn xfce_slides() -> Vec { + vec![ + Slide { + icon: "xfce", + title: t!("xfce_title"), + description: t!("xfce_description"), + }, + Slide { + icon: "xfce_panel_title", + title: t!("xfce_panel_title"), + description: t!("xfce_panel_description"), + }, + Slide { + icon: "file_manager", + title: t!("xfce_thunar_title"), + description: t!("xfce_thunar_description"), + }, + Slide { + icon: "xfce_settings", + title: t!("xfce_settings_title"), + description: t!("xfce_settings_description"), + }, + ] +} + + +// ─── Slayt gösterisi widget'ı ──────────────────────────────────── + +pub struct Slideshow { + slides: Vec, + current: usize, + last_advance: Instant, +} + +impl Slideshow { + pub fn new(desktop: &str) -> Self { + Self { + slides: slides_for_desktop(desktop), + current: 0, + last_advance: Instant::now(), + } + } + + /// Her frame'de çağrılır. Otomatik ilerlemeyi ve çizimi yönetir. + pub fn show(&mut self, ui: &mut egui::Ui) { + // Otomatik ilerleme + if self.last_advance.elapsed() >= SLIDE_INTERVAL { + self.current = (self.current + 1) % self.slides.len(); + self.last_advance = Instant::now(); + ui.ctx().request_repaint_after(SLIDE_INTERVAL); + } else { + // Bir sonraki değişime kadar geri sayım için tekrar çiz + let remaining = SLIDE_INTERVAL + .checked_sub(self.last_advance.elapsed()) + .unwrap_or_default(); + ui.ctx().request_repaint_after(remaining); + } + + let slide = &self.slides[self.current]; + let is_dark = ui.visuals().dark_mode; + + // Eşleşen slayt simgeleri için görsel belirle + let image_source = match slide.icon { + "budgie" => Some(egui::include_image!("../../assets/budgie.png")), + "cinnamon" => Some(egui::include_image!("../../assets/cinnamon.png")), + "community" => Some(egui::include_image!("../../assets/community.png")), + "file_manager" => Some(egui::include_image!("../../assets/file_manager.png")), + "gnome" => Some(egui::include_image!("../../assets/gnome.png")), + "kde" => Some(egui::include_image!("../../assets/kde.png")), + "lxqt" => Some(egui::include_image!("../../assets/lxqt.png")), + "lumina" => Some(egui::include_image!("../../assets/lumina.png")), + "lxde" => Some(egui::include_image!("../../assets/lxde.png")), + "mate" => Some(egui::include_image!("../../assets/mate.png")), + "pisilogo" => { + if is_dark { + Some(egui::include_image!("../../assets/pisi-logo-dark.png")) + } else { + Some(egui::include_image!("../../assets/pisi-logo-light.png")) + } + } + "pisi" => Some(egui::include_image!("../../assets/pisi-software-center.png")), + "pisi_speed" => Some(egui::include_image!("../../assets/pisi_speed.png")), + "securety" => Some(egui::include_image!("../../assets/securety.png")), + "xfce" => Some(egui::include_image!("../../assets/xfce.png")), + "xfce_settings" => Some(egui::include_image!("../../assets/xfce_settings.png")), + _ => None, + }; + + egui::Frame::none() + .fill(crate::ui::theme::c_bg_widget()) + .rounding(egui::Rounding::same(10.0)) + .inner_margin(egui::Margin::same(24.0)) + .show(ui, |ui| { + ui.set_min_height(180.0); + ui.vertical_centered(|ui| { + // Simge veya Görsel + if let Some(img) = image_source { + ui.add( + egui::Image::new(img) + .max_height(64.0) + .rounding(egui::Rounding::same(8.0)), + ); + } else { + ui.label( + egui::RichText::new(slide.icon) + .size(48.0), + ); + } + ui.add_space(10.0); + + // Başlık + ui.label( + egui::RichText::new(slide.title.clone()) + .size(17.0) + .strong() + .color(crate::ui::theme::c_text()), + ); + ui.add_space(8.0); + + // Açıklama + ui.label( + egui::RichText::new(slide.description.clone()) + .size(13.0) + .color(crate::ui::theme::c_text_dim()), + ); + + ui.add_space(16.0); + + // Nokta göstergesi + ui.horizontal(|ui| { + let dot_size = egui::vec2(8.0, 8.0); + for i in 0..self.slides.len() { + let color = if i == self.current { + crate::ui::theme::c_accent() + } else { + crate::ui::theme::c_border() + }; + let (rect, response) = ui.allocate_exact_size(dot_size, egui::Sense::click()); + ui.painter().circle_filled(rect.center(), 4.0, color); + if response.clicked() { + self.current = i; + self.last_advance = Instant::now(); + } + ui.add_space(4.0); + } + }); + }); + }); + } + + pub fn advance(&mut self) { + self.current = (self.current + 1) % self.slides.len(); + self.last_advance = Instant::now(); + } + + pub fn previous(&mut self) { + if self.current == 0 { + self.current = self.slides.len() - 1; + } else { + self.current -= 1; + } + self.last_advance = Instant::now(); + } +} diff --git a/src/ui/theme.rs b/src/ui/theme.rs new file mode 100644 index 0000000..7d7e5df --- /dev/null +++ b/src/ui/theme.rs @@ -0,0 +1,276 @@ +//! PisiLinux kurulum teması. +//! +//! PisiLinux renk paleti: +//! Ana mavi : #1A6FA8 Vurgu mavi: #2196F3 +//! Koyu arka: #050b0c18 Panel arka : #252535 +//! Kenarlık : #3A3A5C Metin : #E0E0F0 +//! Yeşil : #4CAF50 Kırmızı : #F44336 +//! Sarı : #FF9800 + +use eframe::egui::{self, Color32, FontId, Rounding, Stroke, Vec2, Visuals}; + +use std::sync::atomic::{AtomicU32, Ordering}; + +// ─── Renk Atomics ────────────────────────────────────────────── +static BG_DARK: AtomicU32 = AtomicU32::new(0x121214); +static BG_PANEL: AtomicU32 = AtomicU32::new(0x1A1A1E); +static BG_WIDGET: AtomicU32 = AtomicU32::new(0x242428); +static BORDER: AtomicU32 = AtomicU32::new(0x323238); +static TEXT: AtomicU32 = AtomicU32::new(0xF3F3F5); +static TEXT_DIM: AtomicU32 = AtomicU32::new(0x9E9EAF); +static SUCCESS: AtomicU32 = AtomicU32::new(0x4CAF50); +static WARNING: AtomicU32 = AtomicU32::new(0xFF9800); +static ERROR: AtomicU32 = AtomicU32::new(0xF44336); +static SIDEBAR: AtomicU32 = AtomicU32::new(0x0B0B0D); +static ACCENT_COLOR: AtomicU32 = AtomicU32::new(0xd9005b); // Pisi Premium Vurgu (#d9005b) + +// Helper to convert hex to Color32 +fn color_from_hex(rgb: u32) -> Color32 { + Color32::from_rgb((rgb >> 16) as u8, ((rgb >> 8) & 0xFF) as u8, (rgb & 0xFF) as u8) +} + +pub fn c_bg_dark() -> Color32 { color_from_hex(BG_DARK.load(Ordering::Relaxed)) } +pub fn c_bg_panel() -> Color32 { color_from_hex(BG_PANEL.load(Ordering::Relaxed)) } +pub fn c_bg_widget() -> Color32 { color_from_hex(BG_WIDGET.load(Ordering::Relaxed)) } +pub fn c_border() -> Color32 { color_from_hex(BORDER.load(Ordering::Relaxed)) } +pub fn c_text() -> Color32 { color_from_hex(TEXT.load(Ordering::Relaxed)) } +pub fn c_text_dim() -> Color32 { color_from_hex(TEXT_DIM.load(Ordering::Relaxed)) } +pub fn c_success() -> Color32 { color_from_hex(SUCCESS.load(Ordering::Relaxed)) } +pub fn c_warning() -> Color32 { color_from_hex(WARNING.load(Ordering::Relaxed)) } +pub fn c_error() -> Color32 { color_from_hex(ERROR.load(Ordering::Relaxed)) } +pub fn c_sidebar() -> Color32 { color_from_hex(SIDEBAR.load(Ordering::Relaxed)) } + +pub fn set_theme_mode(is_dark: bool) { + if is_dark { + BG_DARK.store(0x121214, Ordering::Relaxed); + BG_PANEL.store(0x1A1A1E, Ordering::Relaxed); + BG_WIDGET.store(0x242428, Ordering::Relaxed); + BORDER.store(0x323238, Ordering::Relaxed); + TEXT.store(0xF3F3F5, Ordering::Relaxed); + TEXT_DIM.store(0x9E9EAF, Ordering::Relaxed); + SIDEBAR.store(0x0B0B0D, Ordering::Relaxed); + } else { + BG_DARK.store(0xF0F0F5, Ordering::Relaxed); + BG_PANEL.store(0xFFFFFF, Ordering::Relaxed); + BG_WIDGET.store(0xE8E8EE, Ordering::Relaxed); + BORDER.store(0xD0D0DA, Ordering::Relaxed); + TEXT.store(0x20202A, Ordering::Relaxed); + TEXT_DIM.store(0x60606A, Ordering::Relaxed); + SIDEBAR.store(0xE4E4EA, Ordering::Relaxed); + } +} + + +pub fn c_accent() -> Color32 { + let rgb = ACCENT_COLOR.load(std::sync::atomic::Ordering::Relaxed); + Color32::from_rgb((rgb >> 16) as u8, ((rgb >> 8) & 0xFF) as u8, (rgb & 0xFF) as u8) +} + +pub fn c_accent_dim() -> Color32 { + let rgb = ACCENT_COLOR.load(std::sync::atomic::Ordering::Relaxed); + let r = (((rgb >> 16) & 0xFF) as f32 * 0.8) as u8; + let g = (((rgb >> 8) & 0xFF) as f32 * 0.8) as u8; + let b = ((rgb & 0xFF) as f32 * 0.8) as u8; + Color32::from_rgb(r, g, b) +} + +/// egui bağlamına PisiLinux temasını uygular. +/// `cc.egui_ctx` üzerinden `setup_custom_fonts` ve `set_visuals` çağrısını birleştirir. +pub fn apply(ctx: &egui::Context, is_dark: bool) { + setup_fonts(ctx); + ctx.set_visuals(build_visuals(is_dark)); + ctx.set_style(build_style()); +} + +fn setup_fonts(ctx: &egui::Context) { + let mut fonts = egui::FontDefinitions::default(); + + // egui'nin yerleşik fontlarına ek olarak sistem fontunu dene. + // ISO ortamında genellikle DejaVu veya Noto bulunur. + // Bulunamazsa egui varsayılanı kullanılır. + for path in [ + "/usr/share/fonts/exo-1/Exo2-Medium.ttf", + "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + "/usr/share/fonts/noto/NotoSans-Regular.ttf", + "/usr/share/fonts/TTF/DejaVuSans.ttf", + ] { + if let Ok(data) = std::fs::read(path) { + fonts.font_data.insert( + "system_font".to_owned(), + egui::FontData::from_owned(data), + ); + fonts + .families + .entry(egui::FontFamily::Proportional) + .or_default() + .insert(0, "system_font".to_owned()); + break; + } + } + + ctx.set_fonts(fonts); +} + +fn build_visuals(is_dark: bool) -> Visuals { + let mut v = if is_dark { Visuals::dark() } else { Visuals::light() }; + + // Genel arka planlar + v.window_fill = c_bg_dark(); + v.panel_fill = c_bg_panel(); + v.faint_bg_color = c_bg_widget(); + v.extreme_bg_color = c_sidebar(); + v.code_bg_color = if is_dark { Color32::from_rgb(0x18, 0x18, 0x28) } else { Color32::from_rgb(0xEE, 0xEE, 0xF5) }; + + // Metin + v.override_text_color = Some(c_text()); + + // Kenarlıklar + v.widgets.noninteractive.bg_stroke = Stroke::new(1.0, c_border()); + v.widgets.inactive.bg_stroke = Stroke::new(1.0, c_border()); + v.widgets.hovered.bg_stroke = Stroke::new(1.5, c_accent()); + v.widgets.active.bg_stroke = Stroke::new(2.0, c_accent()); + + // Widget dolguları + v.widgets.noninteractive.bg_fill = c_bg_widget(); + v.widgets.inactive.bg_fill = c_bg_widget(); + v.widgets.hovered.bg_fill = if is_dark { Color32::from_rgb(0x35, 0x35, 0x55) } else { Color32::from_rgb(0xD5, 0xD5, 0xE5) }; + v.widgets.active.bg_fill = c_accent_dim(); + + // Metin renkleri + v.widgets.noninteractive.fg_stroke = Stroke::new(1.0, c_text_dim()); + v.widgets.inactive.fg_stroke = Stroke::new(1.0, c_text()); + v.widgets.hovered.fg_stroke = Stroke::new(1.5, c_text()); + v.widgets.active.fg_stroke = Stroke::new(2.0, if is_dark { Color32::WHITE } else { Color32::BLACK }); + + // Yuvarlak köşeler + v.widgets.noninteractive.rounding = Rounding::same(6.0); + v.widgets.inactive.rounding = Rounding::same(6.0); + v.widgets.hovered.rounding = Rounding::same(6.0); + v.widgets.active.rounding = Rounding::same(6.0); + + // Seçim rengi + v.selection.bg_fill = c_accent_dim(); + v.selection.stroke = Stroke::new(1.0, c_accent()); + + // Hyperlink + v.hyperlink_color = c_accent(); + + // Pencere kenarlığı + v.window_stroke = Stroke::new(1.0, c_border()); + v.window_rounding = Rounding::same(8.0); + + v +} + +fn build_style() -> egui::Style { + let mut style = egui::Style::default(); + + // Genel boşluk ve boyutlar + style.spacing.item_spacing = Vec2::new(8.0, 6.0); + style.spacing.button_padding = Vec2::new(12.0, 6.0); + style.spacing.indent = 16.0; + style.spacing.scroll.bar_width = 8.0; + + // Metin boyutları + style.text_styles = [ + (egui::TextStyle::Small, FontId::proportional(11.0)), + (egui::TextStyle::Body, FontId::proportional(14.0)), + (egui::TextStyle::Button, FontId::proportional(14.0)), + (egui::TextStyle::Heading, FontId::proportional(20.0)), + (egui::TextStyle::Monospace, FontId::monospace(13.0)), + ] + .into(); + + style +} + +// ─── Yardımcı widget'lar ───────────────────────────────────────── + +/// Vurgulu "ana eylem" butonu (mavi dolgu). +pub fn primary_button(text: &str) -> egui::Button<'_> { + egui::Button::new(egui::RichText::new(text).color(Color32::WHITE)) + .fill(c_accent()) + .stroke(Stroke::new(1.0, c_accent())) + .rounding(Rounding::same(6.0)) + .min_size(Vec2::new(100.0, 32.0)) +} + +/// İkincil "iptal/geri" butonu (şeffaf dolgu). +pub fn secondary_button(text: &str) -> egui::Button<'_> { + egui::Button::new(egui::RichText::new(text).color(c_text_dim())) + .fill(Color32::TRANSPARENT) + .stroke(Stroke::new(1.0, c_border())) + .rounding(Rounding::same(6.0)) + .min_size(Vec2::new(80.0, 32.0)) +} + +/// Kırmızı "tehlikeli eylem" butonu (disk silme onayı vb.). +pub fn danger_button(text: &str) -> egui::Button<'_> { + egui::Button::new(egui::RichText::new(text).color(Color32::WHITE)) + .fill(Color32::from_rgb(0xC6, 0x28, 0x28)) + .stroke(Stroke::new(1.0, c_error())) + .rounding(Rounding::same(6.0)) + .min_size(Vec2::new(100.0, 32.0)) +} + +/// Bölüm başlığı — büyük, açık renkli, alt çizgisiz. +pub fn section_heading(ui: &mut egui::Ui, text: &str) { + ui.label( + egui::RichText::new(text) + .size(18.0) + .color(c_text()) + .strong(), + ); + ui.add_space(2.0); + let (rect, _) = ui.allocate_exact_size(Vec2::new(ui.available_width(), 1.0), egui::Sense::hover()); + ui.painter().line_segment( + [rect.left_center(), rect.right_center()], + Stroke::new(1.0, c_accent_dim()), + ); + ui.add_space(8.0); +} + +/// Hata kutusu — kırmızı çerçeveli bildirim. +pub fn error_box(ui: &mut egui::Ui, msg: &str) { + egui::Frame::none() + .fill(Color32::from_rgba_unmultiplied(0xF4, 0x43, 0x36, 20)) + .stroke(Stroke::new(1.0, c_error())) + .rounding(Rounding::same(6.0)) + .inner_margin(egui::Margin::same(10.0)) + .show(ui, |ui| { + ui.horizontal(|ui| { + ui.colored_label(c_error(), "✗"); + ui.colored_label(c_error(), msg); + }); + }); +} + +/// Uyarı kutusu — turuncu çerçeveli bildirim. +pub fn warning_box(ui: &mut egui::Ui, msg: &str) { + egui::Frame::none() + .fill(Color32::from_rgba_unmultiplied(0xFF, 0x98, 0x00, 20)) + .stroke(Stroke::new(1.0, c_warning())) + .rounding(Rounding::same(6.0)) + .inner_margin(egui::Margin::same(10.0)) + .show(ui, |ui| { + ui.horizontal(|ui| { + ui.colored_label(c_warning(), "⚠"); + ui.colored_label(c_warning(), msg); + }); + }); +} + +/// Başarı kutusu — yeşil çerçeveli bildirim. +pub fn success_box(ui: &mut egui::Ui, msg: &str) { + egui::Frame::none() + .fill(Color32::from_rgba_unmultiplied(0x4C, 0xAF, 0x50, 20)) + .stroke(Stroke::new(1.0, c_success())) + .rounding(Rounding::same(6.0)) + .inner_margin(egui::Margin::same(10.0)) + .show(ui, |ui| { + ui.horizontal(|ui| { + ui.colored_label(c_success(), "✓"); + ui.colored_label(c_success(), msg); + }); + }); +}