From 0041cd9660054b68656ce0534cf84ffa46e3020f Mon Sep 17 00:00:00 2001 From: OverSu Date: Thu, 8 Oct 2026 14:27:17 +0200 Subject: [PATCH] Update shared Gaia workflows and Sargo development tooling Fix camera switching and Contacts/SMS activity routing across shared hosts. Integrate Marketplace installation and native standalone recovery tools, Bluetooth runtime packages and trusted certificates. Update English/French READMEs and the shared changelog with tested scope and remaining radio/audio/Bluetooth limitations. Preview17 remains the existing APK; no new native image is released. Validation: shared JavaScript and native Python tests; Android packaging and payload parity from an isolated publication checkout. --- .gitignore | 3 + README.fr.md | 21 +- README.md | 21 +- .../org/vulpes_os/preview/GaiaServer.java | 14 +- .../org/vulpes_os/preview/InstalledApps.java | 37 + .../org/vulpes_os/preview/MainActivity.java | 31 +- .../vulpes_os/preview/VulpesApplication.java | 37 + android/extension/background.js | 63 +- android/extension/content.js | 2 +- android/extension/manifest.json | 46 +- android/extension/marketplace-content.js | 1 + android/tests/settings-codec.test.mjs | 4 +- android/tools/pack-assets.py | 7 +- .../contacts/js/activities.js | 6 +- .../contacts/js/contacts.js | 4 +- .../contacts/js/views/form.js | 2 + .../gaia_build_defer_index.js | 2 +- .../marketplace.gaiamobile.org/icon.png | Bin 0 -> 190651 bytes .../marketplace.gaiamobile.org/index.html | 5 + .../manifest.webapp | 19 + .../marketplace.css | 1 + .../marketplace.gaiamobile.org/marketplace.js | 32 + .../gaia_build_defer_manage.js | 2 +- .../gaia_build_defer_pick.js | 2 +- .../js/tone_player.js | 2 +- changelog.json | 69 ++ .../communications/contacts/js/activities.js | 6 +- .../communications/contacts/js/contacts.js | 4 +- .../communications/contacts/js/views/form.js | 2 + gaia/apps/homescreen/js/apps.js | 4 + gaia/apps/marketplace/icon.png | Bin 0 -> 190651 bytes gaia/apps/marketplace/index.html | 5 + gaia/apps/marketplace/manifest.webapp | 19 + gaia/apps/marketplace/marketplace.css | 1 + gaia/apps/marketplace/marketplace.js | 32 + gaia/apps/ringtones/js/tone_player.js | 2 +- .../settings/js/modules/page_transitions.js | 48 +- gaia/apps/system/js/system_banner.js | 49 +- host/Runtime.sys.mjs | 58 +- host/Views.sys.mjs | 64 +- host/actors/MarketplaceChild.sys.mjs | 7 + host/actors/MarketplaceParent.sys.mjs | 13 + host/actors/VulpesChild.sys.mjs | 21 + host/desktop.css | 4 + host/gaia-camera.js | 199 +++--- host/gaia-compat.js | 70 +- host/gaia-restoration.js | 10 +- host/gaia-wifi.js | 4 +- host/marketplace-page.js | 14 + host/settings-codec.js | 41 ++ host/shell.js | 11 +- overrides/settings.gaiamobile.org/js/main.js | 238 +++++++ .../resources/branding/vulpes-symbol.png | Bin 0 -> 138726 bytes .../system.gaiamobile.org/js/system_banner.js | 203 ++++++ release.json | 6 +- services/activities.mjs | 114 ++++ services/packages.mjs | 77 +++ tests/ProbeChild.sys.mjs | 11 + tests/activities.test.mjs | 83 +++ tests/android-sms-handoff.test.mjs | 38 ++ tests/camera-lifecycle.test.mjs | 152 +++++ tests/contacts.test.mjs | 59 ++ tests/installed_apps_test.py | 28 + tests/packages.test.mjs | 35 + tests/settings-codec.test.mjs | 35 + tests/settings-transitions.test.mjs | 29 + tests/wifi-throttle.test.mjs | 24 + tools/check-parity.py | 32 +- tools/installed_apps.py | 72 ++ tools/project.py | 9 + tools/refresh-settings-panels.py | 16 +- tools/serve-gaia.py | 52 +- tools/test-camera.py | 7 +- tools/test-contacts.py | 183 +++++ tools/test-system-banner.py | 38 ++ tundra/boot/sparse-backup.c | 46 ++ tundra/boot/standalone-mount.sh | 14 + tundra/droidian/probe.sys.mjs | 643 +++++++++++------- tundra/manifests/sargo-hardware.json | 22 + tundra/runtime/hal_policy.py | 2 +- tundra/runtime/mark-boot-success.py | 38 ++ tundra/runtime/prepare-bluetooth.py | 34 + tundra/runtime/prepare-hardware.py | 3 + tundra/runtime/runtime-packages.py | 82 +++ tundra/runtime/setup-hal.py | 19 +- tundra/tests/test_hardware_status.py | 6 +- tundra/tests/test_runtime_packages.py | 47 ++ tundra/tests/test_sparse_backup.py | 37 + tundra/tests/test_standalone_boot.py | 91 +++ tundra/tests/test_standalone_flash.py | 80 +++ tundra/tests/test_standalone_restore.py | 69 ++ tundra/tools/build-rescue-boot.py | 10 + tundra/tools/build-standalone-boot.py | 146 ++++ tundra/tools/build-standalone-volume.py | 83 +++ tundra/tools/build-system-image.py | 2 +- tundra/tools/flash-standalone-sargo.py | 116 ++++ tundra/tools/install-sargo.py | 2 + tundra/tools/package-standalone-sargo.py | 63 ++ tundra/tools/restore-standalone-sargo.py | 83 +++ tundra/tools/sparse_backup.py | 25 + tundra/tools/standalone_volume.py | 35 + 101 files changed, 4004 insertions(+), 456 deletions(-) create mode 100644 android/app/src/main/java/org/vulpes_os/preview/InstalledApps.java create mode 100644 android/extension/marketplace-content.js create mode 100644 assets/webapps/marketplace.gaiamobile.org/icon.png create mode 100644 assets/webapps/marketplace.gaiamobile.org/index.html create mode 100644 assets/webapps/marketplace.gaiamobile.org/manifest.webapp create mode 100644 assets/webapps/marketplace.gaiamobile.org/marketplace.css create mode 100644 assets/webapps/marketplace.gaiamobile.org/marketplace.js create mode 100644 gaia/apps/marketplace/icon.png create mode 100644 gaia/apps/marketplace/index.html create mode 100644 gaia/apps/marketplace/manifest.webapp create mode 100644 gaia/apps/marketplace/marketplace.css create mode 100644 gaia/apps/marketplace/marketplace.js create mode 100644 host/actors/MarketplaceChild.sys.mjs create mode 100644 host/actors/MarketplaceParent.sys.mjs create mode 100644 host/marketplace-page.js create mode 100644 host/settings-codec.js create mode 100644 overrides/settings.gaiamobile.org/js/main.js create mode 100644 overrides/shared/resources/branding/vulpes-symbol.png create mode 100755 overrides/system.gaiamobile.org/js/system_banner.js create mode 100644 services/activities.mjs create mode 100644 services/packages.mjs create mode 100644 tests/activities.test.mjs create mode 100644 tests/android-sms-handoff.test.mjs create mode 100644 tests/camera-lifecycle.test.mjs create mode 100644 tests/contacts.test.mjs create mode 100644 tests/installed_apps_test.py create mode 100644 tests/packages.test.mjs create mode 100644 tests/settings-codec.test.mjs create mode 100644 tests/settings-transitions.test.mjs create mode 100644 tools/installed_apps.py create mode 100644 tools/test-contacts.py create mode 100644 tools/test-system-banner.py create mode 100644 tundra/boot/sparse-backup.c create mode 100644 tundra/boot/standalone-mount.sh create mode 100644 tundra/manifests/sargo-hardware.json create mode 100644 tundra/runtime/mark-boot-success.py create mode 100644 tundra/runtime/prepare-bluetooth.py create mode 100644 tundra/runtime/runtime-packages.py create mode 100644 tundra/tests/test_runtime_packages.py create mode 100644 tundra/tests/test_sparse_backup.py create mode 100644 tundra/tests/test_standalone_boot.py create mode 100644 tundra/tests/test_standalone_flash.py create mode 100644 tundra/tests/test_standalone_restore.py create mode 100644 tundra/tools/build-standalone-boot.py create mode 100644 tundra/tools/build-standalone-volume.py create mode 100644 tundra/tools/flash-standalone-sargo.py create mode 100644 tundra/tools/package-standalone-sargo.py create mode 100644 tundra/tools/restore-standalone-sargo.py create mode 100644 tundra/tools/sparse_backup.py create mode 100644 tundra/tools/standalone_volume.py diff --git a/.gitignore b/.gitignore index ac57c53e..06812952 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ __pycache__/ # Old B2G registry is unused by the modern host and contains historical paths. /assets/webapps/webapps.json + +# Local issue tracking and roadmap; not included in publication. +/tickets/ diff --git a/README.fr.md b/README.fr.md index 1d2b8e5c..455b266c 100644 --- a/README.fr.md +++ b/README.fr.md @@ -3,7 +3,7 @@

Vulpes OS

L'esprit de Firefox OS. Un Gecko moderne. Une base Gaia commune.
Un projet communautaire pour retrouver une expérience mobile fondée sur le Web, sur PC, Android et téléphone natif.

-Vulpes Preview 15 +Vulpes Preview 17 Gecko bureau 156.0.1 Expérimental

@@ -26,9 +26,9 @@ Ce dépôt contient désormais l'interface commune, l'hôte PC, l'application An | **APK Android** | Preview installable ; Android et ses permissions restent en dessous | GeckoView **156.0** | | **Pixel 3a · Sargo** | Sources Tundra ; build natif de développement testé sur notre appareil | Gecko **156.0.1** ARM64 | -### Android — Preview 15 +### Android — Preview 17 -Téléchargez l'APK et `SHA256SUMS.txt` depuis [la release Preview 15](https://nnsprod.com/git/oversu/VulpesOS/releases/tag/v2.7-preview.15). Une installation par-dessus une ancienne Preview Vulpes signée conserve ses données. +Téléchargez l'APK et `SHA256SUMS.txt` depuis [la release Preview 17](https://nnsprod.com/git/oversu/VulpesOS/releases/tag/v2.7-preview.17). Une installation par-dessus une ancienne Preview Vulpes signée conserve ses données. - Minimum déclaré : **Android 8 / API 26**. Cible : **API 37**. - APK universel : **ARM64, ARMv7 et x86_64** ; environ **600 Mio**, moteur GeckoView inclus. @@ -56,9 +56,20 @@ cd VulpesOS Notre image de développement Sargo installée a passé les contrôles de démarrage et de persistance. Des appels réels et des SMS dans les deux sens ont été observés ; les derniers essais couvrent les conversations, les bascules de capteur photo, la capture JPEG pleine résolution, le focus tactile, le zoom numérique et l'arrêt du vibreur. -**Cette release ne contient pas d'image générique à flasher.** Le boot privé dépend encore de la disposition du stockage du téléphone inventorié, d'images système/données déjà déployées et d'accès de maintenance. Publier ce fichier ne fournirait pas une installation fonctionnelle à un autre Pixel. Les recettes Tundra sont incluses pour les contributeurs ; elles nécessitent un inventaire, des sauvegardes vérifiées et des composants matériels fournis localement. Ne réutilisez pas la sauvegarde d'un autre appareil et ne considérez pas un boot isolé comme une ROM complète. +**Une installation autonome est maintenant testée localement.** Le paquet Fastboot fournit le système, un espace de données vierge et les composants matériels associés au noyau. Il remplace `userdata`, `boot_a`, `dtbo_a` et `vbmeta_a` : il n’utilise plus les fichiers d’une ancienne installation Droidian et ne nécessite pas de session Android ni d’ADB. Deux démarrages depuis le stockage interne ont passé chacun onze contrôles Gaia et dix contrôles natifs, avec conservation des réglages. -Les outils de préparation prennent désormais un dossier privé par appareil : inventaire, sauvegardes, construction RAM, transfert SSH et secours. La procédure reste réservée au noyau qualifié et à un stockage ext4/LVM compatible ; elle ne permet pas encore de partir directement d’Android d’origine. +L’installation demande un **Pixel 3a (Sargo) déverrouillé** et efface toutes les données de `userdata`. Le bootloader et les calibrations propres au téléphone restent en place. Ce candidat réserve actuellement 8 Gio au volume, dont 1 Gio de données modifiables ; l’extension automatique n’est pas encore implémentée. Il a été testé sur notre Pixel, pas sur chaque combinaison de firmware existante. + +**Le paquet autonome n’est pas encore proposé en téléchargement dans cette release.** Les recettes et l’installateur sont préparés ; la revue de provenance et de redistribution des composants matériels reste à terminer. Les sauvegardes et les clés de maintenance du téléphone de développement ne font pas partie du paquet générique. + +## 🛠️ Dernières évolutions des sources · 8 octobre 2026 + +- **Photo :** bascule des capteurs séquencée, libération fiable et transport des images corrigé. Capture avant/arrière, focus, zoom et ouverture dans Galerie testés sur notre Pixel 3a. +- **Contacts :** fiche actualisée après édition, parcours SMS/sélecteur/Téléphone rétablis et sélection d’une photo dans Galerie. Les tests PC couvrent recherche, recadrage, favoris et suppression ; les tests natifs couvrent création, édition et navigation entre applications. +- **Marketplace :** installation d’applications intégrée, permissions restreintes et retour contrôlé vers Gaia. +- **Tundra :** outils de build autonome et de restauration, paquets Bluetooth verrouillés et certificats natifs. La découverte matérielle Bluetooth fonctionne ; l’appairage Gaia et les profils restent à terminer. + +**Ces changements de sources sont postérieurs à l’APK Preview 17 publié.** Les ressources Android sont préparées, mais aucun nouvel APK ni image native contenant tous ces correctifs n’est publié. Le dernier candidat natif est testé en RAM ; l’enregistrement cellulaire reste en cours d’analyse et l’audio des appels dans les deux sens n’est pas encore qualifié. L’historique commun PC/Android/Tundra se trouve dans [`changelog.json`](changelog.json). ## ✨ Ce que nous partageons diff --git a/README.md b/README.md index f21ba9c7..62c3a23a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

Vulpes OS

The spirit of Firefox OS. A modern Gecko. One shared Gaia.
A community project bringing a web-based phone experience to desktop, Android and native hardware.

-Vulpes Preview 15 +Vulpes Preview 17 Desktop Gecko 156.0.1 Experimental

@@ -26,9 +26,9 @@ This repository now contains the shared interface, desktop host, Android applica | **Android APK** | Installable Preview; keeps Android and its permissions underneath | GeckoView **156.0** | | **Pixel 3a · Sargo** | Tundra sources; native development build tested on our device | Gecko **156.0.1** ARM64 | -### Android — Preview 15 +### Android — Preview 17 -Download the APK and `SHA256SUMS.txt` from [the Preview 15 release](https://nnsprod.com/git/oversu/VulpesOS/releases/tag/v2.7-preview.15). Installing over an earlier signed Vulpes Preview preserves its data. +Download the APK and `SHA256SUMS.txt` from [the Preview 17 release](https://nnsprod.com/git/oversu/VulpesOS/releases/tag/v2.7-preview.17). Installing over an earlier signed Vulpes Preview preserves its data. - Minimum declared: **Android 8 / API 26**. Target: **API 37**. - Universal APK: **ARM64, ARMv7 and x86_64**; approximately **600 MiB** including GeckoView. @@ -56,9 +56,20 @@ cd VulpesOS Our installed Sargo development image has passed startup and persistence checks. Real calls and two-way SMS have been observed; the latest checks cover conversation rendering, camera sensor switching, full-resolution JPEG capture, touch focus, digital zoom and bounded vibration. -**A generic flashable image is not included in this release.** The current private boot depends on the inventoried phone's storage layout, staged system/data images and maintenance credentials. Publishing that file would not give another Pixel a working installation. Tundra's source recipes are included for contributors; they require device inventory, verified backups and locally supplied hardware components. Do not use another device's backup or treat a boot image as a complete ROM. +**A standalone installation has now been tested locally.** The Fastboot package provides the system, fresh writable storage and the hardware components paired with the kernel. It replaces `userdata`, `boot_a`, `dtbo_a` and `vbmeta_a`: startup no longer uses files from an old Droidian installation and requires neither an Android session nor ADB. Two boots from internal storage passed eleven Gaia and ten native checks each and retained settings. -Preparation tools now accept a private workspace per device: inventory, backups, RAM builds, SSH transfers and recovery. The procedure remains limited to the qualified kernel and compatible ext4/LVM storage; it does not yet install directly from stock Android. +Installation requires an **unlocked Pixel 3a (Sargo)** and erases all existing `userdata`. The bootloader and device-specific calibration remain in place. This candidate currently reserves an 8 GiB volume, including 1 GiB of writable data; automatic expansion is not implemented yet. It has been tested on our Pixel, not every existing firmware combination. + +**The standalone package is not yet available as a download in this release.** Build recipes and the installer are prepared; hardware component provenance and redistribution review are still pending. Development-phone backups and maintenance keys are excluded from the generic package. + +## 🛠️ Latest source improvements · 8 October 2026 + +- **Camera:** serialized sensor switching, reliable release and binary photo transport. Front/rear capture, focus, zoom and Gallery opening tested on our Pixel 3a. +- **Contacts:** refreshed details after editing, restored SMS/number-picker/dialer flows, and Gallery photo selection. Desktop tests cover search, cropping, favourites and deletion; native tests cover creation, editing and cross-app navigation. +- **Marketplace:** integrated application installation with permission restrictions and controlled return to Gaia. +- **Tundra:** standalone build/recovery tools, pinned Bluetooth runtime packages and native trusted certificates. Bluetooth hardware discovery works; Gaia pairing and profiles remain unfinished. + +**These are source updates, newer than the published Preview 17 APK.** Updated Android assets are prepared, but no new APK or native image containing all these fixes is published. The latest native candidate is tested in RAM; cellular registration remains under investigation and two-way call audio is not yet qualified. See [`changelog.json`](changelog.json) for the shared desktop/Android/Tundra history. ## ✨ What is shared diff --git a/android/app/src/main/java/org/vulpes_os/preview/GaiaServer.java b/android/app/src/main/java/org/vulpes_os/preview/GaiaServer.java index 6ac6e23b..4319721d 100644 --- a/android/app/src/main/java/org/vulpes_os/preview/GaiaServer.java +++ b/android/app/src/main/java/org/vulpes_os/preview/GaiaServer.java @@ -14,11 +14,13 @@ import java.util.zip.*; final class GaiaServer implements Closeable { static final int PORT = 18765; + final InstalledApps installed; private final ZipFile zip; private final ServerSocket socket; private final ExecutorService workers = Executors.newFixedThreadPool(4); GaiaServer(Context context) throws IOException { + try {installed=new InstalledApps(context);}catch(Exception e){throw new IOException(e);} File archive = new File(context.getCacheDir(), "gaia.zip"); // Atomic refresh on every process start; the APK is the source of truth. File temp = new File(context.getCacheDir(), "gaia.zip.tmp"); @@ -94,7 +96,7 @@ final class GaiaServer implements Closeable { } String app = host.substring(0, host.indexOf('.')); if (app.equals("theme")) app = "default_theme"; - if (zip.getEntry(app + "/manifest.webapp") == null) { + if (!InstalledApps.valid(app) && zip.getEntry(app + "/manifest.webapp") == null) { error(out, 404); return; } @@ -109,6 +111,16 @@ final class GaiaServer implements Closeable { return; } if (path.endsWith("/")) path += "index.html"; + if (InstalledApps.valid(app)) { + byte[] body=installed.read(app,path.substring(1)); + if(body==null){error(out,404);return;} + String ext=path.substring(path.lastIndexOf('.')+1).toLowerCase(Locale.ROOT); + String mime=MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext); + if(ext.equals("js"))mime="text/javascript"; + if(ext.equals("webapp"))mime="application/json"; + if(mime==null)mime="application/octet-stream"; + out.write(("HTTP/1.1 200 OK\r\nContent-Type: "+mime+"\r\nContent-Length: "+body.length+"\r\nConnection: close\r\nX-Content-Type-Options: nosniff\r\nCache-Control: no-store\r\nAccess-Control-Allow-Origin: *\r\nContent-Security-Policy: object-src 'none'; frame-ancestors http://*.localhost:"+PORT+"\r\n\r\n").getBytes(StandardCharsets.US_ASCII));out.write(body);return; + } String key = path.startsWith("/_vulpes/") ? path.substring(1) : app + path; ZipEntry entry = zip.getEntry(key); if (entry == null && path.startsWith("/shared/")) entry = zip.getEntry( diff --git a/android/app/src/main/java/org/vulpes_os/preview/InstalledApps.java b/android/app/src/main/java/org/vulpes_os/preview/InstalledApps.java new file mode 100644 index 00000000..8ecd8840 --- /dev/null +++ b/android/app/src/main/java/org/vulpes_os/preview/InstalledApps.java @@ -0,0 +1,37 @@ +package org.vulpes_os.preview; + +import android.content.Context; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.*; +import org.json.*; + +final class InstalledApps { + private final File root; + private final Map items = new HashMap<>(); + InstalledApps(Context context) throws Exception { + root=new File(context.getFilesDir(),"installed-apps");root.mkdirs(); + File[] files=root.listFiles((d,n)->n.matches("user-[a-f0-9]{24}\\.json")); + if(files!=null)for(File file:files){JSONObject item=new JSONObject(new String(Files.readAllBytes(file.toPath()),StandardCharsets.UTF_8));items.put(item.getString("id"),item);} + } + static boolean valid(String id){return id!=null && id.matches("user-[a-f0-9]{24}");} + private JSONObject record(JSONObject item) throws Exception { + String id=item.getString("id"),origin="http://"+id+".localhost:"+GaiaServer.PORT; + JSONObject manifest=new JSONObject(item.getJSONObject("manifest").toString());manifest.put("permissions",new JSONObject());manifest.put("type","web"); + return new JSONObject().put("id",id).put("origin",origin).put("manifestURL",origin+"/manifest.webapp").put("manifest",manifest).put("removable",true).put("installed",true); + } + synchronized JSONArray list() throws Exception {JSONArray result=new JSONArray();for(JSONObject item:items.values())result.put(record(item));return result;} + synchronized void save(JSONObject item) throws Exception { + String id=item.getString("id");if(!valid(id) || !item.has("files"))throw new IOException("INVALID_PACKAGE"); + byte[] data=item.toString().getBytes(StandardCharsets.UTF_8);if(data.length>70*1024*1024)throw new IOException("PACKAGE_TOO_LARGE"); + File stage=new File(root,id+".tmp");try(FileOutputStream out=new FileOutputStream(stage)){out.write(data);out.getFD().sync();} + Files.move(stage.toPath(),new File(root,id+".json").toPath(),StandardCopyOption.REPLACE_EXISTING);items.put(id,item); + } + synchronized void remove(String id) throws Exception {if(!valid(id))throw new IOException("NOT_REMOVABLE");Files.deleteIfExists(new File(root,id+".json").toPath());items.remove(id);} + synchronized byte[] read(String id,String path) throws Exception { + JSONObject item=items.get(id);if(item==null)return null; + if(path.equals("manifest.webapp"))return record(item).getJSONObject("manifest").toString().getBytes(StandardCharsets.UTF_8); + String data=item.getJSONObject("files").optString(path,null);return data==null?null:android.util.Base64.decode(data,android.util.Base64.DEFAULT); + } +} diff --git a/android/app/src/main/java/org/vulpes_os/preview/MainActivity.java b/android/app/src/main/java/org/vulpes_os/preview/MainActivity.java index 221e8f0c..5b4dcba7 100644 --- a/android/app/src/main/java/org/vulpes_os/preview/MainActivity.java +++ b/android/app/src/main/java/org/vulpes_os/preview/MainActivity.java @@ -45,8 +45,7 @@ public final class MainActivity extends Activity { root.setOnApplyWindowInsetsListener((v, insets) -> { if (Build.VERSION.SDK_INT >= 30) { android.graphics.Insets bars = insets.getInsets( - WindowInsets.Type.systemBars() | - WindowInsets.Type.ime() | + WindowInsets.Type.ime() | WindowInsets.Type.displayCutout() ); v.setPadding(bars.left, bars.top, bars.right, bars.bottom); @@ -54,11 +53,12 @@ public final class MainActivity extends Activity { insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), - insets.getSystemWindowInsetBottom() + insets.getSystemWindowInsetBottom() > dp(100) ? insets.getSystemWindowInsetBottom() : 0 ); return insets; }); setContentView(root); + immersive(); // Respect Android's screen timeout; Gaia must not keep the phone awake indefinitely. float brightness = app.getSharedPreferences("android", 0).getFloat("brightness", -1); if (brightness >= 0) { @@ -166,6 +166,28 @@ public final class MainActivity extends Activity { } } + private void immersive() { + if (Build.VERSION.SDK_INT >= 30) { + getWindow().setDecorFitsSystemWindows(false); + WindowInsetsController controller = getWindow().getInsetsController(); + if (controller != null) { + controller.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); + controller.hide(WindowInsets.Type.systemBars()); + } + } else { + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + } + } + + @Override + public void onWindowFocusChanged(boolean focused) { + super.onWindowFocusChanged(focused); + if (focused) immersive(); + } + private int dp(int value) { return Math.round(value * getResources().getDisplayMetrics().density); } @@ -274,7 +296,7 @@ public final class MainActivity extends Activity { setHomeSurface(app.homeVisible); } - private void closeBrowser() { + void closeBrowser() { webPanel.setVisibility(View.GONE); gaiaView.setVisibility(View.VISIBLE); setHomeSurface(app.homeVisible); @@ -356,6 +378,7 @@ public final class MainActivity extends Activity { public void onResume() { super.onResume(); resumed = true; + immersive(); app.activity = this; if (recoverGaia) { recoverGaia = false; diff --git a/android/app/src/main/java/org/vulpes_os/preview/VulpesApplication.java b/android/app/src/main/java/org/vulpes_os/preview/VulpesApplication.java index d9baa910..3a46db7e 100644 --- a/android/app/src/main/java/org/vulpes_os/preview/VulpesApplication.java +++ b/android/app/src/main/java/org/vulpes_os/preview/VulpesApplication.java @@ -17,9 +17,32 @@ public final class VulpesApplication extends Application { GeckoSession gaiaSession; AndroidServices services; AndroidNotifications notifications; + boolean pendingScreenLock; boolean homeVisible; boolean homeAtBottom; + @Override + public void onCreate() { + super.onCreate(); + android.content.BroadcastReceiver receiver = new android.content.BroadcastReceiver() { + @Override public void onReceive(android.content.Context context, android.content.Intent intent) { + pendingScreenLock = true; + sendScreenLock(); + } + }; + android.content.IntentFilter filter = new android.content.IntentFilter(android.content.Intent.ACTION_SCREEN_OFF); + if (android.os.Build.VERSION.SDK_INT >= 33) registerReceiver(receiver,filter,RECEIVER_NOT_EXPORTED); + else registerReceiver(receiver,filter); + } + + void sendScreenLock() { + if (port == null || !pendingScreenLock) return; + try { + port.postMessage(new JSONObject().put("type","android-screen-off")); + pendingScreenLock = false; + } catch (Exception error) {Log.w("Vulpes","Screen lock pending",error);} + } + void prepare() throws IOException { if (runtime != null) return; server = new GaiaServer(this); @@ -58,6 +81,7 @@ public final class VulpesApplication extends Application { @Override public void onConnect(WebExtension.Port p) { port = p; + sendScreenLock(); if (activity != null) notifications.click(activity.getIntent()); p.setDelegate( new WebExtension.PortDelegate() { @@ -80,6 +104,18 @@ public final class VulpesApplication extends Application { return GeckoResult.fromException(new SecurityException("EXTENSION_REQUIRED")); } JSONObject json = (JSONObject) message; + if (json.optString("type").equals("marketplace.return") && activity!=null) {activity.runOnUiThread(()->activity.closeBrowser());return GeckoResult.fromValue(null);} + if (json.optString("type").startsWith("packages.")) { + GeckoResult result=new GeckoResult<>(); + new Thread(()->{try { + String operation=json.getString("type"); + if(operation.equals("packages.save"))server.installed.save(json.getJSONObject("item")); + else if(operation.equals("packages.remove"))server.installed.remove(json.getString("id")); + else if(!operation.equals("packages.list"))throw new IOException("INVALID_OPERATION"); + result.complete(server.installed.list().toString()); + }catch(Exception error){result.completeExceptionally(error);}},"Vulpes-packages").start(); + return result; + } if (json.optString("type").equals("homeScroll")) { homeAtBottom = json.optBoolean("bottom"); if (activity != null) activity.setHomeSurface(homeVisible); @@ -124,6 +160,7 @@ public final class VulpesApplication extends Application { } void resumed() { + sendScreenLock(); if (port == null) return; try { port.postMessage(new JSONObject().put("type", "android-resume")); diff --git a/android/extension/background.js b/android/extension/background.js index c08d901a..e189b1d5 100644 --- a/android/extension/background.js +++ b/android/extension/background.js @@ -1,3 +1,5 @@ +import { Packages, packageURL } from './services/packages.mjs'; +import { Activities, isGaiaActivity } from './services/activities.mjs'; import { authorizePlatform } from './services/platform.mjs'; import { SettingsService } from './services/settings.mjs'; import { DataStoreService } from './services/datastores.mjs'; @@ -7,6 +9,9 @@ import { Messages } from './Messages.mjs'; import { Connections } from './Connections.mjs'; import { Alarms } from './Alarms.mjs'; const peers = new Set(); +let activities, packages; +const nativePackages=(operation,data={})=>browser.runtime.sendNativeMessage('vulpes',{type:'packages.'+operation,...data}).then(JSON.parse); +async function refreshInstalled(){const installed=await nativePackages('list');apps.splice(0,apps.length,...apps.filter(a=>!a.installed),...installed);} let apps, values, settings, dataStores, contacts, messages, connections, alarms, storage; const identity = (peer) => peer.app; function notify(peer, type, data) { @@ -26,7 +31,7 @@ function grants(app) { function broadcast(type, data, target) { for (const peer of peers) { if (target && peer.app.id !== target) continue; - if (type === 'settingchange' && !grants(peer.app).includes('settings.read')) continue; + if (type === 'settingchange' && data.key !== 'language.current' && !grants(peer.app).includes('settings.read')) continue; if ( type === 'contactchange' && !peer.app.manifest.permissions?.contacts?.access?.includes('read') @@ -45,7 +50,7 @@ function broadcast(type, data, target) { notify(peer, type, data); } } -function launch(target, entryPoint, path) { +function launch(target, entryPoint, path, reload = false) { path ||= target.manifest.entry_points?.[entryPoint]?.launch_path || target.manifest.launch_path || @@ -53,7 +58,7 @@ function launch(target, entryPoint, path) { const url = new URL(path, target.origin); if (url.origin !== target.origin) throw Error('INVALID_URL'); broadcast( - 'launch', + reload ? 'activity-launch' : 'launch', { manifestURL: target.manifestURL, origin: target.origin, @@ -66,6 +71,8 @@ function launch(target, entryPoint, path) { } const ready = (async () => { apps = await (await fetch('registry.json')).json(); + await refreshInstalled(); + packages=new Packages({save:item=>nativePackages('save',{item}),changed:refreshInstalled}); const defaults = await (await fetch('defaults.json')).json(); const saved = await browser.storage.local.get('settings'); values = { ...defaults, ...saved.settings }; @@ -82,6 +89,8 @@ const ready = (async () => { values['wallpaper.image.valid'] = false; await browser.storage.local.set({ settings: values }); } + activities = new Activities({identity,apps:()=>apps,notify,uuid:()=>crypto.randomUUID(), + launch:(target,path,{reload=false,entryPoint}={})=>launch(target,entryPoint,path,reload)}); let writes = Promise.resolve(); settings = new SettingsService( { @@ -123,6 +132,12 @@ const ready = (async () => { // Java owns this port. Web pages have no access to native messaging. let native; let systemReady = false; +let pendingScreenLock = false; +function deliverScreenLock() { + if (!systemReady || !pendingScreenLock) return; + pendingScreenLock = false; + broadcast('screen-off', {}, 'system'); +} let pendingNotification; function deliverNotification() { if (!systemReady || !pendingNotification) return; @@ -140,7 +155,15 @@ function connectNative() { native.onMessage.addListener(async (message) => { await ready; if (['home', 'holdhome'].includes(message.type)) broadcast(message.type, {}, 'system'); - if (message.type === 'android-resume') await refreshAndroid().catch(console.warn); + if (message.type === 'android-screen-off') { + pendingScreenLock = true; + deliverScreenLock(); + } + if (message.type === 'android-resume') { + deliverScreenLock(); + broadcast('screen-on', {}, 'system'); + await refreshAndroid().catch(console.warn); + } if (message.type === 'notification-click') { pendingNotification = message.data; deliverNotification(); @@ -206,6 +229,7 @@ async function handle(peer, request) { if (method === 'android.systemReady') { if (app.id !== 'system') throw Error('PERMISSION_DENIED'); systemReady = true; + deliverScreenLock(); deliverNotification(); return null; } @@ -278,6 +302,7 @@ async function handle(peer, request) { } if (!Object.keys(params.values).length) return null; } + if (method === 'locale.current') return values['language.current'] || 'en-US'; if (method === 'settings.snapshot') { if (!grants(app).includes('settings.read')) throw Error('PERMISSION_DENIED'); return { ...values }; @@ -287,6 +312,14 @@ async function handle(peer, request) { if (reply.error) throw Error(reply.error.code); return reply.result; } + if(method.startsWith('marketplace.')) { + if(app.id!=='marketplace')throw Error('PERMISSION_DENIED'); + if(method==='marketplace.poll'){const url=marketplaceDownload;marketplaceDownload=null;return url;} + if(method==='marketplace.cancel'){packages.cancel();return true;} + if(method==='marketplace.prepare')return packages.prepare(params.url); + if(method==='marketplace.install'){const id=await packages.install(params.token);const installed=apps.find(a=>a.id===id);broadcast('apps-installed',installed);return installed;} + throw Error('METHOD_NOT_SUPPORTED'); + } if (method === 'apps.self') { console.info('VULPES app ready', app.id); return app; @@ -298,6 +331,10 @@ async function handle(peer, request) { if (!manage) throw Error('PERMISSION_DENIED'); return apps; } + if(method==='apps.uninstall') { + const installed=apps.find(a=>a.id===params.id && a.installed);if(!manage || !installed)throw Error('PERMISSION_DENIED'); + await nativePackages('remove',{id:params.id});await refreshInstalled();broadcast('apps-uninstalled',installed);return true; + } if (method === 'apps.launch') { const target = apps.find((a) => a.manifestURL === params.manifestURL); if (!target || (!manage && app.id !== target.id)) throw Error('PERMISSION_DENIED'); @@ -319,9 +356,13 @@ async function handle(peer, request) { connections.close(peer, params.id); return null; } + if (method === 'activities.cancel') return activities.cancel(peer); + if (method === 'activities.subscribe') return activities.subscribe(peer); + if (method === 'activities.finish') return activities.finish(peer,params); + if (method === 'activities.start' && isGaiaActivity(params)) return activities.start(peer,params); if (method === 'activities.start') { if (params.name === 'record' && params.data?.type === 'photos') { - if (app.id === 'gallery') { + if (['gallery', 'system'].includes(app.id)) { const camera = apps.find((a) => a.id === 'camera'); if (!camera) throw Error('ACTIVITY_NOT_SUPPORTED'); launch(camera); @@ -430,9 +471,21 @@ browser.runtime.onConnect.addListener((port) => { peers.delete(peer); if (peer.app.id === 'system' && ![...peers].some((p) => p.app.id === 'system')) systemReady = false; + activities.cleanup(peer); connections.cleanup(peer); alarms.cleanup(peer); }) .catch(() => {}); }); }); + +let marketplaceDownload=null; +browser.runtime.onMessage.addListener(async (message,sender)=>{ + if(!message.marketplaceDownload)return; + const origin=new URL(sender.url); + if(origin.origin!=='https://vulpes-os.org' || !origin.pathname.startsWith('/marketplace/'))throw Error('PERMISSION_DENIED'); + await ready;marketplaceDownload=packageURL(message.marketplaceDownload); + const app=apps.find(a=>a.id==='marketplace');launch(app); + await browser.runtime.sendNativeMessage('vulpes',{type:'marketplace.return'}); + return true; +}); diff --git a/android/extension/content.js b/android/extension/content.js index ad150b58..17bbcc85 100644 --- a/android/extension/content.js +++ b/android/extension/content.js @@ -1,6 +1,6 @@ /* Extension world: the browser provides origin/tab/frame identity, never Gaia. */ (() => { - if (location.port !== '18765') return; + if (location.port !== '18765' || location.hostname.startsWith('user-')) return; const win = window.wrappedJSObject; console.info('VULPES Android bridge', location.origin); let port; diff --git a/android/extension/manifest.json b/android/extension/manifest.json index b5ec06a8..3220ceb0 100644 --- a/android/extension/manifest.json +++ b/android/extension/manifest.json @@ -1 +1,45 @@ -{"manifest_version":2,"name":"Vulpes Android host","version":"1.1","browser_specific_settings":{"gecko":{"id":"android-host@vulpes-os.org"}},"permissions":["storage","unlimitedStorage","nativeMessaging","geckoViewAddons","http://*.localhost/*"],"background":{"page":"background.html","persistent":true},"content_scripts":[{"matches":["http://*.localhost/*"],"js":["content.js"],"all_frames":true,"run_at":"document_start"}]} +{ + "manifest_version": 2, + "name": "Vulpes Android host", + "version": "1.1", + "browser_specific_settings": { + "gecko": { + "id": "android-host@vulpes-os.org" + } + }, + "permissions": [ + "storage", + "unlimitedStorage", + "nativeMessaging", + "geckoViewAddons", + "http://*.localhost/*", + "https://vulpes-os.org/*" + ], + "background": { + "page": "background.html", + "persistent": true + }, + "content_scripts": [ + { + "matches": [ + "http://*.localhost/*" + ], + "js": [ + "content.js" + ], + "all_frames": true, + "run_at": "document_start" + }, + { + "matches": [ + "https://vulpes-os.org/marketplace/*" + ], + "js": [ + "marketplace-page.js", + "marketplace-content.js" + ], + "all_frames": true, + "run_at": "document_end" + } + ] +} diff --git a/android/extension/marketplace-content.js b/android/extension/marketplace-content.js new file mode 100644 index 00000000..496dd521 --- /dev/null +++ b/android/extension/marketplace-content.js @@ -0,0 +1 @@ +installMarketplacePage(window,url=>browser.runtime.sendMessage({marketplaceDownload:url}).catch(console.error)); diff --git a/android/tests/settings-codec.test.mjs b/android/tests/settings-codec.test.mjs index ce863a0b..e43eec1f 100644 --- a/android/tests/settings-codec.test.mjs +++ b/android/tests/settings-codec.test.mjs @@ -5,10 +5,10 @@ import { SettingsService } from '../../services/settings.mjs'; const context = vm.createContext({ window: {}, Blob, Uint8Array, btoa, atob }); vm.runInContext( - await readFile(new URL('../ui/settings-codec.js', import.meta.url), 'utf8'), + await readFile(new URL('../../host/settings-codec.js', import.meta.url), 'utf8'), context, ); -const { encode, decode } = context.window.VulpesAndroidSettingsCodec; +const { encode, decode } = context.window.VulpesSettingsCodec; // A binary wallpaper larger than the original 1 MiB JSON ceiling, including // every byte value. Exercise the actual service, JSON storage and observer path. const pixels = Uint8Array.from({ length: 1200000 }, (_, i) => i % 256); diff --git a/android/tools/pack-assets.py b/android/tools/pack-assets.py index e3af8394..e6c9e1ed 100644 --- a/android/tools/pack-assets.py +++ b/android/tools/pack-assets.py @@ -12,7 +12,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT / "tools")) -from project import build_info, validate_assets, release_info +from project import build_info, validate_assets, release_info, application_manifest validate_assets() OUT = ROOT / "android/app/src/main/assets" @@ -39,7 +39,7 @@ for manifest in sorted(APPS.glob("*/manifest.webapp")): id=name, origin=origin, manifestURL=origin + "/manifest.webapp", - manifest=json.loads(translate(manifest.read_text())), + manifest=application_manifest(name, json.loads(translate(manifest.read_text())), "--include-dev-apps" in sys.argv), ) ) info = build_info() @@ -126,7 +126,7 @@ if "--bridge-only" not in sys.argv or not (OUT / "gaia.zip").exists(): .read_text() ) put("_vulpes/" + name, translate(text).encode()) - put("_vulpes/settings-codec.js", (ROOT / "android/ui/settings-codec.js").read_bytes()) + put("_vulpes/settings-codec.js", (ROOT / "host/settings-codec.js").read_bytes()) put("_vulpes/android-ui.js", (ROOT / "android/ui/android-ui.js").read_bytes()) put( "_vulpes/android.css", @@ -145,6 +145,7 @@ for name in ["Connections", "Contacts", "Messages"]: ) (ext / f"{name}.mjs").write_text(text) shutil.copy2(ROOT / "host/Alarms.sys.mjs", ext / "Alarms.mjs") +shutil.copy2(ROOT / "host/marketplace-page.js", ext / "marketplace-page.js") (ext / "release.json").write_text(json.dumps(release)) (ext / "registry.json").write_text(json.dumps(registry, ensure_ascii=False)) settings = json.loads(translate((ROOT / "assets/settings-defaults.json").read_text())) diff --git a/assets/webapps/communications.gaiamobile.org/contacts/js/activities.js b/assets/webapps/communications.gaiamobile.org/contacts/js/activities.js index 12cb2a1f..84e333b1 100644 --- a/assets/webapps/communications.gaiamobile.org/contacts/js/activities.js +++ b/assets/webapps/communications.gaiamobile.org/contacts/js/activities.js @@ -19,7 +19,7 @@ const VCARD_MIME_TYPES = [ var ActivityHandler = { _currentActivity: null, - _launchedAsInlineActivity: (window.location.search == '?pick'), + _launchedAsInlineActivity: new URLSearchParams(window.location.search).has('pick'), mozContactParam: null, @@ -124,6 +124,7 @@ var ActivityHandler = { this.launch_activity(activity, 'add-parameters'); break; case 'pick': + if (window.VulpesCompat) this._launchedAsInlineActivity = true; if (!this._launchedAsInlineActivity) { return; } @@ -356,15 +357,18 @@ var ActivityHandler = { postNewSuccess: function ah_postNewSuccess(contact) { this._currentActivity.postResult({ contact: contact }); this._currentActivity = null; + if (window.VulpesCompat) this._launchedAsInlineActivity = false; }, postPickSuccess: function ah_postPickSuccess(result) { this._currentActivity.postResult(result); this._currentActivity = null; + if (window.VulpesCompat) this._launchedAsInlineActivity = false; }, postCancel: function ah_postCancel() { this._currentActivity.postError('canceled'); this._currentActivity = null; + if (window.VulpesCompat) this._launchedAsInlineActivity = false; } }; diff --git a/assets/webapps/communications.gaiamobile.org/contacts/js/contacts.js b/assets/webapps/communications.gaiamobile.org/contacts/js/contacts.js index 64dc91a5..4ea36df1 100644 --- a/assets/webapps/communications.gaiamobile.org/contacts/js/contacts.js +++ b/assets/webapps/communications.gaiamobile.org/contacts/js/contacts.js @@ -655,7 +655,9 @@ var Contacts = (function() { utils.PerformanceHelper.contentInteractive(); utils.PerformanceHelper.chromeInteractive(); window.setTimeout(Contacts && Contacts.onLocalized); - if (window.navigator.mozSetMessageHandler && window.self == window.top) { + // Vulpes embeds each app in its own permission-checked frame. + if (window.navigator.mozSetMessageHandler && + (window.self == window.top || window.VulpesCompat)) { LazyLoader.load(['/shared/js/contacts/import/utilities/misc.js', '/shared/js/contacts/import/utilities/vcard_reader.js', '/shared/js/contacts/import/utilities/vcard_parser.js'], diff --git a/assets/webapps/communications.gaiamobile.org/contacts/js/views/form.js b/assets/webapps/communications.gaiamobile.org/contacts/js/views/form.js index 865eead5..ef5e805c 100644 --- a/assets/webapps/communications.gaiamobile.org/contacts/js/views/form.js +++ b/assets/webapps/communications.gaiamobile.org/contacts/js/views/form.js @@ -1038,6 +1038,8 @@ contacts.Form = (function() { // (Bug 1041455). if (editingContact) { Contacts.setCurrent(contact); + // The change event may arrive while the edit form is still visible. + Contacts.updateContactDetail(contact.id); } } ); diff --git a/assets/webapps/homescreen.gaiamobile.org/gaia_build_defer_index.js b/assets/webapps/homescreen.gaiamobile.org/gaia_build_defer_index.js index 20c50b10..6b936f7b 100644 --- a/assets/webapps/homescreen.gaiamobile.org/gaia_build_defer_index.js +++ b/assets/webapps/homescreen.gaiamobile.org/gaia_build_defer_index.js @@ -846,7 +846,7 @@ Apps.prototype={get iconSize(){if(!this._iconSize){var children=this.icons.child return this._iconSize;},toggleSmall:function(small){if(this.icons.classList.contains('small')===small){return;} this.icons.classList.toggle('small',small);this.icons.synchronise();this.refreshGridSize();this.snapScrollPosition();},toggleScrollSnapping:function(scrollSnapping){if(this.scrollable.classList.contains('snapping')===scrollSnapping){return;} this.scrollable.classList.toggle('snapping',scrollSnapping);this.snapScrollPosition();},onVisualLoad:function(){this.visualLoadComplete=true;this.icons.thaw();this.icons.classList.remove('loading');window.performance.mark('visuallyLoaded');window.performance.mark('contentInteractive');},addApp:function(app){var manifest=app.manifest||app.updateManifest;if(!manifest){return;} -if(BLACKLIST.includes(app.origin)){return;} +if(HIDDEN_ROLES.includes(manifest.role)||BLACKLIST.includes(app.origin)){return;} if(manifest.entry_points){for(var entryPoint in manifest.entry_points){this.addAppIcon(app,entryPoint);}}else{this.addAppIcon(app);}},addIconContainer:function(icon,entry){var container=document.createElement('div');container.classList.add('icon-container');container.order=-1;container.appendChild(icon);if(entry!==-1&&this.startupMetadata[entry].order>=0){container.order=this.startupMetadata[entry].order;var children=this.icons.children;for(var i=0,iLen=children.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 literal 0 HcmV?d00001 diff --git a/assets/webapps/marketplace.gaiamobile.org/index.html b/assets/webapps/marketplace.gaiamobile.org/index.html new file mode 100644 index 00000000..bee23bd1 --- /dev/null +++ b/assets/webapps/marketplace.gaiamobile.org/index.html @@ -0,0 +1,5 @@ +Marketplace + + + + diff --git a/assets/webapps/marketplace.gaiamobile.org/manifest.webapp b/assets/webapps/marketplace.gaiamobile.org/manifest.webapp new file mode 100644 index 00000000..8cded036 --- /dev/null +++ b/assets/webapps/marketplace.gaiamobile.org/manifest.webapp @@ -0,0 +1,19 @@ +{ + "name": "Marketplace", + "description": "Vulpes OS application catalogue", + "launch_path": "/index.html", + "type": "certified", + "icons": { + "512": "/icon.png" + }, + "permissions": { + "browser": {}, + "webapps-manage": {} + }, + "locales": { + "fr": { + "name": "Marketplace", + "description": "Catalogue des applications Vulpes OS" + } + } +} diff --git a/assets/webapps/marketplace.gaiamobile.org/marketplace.css b/assets/webapps/marketplace.gaiamobile.org/marketplace.css new file mode 100644 index 00000000..0125ce10 --- /dev/null +++ b/assets/webapps/marketplace.gaiamobile.org/marketplace.css @@ -0,0 +1 @@ +html,body{width:100%;height:100%;margin:0;background:#f4f4f4;font-family:Fira Sans,sans-serif}#catalogue{position:absolute;inset:0;width:100%;height:100%;border:0}#message{padding:3rem 2rem;text-align:center;font-size:1.8rem}#message button{display:block;width:100%;padding:1rem;margin:1rem 0;font:inherit}#open[hidden],[hidden]{display:none!important}#confirm{z-index:10}#confirm section{overflow:auto}#permissions{font-size:1.5rem} diff --git a/assets/webapps/marketplace.gaiamobile.org/marketplace.js b/assets/webapps/marketplace.gaiamobile.org/marketplace.js new file mode 100644 index 00000000..84dbc0c5 --- /dev/null +++ b/assets/webapps/marketplace.gaiamobile.org/marketplace.js @@ -0,0 +1,32 @@ +(async()=>{ + const frame=document.getElementById('catalogue'),message=document.getElementById('message'),dialog=document.getElementById('confirm'); + let attempt=0,busy=false,prepared=null,installed=null,language=await VulpesCompat.call('locale.current'); + const fr=()=>/^fr(?:-|$)/i.test(language); + const text=(f,e)=>fr()?f:e; + function labels(){document.getElementById('browse').textContent=text('Ouvrir le catalogue','Open catalogue');document.getElementById('open').textContent=text('Ouvrir','Open');document.getElementById('install').textContent=text('Installer','Install');document.getElementById('cancel').textContent=text('Annuler','Cancel');} + function loadFailed(){status(text('Catalogue inaccessible. Vérifiez la connexion Internet, puis réessayez.','Catalogue unavailable. Check your Internet connection, then try again.'));document.getElementById('open').hidden=true;} + frame.addEventListener('mozbrowsererror',loadFailed); + function browse(){labels();message.hidden=true;dialog.hidden=true;frame.style.visibility='visible';frame.src='https://vulpes-os.org/marketplace/?mode=app&lang='+(fr()?'fr':'en');} + function status(value){frame.style.visibility='hidden';message.hidden=false;document.getElementById('status').textContent=value;} + async function prepare(url){ + if(busy)return;const current=++attempt;busy=true;prepared=null;installed=null;document.getElementById('open').hidden=true; + status(text('Vérification de l’application…','Checking application…')); + try {const value=await VulpesCompat.call('marketplace.prepare',{url});if(current!==attempt)return;prepared=value; + document.getElementById('title').textContent=prepared.name; + document.getElementById('question').textContent=text('Installer cette application archivée ?','Install this archived application?')+' ('+(prepared.bytes/1048576).toFixed(1)+' Mio)'; + document.getElementById('permissions').textContent=text('Elle sera exécutée comme une application web, sans accès aux fonctions système. Certains anciens services peuvent ne plus fonctionner.','It will run as a web application without system access. Some old services may no longer work.'); + message.hidden=true;dialog.hidden=false; + }catch(error){if(current!==attempt)return;status(text('Installation impossible : ','Cannot install: ')+error.message);busy=false;} + } + dialog.addEventListener('submit',async event=>{event.preventDefault();if(!prepared)return;const token=prepared.token;prepared=null;dialog.hidden=true;status(text('Installation…','Installing…')); + try {installed=await VulpesCompat.call('marketplace.install',{token});status(text('Application ajoutée à l’accueil.','Application added to Home.'));document.getElementById('open').hidden=false;} + catch(error){status(text('Installation impossible : ','Cannot install: ')+error.message);}finally{busy=false;} + }); + const cancel=()=>{attempt++;prepared=null;busy=false;VulpesCompat.call('marketplace.cancel').catch(console.error);browse();}; + document.getElementById('cancel').onclick=cancel; + document.getElementById('browse').onclick=cancel; + document.getElementById('open').onclick=()=>installed && VulpesCompat.call('apps.launch',{manifestURL:installed.manifestURL}); + addEventListener('languagechange',()=>{language=navigator.language;if(!busy)browse();}); + browse(); + setInterval(async()=>{if(busy)return;try{const url=await VulpesCompat.call('marketplace.poll');if(url)await prepare(url);}catch(error){console.error(error);}},750); +})(); diff --git a/assets/webapps/ringtones.gaiamobile.org/gaia_build_defer_manage.js b/assets/webapps/ringtones.gaiamobile.org/gaia_build_defer_manage.js index ecc52c01..3ec99130 100644 --- a/assets/webapps/ringtones.gaiamobile.org/gaia_build_defer_manage.js +++ b/assets/webapps/ringtones.gaiamobile.org/gaia_build_defer_manage.js @@ -471,7 +471,7 @@ this.continue();}else{resolve(results);}};cursor.onerror=function(){if(this.erro return{remove:remove,get:get,list:list};})();;'use strict';function TonePlayer(){this._currentTone=null;this._isValid=true;this._player=new Audio();this._player.addEventListener('loadedmetadata',function(){if(this._player.src){this._isValid=true;this._player.dispatchEvent(new CustomEvent('validated',{detail:this._isValid}));}}.bind(this));this._player.addEventListener('error',function(){if(this._player.src){this._isValid=false;this._player.dispatchEvent(new CustomEvent('validated',{detail:this._isValid}));}}.bind(this));this._player.addEventListener('ended',function(){this._firePlayingCallback(false);}.bind(this));window.addEventListener('visibilitychange',function(){if(document.hidden){this.stop();this._setExclusiveMode(false);}}.bind(this));} TonePlayer.prototype={setTone:function(tone,callback){if(tone!==this._currentTone){this._firePlayingCallback(false);this._currentTone=tone;this._playingCallback=callback;if(tone&&tone.url){this._isValid=undefined;this._player.src=tone.url;this._player.play();this._firePlayingCallback(true);this._setExclusiveMode(true);}else{this._isValid=true;this._player.removeAttribute('src');this._player.load();}}else{if(!this._isValid){return;} if(this._player.paused||this._player.ended){this._player.currentTime=0;this._player.play();this._firePlayingCallback(true);this._setExclusiveMode(true);}else{this._player.pause();this._firePlayingCallback(false);}}},stop:function(){this._player.pause();this._firePlayingCallback(false);},get currentTone(){return this._currentTone;},isValid:function(callback){if(this._isValid!==undefined){callback(this._isValid);return;} -this._player.addEventListener('validated',function validated(event){this.removeEventListener('validated',validated);callback(event.detail);});},_firePlayingCallback:function(playing){if(this._playingCallback){this._playingCallback(playing);}},_setExclusiveMode:function(exclusive){if(exclusive){if(!this._source){this._context=new AudioContext('ringer');this._source=this._context.createMediaElementSource(this._player);this._source.connect(this._context.destination);}}else{if(this._source){this._source.disconnect();this._context=null;this._source=null;}}}};;'use strict';var ToneList=(function(){var NONE_ID='none:none';function toneCompare(a,b){if(a.id===NONE_ID&&b.id===NONE_ID){return 0;}else if(a.id===NONE_ID){return-1;}else if(b.id===NONE_ID){return 1;} +this._player.addEventListener('validated',function validated(event){this.removeEventListener('validated',validated);callback(event.detail);});},_firePlayingCallback:function(playing){if(this._playingCallback){this._playingCallback(playing);}},_setExclusiveMode:function(exclusive){if(exclusive){if(!this._source){this._context=new AudioContext();this._source=this._context.createMediaElementSource(this._player);this._source.connect(this._context.destination);}}else{if(this._source){this._source.disconnect();this._context=null;this._source=null;}}}};;'use strict';var ToneList=(function(){var NONE_ID='none:none';function toneCompare(a,b){if(a.id===NONE_ID&&b.id===NONE_ID){return 0;}else if(a.id===NONE_ID){return-1;}else if(b.id===NONE_ID){return 1;} var aName=a.name.toLocaleLowerCase();var bName=b.name.toLocaleLowerCase();var cmp=aName.localeCompare(bName);if(cmp){return cmp;} var aSubtitle=(a.subtitle||'').toLocaleLowerCase();var bSubtitle=(b.subtitle||'').toLocaleLowerCase();return aSubtitle.localeCompare(bSubtitle);} function domify(htmlText){var dummyDiv=document.createElement('div');dummyDiv.innerHTML=htmlText;var element=dummyDiv.firstElementChild;return element;} diff --git a/assets/webapps/ringtones.gaiamobile.org/gaia_build_defer_pick.js b/assets/webapps/ringtones.gaiamobile.org/gaia_build_defer_pick.js index 22920cc3..504d9d47 100644 --- a/assets/webapps/ringtones.gaiamobile.org/gaia_build_defer_pick.js +++ b/assets/webapps/ringtones.gaiamobile.org/gaia_build_defer_pick.js @@ -447,7 +447,7 @@ this.continue();}else{resolve(results);}};cursor.onerror=function(){if(this.erro return{remove:remove,get:get,list:list};})();;;'use strict';function TonePlayer(){this._currentTone=null;this._isValid=true;this._player=new Audio();this._player.addEventListener('loadedmetadata',function(){if(this._player.src){this._isValid=true;this._player.dispatchEvent(new CustomEvent('validated',{detail:this._isValid}));}}.bind(this));this._player.addEventListener('error',function(){if(this._player.src){this._isValid=false;this._player.dispatchEvent(new CustomEvent('validated',{detail:this._isValid}));}}.bind(this));this._player.addEventListener('ended',function(){this._firePlayingCallback(false);}.bind(this));window.addEventListener('visibilitychange',function(){if(document.hidden){this.stop();this._setExclusiveMode(false);}}.bind(this));} TonePlayer.prototype={setTone:function(tone,callback){if(tone!==this._currentTone){this._firePlayingCallback(false);this._currentTone=tone;this._playingCallback=callback;if(tone&&tone.url){this._isValid=undefined;this._player.src=tone.url;this._player.play();this._firePlayingCallback(true);this._setExclusiveMode(true);}else{this._isValid=true;this._player.removeAttribute('src');this._player.load();}}else{if(!this._isValid){return;} if(this._player.paused||this._player.ended){this._player.currentTime=0;this._player.play();this._firePlayingCallback(true);this._setExclusiveMode(true);}else{this._player.pause();this._firePlayingCallback(false);}}},stop:function(){this._player.pause();this._firePlayingCallback(false);},get currentTone(){return this._currentTone;},isValid:function(callback){if(this._isValid!==undefined){callback(this._isValid);return;} -this._player.addEventListener('validated',function validated(event){this.removeEventListener('validated',validated);callback(event.detail);});},_firePlayingCallback:function(playing){if(this._playingCallback){this._playingCallback(playing);}},_setExclusiveMode:function(exclusive){if(exclusive){if(!this._source){this._context=new AudioContext('ringer');this._source=this._context.createMediaElementSource(this._player);this._source.connect(this._context.destination);}}else{if(this._source){this._source.disconnect();this._context=null;this._source=null;}}}};;;'use strict';var ToneList=(function(){var NONE_ID='none:none';function toneCompare(a,b){if(a.id===NONE_ID&&b.id===NONE_ID){return 0;}else if(a.id===NONE_ID){return-1;}else if(b.id===NONE_ID){return 1;} +this._player.addEventListener('validated',function validated(event){this.removeEventListener('validated',validated);callback(event.detail);});},_firePlayingCallback:function(playing){if(this._playingCallback){this._playingCallback(playing);}},_setExclusiveMode:function(exclusive){if(exclusive){if(!this._source){this._context=new AudioContext();this._source=this._context.createMediaElementSource(this._player);this._source.connect(this._context.destination);}}else{if(this._source){this._source.disconnect();this._context=null;this._source=null;}}}};;;'use strict';var ToneList=(function(){var NONE_ID='none:none';function toneCompare(a,b){if(a.id===NONE_ID&&b.id===NONE_ID){return 0;}else if(a.id===NONE_ID){return-1;}else if(b.id===NONE_ID){return 1;} var aName=a.name.toLocaleLowerCase();var bName=b.name.toLocaleLowerCase();var cmp=aName.localeCompare(bName);if(cmp){return cmp;} var aSubtitle=(a.subtitle||'').toLocaleLowerCase();var bSubtitle=(b.subtitle||'').toLocaleLowerCase();return aSubtitle.localeCompare(bSubtitle);} function domify(htmlText){var dummyDiv=document.createElement('div');dummyDiv.innerHTML=htmlText;var element=dummyDiv.firstElementChild;return element;} diff --git a/assets/webapps/ringtones.gaiamobile.org/js/tone_player.js b/assets/webapps/ringtones.gaiamobile.org/js/tone_player.js index 18cf4537..dfb17d68 100644 --- a/assets/webapps/ringtones.gaiamobile.org/js/tone_player.js +++ b/assets/webapps/ringtones.gaiamobile.org/js/tone_player.js @@ -1,4 +1,4 @@ ;;'use strict';function TonePlayer(){this._currentTone=null;this._isValid=true;this._player=new Audio();this._player.addEventListener('loadedmetadata',function(){if(this._player.src){this._isValid=true;this._player.dispatchEvent(new CustomEvent('validated',{detail:this._isValid}));}}.bind(this));this._player.addEventListener('error',function(){if(this._player.src){this._isValid=false;this._player.dispatchEvent(new CustomEvent('validated',{detail:this._isValid}));}}.bind(this));this._player.addEventListener('ended',function(){this._firePlayingCallback(false);}.bind(this));window.addEventListener('visibilitychange',function(){if(document.hidden){this.stop();this._setExclusiveMode(false);}}.bind(this));} TonePlayer.prototype={setTone:function(tone,callback){if(tone!==this._currentTone){this._firePlayingCallback(false);this._currentTone=tone;this._playingCallback=callback;if(tone&&tone.url){this._isValid=undefined;this._player.src=tone.url;this._player.play();this._firePlayingCallback(true);this._setExclusiveMode(true);}else{this._isValid=true;this._player.removeAttribute('src');this._player.load();}}else{if(!this._isValid){return;} if(this._player.paused||this._player.ended){this._player.currentTime=0;this._player.play();this._firePlayingCallback(true);this._setExclusiveMode(true);}else{this._player.pause();this._firePlayingCallback(false);}}},stop:function(){this._player.pause();this._firePlayingCallback(false);},get currentTone(){return this._currentTone;},isValid:function(callback){if(this._isValid!==undefined){callback(this._isValid);return;} -this._player.addEventListener('validated',function validated(event){this.removeEventListener('validated',validated);callback(event.detail);});},_firePlayingCallback:function(playing){if(this._playingCallback){this._playingCallback(playing);}},_setExclusiveMode:function(exclusive){if(exclusive){if(!this._source){this._context=new AudioContext('ringer');this._source=this._context.createMediaElementSource(this._player);this._source.connect(this._context.destination);}}else{if(this._source){this._source.disconnect();this._context=null;this._source=null;}}}}; \ No newline at end of file +this._player.addEventListener('validated',function validated(event){this.removeEventListener('validated',validated);callback(event.detail);});},_firePlayingCallback:function(playing){if(this._playingCallback){this._playingCallback(playing);}},_setExclusiveMode:function(exclusive){if(exclusive){if(!this._source){this._context=new AudioContext();this._source=this._context.createMediaElementSource(this._player);this._source.connect(this._context.destination);}}else{if(this._source){this._source.disconnect();this._context=null;this._source=null;}}}}; \ No newline at end of file diff --git a/changelog.json b/changelog.json index 81936731..4efc193f 100644 --- a/changelog.json +++ b/changelog.json @@ -5,6 +5,69 @@ "en": "# Changelog — Vulpes OS\n\n[Français](CHANGELOG.md)\n\nOne Gaia base, three platforms: **desktop**, **Android (APK)** and **Tundra / Sargo**.\nThis journal covers visible changes and major technical milestones.\n\n**Status:** “In development” refers to local sources, “APK built” to a test package,\nand “Published” to a public repository release. Shared source changes reach installed\nAPKs and phone images only after those packages are updated." }, "entries": [ + { + "id": "2026-10-08-source-publication", + "text": { + "fr": "## 8 octobre 2026 — Mise à jour des sources publiques\n\n### Commun · PC / Android / Tundra\n\n- Regrouper les correctifs récents de caméra, Contacts, SMS, Marketplace et les outils de construction et de restauration Sargo dans les sources publiques. Mettre à jour les README français et anglais avec les capacités et limites vérifiées.\n- Corriger le contrôle de parité Android pour créer son dossier de rapports sur une copie neuve du dépôt. Vérifier que la configuration Wi-Fi native embarque un répertoire de connexions vide.\n- Conserver les tickets, feuilles de route, documents internes, données personnelles et clés hors du dépôt.\n\n### Paquets et qualification\n\n- L’APK public reste Preview17 : les correctifs du 8 octobre nécessitent une prochaine compilation. Aucune nouvelle image native publiée ni flash dans cette étape.\n- Sur Sargo, l’enregistrement cellulaire reste en recherche lors du dernier contrôle ; audio bidirectionnel, appairage Bluetooth et profils restent à qualifier.", + "en": "## 8 October 2026 — Public source update\n\n### Shared · Desktop / Android / Tundra\n\n- Bring recent camera, Contacts, SMS and Marketplace fixes, plus Sargo build and recovery tools, into the public sources. Update both READMEs with verified capabilities and limitations.\n- Make the Android parity check create its report directory in a fresh checkout. Verify that native Wi-Fi configuration ships an empty connections directory.\n- Keep tickets, roadmaps, internal documents, personal data and keys outside the repository.\n\n### Packages and qualification\n\n- The public APK remains Preview17; the 8 October fixes require a future build. No new native image or flash in this step.\n- At the latest Sargo check, cellular registration is still searching; two-way call audio, Bluetooth pairing and profiles remain to be qualified." + } + }, + { + "id": "development-2026-10-08-camera-lifecycle", + "text": { + "fr": "## 8 octobre 2026 — Caméra et parcours Contacts · en développement\n\n### Commun · Gaia / PC / Android / Tundra\n\n- Sérialiser les ouvertures de caméra, attendre la fermeture du capteur précédent et libérer les pistes et ressources vidéo même après un échec. Stabiliser l’identification avant/arrière sur PC et Android.\n- Conserver les images binaires lors des échanges PC/Tundra ; encoder explicitement les photos et dates des contacts pour le pont JSON Android.\n- Corriger l’actualisation de la fiche après modification d’un contact. Rétablir les activités Contacts → SMS, sélection d’un numéro et ouverture du pavé numérique, en préservant les demandes imbriquées et les points d’entrée de Gaia.\n- Réouvrir Galerie en mode sélection pour ajouter une photo à un contact, même lorsque Galerie est déjà ouverte en consultation. Sélection, recadrage et enregistrement de la photo validés sur PC.\n- Ajouter des tests de caméra, de stockage des contacts, de permissions, de transport binaire et de routage des activités.\n\n### PC\n\n- Vérifier le parcours original Appareil photo → capture JPEG → Galerie → ouverture de la photo → retour caméra.\n- Vérifier dans Gaia : création et modification d’un contact, actualisation de la fiche, recherche sans accents et sans résultats, favoris, destinataire SMS, sélection d’un numéro, pavé numérique prérempli, annulation puis confirmation de suppression. Le test n’émet ni appel ni SMS et supprime son contact temporaire.\n\n### Tundra · Sargo\n\n- Vérifier en RAM sur Pixel 3a : autofocus, zoom, quatre alternances avant/arrière avec nouvelles trames, capture JPEG depuis Gaia, stockage, ouverture dans Galerie et arrêt du capteur à l’accueil.\n- Vérifier les conversations déjà stockées, le clavier et les notifications. Recherche Wi-Fi : quatre réseaux détectés. Nouvelle émission/réception SMS et audio des appels encore en qualification.\n- Ajouter les paquets BlueZ et les bibliothèques nécessaires, verrouillés par SHA256. Le contrôleur Bluetooth démarre, s’active et lance une recherche ; l’appairage depuis Gaia et les profils ne sont pas encore validés.\n- Ajouter le magasin de certificats natif : HTTPS vérifié sans désactivation de TLS. Tester les archives altérées, collisions de fichiers et reconstructions répétées.\n\n- Corriger les fichiers Contacts embarqués dans le build de démarrage : la création, l’édition, le passage vers SMS, le sélecteur et le pavé numérique passent aussi avec les gestes tactiles sur Sargo.\n\n### Android · APK\n\n- Publier l’APK Preview17 existant, avec téléchargement et SHA256 vérifiés. Il précède les correctifs du 8 octobre.\n- Corriger la transmission des destinataires et du texte de Gaia vers l’application SMS Android, y compris la réponse à une conversation et le numéro saisi sans validation préalable. Tests du pont réussis ; essai Android réel encore nécessaire.\n- Réempaqueter les ressources communes corrigées pour la prochaine compilation ; aucun nouvel APK incluant ces correctifs n’est publié.\n\n**État :** builds natifs de qualification démarrés en RAM. Aucun flash, push de code ni publication de documentation privée dans cette étape. La qualification complète des fonctions de téléphone reste ouverte.\n", + "en": "## 8 October 2026 — Camera and Contacts workflows · in development\n\n### Shared · Gaia / Desktop / Android / Tundra\n\n- Serialize camera opening, await the previous sensor shutdown and release tracks and video resources after failures. Keep stable front/rear identities on desktop and Android.\n- Preserve binary images across desktop/Tundra transport; explicitly encode contact photos and dates for Android's JSON bridge.\n- Refresh contact details after editing. Restore Contacts → SMS, number picking and prefilled dialer activities, preserving nested requests and Gaia entry points.\n- Reopen Gallery in picker mode when adding a contact photo, even when Gallery is already open for browsing. Selection, cropping and photo persistence verified on desktop.\n- Add camera lifecycle, contact persistence, permissions, binary transport and activity routing tests.\n\n### Desktop\n\n- Verify the original Camera → JPEG capture → Gallery → photo opening → camera workflow.\n- Verify Gaia contact creation, editing, detail refresh, accent-insensitive search and empty results, favourites, SMS recipient, number picker, prefilled keypad, cancelled deletion and confirmed deletion. The test sends no message and makes no call; its temporary contact is removed.\n\n### Tundra · Sargo\n\n- Verify on a RAM-booted Pixel 3a: autofocus, zoom, four front/rear switches with fresh frames, shutter capture, JPEG persistence, Gallery opening and sensor shutdown on Home.\n- Check stored conversations, keyboard and notifications. Wi-Fi scan finds four networks. New SMS transmission/reception and call audio are still being qualified.\n- Add SHA256-pinned BlueZ packages and required libraries. The controller starts, powers on and discovers; pairing through Gaia and Bluetooth profiles are not yet validated.\n- Add native trusted certificates and verify HTTPS without disabling TLS. Test corrupted archives, file collisions and repeatable staging.\n\n- Include the corrected Contacts files in the boot build: contact creation, editing, SMS handoff, picking and dialer prefilling also pass using touch gestures on Sargo.\n\n### Android · APK\n\n- Publish the existing Preview17 APK and verify its download and SHA256. It predates the 8 October fixes.\n- Fix recipient and body handoff from Gaia to the Android SMS app, including replies and a typed recipient that was not yet committed. Bridge tests pass; real Android validation is still required.\n- Repackage corrected shared resources for the next build; no APK containing these new fixes has been published.\n\n**Status:** native qualification builds booted in RAM. No flashing, source push or private documentation publication in this step. Full phone qualification remains open.\n" + } + }, + { + "id": "development-2026-10-06-marketplace-theme", + "text": { + "fr": "## 6 octobre 2026 — Thème Marketplace intégré · en développement\n\n### Commun · Gaia / PC / Android / Tundra\n\n- Ouvrir le catalogue avec `mode=app`, conservé dans les liens, la recherche, les filtres, les fiches et le changement de langue.\n- Préparer un thème web Vulpes dédié : Fira locale, navigation compacte, boutons tactiles, cartes lisibles, filtres repliables et captures défilantes. Retirer les en-têtes du site dans le mode intégré, tout en conservant l’interface du site classique.\n- Conserver les confirmations et messages système côté Gaia. Le thème ne donne aucun privilège supplémentaire aux pages du catalogue.\n- Vérifier 16 pages FR/EN, 2 pages en mode classique et les ressources du thème. Rendus mobiles de 320 et 360 pixels inspectés. Lanceurs PC et Sargo mis à jour ; les sources seront reprises au prochain empaquetage Android.\n\nFichiers du site prêts localement, non déployés sur le serveur public. Aucun push ni nouvelle publication APK/ROM.\n", + "en": "## 6 October 2026 — Embedded Marketplace theme · in development\n\n### Shared · Gaia / Desktop / Android / Tundra\n\n- Open the catalogue with `mode=app`, retained in navigation, search, filters, app details and language switches.\n- Prepare a dedicated Vulpes web theme with local Fira fonts, compact navigation, touch-friendly controls, readable cards, collapsible filters and scrolling screenshots. Omit website headers in embedded mode while preserving the standard website layout.\n- Keep confirmations and system messages in Gaia. The theme grants catalogue pages no additional privileges.\n- Check 16 French/English pages, 2 standard pages and theme assets. Inspect mobile renders at 320 and 360 pixels. Desktop and Sargo launchers updated; shared sources will be included in the next Android packaging run.\n\nWebsite files prepared locally, not deployed to the public server. No push or new APK/ROM publication.\n" + } + }, + { + "id": "development-2026-10-06-system-banner", + "text": { + "fr": "## 6 octobre 2026 — Bandeaux Gaia · en développement\n\n### Commun · Gaia / PC / Android / Tundra\n\n- Faire disparaître le bandeau « Application installée » après son délai normal, même si la fin d’animation ne remonte pas du composant Gaia. Conserver son apparence et permettre sa fermeture au toucher.\n- Annuler les anciens délais lorsqu’un nouveau message remplace le précédent pour éviter une disparition prématurée.\n- Vérifier sur PC l’affichage, l’expiration, le remplacement et la fermeture au clic ; vérifier sur le Pixel le retrait effectif du bandeau après cinq secondes. Correctif déployé sur l’essai Sargo en RAM et disponible dans les sources communes pour le prochain APK.\n\nAucun flash ni publication dans cette étape.\n", + "en": "## 6 October 2026 — Gaia banners · in development\n\n### Shared · Gaia / Desktop / Android / Tundra\n\n- Dismiss the “Application installed” banner after its normal timeout even if the animation-end event does not reach the Gaia component host. Keep its appearance and tap-to-dismiss behavior.\n- Cancel old timers when a new message replaces the previous one, preventing premature dismissal.\n- Check display, expiry, replacement and click dismissal on desktop; verify actual removal after five seconds on the Pixel. Fix deployed to the Sargo RAM trial and available in shared sources for the next APK.\n\nNo flash or publication in this step.\n" + } + }, + { + "id": "development-2026-10-06-wifi", + "text": { + "fr": "## 6 octobre 2026 — Wi-Fi et panneaux Paramètres · en développement\n\n### Commun · Gaia / PC / Android / Tundra\n\n- Terminer l’ouverture d’un panneau Paramètres même si Gecko ne produit pas l’événement de fin d’animation. Conserver les transitions Gaia et éviter les doubles initialisations.\n- Correctif dans les sources communes et le serveur PC ; inclus au prochain empaquetage Android. Aucun nouvel APK publié dans cette étape.\n\n### Tundra · Sargo\n\n- Corriger les événements de signal Wi-Fi : transmettre le réseau associé et ne pas annoncer de signal de connexion lorsque le téléphone est déconnecté. L’événement incomplet faisait échouer l’affichage des réseaux dans Gaia.\n- Sur le Pixel, vérifier le pilote, le service natif, le passage par Gecko et l’affichage du panneau corrigé : quatre points d’accès détectés, regroupés en deux réseaux, sans erreur de recherche.\n- Connexion Wi-Fi confirmée par l’utilisateur ; requête HTTPS réelle réussie depuis Gecko vers example.org (HTTP 200, vérification des certificats active). Correctifs appliqués à l’essai en RAM ; aucun flash ni push.\n", + "en": "## 6 October 2026 — Wi-Fi and Settings panels · in development\n\n### Shared · Gaia / Desktop / Android / Tundra\n\n- Complete Settings panel navigation even when Gecko does not emit an animation-end event. Preserve Gaia transitions and prevent duplicate initialization.\n- Updated shared sources and the desktop server; included in the next Android packaging run. No new APK published in this step.\n\n### Tundra · Sargo\n\n- Fix Wi-Fi signal events: include the associated network and do not emit connection information while disconnected. The incomplete event prevented Gaia from displaying scan results.\n- Check the driver, native service, Gecko bridge and corrected panel on the Pixel: four access points detected, grouped into two networks, with no scan error.\n- Wi-Fi connection confirmed by the user; a real HTTPS request from Gecko to example.org passed (HTTP 200, certificate verification enabled). Fixes applied to the RAM trial; no flash or Git push.\n" + } + }, + { + "id": "development-2026-10-06-marketplace-views", + "text": { + "fr": "## 6 octobre 2026 — Marketplace · en développement\n\n### PC / Tundra · Sargo\n\n- Maintenir le catalogue sous la barre de statut et dans les limites de son application. Masquer sa vue web à l’accueil et dans le multitâche ; la retirer à la fermeture de l’application.\n- Éviter qu’une navigation annulée ou l’ancienne page d’erreur masque une nouvelle tentative.\n- Afficher un message local et proposer une nouvelle tentative lorsque le catalogue est inaccessible, au lieu de laisser sa page d’erreur recouvrir Gaia.\n- Sur PC : navigation, erreur réseau, nouvelle tentative, retour à l’accueil et fermeture depuis le multitâche vérifiés. Sept contrôles directs passent sur Sargo en RAM, sans fenêtre de débogage, avec une page locale et une précondition de déverrouillage forcée ; le catalogue distant nécessite une connexion Internet sur le téléphone.\n\n### Android · APK\n\n- Reconstruire l’APK local Preview17 avec le message d’erreur Marketplace commun. Signature, alignement et parité des ressources vérifiés ; nouvelle régression sur appareil Android non effectuée dans cette étape.\n\nAucune publication dans cette étape.\n", + "en": "## 6 October 2026 — Marketplace · in development\n\n### Desktop / Tundra · Sargo\n\n- Keep the catalogue below the status bar and inside its owning application. Hide its web view on Home and in the task switcher; remove it when the app closes.\n- Prevent a cancelled navigation or a previous error page from hiding a retry.\n- Show a local error message with a retry action when the catalogue is unavailable, instead of leaving its error page over Gaia.\n- Desktop navigation, network failure, retry, Home and closing from the task switcher checked. Seven direct checks pass on Sargo in RAM without a debugger window, using a local page and a forced-unlock precondition; the remote catalogue requires an Internet connection on the phone.\n\n### Android · APK\n\n- Rebuild the local Preview17 APK with the shared Marketplace error message. Signature, alignment and asset parity checked; no new Android device regression run in this step.\n\nNothing published in this step.\n" + } + }, + { + "id": "2.7-preview.17", + "text": { + "fr": "## 2.7-preview.17 — APK construit · 5 octobre 2026\n\n### Commun · Gaia / PC\n\n- Remettre Marketplace sur l’accueil avec son icône originale et le catalogue Vulpes. Ouvrir sa version française pour les langues fr, anglaise sinon.\n- Adapter les téléchargements du catalogue en installations confirmées : vérifier les archives ZIP, ajouter l’application à l’accueil et permettre son lancement et sa désinstallation.\n- Conserver les applications installées séparément des sources Gaia, sur des origines distinctes et sans privilèges système hérités des anciens manifestes.\n- Valider sur PC le parcours réel avec 2048 : catalogue, confirmation, installation, lancement, persistance et désinstallation. Contrôler les archives corrompues, chemins invalides, limites, annulation et confirmations à usage unique.\n\n### Android · APK\n\n- Construire et signer Preview17 avec le même Marketplace et le même service d’installation. Utiliser la vue GeckoView existante pour le catalogue et le stockage privé Android pour les paquets.\n- Vérifier sur émulateur Android 16/API36 le clic Installer, la confirmation, l’apparition sur l’accueil et le lancement de 2048 sans accès au pont système Vulpes. Vérifier aussi la conservation après arrêt forcé et relance, puis la désinstallation.\n\n### Tundra · Sargo\n\n- Préparer une image de boot locale incluant Marketplace, l’installateur et le serveur des applications ajoutées. Démarrage en RAM effectué sur le Pixel le 6 octobre : accueil et ressources Marketplace vérifiés, sans flash. Neuf contrôles système sur dix passent ; le contrôle global Gaia relève une variation du viewport au déverrouillage. Installation de paquets sur Sargo encore à qualifier.\n\n**Limites :** compatibilité initiale avec les applications web empaquetées. Les anciennes API privilégiées, applications hébergées et services disparus ne sont pas restaurés automatiquement. Rien publié sur Forgejo ni sur le site.\n", + "en": "## 2.7-preview.17 — APK built · 5 October 2026\n\n### Shared · Gaia / Desktop\n\n- Restore Marketplace on Home with its original icon and the Vulpes catalogue. Select French for fr languages and English otherwise.\n- Turn catalogue downloads into confirmed installations: validate ZIP archives, add the application to Home and support launch and removal.\n- Store installed applications separately from Gaia sources, on distinct origins and without system privileges inherited from archived manifests.\n- Validate the real desktop workflow with 2048: catalogue, confirmation, installation, launch, persistence and removal. Check damaged archives, invalid paths, limits, cancellation and single-use confirmations.\n\n### Android · APK\n\n- Build and sign Preview17 with the same Marketplace and installation service. Use the existing GeckoView browser for the catalogue and private Android storage for packages.\n- Verify the Install click, confirmation, Home icon and 2048 launch without access to the Vulpes system bridge on an Android 16/API36 emulator. Also verify persistence after force-stop/relaunch and removal.\n\n### Tundra · Sargo\n\n- Prepare a local boot image containing Marketplace, the installer and the added-application server. RAM boot performed on the Pixel on 6 October: Home and Marketplace resources verified, without flashing. Nine of ten system checks pass; the overall Gaia check records a viewport change during unlocking. Package installation on Sargo still needs qualification.\n\n**Limitations:** initial support for packaged web applications. Old privileged APIs, hosted apps and discontinued services are not restored automatically. Nothing published to Forgejo or the website.\n" + } + }, + { + "id": "2.7-preview.16", + "text": { + "fr": "## 2.7-preview.16 — APK construit · 5 octobre 2026\n\n### Commun · Gaia / PC\n\n- Rétablir les sélecteurs Gaia de fond d’écran et de sons, leur retour vers Paramètres et leur annulation par Accueil. Partager le transport des images et sons enregistrés entre PC et Android.\n- Propager les changements de langue à l’accueil, y compris sans permission de lecture générale des réglages. Vérifier les libellés FR/EN et la persistance.\n- Rétablir l’arrêt du balayage horizontal sur une page et masquer les applications de développement sur l’accueil, sans les supprimer des sources.\n- Utiliser le logo Vulpes fourni dans le splash et adapter les composants originaux de la liste des sons au moteur actuel.\n- Vérifier sur PC deux changements consécutifs de fond, le choix d’un son et les panneaux Gaia restaurés.\n\n### Android · APK\n\n- APK local Preview16 construit et signé ; contenu commun et version vérifiés. Aucune publication dans cette étape.\n- Valider Vulpes comme lanceur HOME, afficher le verrouillage Gaia après veille et rétablir le retour Android depuis la caméra ouverte au verrouillage.\n- Masquer les barres système Android en mode immersif, en conservant leur accès temporaire par balayage.\n- Tests sur émulateur Android 16/API36 : verrouillage, caméra/retour, FR/EN, accueil sans applications de test, fond d’écran et son. Fond conservé après arrêt forcé et relance, sans changement répété pendant 15 secondes. Autres appareils Android non qualifiés dans cette étape.\n\n### Tundra · Sargo\n\n- Inclure les mêmes correctifs et la politique des applications dans une nouvelle image de boot de test. Le boot précédent réappliquait une copie ancienne des fichiers et annulait les modifications à chaud.\n- Démarrage en RAM sur le Pixel réussi : six contrôles de langues/accueil/sélecteurs et dix contrôles système passent. Sélecteurs image/son vérifiés sans écraser les choix personnels. Le boot installé reste Preview15 ; aucune partition flashée dans cette étape.\n\n**Limites :** l’installation tierce FFAA reste ouverte. Le site dépend d’anciennes API mozApps et d’un script nomodule ; un installateur isolant les applications et leurs permissions reste à construire. Le choix d’un son Gaia ne modifie pas la sonnerie globale Android ; l’audio d’appel réel n’a pas été qualifié ici.", + "en": "## 2.7-preview.16 — APK built · 5 October 2026\n\n### Shared · Gaia / Desktop\n\n- Restore Gaia wallpaper and sound pickers, return navigation to Settings and cancellation through Home. Share persisted image and sound transport between desktop and Android.\n- Propagate language changes to Home without granting general settings read access. Check French/English labels and persistence.\n- Restore horizontal page snapping and hide development apps from Home without deleting their sources.\n- Use the supplied Vulpes logo in the splash and adapt the original sound-list components to the current engine.\n- Verify two consecutive wallpaper changes, sound selection and restored Gaia panels on desktop.\n\n### Android · APK\n\n- Build and sign local Preview16; verify shared payload and version. Nothing published in this step.\n- Validate Vulpes as the HOME launcher, restore Gaia locking after sleep and Android Back navigation from the lockscreen camera.\n- Hide Android system bars in immersive mode while retaining temporary swipe access.\n- Android 16/API36 emulator checks: locking, camera/Back, French/English, Home without test apps, wallpaper and sound. Wallpaper retained after force-stop/relaunch with no repeated changes over 15 seconds. Other Android devices not qualified in this step.\n\n### Tundra · Sargo\n\n- Include shared fixes and app policy in a new test boot image. The previous boot reapplied an old file snapshot, undoing hot updates.\n- RAM boot on Pixel passed: six language/Home/picker checks and ten system checks. Image/sound picker results verified without replacing personal selections. Installed boot remains Preview15; no partition flashed in this step.\n\n**Limitations:** third-party FFAA installation remains open. The site depends on old mozApps APIs and a nomodule script; an installer with application and permission isolation still needs implementation. Selecting a Gaia sound does not change the global Android ringtone; actual call audio was not qualified here." + } + }, + { + "id": "2026-10-04-sargo-standalone", + "text": { + "fr": "## En développement — 4 octobre 2026 — Installation autonome Sargo\n\n### Tundra · Sargo\n\n- Construction d’un volume ext4 neuf directement destiné à userdata : système, données et composants matériels vendor/modem embarqués. Le démarrage ne cherche plus de fichiers dans une installation Droidian ; aucune session Android ni connexion ADB n’est nécessaire à l’installation.\n- Installateur Fastboot en Python : contrôle du modèle Sargo, du déverrouillage, des tailles et des empreintes, puis remplacement de userdata, dtbo_a, vbmeta_a et boot_a. Le bootloader reste déverrouillé ; les calibrations propres au téléphone sont conservées.\n- Sauvegarde complète de userdata hors ligne, comparaison intégrale avec le téléphone et vérification de l’archive de restauration avant le flash. Les sauvegardes restent privées ; une restauration réelle n’a pas été effectuée dans cette étape.\n- Deux démarrages depuis le stockage interne réussis : onze contrôles Gaia et dix contrôles natifs par démarrage, image de boot relue et vérifiée, réglages conservés. Le slot A est marqué réussi uniquement après validation du démarrage Gaia courant.\n- Variante générique sans serveur SSH ni clés de maintenance : flash de boot_a et démarrage réel réussis. La variante de développement est ensuite remise sur le Pixel pour poursuivre les travaux. Les images du paquet générique conservent leur état initial vierge.\n- Contrôles finaux sur le démarrage autonome de développement : Photo (dont bascules de capteur), clavier Gaia et notifications réussis.\n- Paquet Fastboot local assemblé avec empreintes et rapport de qualification. 44 tests ciblés passent. Il n’est pas encore publié : la provenance et la redistribution de certains composants matériels restent à finaliser.\n- Limites : qualification sur un Pixel 3a, pas sur toutes les combinaisons de firmware ; volume de 8 Gio comprenant 1 Gio de données modifiables, sans extension automatique. Les fonctionnalités matérielles restent expérimentales.\n\n### PC / Android · APK\n\n- Aucun changement d’interface ni nouveau binaire dans cette étape. Gaia reste partagé entre les trois plateformes.", + "en": "## In development — 4 October 2026 — Standalone Sargo installation\n\n### Tundra · Sargo\n\n- Build a fresh ext4 volume directly for userdata, including the system, writable data and vendor/modem hardware images. Startup no longer looks for files in a Droidian installation; installation requires neither an Android session nor ADB.\n- Python Fastboot installer checks the Sargo model, unlock state, partition sizes and checksums, then replaces userdata, dtbo_a, vbmeta_a and boot_a. The bootloader stays unlocked and device-specific calibration is retained.\n- Full offline userdata backup, complete comparison against the phone and recovery archive verification before flashing. Backups remain private; an actual restoration was not performed in this step.\n- Two successful boots from internal storage: eleven Gaia and ten native checks per boot, verified boot-image readback and retained settings. Slot A is marked successful only after validating Gaia startup in the current boot.\n- Generic variant without an SSH server or maintenance keys: actual boot_a flash and boot passed. The development variant was then restored on the Pixel for further work. Generic package images retain their original fresh state.\n- Final checks on the standalone development boot passed for Camera (including lens switches), the Gaia keyboard and notifications.\n- Local Fastboot package assembled with checksums and a qualification report. 44 targeted tests pass. It is not published yet: provenance and redistribution of some hardware components still need final review.\n- Limits: qualified on one Pixel 3a, not every firmware combination; an 8 GiB volume including 1 GiB of writable data, without automatic expansion. Hardware functionality remains experimental.\n\n### Desktop / Android · APK\n\n- No interface changes or new binary in this step. Gaia remains shared by all three platforms." + } + }, { "id": "2026-10-03-sargo-per-device-installation", "text": { @@ -185,6 +248,12 @@ "version": "2.7-preview.15", "after": "2.7-preview.14", "summary": "## 🇫🇷 Vulpes OS — Preview 15\n\nPremière publication des **sources communes PC / Android / Tundra**, accompagnée d'un nouvel APK expérimental.\n\n### Télécharger et essayer\n- **Android :** installer `vulpes-os-preview-2.7-preview.15.apk`. Android 8 minimum déclaré, API 37 ciblée ; ARM64, ARMv7 et x86_64. L'APK garde la signature des précédentes Preview.\n- **PC Linux :** cloner le dépôt, puis exécuter `./setup.sh` et `./run.sh`. Le moteur Mozilla épinglé est téléchargé et son empreinte vérifiée.\n- **Sargo :** les sources Tundra sont incluses. **Aucune ROM générique flashable n'est fournie** : notre image privée dépend encore de l'installation et du partitionnement du téléphone de développement.\n\n### Depuis la Preview 14\n- Correction du format des dates des SMS qui laissait les conversations Gaia vides ; conservation des messages et des états d'envoi/échec côté hôte.\n- Libération et remplacement des flux caméra fiabilisés, pour empêcher une ancienne session de fermer le nouveau capteur.\n- Sources Tundra : focus tactile, zoom numérique et capture JPEG du capteur ; aperçu distinct de la photo en pleine résolution. Coupure du vibreur corrigée et arrêt de secours du service.\n- Sources PC, APK et Tundra réunies, scripts de préparation et de compilation inclus, README français et anglais remis à jour. Les profils privés et la documentation de travail ne sont pas publiés.\n\n**Validation :** 42 tests de services, démarrage et navigation sur PC avec Gecko 156.0.1 ; sur émulateur Android 16, capture Photo/Galerie, reprise de caméra, dix retours depuis l’arrière-plan et récupération après arrêt du processus d’affichage. APK compilé depuis `b38dea0` ; le tag ajoute uniquement un correctif des scripts de test PC.\n\n**Versions :** Vulpes `2.7-preview.15` · Gaia `2.7.0` · Gecko PC `156.0.1` · GeckoView Android `156.0`. Les fonctions matérielles diffèrent selon la plateforme : sous Android, appels et SMS sont délégués aux applications Android, pas au modem Tundra.\n\n**Limites connues :** build de développement signé, débogage Gecko accessible via ADB autorisé ; toutes les versions et tous les modèles Android ne sont pas qualifiés. Sur Sargo : aperçu caméra autour de 16 i/s, flash/vidéo, rotation automatique et veille profonde incomplets, audio des appels à qualifier. Le grand dialogue signalé après un envoi SMS reste à identifier. Cette release n'annonce pas la résolution de ces limites.\n\n## 🇬🇧 Vulpes OS — Preview 15\n\nFirst publication of the **shared desktop / Android / Tundra sources**, with a new experimental APK.\n\n### Download and try\n- **Android:** install `vulpes-os-preview-2.7-preview.15.apk`. Declared minimum Android 8, target API 37; ARM64, ARMv7 and x86_64. Signed with the same key as previous Preview builds.\n- **Linux desktop:** clone the repository, then run `./setup.sh` and `./run.sh`. The pinned Mozilla engine is downloaded and its checksum verified.\n- **Sargo:** Tundra sources are included. **No generic flashable ROM is supplied**: our private image still depends on the development phone's installation and storage layout.\n\n### Since Preview 14\n- Fix SMS date formatting that left Gaia conversations empty; retain messages and sent/failed states in the host.\n- Make camera stream release and replacement reliable, so an older session cannot close the new sensor.\n- Tundra sources: touch focus, digital zoom and sensor JPEG capture, separating preview from full-resolution photos. Fix vibration shutdown and add a service stop safeguard.\n- Publish desktop, APK and Tundra sources with setup/build scripts and updated English/French READMEs. Private profiles and internal working documents are excluded.\n\n**Validation:** 42 service tests, desktop startup/navigation on Gecko 156.0.1; Android 16 emulator Photo/Gallery capture, camera resume, ten background/resume cycles and recovery after renderer termination. APK built from `b38dea0`; the tag adds only a desktop test-script fix.\n\n**Versions:** Vulpes `2.7-preview.15` · Gaia `2.7.0` · desktop Gecko `156.0.1` · Android GeckoView `156.0`. Hardware capabilities differ by platform: Android calls and SMS hand off to Android apps, not to the Tundra modem.\n\n**Known limits:** signed development build, Gecko debugging through authorized ADB; not every Android version/device is qualified. On Sargo: approximately 16 fps camera preview, incomplete flash/video, automatic rotation and deep suspend, call audio awaiting qualification. A reported large dialog after SMS sending remains under investigation. This release does not claim those limits are fixed.\n" + }, + "v2.7-preview.17": { + "version": "2.7-preview.17", + "after": "2.7-preview.15", + "url": "https://nnsprod.com/git/oversu/VulpesOS/releases/tag/v2.7-preview.17", + "summary": "# Français\n\nAPK expérimental Android : Vulpes OS 2.7-preview.17, Gaia 2.7.0, GeckoView 156.0. Installation par-dessus une Preview précédente signée avec la même clé. Android 8.0/API26 minimum ; essais réalisés sur émulateur Android 16/API36.\n\n## 2.7-preview.17 — APK construit · 5 octobre 2026\n\n### Commun · Gaia / PC\n\n- Remettre Marketplace sur l’accueil avec son icône originale et le catalogue Vulpes. Ouvrir sa version française pour les langues fr, anglaise sinon.\n- Adapter les téléchargements du catalogue en installations confirmées : vérifier les archives ZIP, ajouter l’application à l’accueil et permettre son lancement et sa désinstallation.\n- Conserver les applications installées séparément des sources Gaia, sur des origines distinctes et sans privilèges système hérités des anciens manifestes.\n- Valider sur PC le parcours réel avec 2048 : catalogue, confirmation, installation, lancement, persistance et désinstallation. Contrôler les archives corrompues, chemins invalides, limites, annulation et confirmations à usage unique.\n\n### Android · APK\n\n- Construire et signer Preview17 avec le même Marketplace et le même service d’installation. Utiliser la vue GeckoView existante pour le catalogue et le stockage privé Android pour les paquets.\n- Vérifier sur émulateur Android 16/API36 le clic Installer, la confirmation, l’apparition sur l’accueil et le lancement de 2048 sans accès au pont système Vulpes. Vérifier aussi la conservation après arrêt forcé et relance, puis la désinstallation.\n\n## 2.7-preview.16 — APK construit · 5 octobre 2026\n\n### Commun · Gaia / PC\n\n- Rétablir les sélecteurs Gaia de fond d’écran et de sons, leur retour vers Paramètres et leur annulation par Accueil. Partager le transport des images et sons enregistrés entre PC et Android.\n- Propager les changements de langue à l’accueil, y compris sans permission de lecture générale des réglages. Vérifier les libellés FR/EN et la persistance.\n- Rétablir l’arrêt du balayage horizontal sur une page et masquer les applications de développement sur l’accueil, sans les supprimer des sources.\n- Utiliser le logo Vulpes fourni dans le splash et adapter les composants originaux de la liste des sons au moteur actuel.\n- Vérifier sur PC deux changements consécutifs de fond, le choix d’un son et les panneaux Gaia restaurés.\n\n### Android · APK\n\n- APK local Preview16 construit et signé ; contenu commun et version vérifiés. Aucune publication dans cette étape.\n- Valider Vulpes comme lanceur HOME, afficher le verrouillage Gaia après veille et rétablir le retour Android depuis la caméra ouverte au verrouillage.\n- Masquer les barres système Android en mode immersif, en conservant leur accès temporaire par balayage.\n- Tests sur émulateur Android 16/API36 : verrouillage, caméra/retour, FR/EN, accueil sans applications de test, fond d’écran et son. Fond conservé après arrêt forcé et relance, sans changement répété pendant 15 secondes. Autres appareils Android non qualifiés dans cette étape.\n\nLes correctifs caméra du 8 octobre ainsi que les derniers correctifs Wi-Fi, bannière et thème Marketplace du 6 octobre ne sont pas inclus dans cet APK. La validation de la caméra avant sur Sargo reste ouverte. Cette publication concerne uniquement Android.\n\n# English\n\nExperimental Android APK: Vulpes OS 2.7-preview.17, Gaia 2.7.0, GeckoView 156.0. Install over an earlier Preview signed with the same key. Android 8.0/API26 minimum; tested on an Android 16/API36 emulator.\n\n## 2.7-preview.17 — APK built · 5 October 2026\n\n### Shared · Gaia / Desktop\n\n- Restore Marketplace on Home with its original icon and the Vulpes catalogue. Select French for fr languages and English otherwise.\n- Turn catalogue downloads into confirmed installations: validate ZIP archives, add the application to Home and support launch and removal.\n- Store installed applications separately from Gaia sources, on distinct origins and without system privileges inherited from archived manifests.\n- Validate the real desktop workflow with 2048: catalogue, confirmation, installation, launch, persistence and removal. Check damaged archives, invalid paths, limits, cancellation and single-use confirmations.\n\n### Android · APK\n\n- Build and sign Preview17 with the same Marketplace and installation service. Use the existing GeckoView browser for the catalogue and private Android storage for packages.\n- Verify the Install click, confirmation, Home icon and 2048 launch without access to the Vulpes system bridge on an Android 16/API36 emulator. Also verify persistence after force-stop/relaunch and removal.\n\n## 2.7-preview.16 — APK built · 5 October 2026\n\n### Shared · Gaia / Desktop\n\n- Restore Gaia wallpaper and sound pickers, return navigation to Settings and cancellation through Home. Share persisted image and sound transport between desktop and Android.\n- Propagate language changes to Home without granting general settings read access. Check French/English labels and persistence.\n- Restore horizontal page snapping and hide development apps from Home without deleting their sources.\n- Use the supplied Vulpes logo in the splash and adapt the original sound-list components to the current engine.\n- Verify two consecutive wallpaper changes, sound selection and restored Gaia panels on desktop.\n\n### Android · APK\n\n- Build and sign local Preview16; verify shared payload and version. Nothing published in this step.\n- Validate Vulpes as the HOME launcher, restore Gaia locking after sleep and Android Back navigation from the lockscreen camera.\n- Hide Android system bars in immersive mode while retaining temporary swipe access.\n- Android 16/API36 emulator checks: locking, camera/Back, French/English, Home without test apps, wallpaper and sound. Wallpaper retained after force-stop/relaunch with no repeated changes over 15 seconds. Other Android devices not qualified in this step.\n\nThe October 8 camera changes and the later October 6 Wi-Fi, banner and Marketplace theme changes are not included in this APK. Front-camera validation on Sargo remains open. This release concerns Android only." } } } diff --git a/gaia/apps/communications/contacts/js/activities.js b/gaia/apps/communications/contacts/js/activities.js index 12cb2a1f..84e333b1 100755 --- a/gaia/apps/communications/contacts/js/activities.js +++ b/gaia/apps/communications/contacts/js/activities.js @@ -19,7 +19,7 @@ const VCARD_MIME_TYPES = [ var ActivityHandler = { _currentActivity: null, - _launchedAsInlineActivity: (window.location.search == '?pick'), + _launchedAsInlineActivity: new URLSearchParams(window.location.search).has('pick'), mozContactParam: null, @@ -124,6 +124,7 @@ var ActivityHandler = { this.launch_activity(activity, 'add-parameters'); break; case 'pick': + if (window.VulpesCompat) this._launchedAsInlineActivity = true; if (!this._launchedAsInlineActivity) { return; } @@ -356,15 +357,18 @@ var ActivityHandler = { postNewSuccess: function ah_postNewSuccess(contact) { this._currentActivity.postResult({ contact: contact }); this._currentActivity = null; + if (window.VulpesCompat) this._launchedAsInlineActivity = false; }, postPickSuccess: function ah_postPickSuccess(result) { this._currentActivity.postResult(result); this._currentActivity = null; + if (window.VulpesCompat) this._launchedAsInlineActivity = false; }, postCancel: function ah_postCancel() { this._currentActivity.postError('canceled'); this._currentActivity = null; + if (window.VulpesCompat) this._launchedAsInlineActivity = false; } }; diff --git a/gaia/apps/communications/contacts/js/contacts.js b/gaia/apps/communications/contacts/js/contacts.js index 64dc91a5..4ea36df1 100755 --- a/gaia/apps/communications/contacts/js/contacts.js +++ b/gaia/apps/communications/contacts/js/contacts.js @@ -655,7 +655,9 @@ var Contacts = (function() { utils.PerformanceHelper.contentInteractive(); utils.PerformanceHelper.chromeInteractive(); window.setTimeout(Contacts && Contacts.onLocalized); - if (window.navigator.mozSetMessageHandler && window.self == window.top) { + // Vulpes embeds each app in its own permission-checked frame. + if (window.navigator.mozSetMessageHandler && + (window.self == window.top || window.VulpesCompat)) { LazyLoader.load(['/shared/js/contacts/import/utilities/misc.js', '/shared/js/contacts/import/utilities/vcard_reader.js', '/shared/js/contacts/import/utilities/vcard_parser.js'], diff --git a/gaia/apps/communications/contacts/js/views/form.js b/gaia/apps/communications/contacts/js/views/form.js index 865eead5..ef5e805c 100755 --- a/gaia/apps/communications/contacts/js/views/form.js +++ b/gaia/apps/communications/contacts/js/views/form.js @@ -1038,6 +1038,8 @@ contacts.Form = (function() { // (Bug 1041455). if (editingContact) { Contacts.setCurrent(contact); + // The change event may arrive while the edit form is still visible. + Contacts.updateContactDetail(contact.id); } } ); diff --git a/gaia/apps/homescreen/js/apps.js b/gaia/apps/homescreen/js/apps.js index 9a982135..e7725e97 100755 --- a/gaia/apps/homescreen/js/apps.js +++ b/gaia/apps/homescreen/js/apps.js @@ -408,6 +408,10 @@ return; } + if (HIDDEN_ROLES.includes(manifest.role)) { + return; + } + // Do not add blacklisted apps if (BLACKLIST.includes(app.origin)) { return; diff --git a/gaia/apps/marketplace/icon.png b/gaia/apps/marketplace/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9880f58aec887a6796c53cc02872398d658c680e GIT binary patch literal 190651 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 literal 0 HcmV?d00001 diff --git a/gaia/apps/marketplace/index.html b/gaia/apps/marketplace/index.html new file mode 100644 index 00000000..bee23bd1 --- /dev/null +++ b/gaia/apps/marketplace/index.html @@ -0,0 +1,5 @@ +Marketplace + + + + diff --git a/gaia/apps/marketplace/manifest.webapp b/gaia/apps/marketplace/manifest.webapp new file mode 100644 index 00000000..8cded036 --- /dev/null +++ b/gaia/apps/marketplace/manifest.webapp @@ -0,0 +1,19 @@ +{ + "name": "Marketplace", + "description": "Vulpes OS application catalogue", + "launch_path": "/index.html", + "type": "certified", + "icons": { + "512": "/icon.png" + }, + "permissions": { + "browser": {}, + "webapps-manage": {} + }, + "locales": { + "fr": { + "name": "Marketplace", + "description": "Catalogue des applications Vulpes OS" + } + } +} diff --git a/gaia/apps/marketplace/marketplace.css b/gaia/apps/marketplace/marketplace.css new file mode 100644 index 00000000..0125ce10 --- /dev/null +++ b/gaia/apps/marketplace/marketplace.css @@ -0,0 +1 @@ +html,body{width:100%;height:100%;margin:0;background:#f4f4f4;font-family:Fira Sans,sans-serif}#catalogue{position:absolute;inset:0;width:100%;height:100%;border:0}#message{padding:3rem 2rem;text-align:center;font-size:1.8rem}#message button{display:block;width:100%;padding:1rem;margin:1rem 0;font:inherit}#open[hidden],[hidden]{display:none!important}#confirm{z-index:10}#confirm section{overflow:auto}#permissions{font-size:1.5rem} diff --git a/gaia/apps/marketplace/marketplace.js b/gaia/apps/marketplace/marketplace.js new file mode 100644 index 00000000..84dbc0c5 --- /dev/null +++ b/gaia/apps/marketplace/marketplace.js @@ -0,0 +1,32 @@ +(async()=>{ + const frame=document.getElementById('catalogue'),message=document.getElementById('message'),dialog=document.getElementById('confirm'); + let attempt=0,busy=false,prepared=null,installed=null,language=await VulpesCompat.call('locale.current'); + const fr=()=>/^fr(?:-|$)/i.test(language); + const text=(f,e)=>fr()?f:e; + function labels(){document.getElementById('browse').textContent=text('Ouvrir le catalogue','Open catalogue');document.getElementById('open').textContent=text('Ouvrir','Open');document.getElementById('install').textContent=text('Installer','Install');document.getElementById('cancel').textContent=text('Annuler','Cancel');} + function loadFailed(){status(text('Catalogue inaccessible. Vérifiez la connexion Internet, puis réessayez.','Catalogue unavailable. Check your Internet connection, then try again.'));document.getElementById('open').hidden=true;} + frame.addEventListener('mozbrowsererror',loadFailed); + function browse(){labels();message.hidden=true;dialog.hidden=true;frame.style.visibility='visible';frame.src='https://vulpes-os.org/marketplace/?mode=app&lang='+(fr()?'fr':'en');} + function status(value){frame.style.visibility='hidden';message.hidden=false;document.getElementById('status').textContent=value;} + async function prepare(url){ + if(busy)return;const current=++attempt;busy=true;prepared=null;installed=null;document.getElementById('open').hidden=true; + status(text('Vérification de l’application…','Checking application…')); + try {const value=await VulpesCompat.call('marketplace.prepare',{url});if(current!==attempt)return;prepared=value; + document.getElementById('title').textContent=prepared.name; + document.getElementById('question').textContent=text('Installer cette application archivée ?','Install this archived application?')+' ('+(prepared.bytes/1048576).toFixed(1)+' Mio)'; + document.getElementById('permissions').textContent=text('Elle sera exécutée comme une application web, sans accès aux fonctions système. Certains anciens services peuvent ne plus fonctionner.','It will run as a web application without system access. Some old services may no longer work.'); + message.hidden=true;dialog.hidden=false; + }catch(error){if(current!==attempt)return;status(text('Installation impossible : ','Cannot install: ')+error.message);busy=false;} + } + dialog.addEventListener('submit',async event=>{event.preventDefault();if(!prepared)return;const token=prepared.token;prepared=null;dialog.hidden=true;status(text('Installation…','Installing…')); + try {installed=await VulpesCompat.call('marketplace.install',{token});status(text('Application ajoutée à l’accueil.','Application added to Home.'));document.getElementById('open').hidden=false;} + catch(error){status(text('Installation impossible : ','Cannot install: ')+error.message);}finally{busy=false;} + }); + const cancel=()=>{attempt++;prepared=null;busy=false;VulpesCompat.call('marketplace.cancel').catch(console.error);browse();}; + document.getElementById('cancel').onclick=cancel; + document.getElementById('browse').onclick=cancel; + document.getElementById('open').onclick=()=>installed && VulpesCompat.call('apps.launch',{manifestURL:installed.manifestURL}); + addEventListener('languagechange',()=>{language=navigator.language;if(!busy)browse();}); + browse(); + setInterval(async()=>{if(busy)return;try{const url=await VulpesCompat.call('marketplace.poll');if(url)await prepare(url);}catch(error){console.error(error);}},750); +})(); diff --git a/gaia/apps/ringtones/js/tone_player.js b/gaia/apps/ringtones/js/tone_player.js index aa92cd42..97358a05 100755 --- a/gaia/apps/ringtones/js/tone_player.js +++ b/gaia/apps/ringtones/js/tone_player.js @@ -143,7 +143,7 @@ TonePlayer.prototype = { _setExclusiveMode: function(exclusive) { if (exclusive) { if (!this._source) { - this._context = new AudioContext('ringer'); + this._context = new AudioContext(); this._source = this._context.createMediaElementSource(this._player); this._source.connect(this._context.destination); } diff --git a/gaia/apps/settings/js/modules/page_transitions.js b/gaia/apps/settings/js/modules/page_transitions.js index 11951804..59f84c11 100755 --- a/gaia/apps/settings/js/modules/page_transitions.js +++ b/gaia/apps/settings/js/modules/page_transitions.js @@ -43,7 +43,39 @@ define(function() { return; } + // A hidden or newly inserted panel may not animate. Complete navigation + // in that case too, otherwise its onShow hook never runs. + var completed = false; + var fallback; + function paintWait(event) { + if (event && event.target !== newPanel) { + return; + } + if (completed) { + return; + } + completed = true; + clearTimeout(fallback); + newPanel.removeEventListener('transitionend', paintWait); + newPanel.removeEventListener('transitioncancel', paintWait); + _sendPanelReady(oldPanel && '#' + oldPanel.id, '#' + newPanel.id); + if (callback) { + callback(); + } + } + newPanel.addEventListener('transitionend', paintWait); + newPanel.addEventListener('transitioncancel', paintWait); newPanel.className = 'current'; + var style = window.getComputedStyle(newPanel); + var seconds = function(value) { + return parseFloat(value) * (value.trim().endsWith('ms') ? 1 : 1000) || 0; + }; + var durations = style.transitionDuration.split(',').map(seconds); + var delays = style.transitionDelay.split(',').map(seconds); + var duration = Math.max.apply(Math, durations.map(function(value, index) { + return value + delays[index % delays.length]; + })); + fallback = setTimeout(paintWait, Math.max(0, duration) + 100); /** * Most browsers now scroll content into view taking CSS transforms into @@ -57,22 +89,6 @@ define(function() { window.scrollTo(0, 0); } - newPanel.addEventListener('transitionend', function paintWait() { - newPanel.removeEventListener('transitionend', paintWait); - if (oldPanel) { - _sendPanelReady('#' + oldPanel.id, '#' + newPanel.id); - - if (oldPanel.className === 'current') { - return; - } - } else { - _sendPanelReady(null, '#' + newPanel.id); - } - - if (callback) { - callback(); - } - }); }, /** diff --git a/gaia/apps/system/js/system_banner.js b/gaia/apps/system/js/system_banner.js index 943eadaf..c88f6b55 100755 --- a/gaia/apps/system/js/system_banner.js +++ b/gaia/apps/system/js/system_banner.js @@ -10,7 +10,9 @@ * application installation, crash reporter, and low storage notices. * @class SystemBanner */ - function SystemBanner() {} + function SystemBanner() { + this._generation = 0; + } /** * Amount of time before banner is automatically dismissed. @@ -77,10 +79,18 @@ * { label: l10nAttrs, callback: ..., dismiss: ... } */ show: function(messages, buttonParams) { + var generation = ++this._generation; + clearTimeout(this._dismissTimer); + if (this._cancelRemoval) { + this._cancelRemoval(); + } this._clicked = false; this._showing = true; return this.getBanner().then(banner => { + if (generation !== this._generation || !this._showing) { + return; + } // Clear the button and message containers. var messageContainer = banner.querySelector('.messages'); var buttonContainer = banner.querySelector('.buttons'); @@ -110,13 +120,16 @@ // Hide banner and invoke button dismiss() on click or timeout. var hideBanner = () => { + if (generation !== this._generation || !this._showing) { + return; + } this.hide(); if (!this._clicked) { buttonParams && buttonParams.dismiss && buttonParams.dismiss(); } }; banner.onclick = hideBanner; - setTimeout(hideBanner, SystemBanner.TIMEOUT); + this._dismissTimer = setTimeout(hideBanner, SystemBanner.TIMEOUT); document.getElementById('screen').appendChild(banner); banner.show(); @@ -131,15 +144,37 @@ return; } this._showing = false; + clearTimeout(this._dismissTimer); + var generation = this._generation; return this.getBanner().then(banner => { - banner.addEventListener('animationend', function removeBanner() { - banner.removeEventListener('animationend', removeBanner); - // Only remove banner if we haven't called show() in the meantime. - if (!this._showing) { + if (generation !== this._generation || this._showing) { + return; + } + // Animation events inside a modern shadow root do not reach the host. + var animation = banner.shadowRoot && + banner.shadowRoot.querySelector('.bread') || banner; + var cleanup = () => { + clearTimeout(this._removeTimer); + animation.removeEventListener('animationend', removeBanner); + animation.removeEventListener('animationcancel', removeBanner); + this._cancelRemoval = null; + }; + var removeBanner = event => { + if (event && event.target !== animation) { + return; + } + cleanup(); + if (!this._showing && generation === this._generation) { banner.parentNode && banner.parentNode.removeChild(banner); } - }.bind(this)); + }; + this._cancelRemoval = cleanup; + animation.addEventListener('animationend', removeBanner); + animation.addEventListener('animationcancel', removeBanner); + // Gaia's exit animation lasts 600 ms. Also dismiss if it is disabled + // or no animation event is produced. + this._removeTimer = setTimeout(removeBanner, 700); banner.hide(); }); } diff --git a/host/Runtime.sys.mjs b/host/Runtime.sys.mjs index 0b11845d..e328a542 100644 --- a/host/Runtime.sys.mjs +++ b/host/Runtime.sys.mjs @@ -1,6 +1,8 @@ -import { setInterval } from 'resource://gre/modules/Timer.sys.mjs'; +import { setInterval, setTimeout, clearTimeout } from 'resource://gre/modules/Timer.sys.mjs'; import {Input} from 'resource://vulpes/host/Input.sys.mjs'; import { ScreenPower } from 'resource://vulpes/services/screen-power.mjs'; +import { Packages } from 'resource://vulpes/services/packages.mjs'; +import { Activities, isGaiaActivity } from 'resource://vulpes/services/activities.mjs'; import { SettingsService } from 'resource://vulpes/services/settings.mjs'; import { DataStoreService } from 'resource://vulpes/services/datastores.mjs'; import { DataStoresIndexedDB } from 'resource://vulpes/adapters/datastores-indexeddb.mjs'; @@ -29,6 +31,7 @@ export const Runtime = { wakeLocks: new Map(), idleListeners: new Map(), cleanup(actor) { + this.activities?.cleanup(actor); this.input?.cleanup(actor); this.platform?.nativeCamera.cleanup(actor); this.connections?.cleanup(actor); @@ -45,6 +48,22 @@ export const Runtime = { this.input = new Input(this); const root = Services.env.get('VULPES_WORKSPACE_ROOT'); this.apps = await IOUtils.readJSON(PathUtils.join(root, 'assets', 'registry.json')); + const storeURL = 'http://system.localhost:8765/_vulpes/packages/'; + const store = async (operation, item) => { + const token = await IOUtils.readUTF8(PathUtils.join(root,'profiles','installed-apps','.token')); + const response = await fetch(storeURL+operation,{method:'POST',headers:{'X-Vulpes-Install':token,'Content-Type':'application/json'},body:JSON.stringify(item)}); + if(!response.ok)throw Error('PACKAGE_STORAGE_FAILED'); + return response.json(); + }; + this.refreshInstalled = async () => { + const response=await fetch(storeURL+'list');if(!response.ok)throw Error('PACKAGE_STORAGE_FAILED'); + const installed=await response.json(); + this.apps.splice(0,this.apps.length,...this.apps.filter(a=>!a.installed),...installed); + return installed; + }; + this.packages = new Packages({schedule:setTimeout,unschedule:clearTimeout,save:item=>store('save',item),changed:()=>this.refreshInstalled(),uuid:()=>Services.uuid.generateUUID().toString()}); + this.removePackage = async id => {const app=this.apps.find(a=>a.id===id && a.installed);if(!app)throw Error('NOT_REMOVABLE'); + await store('remove',{id});await this.refreshInstalled();this.broadcast('apps-uninstalled',app);}; // Installed Gaia audio apps must be able to ring when an alarm fires. This // permission is scoped to their origins in this profile, never web pages. for (const app of this.apps) @@ -91,6 +110,11 @@ export const Runtime = { this.values['vulpes.gaia-restoration.v1'] = true; } Services.prefs.setStringPref('intl.accept_languages', this.values['language.current']); + this.activities = new Activities({identity:actor=>this.identity(actor),apps:()=>this.apps, + uuid:()=>Services.uuid.generateUUID().toString(), + notify:(actor,type,data)=>actor.sendAsyncMessage('Vulpes:Event',{type,data}), + launch:(target,path,{reload=false,entryPoint}={})=>this.broadcast(reload?'activity-launch':'launch',{manifestURL:target.manifestURL,origin:target.origin, + entryPoint,url:new URL(path || target.manifest.launch_path || '/index.html',target.origin).href,timestamp:Date.now()},'system')}); this.writeQueue = Promise.resolve(); this.settings = new SettingsService({ get: async (key) => this.values[key], @@ -115,7 +139,7 @@ export const Runtime = { this.writeQueue = write.catch(() => {}); return write; }, - }); + }, {maxBytes:32 * 1024 * 1024}); const storage = new DataStoresIndexedDB(indexedDB, IDBKeyRange, () => Services.uuid.generateUUID().toString(), ); @@ -202,6 +226,16 @@ export const Runtime = { this.actors.add(actor); const { method, params } = request; if (typeof method !== 'string') return { error: { code: 'INVALID_REQUEST' } }; + if(method.startsWith('marketplace.')) { + if(app.id!=='marketplace')return {error:{code:'PERMISSION_DENIED'}}; + try { + if(method==='marketplace.poll'){const url=this.marketplaceDownload;this.marketplaceDownload=null;return {result:url||null};} + if(method==='marketplace.cancel'){this.packages.cancel();return {result:true};} + if(method==='marketplace.prepare')return {result:await this.packages.prepare(params.url)}; + if(method==='marketplace.install') {const id=await this.packages.install(params.token);const installed=this.apps.find(a=>a.id===id);this.broadcast('apps-installed',installed);return {result:installed};} + } catch(error) {return {error:{code:error.message}};} + return {error:{code:'METHOD_NOT_SUPPORTED'}}; + } if(method==='hardware.vibrate') { if(app.id!=='system' || Services.env.get('VULPES_TUNDRA')!=='1') return {error:{code:'NOT_SUPPORTED'}}; const pattern=params?.pattern; @@ -267,10 +301,19 @@ export const Runtime = { } } if (typeof method !== 'string') return { error: { code: 'INVALID_REQUEST' } }; + if (['activities.subscribe','activities.finish','activities.cancel'].includes(method) || (method === 'activities.start' && isGaiaActivity(params))) { + try { + const result = method === 'activities.cancel' ? this.activities.cancel(actor) + : method === 'activities.subscribe' ? this.activities.subscribe(actor) + : method === 'activities.finish' ? this.activities.finish(actor,params) + : await this.activities.start(actor,params); + return {result:result ?? null}; + } catch(error) {return {error:{code:error.message}};} + } if (method === 'activities.start') { if (params?.name === 'record' && params.data?.type === 'photos') { - // Gallery's Photo button opens the shared Gaia UI; it expects no result file. - if (app.id === 'gallery') { + // Gallery and the lockscreen open Gaia Camera without expecting a file result. + if (['gallery', 'system'].includes(app.id)) { const camera = this.apps.find((a) => a.id === 'camera'); if (!camera) return { error: { code: 'ACTIVITY_NOT_SUPPORTED' } }; this.broadcast( @@ -316,6 +359,7 @@ export const Runtime = { return { error: { code: error.message || 'VIEW_ERROR' } }; } } + if (method === 'locale.current') return { result: this.values['language.current'] || 'en-US' }; if (method === 'settings.snapshot') return this.grants(app).includes('settings.read') ? { result: { ...this.values } } @@ -441,6 +485,10 @@ export const Runtime = { if (method === 'apps.self') return { result: app }; if (method === 'apps.list') return manage ? { result: this.apps } : { error: { code: 'PERMISSION_DENIED' } }; + if(method==='apps.uninstall') { + if(!manage)return {error:{code:'PERMISSION_DENIED'}}; + try {await this.removePackage(params.id);return {result:true};}catch(error){return {error:{code:error.message}};} + } if (method === 'apps.launch') { const target = this.apps.find((a) => a.manifestURL === params?.manifestURL); if (!target || (!manage && app.id !== target.id)) @@ -469,7 +517,7 @@ export const Runtime = { try { const app = this.identity(actor); if (!app || (target && app.id !== target)) continue; - if (type === 'settingchange' && !this.grants(app).includes('settings.read')) continue; + if (type === 'settingchange' && data.key !== 'language.current' && !this.grants(app).includes('settings.read')) continue; if ( type === 'mediachange' && !app.manifest.permissions?.['device-storage:' + data.type]?.access?.includes('read') diff --git a/host/Views.sys.mjs b/host/Views.sys.mjs index 20ebed76..3884c1cd 100644 --- a/host/Views.sys.mjs +++ b/host/Views.sys.mjs @@ -15,12 +15,52 @@ export const Views = { ); Services.ppmm.sharedData.flush(); }, + hideAll() { + for (const entry of this.entries.values()) entry.browser.style.visibility='hidden'; + }, + async layout(entry) { + const geometry=entry.geometry; + if (!geometry) return; + let {left,top,width,height,visible}=geometry; + let right=left+width,bottom=top+height; + try { + // A child document can remain visible while its owning Gaia app is hidden. + // Check every embedding frame in its own process, up to the system app. + for (let child=entry.actor.browsingContext;child.parent;child=child.parent) { + const state=await child.parent.currentWindowGlobal.getActor('Vulpes').sendQuery( + 'Vulpes:ViewState',{contextId:child.id}); + visible=visible && state.visible; + if (!visible) break; + left=Math.max(left,state.left);top=Math.max(top,state.top); + right=Math.min(right,state.right);bottom=Math.min(bottom,state.bottom); + } + } catch (_) {visible=false;} + if (entry.geometry!==geometry || !entry.browser.isConnected) return; + const shell=entry.browser.ownerDocument.defaultView; + const bounds=shell.document.getElementById('screen').getBoundingClientRect(); + const x=shell.mozInnerScreenX+bounds.left,y=shell.mozInnerScreenY+bounds.top; + left=Math.max(x,left);top=Math.max(y,top); + right=Math.min(x+bounds.width,right);bottom=Math.min(y+bounds.height,bottom); + Object.assign(entry.browser.style,{left:(left-x)+'px',top:(top-y)+'px', + width:Math.max(0,right-left)+'px',height:Math.max(0,bottom-top)+'px', + visibility:visible && right>left && bottom>top?'visible':'hidden'}); + }, prune() { for (const [id, entry] of this.entries) { if (!BrowsingContext.get(id)?.parent) { this.remove(id, entry); continue; } + this.layout(entry); + const document=entry.browser.browsingContext?.currentWindowGlobal; + const page=document?.documentURI.spec || ''; + // A retry keeps the previous error document until the next navigation commits. + if (document?.innerWindowId!==entry.previousDocumentId && + /^about:(neterror|certerror|tabcrashed)/.test(page) && entry.errorPage!==page) { + entry.errorPage=page; + try {entry.actor.sendAsyncMessage('Vulpes:Event',{type:'view', + data:{contextId:id,type:'error',detail:{type:'other'}}});} catch (_) {} + } // A detached iframe's BrowsingContext can outlive its DOM element. // Ask the trusted child actor about actual ownership, not just the BC tree. if (entry.checking) continue; @@ -123,7 +163,9 @@ export const Views = { if (flags & Ci.nsIWebProgressListener.STATE_STOP) { emit('loadend', { backgroundColor: 'rgb(255, 255, 255)' }); emit('titlechange', browser.contentTitle || browser.currentURI.spec); - if (!Components.isSuccessCode(status)) emit('error', { type: 'other', status }); + // Replacing a navigation cancels the previous request normally. + if (!Components.isSuccessCode(status) && status !== Cr.NS_BINDING_ABORTED) + emit('error', { type: 'other', status }); } }, onProgressChange() {}, @@ -143,6 +185,8 @@ export const Views = { this.entries.set(contextId, entry); } entry.url = url; + entry.errorPage=null; + entry.previousDocumentId=entry.browser.browsingContext?.currentWindowGlobal?.innerWindowId; entry.browser.loadURI(uri, { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }); @@ -153,22 +197,8 @@ export const Views = { if (operation === 'geometry') { const { left, top, width, height, visible } = geometry || {}; if (![left, top, width, height].every(Number.isFinite)) throw new Error('INVALID_GEOMETRY'); - const shell = browser.ownerDocument.defaultView, - screen = shell.document.getElementById('screen'); - const bounds = screen.getBoundingClientRect(); - const x = left - shell.mozInnerScreenX - bounds.left; - const y = top - shell.mozInnerScreenY - bounds.top; - const right = Math.min(480, x + width), - bottom = Math.min(800, y + height); - const clippedX = Math.max(0, x), - clippedY = Math.max(0, y); - Object.assign(browser.style, { - left: clippedX + 'px', - top: clippedY + 'px', - width: Math.max(0, right - clippedX) + 'px', - height: Math.max(0, bottom - clippedY) + 'px', - visibility: visible && right > clippedX && bottom > clippedY ? 'visible' : 'hidden', - }); + entry.geometry={left,top,width,height,visible}; + await this.layout(entry); return null; } if (operation === 'back') { diff --git a/host/actors/MarketplaceChild.sys.mjs b/host/actors/MarketplaceChild.sys.mjs new file mode 100644 index 00000000..7181ffd4 --- /dev/null +++ b/host/actors/MarketplaceChild.sys.mjs @@ -0,0 +1,7 @@ +export class VulpesMarketplaceChild extends JSWindowActorChild { + handleEvent() { + const scope={}; + Services.scriptloader.loadSubScript('resource://vulpes/host/marketplace-page.js',scope); + scope.installMarketplacePage(this.contentWindow,url=>this.sendAsyncMessage('Marketplace:Download',{url})); + } +} diff --git a/host/actors/MarketplaceParent.sys.mjs b/host/actors/MarketplaceParent.sys.mjs new file mode 100644 index 00000000..f59695ca --- /dev/null +++ b/host/actors/MarketplaceParent.sys.mjs @@ -0,0 +1,13 @@ +import { Runtime } from 'resource://vulpes/host/Runtime.sys.mjs'; +import { Views } from 'resource://vulpes/host/Views.sys.mjs'; +import { packageURL } from 'resource://vulpes/services/packages.mjs'; +export class VulpesMarketplaceParent extends JSWindowActorParent { + receiveMessage(message) { + if(message.name!=='Marketplace:Download' || this.manager.documentPrincipal.originNoSuffix!=='https://vulpes-os.org')return; + const view=[...Views.entries.values()].find(v=>v.browser.browsingContext.top.id===this.browsingContext.top.id); + if(!view || !Runtime.identity(view.actor))return; + Runtime.marketplaceDownload=packageURL(message.data.url); + const app=Runtime.apps.find(a=>a.id==='marketplace'); + Runtime.broadcast('launch',{manifestURL:app.manifestURL,origin:app.origin,url:app.origin+'/index.html',timestamp:Date.now()},'system'); + } +} diff --git a/host/actors/VulpesChild.sys.mjs b/host/actors/VulpesChild.sys.mjs index ed38d710..c69ed27f 100644 --- a/host/actors/VulpesChild.sys.mjs +++ b/host/actors/VulpesChild.sys.mjs @@ -141,6 +141,27 @@ export class VulpesChild extends JSWindowActorChild { } receiveMessage(message) { if(message.name==='Vulpes:Edit') return this.edit(message.data); + if (message.name === 'Vulpes:ViewState') { + const frame = Array.from(this.document.querySelectorAll('iframe')).find( + f => f.browsingContext?.id === message.data.contextId); + if (!frame?.isConnected) return {visible:false}; + const win = this.contentWindow, rect = frame.getBoundingClientRect(); + const visible = !this.document.hidden && frame.checkVisibility({checkOpacity:true,checkVisibilityCSS:true}) && + [[.5,.5],[.05,.05],[.95,.05],[.05,.95],[.95,.95]].every(([x,y]) => + this.document.elementFromPoint(rect.left+rect.width*x,rect.top+rect.height*y)===frame); + let top = Math.max(0,rect.top); + // Gaia's status bar belongs above all app content, including native web views. + if (this.document.location.hostname === 'system.localhost') { + const bar=this.document.getElementById('statusbar'); + if (bar?.checkVisibility({checkOpacity:true,checkVisibilityCSS:true})) { + const r=bar.getBoundingClientRect(); + if (r.width>0 && r.bottom>top && r.top<=top) top=r.bottom; + } + } + return {visible,left:Math.max(0,rect.left)+win.mozInnerScreenX, + top:top+win.mozInnerScreenY,right:Math.min(win.innerWidth,rect.right)+win.mozInnerScreenX, + bottom:Math.min(win.innerHeight,rect.bottom)+win.mozInnerScreenY}; + } if (message.name === 'Vulpes:ViewAlive') { return Array.from(this.document.querySelectorAll('iframe')).some( (frame) => frame.isConnected && frame.browsingContext?.id === message.data.contextId, diff --git a/host/desktop.css b/host/desktop.css index d7e4cb4b..40a36351 100644 --- a/host/desktop.css +++ b/host/desktop.css @@ -196,3 +196,7 @@ html[data-vulpes-app='communications'] body { /* Camera gestures must not magnify the application chrome. */ html[data-vulpes-app='camera'], html[data-vulpes-app='camera'] body { touch-action:none; } + +/* Homescreen pages must settle at their boundary after a drag (Forgejo #3). */ +html[data-vulpes-app="homescreen"] #panels { scroll-snap-type:x mandatory; } +html[data-vulpes-app="homescreen"] #panels > * { scroll-snap-align:start; } diff --git a/host/gaia-camera.js b/host/gaia-camera.js index 304c704a..b056ff2d 100644 --- a/host/gaia-camera.js +++ b/host/gaia-camera.js @@ -6,6 +6,26 @@ current = null, generation = 0; let cameraError = null; + let opening = Promise.resolve(), closing = Promise.resolve(); + const releases = new WeakMap(); + function releaseStream(stream, preview) { + if (releases.has(stream)) return releases.get(stream); + if (current === stream) current = null; + const release = Promise.resolve().then(async () => { + for (const video of document.querySelectorAll('video')) { + if (video.srcObject === stream) { + video.pause(); video.srcObject = null; + if ('vulpesCapture' in video.dataset) video.remove(); + } + } + preview?.remove(); + try { await stream.vulpesCameraClose?.(); } + finally { stream.getTracks().forEach(track => track.stop()); } + }); + releases.set(stream, release); + closing = release.catch(recordError); + return release; + } function recordError(error) { cameraError = { name: error.name || 'Error', message: error.message || '' }; console.warn('Vulpes Camera:', cameraError.name, cameraError.message); @@ -87,7 +107,7 @@ Object.assign(event, detail); target.dispatchEvent(event); } - async function discover(stream) { + async function discover(stream, name) { if (stream.vulpesNative) { cameras = ['back', 'front']; return; @@ -104,12 +124,15 @@ const active = list.find((d) => d.deviceId === settings.deviceId) || list[0]; const back = list.find((d) => /back|rear|environment/i.test(d.label)); const front = list.find((d) => /front|user|face/i.test(d.label)); - const first = - back || - (settings.facingMode === 'user' && list.length > 1 ? list.find((d) => d !== active) : active); + // Unlabelled webcams must not exchange identities every time we switch. + const previousBack = list.find(d => d.deviceId === devices.get('back')); + const previousFront = list.find(d => d.deviceId === devices.get('front')); + const first = back || previousBack || + ((settings.facingMode === 'user' || name === 'front') && list.length > 1 + ? list.find(d => d !== active) : active); devices = new Map(); if (first) devices.set('back', first.deviceId); - const second = front && front !== first ? front : list.find((d) => d !== first); + const second = [front, previousFront].find(d => d && d !== first) || list.find(d => d !== first); if (second) devices.set('front', second.deviceId); cameras = devices.size ? [...devices.keys()] : ['back']; } @@ -129,75 +152,79 @@ await call({action:'stop'}); throw new DOMException('Camera preview requires WebGL', 'NotSupportedError'); } - function shader(type, source) { - const value = gl.createShader(type); - gl.shaderSource(value, source); gl.compileShader(value); - if (!gl.getShaderParameter(value, gl.COMPILE_STATUS)) throw Error('Camera shader compilation failed'); - return value; - } - const program = gl.createProgram(); - gl.attachShader(program, shader(gl.VERTEX_SHADER, ` - attribute vec2 position; varying vec2 coord; - void main() { gl_Position=vec4(position,0.,1.); coord=vec2(position.x*.5+.5,.5-position.y*.5); } - `)); - gl.attachShader(program, shader(gl.FRAGMENT_SHADER, ` - precision mediump float; varying vec2 coord; - uniform sampler2D luma; uniform sampler2D chroma; uniform float rotation; - void main() { - vec2 p=coord; - if(rotation==90.) p=vec2(coord.y,1.-coord.x); - else if(rotation==270.) p=vec2(1.-coord.y,coord.x); - else if(rotation==180.) p=1.-coord; - float y=1.16438356*(texture2D(luma,p).r-16./255.); - vec4 vu=texture2D(chroma,p); - float v=vu.r-128./255.; float u=vu.a-128./255.; - gl_FragColor=vec4(y+1.59602678*v,y-.39176229*u-.81296764*v,y+2.01723214*u,1.); - } - `)); - gl.linkProgram(program); - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw Error('Camera shader link failed'); - gl.useProgram(program); - const buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,buffer); - gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),gl.STATIC_DRAW); - const position=gl.getAttribLocation(program,'position'); - gl.enableVertexAttribArray(position);gl.vertexAttribPointer(position,2,gl.FLOAT,false,0,0); - gl.uniform1f(gl.getUniformLocation(program,'rotation'),meta.orientation); - const textures = ['luma','chroma'].map((name,index) => { - const texture=gl.createTexture();gl.activeTexture(gl.TEXTURE0+index);gl.bindTexture(gl.TEXTURE_2D,texture); - gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE); - gl.uniform1i(gl.getUniformLocation(program,name),index);return texture; - }); const timing = {frames:0, startedAt:performance.now(), conversionMs:0}; - let stopped = false, timer, stream, sequence = -1, closing; + let stopped = false, timer, stream, sequence = -1, closing, program, buffer; + const textures = [], shaders = []; const stop = () => { if (closing) return closing; stopped = true; clearTimeout(timer); closing = call({action:'stop'}).finally(() => { textures.forEach(texture => gl.deleteTexture(texture)); - gl.deleteBuffer(buffer); gl.deleteProgram(program); + shaders.forEach(value => gl.deleteShader(value)); + if (buffer) gl.deleteBuffer(buffer); + if (program) gl.deleteProgram(program); gl.getExtension('WEBGL_lose_context')?.loseContext(); }); return closing; }; - const draw = async () => { - const frame = await call({action:'frame'}); - if (stopped || !frame.data || frame.sequence === sequence) return false; - const data = new Uint8Array(frame.data), w = meta.width, h = meta.height; - if (data.length !== w * h * 3 / 2) throw Error('Invalid native camera frame'); - sequence = frame.sequence; - const start=performance.now(); - gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,textures[0]); - gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE,w,h,0,gl.LUMINANCE,gl.UNSIGNED_BYTE,data.subarray(0,w*h)); - gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D,textures[1]); - gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE_ALPHA,w/2,h/2,0,gl.LUMINANCE_ALPHA,gl.UNSIGNED_BYTE,data.subarray(w*h)); - gl.drawArrays(gl.TRIANGLE_STRIP,0,4); - timing.frames++;timing.conversionMs+=performance.now()-start; - return true; - }; try { + function shader(type, source) { + const value = gl.createShader(type); + shaders.push(value); + gl.shaderSource(value, source); gl.compileShader(value); + if (!gl.getShaderParameter(value, gl.COMPILE_STATUS)) throw Error('Camera shader compilation failed'); + return value; + } + program = gl.createProgram(); + gl.attachShader(program, shader(gl.VERTEX_SHADER, ` + attribute vec2 position; varying vec2 coord; + void main() { gl_Position=vec4(position,0.,1.); coord=vec2(position.x*.5+.5,.5-position.y*.5); } + `)); + gl.attachShader(program, shader(gl.FRAGMENT_SHADER, ` + precision mediump float; varying vec2 coord; + uniform sampler2D luma; uniform sampler2D chroma; uniform float rotation; + void main() { + vec2 p=coord; + if(rotation==90.) p=vec2(coord.y,1.-coord.x); + else if(rotation==270.) p=vec2(1.-coord.y,coord.x); + else if(rotation==180.) p=1.-coord; + float y=1.16438356*(texture2D(luma,p).r-16./255.); + vec4 vu=texture2D(chroma,p); + float v=vu.r-128./255.; float u=vu.a-128./255.; + gl_FragColor=vec4(y+1.59602678*v,y-.39176229*u-.81296764*v,y+2.01723214*u,1.); + } + `)); + gl.linkProgram(program); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw Error('Camera shader link failed'); + gl.useProgram(program); + buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,buffer); + gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),gl.STATIC_DRAW); + const position=gl.getAttribLocation(program,'position'); + gl.enableVertexAttribArray(position);gl.vertexAttribPointer(position,2,gl.FLOAT,false,0,0); + gl.uniform1f(gl.getUniformLocation(program,'rotation'),meta.orientation); + ['luma','chroma'].forEach((name,index) => { + const texture=gl.createTexture();textures.push(texture);gl.activeTexture(gl.TEXTURE0+index);gl.bindTexture(gl.TEXTURE_2D,texture); + gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE); + gl.uniform1i(gl.getUniformLocation(program,name),index); + }); + const draw = async () => { + const frame = await call({action:'frame'}); + if (stopped || !frame.data || frame.sequence === sequence) return false; + const data = new Uint8Array(frame.data), w = meta.width, h = meta.height; + if (data.length !== w * h * 3 / 2) throw Error('Invalid native camera frame'); + sequence = frame.sequence; + const start=performance.now(); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,textures[0]); + gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE,w,h,0,gl.LUMINANCE,gl.UNSIGNED_BYTE,data.subarray(0,w*h)); + gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D,textures[1]); + gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE_ALPHA,w/2,h/2,0,gl.LUMINANCE_ALPHA,gl.UNSIGNED_BYTE,data.subarray(w*h)); + gl.drawArrays(gl.TRIANGLE_STRIP,0,4); + timing.frames++;timing.conversionMs+=performance.now()-start; + return true; + }; const deadline = Date.now() + 6000; while (!(await draw())) { if (Date.now() > deadline) throw new DOMException('No camera frames', 'NotReadableError'); @@ -227,11 +254,19 @@ return stream; } catch (error) { await stop().catch(() => {}); throw error; } } - async function getCamera(name, config = {}) { + function getCamera(name, config = {}) { + const ticket = ++generation; + const request = opening.then(() => openCamera(name, config, ticket)); + opening = request.catch(() => {}); + return request; + } + async function openCamera(name, config, ticket) { if (config.mode && config.mode !== 'picture') throw new DOMException('Video capture is not ported yet', 'NotSupportedError'); - const ticket = ++generation; - await current?.release?.(); + if (current) await releaseStream(current); + await closing; + if (document.hidden || ticket !== generation) + throw new DOMException('Camera request superseded or hidden', 'AbortError'); const selected = devices.get(name); cameraError = null; @@ -245,7 +280,7 @@ video: { ...(selected ? { deviceId: { exact: selected } } - : { facingMode: { ideal: 'environment' } }), + : { facingMode: { ideal: name === 'front' ? 'user' : 'environment' } }), width: { ideal: 1920 }, height: { ideal: 1080 }, }, @@ -255,7 +290,7 @@ throw error; } if (document.hidden || ticket !== generation) { - stream.getTracks().forEach((t) => t.stop()); + await releaseStream(stream); const error = new DOMException('Camera hidden', 'AbortError'); recordError(error); throw error; @@ -264,7 +299,7 @@ current = stream; let preview; try { - await discover(stream); + await discover(stream, name); if (document.hidden || ticket !== generation) throw new DOMException('Camera hidden', 'AbortError'); @@ -294,7 +329,7 @@ const native = stream.vulpesCameraMetadata; const pictureSizes = native?.pictureSizes || [size]; let pictureSize = pictureSizes.reduce((a,b)=>a.width*a.height>b.width*b.height?a:b); - let focusArea = null, zoom = 1, releasing; + let focusArea = null, zoom = 1; const configuration = () => ({ mode: 'picture', previewSize: size, @@ -378,19 +413,7 @@ emit(stream, 'previewstatechange', { newState: 'started' }); }, release() { - if (releasing) return releasing; - // Detach first: visibility changes and Gaia may release the same stream - // again while its hardware worker is still shutting down. - if (current === stream) current = null; - releasing = Promise.resolve().then(async () => { - for (const video of document.querySelectorAll('video')) { - if (video.srcObject === stream) { video.pause(); video.srcObject = null; } - } - preview.remove(); - await stream.vulpesCameraClose?.(); - stream.getTracks().forEach(t => t.stop()); - }); - return releasing; + return releaseStream(stream, preview); }, async startRecording() { throw new DOMException('Video unavailable', 'NotSupportedError'); @@ -416,12 +439,7 @@ return { camera: stream, configuration: configuration() }; } catch (error) { recordError(error); - stream.getTracks().forEach((t) => t.stop()); - if (preview) { - preview.srcObject = null; - preview.remove(); - } - if (current === stream) current = null; + await releaseStream(stream, preview).catch(recordError); throw error; } } @@ -433,8 +451,7 @@ // Keep that request valid; its completion still checks visibility. if (!current) return; ++generation; - if (current?.release) current.release().catch(recordError); - else current?.getTracks().forEach((t) => t.stop()); + releaseStream(current).catch(recordError); }; addEventListener('pagehide', stop); addEventListener('visibilitychange', () => { diff --git a/host/gaia-compat.js b/host/gaia-compat.js index 5631b14a..b0c4627b 100644 --- a/host/gaia-compat.js +++ b/host/gaia-compat.js @@ -21,7 +21,7 @@ addEventListener('error', (event) => record('error', [event.message, event.filename, event.lineno]), ); - // Desktop transports Blobs directly; Android installs a JSON-compatible codec. + // Binary settings use the same persistence format on every host. const battery = Object.assign(new EventTarget(), {level:NaN, charging:false, chargingTime:Infinity, dischargingTime:Infinity}); Object.defineProperty(navigator, 'battery', {value:battery}); async function refreshBattery() { @@ -128,15 +128,16 @@ Object.defineProperty(navigator, 'mozPhoneNumberService', {value:{ normalize: number => String(number || '').normalize('NFKC').replace(/[^0-9+*#]/g, '') }}); - const settingsCodec = window.VulpesAndroidSettingsCodec; + const settingsCodec = window.VulpesSettingsCodec; async function call(method, params) { if (!navigator.vulpesRequest) return Promise.reject(new Error('VULPES_HOST_UNAVAILABLE')); - if (settingsCodec && ['settings.set', 'media.request'].includes(method)) + if (settingsCodec && (method === 'settings.set' || + (window.VulpesPlatform === 'android' && ['media.request', 'activities.finish', 'contacts.request'].includes(method)))) params = await settingsCodec.encode(params); return navigator.vulpesRequest({ version: 1, id: ++sequence, method, params }).then((reply) => { if (reply.error) throw new DOMException(reply.error.code, reply.error.code); return settingsCodec && - ['settings.get', 'settings.snapshot', 'media.request'].includes(method) + ['settings.get', 'settings.snapshot', 'media.request', 'activities.start', 'contacts.request'].includes(method) ? settingsCodec.decode(reply.result) : reply.result; }); @@ -165,6 +166,16 @@ } return r; } + let language = navigator.language; + function setLanguage(value) { + if (typeof value !== 'string' || !/^[a-z]{2,3}(?:-[a-zA-Z0-9]{2,8})*$/.test(value)) return; + const changed = language !== value; + language = value; + if (changed) dispatchEvent(new Event('languagechange')); + } + Object.defineProperty(navigator, 'language', {get:() => language}); + Object.defineProperty(navigator, 'languages', {get:() => Object.freeze([language])}); + call('locale.current').then(setLanguage).catch(() => {}); const observers = new Map(); const settings = new EventTarget(); settings.createLock = () => ({ @@ -196,6 +207,7 @@ addEventListener('vulpes-service-event', (event) => { const { type, data } = event.detail; if (type === 'settingchange') { + if (data.key === 'language.current') setLanguage(data.value); const change = { settingName: data.key, settingValue: settingsCodec ? settingsCodec.decode(data.value) : data.value, @@ -205,8 +217,17 @@ } if (type === 'callscreen-closed') document.querySelector('iframe[name="call_screen"]')?.dispatchEvent(new CustomEvent('mozbrowserclose',{bubbles:true})); if (type === 'hardware-key') dispatchEvent(new CustomEvent('softwareButtonEvent', {detail:data})); + if (type === 'activity-launch') dispatchEvent(new CustomEvent('open-app', {detail:{...data,showApp:true,onlyShowApp:false}})); if (type === 'launch') dispatchEvent(new CustomEvent('webapps-launch', { detail: data })); - if (type === 'home' || type === 'holdhome') dispatchEvent(new CustomEvent(type)); + if (type === 'screen-off') { + dispatchEvent(new CustomEvent('secure-killapps')); + window.Service?.request('lock').catch(console.error); + } + if (type === 'screen-on') window.ScreenManager?.turnScreenOn(true); + if (type === 'home' || type === 'holdhome') { + call('activities.cancel', {}).catch(console.error); + dispatchEvent(new CustomEvent(type)); + } if (type === 'activity-view') dispatchEvent(new CustomEvent('activity-view', { detail: data })); }); function application(record) { @@ -215,7 +236,7 @@ const { id, ...publicRecord } = record; const app = Object.assign(new EventTarget(), publicRecord, { installState: 'installed', - removable: false, + removable: record.removable === true, installTime: 0, updateTime: 0, downloadAvailable: false, @@ -238,6 +259,14 @@ } const mgmt = new EventTarget(); mgmt.getAll = () => request(call('apps.list').then((apps) => apps.map(application))); + mgmt.uninstall = app => request(call('apps.uninstall',{id:new URL(app.origin).hostname.split('.')[0]})); + addEventListener('vulpes-service-event',event=>{ + const {type,data}=event.detail; + if(!['apps-installed','apps-uninstalled'].includes(type))return; + const name=type==='apps-installed'?'install':'uninstall'; + const change=new Event(name);Object.defineProperty(change,'application',{value:application(data)}); + mgmt.dispatchEvent(change);if(typeof mgmt['on'+name]==='function')mgmt['on'+name](change); + }); mgmt.getNotInstalled = () => request(Promise.resolve([])); mgmt.getIcon = async (app, size, entry) => { const manifest = app.manifest.entry_points?.[entry] || app.manifest; @@ -319,10 +348,19 @@ const handlers = new Map(); navigator.mozSetMessageHandler = (name, fn) => { handlers.set(name, fn); + if (name === 'activity') call('activities.subscribe', {}).catch(console.error); if (name === 'connection') call('iac.subscribe', {}).catch(console.error); if (name === 'alarm') call('alarms.request', { operation: 'subscribe' }).catch(console.error); }; - navigator.mozHasPendingMessage = () => false; + addEventListener('vulpes-service-event', ({detail}) => { + if (detail.type !== 'activity') return; + const {id,source} = detail.data; + setTimeout(() => handlers.get('activity')?.({source, + postResult: result => call('activities.finish',{id,result}).catch(console.error), + postError: error => call('activities.finish',{id,error:String(error)}).catch(console.error) + }),0); + }); + navigator.mozHasPendingMessage = name => name === 'activity' && (new URLSearchParams(location.search).has('activity') || /\/(pick|share)\.html$/.test(location.pathname)); navigator.mozSetMessageHandlerPromise = (promise) => promise; window.VulpesCompat = { call, request, handlers }; window.MozActivity = function (source) { @@ -657,13 +695,29 @@ Object.setPrototypeOf(GaiaElement.prototype, prototype); customElements.define(name, GaiaElement); registered.add(name); - return GaiaElement; + function LegacyGaiaElement() { + return initialize(nativeCreate(name)); + } + LegacyGaiaElement.prototype = GaiaElement.prototype; + return LegacyGaiaElement; }; document.createElement = function (name, options) { const element = nativeCreate(name, options); if (name.toLowerCase() === 'iframe') wire(element); return registered.has(name) ? initialize(element) : element; }; + // v0 created callbacks ran for detached fragments too. Gaia reads component + // state immediately after parsing its templates, before attaching them. + const innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML'); + Object.defineProperty(Element.prototype, 'innerHTML', { + ...innerHTML, + set(value) { + innerHTML.set.call(this, value); + for (const element of this.querySelectorAll('*')) { + if (registered.has(element.localName)) initialize(element); + } + }, + }); HTMLElement.prototype.createShadowRoot = function () { const host = this, root = this.attachShadow({ mode: 'open' }); diff --git a/host/gaia-restoration.js b/host/gaia-restoration.js index f4e974b6..d5d72a6f 100644 --- a/host/gaia-restoration.js +++ b/host/gaia-restoration.js @@ -84,9 +84,15 @@ if (!event.target.closest('#messages-send-button')) return; event.preventDefault(); event.stopImmediatePropagation(); // Android owns final confirmation and delivery. Do not fabricate a sent SMS. + const view = window.ConversationView; + view?.assimilateRecipients(); + const numbers = window.Navigation?.isCurrentPanel('composer') ? + view?.recipients?.numbers : view?.activeThread?.participants; + const body = window.Compose?.getText?.() || ''; + if (!numbers?.length || !body) return; + if (window.Compose.type !== 'sms') { notice(unavailable()); return; } VulpesCompat.call('platform.sms', { - number:window.ThreadUI?.recipients?.numbers?.join(';') || '', - body:window.Compose?.getText?.() || '' + number:numbers.join(';'), body }).catch(() => notice(unavailable())); }, true); } diff --git a/host/gaia-wifi.js b/host/gaia-wifi.js index a632cd95..e2d81f9d 100644 --- a/host/gaia-wifi.js +++ b/host/gaia-wifi.js @@ -23,7 +23,9 @@ manager.connection = {status, network}; manager.connectionInformation = network ? {relSignalStrength:network.relSignalStrength} : null; if (changed) emit('statuschange', manager.connection); - emit('connectioninfoupdate', manager.connectionInformation || {}); + // Gaia's signal listeners require the associated network. A scan while + // disconnected must not announce connection information for a missing AP. + if (network) emit('connectioninfoupdate', {network, ...manager.connectionInformation}); } let scanPending; function scan() { diff --git a/host/marketplace-page.js b/host/marketplace-page.js new file mode 100644 index 00000000..e2cf40e9 --- /dev/null +++ b/host/marketplace-page.js @@ -0,0 +1,14 @@ +// Runs only on our remote catalogue. It exposes no privileged API to the page. +function installMarketplacePage(win, send) { + if(win.location.origin!=='https://vulpes-os.org' || !win.location.pathname.startsWith('/marketplace/'))return; + const doc=win.document; + for(const link of doc.querySelectorAll('a[href]')) { + const url=new URL(link.href); + if(url.origin!=='https://vulpes-os.org' || url.pathname!=='/marketplace/index.php' || !/^\d{1,10}$/.test(url.searchParams.get('download')||''))continue; + link.textContent=doc.documentElement.lang==='fr'?'Installer dans Vulpes':'Install in Vulpes'; + link.addEventListener('click',event=>{ + if(!event.isTrusted || event.button!==0 || event.ctrlKey || event.metaKey || event.shiftKey)return; + event.preventDefault();send(url.href); + }); + } +} diff --git a/host/settings-codec.js b/host/settings-codec.js new file mode 100644 index 00000000..bb361377 --- /dev/null +++ b/host/settings-codec.js @@ -0,0 +1,41 @@ +// Settings persistence and Android RPC use JSON. Preserve binary Gaia values across +// both boundaries and reconstruct Blobs in the application's own JS realm. +(() => { + const marker = '__vulpesBlobV1'; + async function encode(value) { + if (value instanceof Date) return value.toJSON(); + if (value instanceof Blob) { + if (value.size > 16 * 1024 * 1024) throw new Error('SETTING_BLOB_TOO_LARGE'); + const bytes = new Uint8Array(await value.arrayBuffer()); + const chunks = []; + for (let i = 0; i < bytes.length; i += 16384) { + chunks.push(String.fromCharCode(...bytes.subarray(i, i + 16384))); + } + return { [marker]: true, type: value.type, base64: btoa(chunks.join('')) }; + } + if (Array.isArray(value)) return Promise.all(value.map(encode)); + if (value && typeof value === 'object') { + return Object.fromEntries( + await Promise.all( + Object.entries(value).map(async ([key, item]) => [key, await encode(item)]), + ), + ); + } + return value; + } + function decode(value) { + if (!value || typeof value !== 'object' || value instanceof Blob || value instanceof Date) return value; + if ( + value[marker] === true && + typeof value.type === 'string' && + typeof value.base64 === 'string' && + Object.keys(value).length === 3 + ) { + const bytes = Uint8Array.from(atob(value.base64), (c) => c.charCodeAt(0)); + return new Blob([bytes], { type: value.type }); + } + if (Array.isArray(value)) return value.map(decode); + return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, decode(item)])); + } + window.VulpesSettingsCodec = Object.freeze({ encode, decode }); +})(); diff --git a/host/shell.js b/host/shell.js index b1e22863..2c57bc75 100644 --- a/host/shell.js +++ b/host/shell.js @@ -50,7 +50,12 @@ window.addEventListener('load', async () => { }, allFrames: true, safeForUntrustedWebProcess: true, - matches: Runtime.apps.map((app) => 'http://' + Services.io.newURI(app.origin).host + '/*'), + matches: Runtime.apps.filter(app=>!app.installed).map((app) => 'http://' + Services.io.newURI(app.origin).host + '/*'), + }); + ChromeUtils.registerWindowActor('VulpesMarketplace', { + parent:{esModuleURI:'resource://vulpes/host/actors/MarketplaceParent.sys.mjs'}, + child:{esModuleURI:'resource://vulpes/host/actors/MarketplaceChild.sys.mjs',events:{DOMContentLoaded:{capture:true}}}, + allFrames:true,safeForUntrustedWebProcess:true,matches:['https://vulpes-os.org/marketplace/*'] }); ChromeUtils.registerWindowActor('VulpesTouch', { child: { @@ -154,6 +159,7 @@ window.addEventListener('load', async () => { home.setPointerCapture(event.pointerId); holdTimer = setTimeout(() => { held = true; + Views.hideAll(); Runtime.broadcast('holdhome', {}, 'system'); }, 650); }); @@ -162,12 +168,13 @@ window.addEventListener('load', async () => { home.addEventListener('pointerup', cancel); home.addEventListener('pointercancel', cancel); home.addEventListener('click', () => { - if (!held) Runtime.broadcast('home', {}, 'system'); + if (!held) {Views.hideAll();Runtime.broadcast('home', {}, 'system');} held = false; }); window.addEventListener('keydown', (event) => { if (event.ctrlKey && event.code === 'Space') { event.preventDefault(); + Views.hideAll(); Runtime.broadcast('holdhome', {}, 'system'); } }); diff --git a/overrides/settings.gaiamobile.org/js/main.js b/overrides/settings.gaiamobile.org/js/main.js new file mode 100644 index 00000000..fe93178a --- /dev/null +++ b/overrides/settings.gaiamobile.org/js/main.js @@ -0,0 +1,238 @@ + +require.config({baseUrl:'/js',paths:{'modules':'modules','panels':'panels','shared':'../shared/js','views':'../views'},waitSeconds:0,shim:{'dsds_settings':{exports:'DsdsSettings'},'settings':{exports:'Settings'},'shared/addons/match_pattern':{exports:'MatchPattern'},'shared/airplane_mode_helper':{exports:'AirplaneModeHelper'},'shared/apn_helper':{exports:'ApnHelper'},'shared/async_storage':{exports:'asyncStorage'},'shared/bluetooth_helper':{exports:'BluetoothHelper'},'shared/device_storage/enumerate_all':{exports:'enumerateAll'},'shared/download/download_formatter':{exports:'DownloadFormatter'},'shared/download/download_store':{exports:'DownloadStore'},'shared/download/download_ui':{exports:'DownloadUI'},'shared/download/download_helper':{exports:'DownloadHelper'},'shared/fxa_iac_client':{exports:'FxAccountsIACHelper'},'shared/homescreens/homescreen_settings':{exports:'homescreenSettings'},'shared/icc_helper':{exports:'IccHelper'},'shared/keyboard_helper':{exports:'KeyboardHelper',deps:['shared/input_mgmt/input_app_list']},'shared/language_list':{exports:'LanguageList'},'shared/lazy_loader':{exports:'LazyLoader'},'shared/manifest_helper':{exports:'ManifestHelper'},'shared/mime_mapper':{exports:'MimeMapper'},'shared/mobile_operator':{exports:'MobileOperator'},'shared/omadrm/fl':{exports:'ForwardLock'},'shared/passcode_helper':{exports:'PasscodeHelper'},'shared/sanitizer':{exports:'Sanitizer'},'shared/screen_layout':{exports:'ScreenLayout'},'shared/search_provider':{exports:'SearchProvider'},'shared/settings_helper':{exports:'SettingsHelper'},'shared/settings_listener':{exports:'SettingsListener'},'shared/settings_url':{exports:'SettingsURL'},'shared/sim_settings_helper':{exports:'SimSettingsHelper'},'shared/simslot':{exports:'SIMSlot'},'shared/simslot_manager':{exports:'SIMSlotManager',deps:['shared/simslot']},'shared/stk_helper':{exports:'STKHelper'},'shared/text_normalizer':{exports:'Normalizer'},'shared/toaster':{exports:'Toaster'},'shared/tz_select':{exports:'tzSelect',deps:['shared/icc_helper']},'shared/uuid':{exports:'uuid'},'shared/findmydevice_iac_api':{exports:'wakeUpFindMyDevice'},'shared/wifi_helper':{exports:'WifiHelper'},'vendor/jszip':{exports:'JSZip'}},modules:[{name:'main'},{name:'modules/apn/apn_settings_manager',exclude:['main','modules/async_storage']},{name:'modules/dialog_service',exclude:['main']},{name:'panels/about/panel',exclude:['main']},{name:'panels/about_more_info/panel',exclude:['main','modules/bluetooth/bluetooth_context']},{name:'panels/app_permissions_detail/panel',exclude:['main']},{name:'panels/app_permissions_list/panel',exclude:['main','modules/apps_cache']},{name:'panels/app_storage/panel',exclude:['main','modules/app_storage','modules/storage_helper']},{name:'views/phone/bluetooth/panel',exclude:['main','modules/mvvm/list_view','modules/dialog_service','modules/bluetooth/bluetooth_context']},{name:'panels/browsing_privacy/panel',exclude:['main','modules/dialog_service']},{name:'panels/call_barring/panel',exclude:['main']},{name:'panels/call_barring_passcode_change/panel',exclude:['main']},{name:'panels/date_time/panel',exclude:['main','modules/date_time']},{name:'panels/developer/panel',exclude:['main','modules/dialog_service','modules/apps_cache']},{name:'panels/developer_hud/panel',exclude:['main']},{name:'panels/display/panel',exclude:['main']},{name:'panels/feedback_choose/panel',exclude:['main']},{name:'panels/feedback_send/panel',exclude:['main']},{name:'panels/findmydevice/panel',exclude:['main','modules/settings_utils']},{name:'panels/firefox_accounts/panel',exclude:['main']},{name:'panels/firefox_sync/panel',exclude:['main','modules/settings_utils']},{name:'panels/frame/panel',exclude:['main']},{name:'panels/help/panel',exclude:['main']},{name:'panels/homescreens/panel',exclude:['main','modules/apps_cache']},{name:'panels/hotspot/panel',exclude:['main','modules/dialog_service']},{name:'panels/hotspot_wifi_settings/panel',exclude:['main']},{name:'panels/keyboard/panel',exclude:['main','modules/mvvm/list_view','modules/keyboard_context']},{name:'panels/keyboard_add_layouts/panel',exclude:['main','modules/mvvm/list_view','modules/keyboard_context','shared/keyboard_helper']},{name:'panels/languages/panel',exclude:['main','shared/keyboard_helper','modules/date_time']},{name:'panels/messaging/panel',exclude:['main','modules/messaging','modules/settings_utils']},{name:'panels/messaging_details/panel',exclude:['main','modules/messaging','modules/settings_utils']},{name:'panels/operator_settings/panel',exclude:['main','dsds_settings','modules/defer','modules/state_model','modules/mvvm/list_view','modules/dialog_service','modules/customized_network_type_map','modules/mobile/supported_network_info']},{name:'panels/root/panel',exclude:['main','panels/root/low_priority_items','modules/apps_cache','modules/addon_manager','modules/storage_helper']},{name:'panels/root/low_priority_items',exclude:['main','modules/app_storage','modules/battery','modules/bluetooth/bluetooth_context','modules/media_storage','modules/sim_security','modules/wifi_context']},{name:'panels/screen_lock/panel',exclude:['main']},{name:'panels/screen_lock_passcode/panel',exclude:['main','modules/settings_utils']},{name:'panels/search/panel',exclude:['main']},{name:'panels/simcard_manager/panel',exclude:['main']},{name:'panels/simpin/panel',exclude:['main','modules/sim_security']},{name:'panels/sound/panel',exclude:['main','modules/mobile/supported_network_info']},{name:'panels/usb_storage/panel',exclude:['main','modules/media_storage']},{name:'panels/wifi/panel',exclude:['main','modules/dialog_service']},{name:'panels/wifi_auth/panel',exclude:['main']},{name:'panels/wifi_enter_certificate_nickname/panel',exclude:['main']},{name:'panels/wifi_join_hidden/panel',exclude:['main']},{name:'panels/wifi_manage_certificates/panel',exclude:['main','modules/settings_utils']},{name:'panels/wifi_manage_networks/panel',exclude:['main','modules/dialog_service']},{name:'panels/wifi_select_certificate_file/panel',exclude:['main','modules/settings_utils']},{name:'panels/wifi_status/panel',exclude:['main']},{name:'panels/wifi_wps/panel',exclude:['main']}]});define("config/require",function(){});define('modules/base/module',[],function(){'use strict';const LOG_LEVEL={NONE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,ALL:5};var _constructorMap=(function(){var _ctorMap=new Map();var _getConstructor=function(Module){return _ctorMap.get(Module)||function(){};};var _registerConstructor=function(Module,constructor){_ctorMap.set(Module,constructor||function(){});};return{getConstructor:_getConstructor,registerConstructor:_registerConstructor};})();var _emptyFunction=function(){};var _createLogger=function(name){switch(name){case'DEBUG':return function(msg){console.log(this._msgPrefix+msg);};case'INFO':return function(msg){console.info(this._msgPrefix+msg);};case'WARN':return function(msg){console.warn(this._msgPrefix+msg);};case'ERROR':return function(msg){console.error(this._msgPrefix+msg);};}};var ModulePrototype={get _msgPrefix(){return'['+this.$name+']: ';},debug:_emptyFunction,info:_emptyFunction,warn:_emptyFunction,error:_emptyFunction,throw:function(msg){throw new Error(this._msgPrefix+msg);},set _logLevel(value){Object.keys(LOG_LEVEL).forEach((name)=>{var level=LOG_LEVEL[name];if(value>=level&&value>0){this[name.toLowerCase()]=_createLogger(name);}});},super:_constructorMap.getConstructor};var _extend=function(){switch(arguments.length){case 0:break;case 1:var Module=arguments[0];for(var prop in Module.prototype){if(prop==='$name'){continue;} +var pd=Object.getOwnPropertyDescriptor(Module.prototype,prop);if(pd){Object.defineProperty(this.prototype,prop,pd);}} +break;default:Array.prototype.forEach.call(arguments,(Module)=>{_extend.call(this,Module);});break;} +return this;};function _create(constructor){if(constructor&&typeof constructor!=='function'){throw new Error('[Module]: Invalid constructor');} +var ModuleFunc=function(){};ModuleFunc.prototype=Object.create(ModulePrototype);ModuleFunc.prototype.$name=constructor&&constructor.name||'';var Module=function(){var instance=new ModuleFunc();if(constructor){constructor.apply(instance,arguments);} +return instance;};_constructorMap.registerConstructor(Module,constructor);Module.extend=_extend;Module.prototype=ModuleFunc.prototype;return Module;} +return{LOG_LEVEL:LOG_LEVEL,create:_create};});define('modules/base/dependency_graph',['require','modules/base/module'],function(require){'use strict';var Module=require('modules/base/module');var DependencyGraph=Module.create(function DependencyGraph(dpGraph){this._nodes=dpGraph?JSON.parse(JSON.stringify(dpGraph._nodes)):{};});DependencyGraph.prototype._printNodes=function dg_printNodes(){Object.keys(this._nodes).forEach((name)=>{var node=this._nodes[name];console.log('name: '+name);console.log('children: '+ +node.children.reduce((result,name)=>{return result+' '+name;},''));console.log('dependent nodes: '+ +node.dependentNodes.reduce((result,name)=>{return result+' '+name;},''));console.log('======================');});};DependencyGraph.prototype._addDependentNodes=function dg_addDependentNodes(node,dependentNodes,traversedNodes){traversedNodes=traversedNodes||[];if(traversedNodes.indexOf(node.name)>=0){traversedNodes.push(node.name);var error=traversedNodes.join(' -> ');this.throw('circular dependency detected! '+error);} +if(dependentNodes){dependentNodes.forEach((name)=>{if(node.dependentNodes.indexOf(name)<0){node.dependentNodes.push(name);}});}else{dependentNodes=Array.prototype.slice.call(node.dependentNodes);} +dependentNodes.push(node.name);traversedNodes.push(node.name);node.children.forEach((name)=>{this._addDependentNodes(this._nodes[name],dependentNodes,traversedNodes);});dependentNodes.pop();traversedNodes.pop();};DependencyGraph.prototype.addDependency=function dg_addDep(name1,name2){var node1=this._nodes[name1];var node2=this._nodes[name2];if(!node1){node1=this._nodes[name1]={name:name1,children:[],dependentNodes:[]};} +if(!node2){node2=this._nodes[name2]={name:name2,children:[],dependentNodes:[]};} +if(node1.children.indexOf(name2)<0){node1.children.push(name2);this._addDependentNodes(node1);}};DependencyGraph.prototype.getAllDependent=function dg_getAllDep(name){var node=this._nodes[name];return node&&node.dependentNodes;};return DependencyGraph;});define('modules/mvvm/observable',['require','modules/base/module','modules/base/dependency_graph'],function(require){'use strict';var Module=require('modules/base/module');var DependencyGraph=require('modules/base/dependency_graph');var OP_PREFIX=(name)=>{return'$OP_'+name;};var Observable=Module.create(function Observable(object){this._observers={};if(object){this._initWithObject(object);}});Observable.prototype._initWithObject=function o_init(object){for(var name in object){if(typeof object[name]==='function'){this[name]=object[name];}else{_defineObservableProperty(this,name,{value:object[name]});}}};Observable.prototype._notify=function o__notify(name,newValue,oldValue){var observers=this._observers[name];if(observers){observers.forEach(function(observer){observer(newValue,oldValue);});}};Observable.prototype._removeObserver=function o__removeObserver(observer,name){var observers=this._observers[name];if(observers){var index=observers.indexOf(observer);if(index>=0){observers.splice(index,1);}}};Observable.prototype.observe=function o_observe(name,observer){if(typeof observer!=='function'){return;} +(this._observers[name]=this._observers[name]||[]).push(observer);};Observable.prototype.unobserve=function o_unobserve(name,observer){if(typeof name==='function'){Object.keys(this._observers).forEach(this._removeObserver.bind(this,name));}else{if(observer){this._removeObserver(observer,name);}else if(name in this._observers){this._observers[name]=[];}}};var _dependencyGraphs=new Map();function _getDependencyGraph(modulePrototype){var dependencyGraph=_dependencyGraphs.get(modulePrototype);if(!dependencyGraph){dependencyGraph=DependencyGraph(modulePrototype._dependencyGraph);modulePrototype._dependencyGraph=dependencyGraph;_dependencyGraphs.set(modulePrototype,dependencyGraph);} +return dependencyGraph;} +function _getAllDependentValues(observable,sourceProperty){var dependentList=observable._dependencyGraph&&observable._dependencyGraph.getAllDependent(sourceProperty);if(dependentList&&dependentList.length){return dependentList.map((name)=>{return{name:name,value:observable[name]};});}else{return null;}} +function _getterTemplate(name,defaultValue){return function(){var value=this[OP_PREFIX(name)];if(typeof value==='undefined'){value=this[OP_PREFIX(name)]=defaultValue;} +return value;};} +function _setterTemplate(name){return function(value){var oldValue=this[name];if(oldValue!==value){var dependentValues=_getAllDependentValues(this,name);this[OP_PREFIX(name)]=value;this._notify(name,value,oldValue);if(dependentValues){dependentValues.forEach((obj)=>{this._notify(obj.name,this[obj.name],obj.value);});}}};} +function _defineObservablePropertyCore(object,name,options){var dependency=options&&options.dependency;if(dependency){var dependencyGraph=_getDependencyGraph(object);dependency.forEach((dependentName)=>{dependencyGraph.addDependency(name,dependentName);});} +Object.defineProperty(object,name,{enumerable:true,get:options.get,set:options.set});} +function _defineObservableProperty(object,name,options){if(options&&options.readonly){var internalName='_'+name;_defineObservablePropertyCore(object,name,{dependency:[internalName],get:function(){return this[internalName];}});_defineObservablePropertyCore(object,internalName,{get:_getterTemplate(internalName,options&&options.value),set:_setterTemplate(internalName)});}else if(options&&options.dependency&&options.dependency.length){if(typeof options.get!=='function'){throw new Error('Observable: getter of '+name+' is invalid');} +_defineObservablePropertyCore(object,name,{dependency:options.dependency,get:options.get});}else{_defineObservablePropertyCore(object,name,{get:_getterTemplate(name,options&&options.value),set:_setterTemplate(name)});}} +Object.defineProperty(Observable,'defineObservableProperty',{get:function(){return _defineObservableProperty;}});return Observable;});define('modules/base/event_emitter',['require','modules/base/module'],function(require){'use strict';var Module=require('modules/base/module');var EventEmitter=Module.create(function EventEmitter(eventNames){if(eventNames&&eventNames.length){this._eventListeners=eventNames.reduce((result,eventName)=>{result[eventName]=[];return result;},{});}else{this.throw('no valid registered events');}});EventEmitter.prototype._emitEvent=function(eventName,value){var listeners=this._eventListeners[eventName];if(!listeners){this.throw('invalid event name: '+eventName);} +this.debug('_emitEvent:'+eventName+' '+value);var eventObj={type:eventName,detail:value};listeners.forEach((listener)=>{listener.call(this,eventObj);});};EventEmitter.prototype.addEventListener=function(eventName,listener){var listeners=this._eventListeners[eventName];if(listener&&listeners){switch(typeof listener){case'function':break;case'object':if(typeof listener.handleEvent==='function'){listener=listener.handleEvent;}else{listener=null;} +break;default:listener=null;break;} +if(listener&&listeners.indexOf(listener)<0){listeners.push(listener);}}else{this.error('addEventListener: invalid listener for '+eventName);}};EventEmitter.prototype.removeEventListener=function(eventName,listener){var listeners=this._eventListeners[eventName];if(listener&&listeners){var index=-1;var type=typeof listener;switch(type){case'function':index=listeners.indexOf(listener);break;case'object':index=listeners.indexOf(listener.handleEvent);break;} +if(index>=0){listeners.splice(index,1);}}else{this.error('removeEventListener: invalid listener for '+eventName);}};return EventEmitter;});define('modules/mvvm/observable_array',['require','modules/base/module','modules/base/event_emitter','modules/mvvm/observable'],function(require){'use strict';var Module=require('modules/base/module');var EventEmitter=require('modules/base/event_emitter');var Observable=require('modules/mvvm/observable');var Events=['insert','remove','replace','reset'];var ReadOnlyMethods=['forEach','map','every','some','indexOf','lastIndexOf','reduce','reduceRight'];var ObservableArray=Module.create(function ObservableArray(array){this.super(Observable).call(this);this.super(EventEmitter).call(this,Events);this._array=array||[];this._length=this._array.length;}).extend(Observable,EventEmitter);Observable.defineObservableProperty(ObservableArray.prototype,'length',{readonly:true});Observable.defineObservableProperty(ObservableArray.prototype,'array',{readonly:true});ReadOnlyMethods.forEach(function(op){ObservableArray.prototype[op]=function(){return this._array[op].apply(this._array,arguments);};});ObservableArray.prototype.push=function(item){this._array.push(item);this._length=this._array.length;this._emitEvent('insert',{index:this._array.length-1,count:1,items:[item]});};ObservableArray.prototype.pop=function(){if(!this._array.length){return null;} +var item=this._array.pop();this._length=this._array.length;this._emitEvent('remove',{index:this._array.length,count:1,items:[item]});return item;};ObservableArray.prototype.splice=function(index,count){if(arguments.length<2){return[];} +if(index>=this._length){index=this._length-1;}else if(index<0){index=this._length+index;} +if(count<0){count=0;} +var addedItems=Array.prototype.slice.call(arguments,2);var removedItems=this._array.splice.apply(this._array,arguments);this._length=this._array.length;if(removedItems.length){this._emitEvent('remove',{index:index,count:count,items:removedItems});} +if(addedItems.length){this._emitEvent('insert',{index:index,count:addedItems.length,items:addedItems});} +return removedItems;};ObservableArray.prototype.set=function(index,value){if(index<0||index>=this._array.length){this.throw('set: out of range');} +var oldValue=this._array[index];this._array[index]=value;this._emitEvent('replace',{index:index,oldValue:oldValue,newValue:value});};ObservableArray.prototype.get=function(index){return this._array[index];};ObservableArray.prototype.reset=function(array){this._array=array||[];this._length=this._array.length;this._emitEvent('reset',{items:this._array});};return ObservableArray;});/** + * PageTransitions provides transition functions used when navigating panels. + * + * @module PageTransitions + */ +define('modules/page_transitions',[],function() { + 'use strict'; + + var _sendPanelReady = function _send_panel_ready(oldPanelHash, newPanelHash) { + var detail = { + previous: oldPanelHash, + current: newPanelHash + }; + var event = new CustomEvent('panelready', {detail: detail}); + window.dispatchEvent(event); + }; + + return { + /** + * Typically used with phone size device layouts. + * + * @alias module:PageTransitions#oneColumn + * @param {String} oldPanel + * @param {String} newPanel + * @param {Function} callback + */ + oneColumn: function pt_one_column(oldPanel, newPanel, callback) { + if (oldPanel === newPanel) { + callback(); + return; + } + + // switch previous/current classes + if (oldPanel) { + oldPanel.className = newPanel.className ? '' : 'previous'; + } + if (newPanel.className === 'current') { + _sendPanelReady(oldPanel && '#' + oldPanel.id, '#' + newPanel.id); + + if (callback) { + callback(); + } + return; + } + + // A hidden or newly inserted panel may not animate. Complete navigation + // in that case too, otherwise its onShow hook never runs. + var completed = false; + var fallback; + function paintWait(event) { + if (event && event.target !== newPanel) { + return; + } + if (completed) { + return; + } + completed = true; + clearTimeout(fallback); + newPanel.removeEventListener('transitionend', paintWait); + newPanel.removeEventListener('transitioncancel', paintWait); + _sendPanelReady(oldPanel && '#' + oldPanel.id, '#' + newPanel.id); + if (callback) { + callback(); + } + } + newPanel.addEventListener('transitionend', paintWait); + newPanel.addEventListener('transitioncancel', paintWait); + newPanel.className = 'current'; + var style = window.getComputedStyle(newPanel); + var seconds = function(value) { + return parseFloat(value) * (value.trim().endsWith('ms') ? 1 : 1000) || 0; + }; + var durations = style.transitionDuration.split(',').map(seconds); + var delays = style.transitionDelay.split(',').map(seconds); + var duration = Math.max.apply(Math, durations.map(function(value, index) { + return value + delays[index % delays.length]; + })); + fallback = setTimeout(paintWait, Math.max(0, duration) + 100); + + /** + * Most browsers now scroll content into view taking CSS transforms into + * account. That's not what we want when moving between
s, + * because the being-moved-to section is offscreen when we navigate to its + * #hash. The transitions assume the viewport is always at document 0,0. + * So add a hack here to make that assumption true again. + * https://bugzilla.mozilla.org/show_bug.cgi?id=803170 + */ + if ((window.scrollX !== 0) || (window.scrollY !== 0)) { + window.scrollTo(0, 0); + } + + }, + + /** + * Typically used with tablet size device layouts. + * + * @alias module:PageTransitions#twoColumn + * @param {String} oldPanel + * @param {String} newPanel + * @param {Function} callback + */ + twoColumn: function pt_two_column(oldPanel, newPanel, callback) { + if (oldPanel === newPanel) { + callback(); + return; + } + + if (oldPanel) { + oldPanel.className = newPanel.className ? '' : 'previous'; + newPanel.className = 'current'; + _sendPanelReady('#' + oldPanel.id, '#' + newPanel.id); + } else { + newPanel.className = 'current'; + _sendPanelReady(null, '#' + newPanel.id); + } + + if (callback) { + callback(); + } + } + }; +}); + +define('modules/panel',[],function(){'use strict';var _emptyFunc=function panel_emptyFunc(){};var Panel=function ctor_panel(options){var _initialized=false;options=options||{};options.onInit=options.onInit||_emptyFunc;options.onUninit=options.onUninit||_emptyFunc;options.onShow=options.onShow||_emptyFunc;options.onHide=options.onHide||_emptyFunc;options.onBeforeShow=options.onBeforeShow||_emptyFunc;options.onBeforeHide=options.onBeforeHide||_emptyFunc;return{get initialized(){return _initialized;},init:function(panel,initOptions){if(_initialized){return;} +_initialized=true;return options.onInit(panel,initOptions);},uninit:function(){if(!_initialized){return;} +_initialized=false;options.onUninit();},show:function(panel,showOptions){return Promise.resolve(this.init(panel,showOptions)).then(function(){return options.onShow(panel,showOptions);});},hide:function(){return options.onHide();},beforeShow:function(panel,beforeShowOptions){return Promise.resolve(this.init(panel,beforeShowOptions)).then(function(){return options.onBeforeShow(panel,beforeShowOptions);});},beforeHide:function(){return options.onBeforeHide();}};};return Panel;});define('modules/settings_cache',[],function(){'use strict';var _settings=window.navigator.mozSettings;var _settingsCache=null;var _settingsCacheRequestSent=null;var _pendingSettingsCallbacks=[];var _callbacks=[];var _onSettingsChange=function sc_onSettingsChange(event){var key=event.settingName;var value=event.settingValue;if(_settingsCache){_settingsCache[key]=value;} +_callbacks.forEach(function(callback){callback(event);});};if(_settings){_settings.onsettingchange=_onSettingsChange;} +var SettingsCache={reset:function sc_reset(){_settings=window.navigator.mozSettings;if(_settings){_settings.onsettingchange=_onSettingsChange;} +_settingsCache=null;_settingsCacheRequestSent=null;_pendingSettingsCallbacks=[];_callbacks=[];},get cache(){return _settingsCache;},getSettings:function sc_getSettings(callback){if(!_settings){return;} +if(_settingsCache&&callback){callback(_settingsCache);return;} +if(!_settingsCacheRequestSent&&!_settingsCache){_settingsCacheRequestSent=true;var lock=_settings.createLock();var request=lock.get('*');request.onsuccess=function(e){var result=request.result;var cachedResult={};for(var attr in result){cachedResult[attr]=result[attr];} +_settingsCache=cachedResult;var cbk;while((cbk=_pendingSettingsCallbacks.pop())){cbk(result);}};} +if(callback){_pendingSettingsCallbacks.push(callback);}},addEventListener:function sc_addEventListener(eventName,callback){if(eventName!=='settingsChange'){return;} +var index=_callbacks.indexOf(callback);if(index===-1){_callbacks.push(callback);}},removeEventListener:function sc_removeEventListsner(eventName,callback){if(eventName!=='settingsChange'){return;} +var index=_callbacks.indexOf(callback);if(index!==-1){_callbacks.splice(index,1);}}};SettingsCache.getSettings(null);return SettingsCache;});define('modules/panel_utils',['require','settings','modules/settings_cache','shared/lazy_loader'],function(require){'use strict';var Settings=require('settings');var SettingsCache=require('modules/settings_cache');var LazyLoader=require('shared/lazy_loader');var _settings=navigator.mozSettings;function openDialog(dialogID,onSubmit,onReset){if('#'+dialogID===Settings.currentPanel){return;} +var origin=Settings.currentPanel;Settings.currentPanel=dialogID;var dialog=document.getElementById(dialogID);var submit=dialog.querySelector('[type=submit]');if(submit){submit.onclick=function onsubmit(){if(typeof onSubmit==='function'){(onSubmit.bind(dialog))();} +Settings.currentPanel=origin;};} +var reset=dialog.querySelector('[type=reset]');if(reset){reset.onclick=function onreset(){if(typeof onReset==='function'){(onReset.bind(dialog))();} +Settings.currentPanel=origin;};}} +function openLink(url){if(url.startsWith('tel:')){var telActivity=new window.MozActivity({name:'dial',data:{type:'webtelephony/number',number:url.substr(4)}});telActivity.onsuccess=function(){};}else if(!url.startsWith('#')){var linkActivity=new window.MozActivity({name:'view',data:{type:'url',url:url}});linkActivity.onsuccess=function(){};}} +var _openDialog=function pu_openDialog(dialogID){var dialog=document.getElementById(dialogID);var fields=Array.prototype.slice.call(dialog.querySelectorAll('[data-setting]:not([data-ignore])'));var updateInput=function(lock,input){var key=input.dataset.setting;var request=lock.get(key);request.onsuccess=function(){switch(input.type){case'gaia-radio':input.checked=(input.value==request.result[key]);break;case'checkbox':case'gaia-checkbox':input.checked=request.result[key]||false;break;case'select-one':input.value=request.result[key]||'';break;default:input.value=request.result[key]||'';break;}};};function reset(){if(_settings){var lock=_settings.createLock();fields.forEach(updateInput.bind(null,lock));}} +function submit(){if(_settings){fields=Array.prototype.slice.call(dialog.querySelectorAll('[data-setting]:not([data-ignore])'));var cset={},key;var lock=_settings.createLock();fields.forEach(function(input){key=input.dataset.setting;switch(input.type){case'gaia-radio':if(input.checked){cset[key]=input.value;} +break;case'checkbox':case'gaia-checkbox':cset[key]=input.checked;break;default:cset[key]=input.value;break;}});lock.set(cset);}} +reset();openDialog(dialogID,submit);};return{activate:function pu_activate(panel){var scripts=panel.getElementsByTagName('script');var scripts_src=Array.prototype.map.call(scripts,function(script){return script.getAttribute('src');});LazyLoader.load(scripts_src);var _onclick=function(evt){if(!this.dataset.href){this.dataset.href=this.href;this.href='#';} +var href=this.dataset.href;if(!href.startsWith('#')){evt.target.blur();openLink(href);}else if(!href.endsWith('Settings')){openDialog(href.substr(1));}else{_openDialog(href.substr(1));} +return false;};var rule='a[href^="http"], a[href^="tel"], [data-href]';var links=panel.querySelectorAll(rule);var i,count;for(i=0,count=links.length;i{switch(input.type){case'gaia-switch':case'gaia-checkbox':case'checkbox':case'switch':value=!!value;if(input.checked===value){return;} +input.checked=value;break;case'range':if(input.value===value){return;} +input.value=value;break;case'select':for(i=0,count=input.options.length;i gaia-header';var header=document.querySelector(headerSelector);return(header&&header.dataset.href||'').replace('#','');};var _shallCloseActivity=function ss_shallCloseActivity(panelId){if(panelId==='close'){return true;} +if(!_currentNavigation){return false;} +var parentPanelId=_retriveParentPanelId(_currentNavigation.panelId);return _currentNavigation.panelId===_activityHandler.targetPanelId&&panelId===parentPanelId;};var _transit=function ss_transit(oldPanel,newPanel,callback){var promise=new Promise(function(resolve){var wrappedCallback=function(){if(typeof callback==='function'){callback();} +resolve();};if(_isTabletAndLandscape()){PageTransitions.twoColumn(oldPanel,newPanel,wrappedCallback);}else{PageTransitions.oneColumn(oldPanel,newPanel,wrappedCallback);}});return promise;};var _loadPanel=function ss_loadPanel(panelId,callback){var panelElement=document.getElementById(panelId);if(panelElement.dataset.rendered){callback();return;} +panelElement.dataset.rendered=true;if(panelElement.dataset.requireSubPanels){var selector='section[id^="'+panelElement.id+'-"]';var subPanels=document.querySelectorAll(selector);for(var i=0,il=subPanels.length;i1){pendingTargetPanel='call-iccs';} +SettingsService.navigate(pendingTargetPanel);break;default:if(pendingTargetPanel){SettingsService.navigate(pendingTargetPanel);} +break;}} +window.removeEventListener('panelready',onPanelReady);window.performance.mark('visuallyLoaded');document.body.dataset.ready=true;},false);window.addEventListener('telephony-settings-loaded',function onTelephonySettingsLoaded(){window.removeEventListener('telephony-settings-loaded',onTelephonySettingsLoaded);window.performance.mark('fullyLoaded');});SettingsService.init({rootPanelId:'root',context:window.LaunchContext});var options={SettingsService:SettingsService,ScreenLayout:ScreenLayout};Settings.init(options);if(navigator.mozAudioChannelManager){navigator.mozAudioChannelManager.volumeControlChannel='notification';}});require(['boot']);});define("main",function(){}); \ No newline at end of file diff --git a/overrides/shared/resources/branding/vulpes-symbol.png b/overrides/shared/resources/branding/vulpes-symbol.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd01e6349d45c26c18c790e8f8d4c3bc3ea2310 GIT binary patch literal 138726 zcmX6^bzGD0*9HTn^oukIC?#DZq@|@nx&_9NRw-$ak}iqS-917Y=@=U_x}`_M=zJf4 z?;rb|XZvfYLOd!wEG#TS#rLuwu&}US{`)+|0e&Gp!CwXp?&tRg z&RAIZ#Q#3nSgGk0z>lvi-+xfW!t!Lo!txKn!n(Wz><$)|D-RadwgncJND3Afxl@S; zqdnFG8hb@qDeZ5wySJ|TiMP!Men`YM*>2~)>`>>v8c9n_OSO@R9Fc|;Yur9gL5uPu z)`vuo^1IJ5{jO2ii_ZJEV%L{@ZGP-)ZxNORDb7vC%HNKJkxs@P4}H&JzLUr+gL|Rv z&3oeiJxcz*G?3h}zJ0W5eM?@9CJXk{66B;P{MPaDOh4gc?^%Ymurw_`=3t< z57KJR@x9ko@mEOTi*1@UEby$0U&UXKS96snih57A%9T?fCS50+Oz>(}t3n5xTaK3V zMA+`49-_`KOS1d#Z5sL+-3p}jVoMZtls95uq%IFL8LC7$bBeZ3!|c1+mXNT?$3LIX zkr^H}X5Ewh`*-(pw&Q!_9VZ=`xv$&>JYe$^Khtijie{d*Cen(YsL9U^cu_`94t*?F z!#Qq-MotY&OG)B0<-OF7bcTM6A7(@esraV!lfW8P1d!ILRuZTz5}w;ZQHX?3KgW(V zM3No6kD=d~Aps#9QZCPWIX<(P|Bd)SCY)3|jTTonmZ%l7#QPZ_b%q}Kb^Pzk_ zGixZx!zbKiTL;oI-m<&FmsLB$ek;Ll|Fq;{80puYwR}^4pFOea5@ftd{CBuHGjepx zgL$ldDL5rkD%m0})HKX`y8cnf(tB{v2v~mc1@MB5@=J;k_yS4aqB101m+g2K9XX|{ zpeadg7096-Sqr?$NYAyfif?R0=?t|t-8ygY4JV3Yk?;141Spe)2V)}vD_`Q>Gs_NvFSm7C^dBXRv-0r$bApzjsL_P!&^tbT?p_ zrCxlUSTlL=3`_O%=u_(WdTr&qPBnbf!J&m;8hd@|bW5C`b?VpTnepvZVW#^vUdHp# zmwR70#?|)0`kMEkD#~wy=>eNvl%KiMr8XHT%83SJl{E?4NJd84YY1AX`VZ}n2s+4+ zKX$%Ewh|$W({Ll(Ns-f{VUaCqL9GzJ)p{+BaaB1*ZbH&P7iJ0w&!4vuip&Nof+O;$ zQqQ#DUsJAFl5NO5;MH);jf6(HXDZUZ%zH!3tKT@y9p1?geQU})w)4Ma#Mx7^Nm zw%zdu?9r9aO0_kfSKO>355oS(V-%CutHX1@rM)s1*pzzS=HJeDO_sj}Zq**4&cE^8 zMn6FvfLU(UgL#)v*m2T{Y?q;W1S03Dzc;%nyw(%61`W~&zAN(c28zT9kLEkrcZ7q&Lp;!4+7f< zXwHfb;;^o0@$(OAUI8X|2{2ht%{vD*a@2zP4z-^?R1f9bQlSV$gz#R>vxgWzwcZN; z9AZLXeNpf<#4P+{&-#0L(>|7|8C3e&0g4%$=Ip>H%|hHuOil?h7T6L6)7u z?A)xON8S9)R0W{Hw}FGq(Bf1G@2R;Uigul6fj*Qn$tmTOF=j^B32JB3DTXW75X@1> zZSg09o~(n#BFvIk*^CSZF9}*l6qJ8vwJNYH!HQ}55tEFCqyjKG1u$`<-1fC9$K1n3 z?!Qhxd5X3+c_&Q$y}kPN*0929XLu0+i%`YW^4&X(7y8Xx$sIopzq!944M-6Zy6@#} z;kAG2xKlrsW_sN_yQz9`yLck8ER!VzKy;+AU;GsL2kVN4Fng)y-4)&Q-21RsIPbT? zJP*}_dA3}h1|mcF){I$X5TU#$U3MWht&m?okORX+ku8x_G-iI3!$4l-So)@F-ttx zinPv*VVedL7>C80&V8DQU3`OGje&S_IgT$J+gR$j?8Zt4uY)%qmi6c=e;9L9wr`re z!o_{RZ~)rI&N8682tExk(h=z(zYz1o2CL6y~NS=|1(={O9`~sZE-WJfxD)3&HJa) z`_=WyQTeKpxP7O3l$z2L@hWUW4=26@J3ock9JZe!|oq zeR6mwx2@DMG(3FM{_OIy?VLFMUhp(DDzo-}e#JF^hbyaizooUqeQ90p+$8g4dR-A| z@_=95y$NNROfBx#H0In$-FE)#k54jthojrt6el-@?|hochGJ{vb>})crOV=;)RK(E ziTJK^M|b;)=!(KUgYSvtw!*!oFTvXlr2pz2ff!|Hb^%9vWW2gEKf zpvB2O;BFFaxo?Fj5S~+WX4FV+$`MPb0hut|H+?w0$SKA8H0ct#Slh{*6)gCeqmJ`q zTm}}>B2=18wAHf2@-+aT{=P9BZ}Wxjub{rnv}h=Cq7y{xZxPl|E+6%IEErS8>{Mg4$7o-qbFTHu+=@>|x$Hc8L0% zdyO9WKk<3~ZS+3-&BJFNyoa&m4`aUZ9u^BdjKRGikk}uNCH5r{Uq@D>umLy+4gok@ z|LbCj`cK}B;1)ZxW~z(QUHrvmnkLJ9v^?68V<`2D%4oE8t|LA1X#x}+ORp-Xr81Uc zn~I1Gg~C05_HsnL-1uQ*y$>K*kFd-i#?KSW?LdBB(e$$HjJWE%^us`vTHuS7@E!A z7Gi(Ukzqz=Jh!uXz7OE&JOY{YC?2pst47!MR+M0v$(!xJ=IlVMn;pLv?l8XrO#TkD zLbHQg{&iBah47fqFuq6yY<m^7jw-3EplY`~ztT#C8WeyB7gR9m%#_ zBoNu?US5@u>;$dYzhXc><~{a~CCTJX?tb*GvK2C4|9QUV$ht%Tk1#oMpfZ6-+=UIRBrBp7c<_;h=hiES8d;_gji z8ae6)t>aQW$z~!jw4v^j1Zhm{CdwH~`WqkEIBHtjt%K*Dm@n@h1x);d^)gH+{+P|O zzVT7!*Ku!l{nh(K0qlu#!cudS_YMh$pEE{|vpo~DmWF{dKuj8B-1zQL$aRXeHf^4v z+1{;Sn3-I}$)#`@N1@sAbN+A$xy!=EcSmZPt>)jEmDGFahCc!Oz_<3n0JBN4O*-32 z_}F3Z>l+%^s0u6qSk0wrX-jAPr4B!*s)mEQdfb(|x(40@`KPsW>07Y5V2PIWtu|Dc zL`z2O+^Wh_8v>9C>HAy96Uk+HKcYoFOjGe93{dX`H+K(b|h)xFlO?&}Dz511%^;v*w|LA@hm zXFzU9SHoB5+uK)MD0y>3dyk9oBlx7-bcd$1%WxlZ{5-hZ`kQiwP|aoWFrI6N23@-t zz_qiBu0=!xW~+HIx^ia^4H(BAhppy);f_*+qp5ZE6wg`W{zG?ue%w)hfyS}XX*LVg z(0Rj|3yO%Q=V#t({O_fynLl1F3~h}a*~l~UlbOHovog5j=1yNUEvTIU5O)9&Fa3kK zlHl!fpMT&!;KRSOyJ-m|wg+P^O$mheM@ESy2t?7thg!Y_l6%M>uz<+768pvMa)Q7ALw<^b2fQBZb< zRQJjVhf5Ul;1Z~#J06V;OWxKZtc;QgD=#yq+GOQ#AJ=Yk$C_BHTf2HS7tj5XTS(%v zbJ(gq6E+#oLb+xTE=FpY{6C^e-$-*)rcZ$THr=E_J`fk zi#@Tz7w(XZL&&ruT}alM{WRF^ASh`#C$?7-?l~(&ino{a zIbHf|l3j4ix0La`NFCGl^0NwX{gU4JgHnBB{qEUi!^x1zoV(J1Q=%yQAGQz~73X$C z6-)ym?ug{yOI*Z##?>m@rsPfOeqGbBXVE-j$8^j90Naix*2FG!m&yn{H9hJv;w)0- zp_VLwMAvRmnoNo14O7`QSJvkarxx9~h6#&L89Cp2Jjg1edi2RKh#wWLichFoQPl)gjBe~WG@zVv0q zZ9bszdHth?T!zA3nBA=$rK-=I9)F?{d|&!t@b$J6EcDmLnDWoW z%LZrzgwg???xn9)y&tJM}Z?}49=yXlnG?Ql85j%KTM5_?AA>;a#x;6SOkg4-zwtY?JsNF>eB zGy3Cks?}U<@JDAPywXMa^aX^)#Nc&Ma5EylWk6WjU1kuPvBvD#a;_Z zYV;oQk|>A1&pnr%^=;d`yY{i~wAAJ3ra!5f)LDP*Fd$Ednw)boqbvLR0;HSQn%gu( zBj&M>yYQG3Qu%7n)uPkX8fV|#d>NY@ht|bv^tBKUotxzVk$VVjLg(s8HSr>Wh5=BxL6Qm>PoJ_I(->6*j}@Gr^)T48aFB%#GjTYx zSwS&g*tE$p9L~1`UmN*!zj;G~H_3H9^=gM2@#_6;#~;`k5P#@T)jKT?6{_Z{jU(h$ zwU4xeXi0<85>jW<$KnezXImW=+%QO{Q$SP>%KR!DvgQqL{#*nnVkKg-N_ntzSZ({{HBDA(mk04t5&HZx7vC` zB#a#5<{+W-ZeCaWpR*6to?PwuO5KY`pDbO+V_&CJ{91xaJxQnZ9!>lmYE0?f6ZKj_ z9Ps&se?ITl6+u+wP2n*c`p5c~!bifthDs{3jf5jVqs%HQ;%WTSh8l`1j{qkeYRb;d< z&zHvq>PF}33Bs7@mTak6iG{9je<__ZyuHKiy>TuOUYOuS=Qt`pKkYv;z7NWz&K$Mt z*79_yEj-__K3TkZ*;FAo-~h`zcqV$aUtP4s1%UtcW2d76&aTg3r;i%J>;ZiFA%Z|+ zt!r7Pl0bO3Z_##vngyCWmqvK^?Y#fbIl?eX+KvFFp6 zR~y4u$eB3YILwcRKm3iR-HhRIz3ky@{F>yYUEQ_A&hA}ifHvzc^>-?NR%-Q6V@#*= zXlDklw&VqS1ZsJ6!lDLM?bYl6u<_@d4X5L#j(rq-%NCMWlI|q^+yLA=8e$+#BTH5j z_EiIwzNXx;ZAw1&iZ}!F;N9?|fy!@@yT|*gE64zc z&%gm>8{`{9Xg*jVeLa45+fS)#2|A4$85er0qqoHIk%9iW;F#JFa;IXLH&WdsRE_zO zEDu0IBZ()W%g}fPM2=+cHI;L7l|WHwGn4p~!I*P~zj{@aI=byo_+nZ)8n#aP)yQG1 zWdx^bui<3DT%jZ5>||-L(_fsM;@4DMz_lsgrw-!4Gf~`&moDa8uk}J`T&;V)JeSWr z1h26=$!DEfoe2B&g>z0$NBoX#dHMY&ag=T>dZpt1&x7|6QC^ktaH|iYbr|kLilRH7 zk4ao5l0z0rfY@_>O<~_(hgv62wddb)WIaaW>wm;V2fGDx)N)(I$?!&){;Zy^`Ps|8 z1e-=PD5nqWZyO@`&he7Ge5``iN!f30^(hadbfjF%pOMa$4&Y463Drte#u0`^*(*6% zI72{lUk#^^3WGB)Id@s@t;}rfZY!U2PBr-0-(DlL3IH+kt57R*NOCo`GGS@?pu)?Z z`LvS*_6`EYir5`f7~m2h-g%voES^7ntl(mL7F#(?dmQt)@5ZN{S0PHKq?|}_UqI=D zYJa>xLoSMiE9~JTS#Vz6HtjuybI?99V$@+pu8(tS%~>w0uI-9bakuXJP_JgrD7b+KYs75SKX^h#!4mL(f>eMD`}dOJwH zA?`CQw$liQA*|bfARZifMg~7);_%cQqVGTF@Vt!cRkPyw!fIXO^?10oy%ye*N=pBh zJ9GHZ8ysL<1`1l za`Nl*r$JKwLL~+Kqi!x!3ZSm_AlM%v^(KVwi+PWxkUZ@v75h)epgeE(2Z?h;D!-_EgIfNm{CZ;p3%W$a?CHMH>e03P z*M&GJ!cBY9D`+>FXa9One}iw1FIiaqIOY0;)42izJumn7K;lE4w0gW-UXV?9Sm&%N zkhO7G)}(w+^3<&X!fM@Dpgh)}SU1K{_Mu%KwPuWyh0j;ww6U}~l&UX&%c20R=oeJH zS9O=o-a7V6NyNnnBHLIH;$q||d%oWHk4oAy6?DxNw)h0?m{t!EcEW9w|Ag>g z*r{Yisc*rKaKENyjk;sBt{m%g?;EU7mhRHAMI9)94JS#p>`}H(1-!mC<FlJi`BNxQ{hH@0lG_q_dFzk37=F!SOelw*1vqP!zl6MHYoym`q8SVlr58)B>H28E zo}@VYMP)3?NnLa$d{TRr1e-=Nf=T$5EthGSIdnL^-zf#N1~7(~a=lA~$t34RHvGIi zqtm}wNx+JB7LHh8H(0q$w33+MIKO80C;ouko+2!k6Rc%!AUf@lpDYrr5r&0T2#@Rz z*qJN%f?Dv>3P$abc3?ZlhenS+O{eJgU;Q*3Pp~zhIp?&Oa@nf}(vrK8kKw1IYp!8B zx}PStrc*XY3?iJK?~8&92RK?|;17twWIsCLLb8x{Y(C6M9JJ_75*HuFB`%{#dGoUQ z#_CGEnR~LEm(d9Cos9GKNB!Dy&c}s0(B>;<^d{$u?ReC6yUPa=^(D%wEy*2`hrY#j z1Svil*sv;;RW1&*VBGzK=rsl|SP&w@1>O2Src(I?-7K5sI83m`72F?0TlUD?v(oon zl>p?#@cO;K!b1Au4(AqZ@kJA1(tv}v^wNm>R?9l;ZG!>I?;3=o^ryyhl=k}B)?3hS zbwphom4~#y^+^dG3h_4T-5NIz?_F)I8%b42&NMdd`rHFCHupTurZ?rERL3K&a&=!O zxV-4mWyjVT)Wl`T=}qN=?uo&{g$7B}kaeD6`sA4yObUiSt7-Be<+}WbhhPC5cHQ}% zJWK!L7!;A-Q9V!*&y=adfhjQ$_Tyy#zO7Gch}=HJ83#&c>ZyU|HD|Pel!z z0XngHx2XlR+u)4```jw@-|Ug^C>5DYIA1w!Ne!g=E-i*9}B2Y2MH~SS9H5nJW&W z{dcyo5T)2TS>WcP#prw*L8g1eZ~XmH>q!T}^cwQ#j(0n@6W7QI0#i$sqRUwqgM67} zIT06=a)m~wD;Fc%ca2sdC;H~HF{FJb#vWOwWvb{B=79dl#qF4_yt^L~I~-fE-|-UE zbPSD(??rDL4MFc_EoR>T`TrQBp>!K9p~S@!bO~PR zKC=65uIFrCz5zS|W6g_>vZ*guz6P zP#^M{8TX5fA*-K_DY1ISfBq6^W1PlR67;*SXRpp|{|oKe|4n(4;Tj?3><9uca)!X$ zdSg8rDMaoCWyt5ProXokn0!k%kJ#t+4kMFE-s16%dfiLcaaWD4!N>1t>nP>g`1n4> zH57pnK#Q3raN*Z&HNOvaR6f~i(9YUdCfsU=$I=c*Z8eRhWR|IHu?8sYVYf|6Sp$)-b3wGN=ub=zSYy zbB=-@z0!KOsrd{v;taKl>)(Cz7+&+@cg^j9cc?ntox?gn`EkU2M{Q48s#W`vK9N3q ze%e0)9ES-40vH4cAb+iJUYvvQ2q1cp%@&B;notdAqg41v$hhI_i5`G5qmk_`HeEUG zniW^3;chkq+7E-Z%SuT&y4C#Ix!#5Dz2Sf)>KSdD-fUHwB&AReb9r8vxaF|&VWQ$l zQIT+CY^s?i&jG|ADK{X<=(%cP2d_apTzs(oQJYB`Fl130(#Pprl>a-jZNvM8(5ir- zt9@FkZ=f>f`RIGRR|1>jmPy+@pAilr+^til5&V=j`UynJfRT+LQm&_LQc2ciKcQ$F z^T);)IEom!tSQ*8X0o1uZr*qd35X!uqIT!!Tr&NVx$ybX%^DA4xE7MP|M-+(iziW! zS~k5FXFM!#R!2@0(u-NF7+6QoMb+KXP#svtH&>9P{`cd&~XU z<(V+(<_9$clb5U7H@@S1@;t=TGJPPMfzH13Oi{Y?KD|_y%+33JD-bTk5ac5&nNI`A zVm@bs{tAyrtrTBrymCh*D#cAQ5dEAFdc>1P8S@otbChHdgP-D{15dXufY)CSh_Sv+ zeDHR0f&+8ST&HC&En3gq98mv-uw2;|Y-z|~RGT`TG}jZ|IAZTN*E5+8)D#mDoZ6f_ zcP6DCI)lffcu6>Z=8DVYWWelrpekLiJ(d_ODn0LM?>GRe|?tQ*$ zMV?CEvMlkBFR1koxUmm-WBWBofgCy`G60{HcWWTygYm~fU6a*7P7EN7ARovv+%-@Q zRfQ1^#=vK+<>hoTNT>&m3)S$H80t?|z02%Kl)srV=o-zrvz2bAH0}^R+?a=qzu=VT z`~&`HxF^g{zM9BajatI-#QVy}t#_3k_EqqK(^H9#ZTkoei-Qp;JxTkkou`NZQN)e; ziX7N_=^f;Z5WG2`ivj3_`l-t*q&Y^^q1*M7_mxi`c_&ehS_Ts>=ut#m{5UN4c<1B_ z1e90MJPvR`tIJ+uR=#o|`h%V}-D|L1rUkkhZrMn#C!PnsQdw=>X!p)wsn7+WW110H z+sm?NJyea)^l?w;7|KaKJN@m89o>|Ukabp$H6=?ZfT=9HVd@jT8g5t;c%C-Fr zFf(-_PcKViNgtYC!~o7SY*pBVg(xrTg?pT3HZ{;eHxHqgYG(S&SBY}_Ivhupkdk{L z-A7Y3eC3%FM1GI@s&(!}-8I0nY^E{ApSR0GJRFN(&kaT;dZJThVEvD z49PpNgTkGdX>TXJ%?7zw9a<6!MU;A5{Hu7ipsLrR*EkuQi@BIqQI`zA7)Sg^-p!n2 zxpNjY&D?(quK9eLxk1_2Umto_^5vG`N<_1|me6R~m^MtLG(3?==U)c2`SDa0h|^0yNRB!s ze(P|`!DW~SEgf{{EI_!DE@ky5U#$);pV^fnUXuNay9sP(uVPt z0dE45=@Pg1177Y$&+i@!^^H(NIgQ!O5{js{s1?~vZSn810hAwl1%p)P^Up1*nVto7 zOt|_NGz6s1;*^SNPYC7M+6J5S>sB5SqTWfRI?&eS;)2=7-B31+0X%7 zn-pQv(_Ell5nLF@KUQ}%%^bg!r-D;mjPe(rAwK||lh0OUvJ;@|XHz8X_EBCVKFw9_ zF}rv`-;<~CpiewdX# z*^~S%x4;d3*KhNPfxD3A-+9m!Uq(}mD#u%yPa|4>-SLS_-3qigfkjoM6o*xXSIM$e zkr_p|#@D^e3F2Jj#VF#!DkOQPHi$8%KS4_+@sBHYI8KT!!qf?eAJ`fY84qtyxfaV! zzyvEZPs0f9-#dJChA_-IQ_rMwa(FnsudvMc0c1;CU3p#H66W#`sh`NMl3|_d@A)xp zvY+PVJ{d29=1P7Va4V;r*8VhzE`WO)T=|6ipz8;pS#|uIpnl(O?mV2T#E+bBfeU40 z#Kggy+w|;;d=|ru?1~@|kTUxmL`Hte6;TSI`ENx!)Y{~WN~U6=Y>I+<7kMj`@|CR$ zf3NY5QodI=%0Ez5bzqoSqAI?cd_U2M^VcUz!>nThb7~}>C~#WmbFVfz$44?n!Rr{z zg;#c}sST2~so)*jW-cyoi5a@OR++!>4@;xvv4K%0G>TaqlR4XzI0{%F>*7Q9>ghY` zYP;LE_sVo6s$drhE3Cen;{8=xT%$Gs^MxkTZhfR+YtsVEuANJ!vrN#Ypb7bW!JM>e zGw1jVBTk2A?umkaKJjL*i2{@~=UvUah|IDm4RMQZ^E|A~i+rMt(}3q@w#81L3JVGn zHy}A}<)se!wS@txSImY+bI)@c8X9U$?*$${Yr^ebTiTtX^qEwj&fw@`@Y9@!IWv*S z@uFE4fBdIgwraG~hhtwJtEA!1yRq*E`*+)v)~ zUh)lL9loVg_6V^ugO%&3b?ha5O2gspLy<|@sT!{KOu|7zdnMwtN&6AUk6NBI)FKGG z+%f~oqr~;9AZ^&&E&Pa^VS{C(KJP5Pjj%9C^wSah&2#uyHll0~O*ovq7w*Dh5#mDx z+Kqsko54xaEY54xC2#&^;{i)k5&P^JMCKdAadU=*A0cooWUgAk8k4+$Jf{^&f%7uHe2gJdQ(?tvKWY~kmvXez zz&mBSD#3%bmn=u)m&GWFNa58tTv<wkf~Ifdy!v*#0^N`nS4tDGo+`#-ZGBFIIn;#sf7C&ay6B&4^+d z@dhBsPwiDoter!!5X^&jsXTQVm<_PD!z?pP2#Y{I>NOeTaEPT}m|~C5(C>q*y*kO~+$}ktuW( zu$&ciE_7=AxPj=0&z}Yvv}Ex)pKC$($QF?^)+6%|1yvTTqMS9(o}=ZDyEF7optK;a zL!m^i8$L9Dhlg+H-(Q1we<)O1CfdkD}B`moAJAlrN_YCG;khmh`kIKActr6mIBleGU#; zt35y7#$h%-v>G4+I(^R8J-jhz#G7ws|Jp3Ui2ZMZ-}NcSBi1!YdZNCEPnqVqFtpNS zi1GsEnB2PQOX50Ut1to1xBzTsg0pSYM}A&=s0euVy9~d8gfGLtuvqU8<88F~Smo#m zDBsxX(;5$#PSpc)o=dBTyvp|!ESQ8b!A!%WJf#WkEK2oBFB3_t*bT_o;I{wLb3hE% zh?qJN6*(?H6QJ81j8xb3kXiDufmX{@RcuryzQCygwpQjksJGdlRrhhRVFx?4wI=`G zo45CIv&Bs!+Zon&0xp>aiq=F_Gn9>S(AU`V?|Jzw!Y^Hibcmqrdp7c?FZi^$j)uX6 zcZFY*I@mH-ka$I-eq_wz%!t=1 zO8_t+r+a6zm$l}9h`b>Cu=REsX|HDV=!Zm|aUSp>;a#~)x}VzHK}j98!{H#}8xgd& zs0fN5s50Wr3QgCL#7G8F3?J+a`US}r`D5H7TtfHg4kHvU;k~|at%N7(U2tJZ%4DU} zdT%_^&n@ub(-6BIYuOEOY@iw8thoQGsGs&LO{8QQzx!DWUJ*Rz7iguJy4&wz3^;E& z1?3w_nv5*iGJf%==|#xD&^ESH7g1`=)odna_@2=DXpfP3JD*2UGH_6Srda7WD`W%p z9A3+68SNwNoWTY?FzuB-uqC^msuo+Dd%ic`_tUch{9};0iR`q8YTTkspUEMoz4~o+ zdT_fH{QPbta^uOT@SuhgnN;Z6O@==l^Pmvu}v{!(7t7kb1cKZ0z}Tb(4SDoAMWY3Q8+Y#o-+p*VLRaT{qjg7|R*zEiJArs;`fF zC}d0tlQw(L52Rz)h#&B0&XD~&@FbV=#;!+KYnv{|w9`meAX49Di!$Pwq~+1yO%4f* z;rKi^4q;nl?J9SQ-*l#3Oqbsy1(g>|+fdSaVHOx4z>1yssygXogU{K6Euk*m3yRG z0^(JNZn7$Q#;=br`VvElQrcNz~@Pak0CSdDC;4li>Zt$TWvEH1rSVS#S%4Ka_0>BYY| zn2gH?9S4!;`9&av{nn6AUU5H5SmzGryZcJ9TGeWCQxCXA%)7txB;kz~n$2nc$8ECO zbstiS(|$8{zhq8pwHgYPE=(l{-3~s1h}|>#uYMSmu3{s*)P?a^hme{Jlt*8Lc-qrY zC+tk8>-LANITiQo=8;_{CjLzXPGBDuHH7hRXSGINPMu4qejyo)1Pg)|8e(k(4^r-0 z{cVuPPza}XKO@7>M^GVYgLd=yUTS88HM}a|f(RJef1%)1zcv!#cMlYCY1eiepKfz@ z%DtYqz*_@%PmH8n7%4AGO$!sYt-#vcuk$<=KP3VdWDp22kNM{aI#T|H2kFBcl2<`6 z9BgAhlHZ9>{(edc`Z~y%()HY|K!L1%Lh!i0*)*u|?1}LZTe~JRLcq7&kgb&Z!uT?( z;7Jyrc?K@3Q8Bv)dQeiUP zV{jJ6ZQ!+tdx}96XE<+UCsn!F+%#I3>eBFUxXUzP8jqe_gm%5Yd+R3YN9+Dy;;Esr z5PpvkTUK%1dC(j3BaxCHDJL&pz!npJ-e&$xf1bbQ`)Y4Qfe$l0z{#=ca72!$#GZfn zzO*67pm|&p63n&0Y%^-GPT<8gb65Rxacs74%x>{y2GSiX{)}K|b6^yhn2Rs>R0kpm zBpC~7aYg#YDP5)C-Ux5haa$su?j^>$eUI&+==!CcGhpV+WdEX-?DqvVu(lm3g?1Ag zawpcDR5AbVh?79ztSK-^{+rd@P~o$2N9|}?c(1Px2YxAJz09dt&d1Wkn=|dh_H>Hz zaPze7IDM%;rS9NyEH_77orY;v(Al7z{%q!DZVEL1bu|g}j1e@!mQ`XAu1Ol8=@TEi zy(&~}=q4-g56Si5BBopC`>V;tX2B{sWH}$$8p=RNa`zWV_U_e}T2oMW`)2sB;N3cE z>0IbnIe$p)G@I&JHj0tZH^U`BErIJ52>qZ#?QOqVU)J(L_?uX>iori#v|^uCqz^n^ zl1ECvEuijHY{Pmse@6f6s^U;)Y)sz7hZv~owY4XX*UNaySjsN?ins;5uRe75A5%#r z`K_)dJ4v?s-8Y3KB?(44Flg#q!r=}v`C*X7#eVqGd63+ba((X$O66!V>lsZW-ItA) zr?^kX)r6}zPVgr)U1e|Ql_yO;TiiZ=Blzhp>?j^Tjk~259WHu(a0xVs?z;*77XV`LF7*@j{M#ne+&!V?gY?1qN4{gORTw1@Ms-KBXT> zHYVP(pKJ5y`5m|Kb)_hqf~Cg>xl6LM>%QN_-nmnECgKNj_)N8ne{kSkt2nUh7** zcdpnk2QzX@gix(Sm?1V%f!D_khO0B#0- z%Ixk@5LWs2GceqsL0_0f94>z;C8+e=S;I4B_$^8-?eF>0EpQR+{z=(&x|iRc2&TaZ zn6}4}&M{+CnLlHY+L#L4MDriL>`)WyuVO2@#Qe&;(Yho7HKu(=iIF_Hf5|aF_REnB zVbJ{wL51^GS2DKy-20Cot(>zmJ7_E-jO;6t?p33XS~VGM8~g>semT! zAopF@{6Y-0eIjy3lryDeF8(n+zw$G2%bB=M4oS%Hv87qd*<`+ zuqY~oee+h=hBCsweYb0pz0$sAqc578cDETl*xs^8;#Yb#()PCN`Nd;ZQQs*CR&iz; zizU}5rjHijbT2 z&wXZL@BSK+;0dj0v}Od2wP|bDfuO}%!;E>}%#th?;c~2~3JG4+KFB%a(PuI*KP#vo zDZ7lFM#M#5^Djd|Mqe56LaO>7Rpp*Q3qG5hR$ih-o1?$FGPJLk(CY z2c!r2@#Rn|B&skCo)P)q{Gq(eO_hO>$M?rT=6N{byx->MlI1$rv2#N0lIfPOPzzTTcXiw6?6mWN2_-u{jR6kodg4~-p0fxD8E8-;J8_gV>i89au=!n?IP-I?1 zj^;&4sk8WZZ^yn6z76V`a)H^wpy=g2rc8zk4;TPWrb4FRteVYy{43gg0nxyBfhPw ztf|(<3JpT)zC_=@>ISw>9&P$ro~C-8ABaPio^1)P;+Pbg6kvW152&=ifAi(ydM5~W zQ~EW;Ob2loacpzPzt7^QC-!^Zq>y4-_V0@;GP?s6g58y0kh5^*bD5@Zl0WhL9=x?C zd@$`c7;H_exWX1QD(_QCLOha8r6ijD!BAIqu!v2G5xCrl`wlp=4*KXJZp777U^~3{ z=SDRb%b?d2FMSc=mJQ`1=E&`Yy**SjEZY9pGCWC{%f4l$FWPQ@xAiZg5|Eg7^zTd~ z+TE7D!Mm2lm(82q=A33{OGoslBSp{HbsWYLOM7WM9ok2Eyz{81nhsh`_Bz?4dm;+O0|6)joku2Zkdvfr4qX$S&F6X4FtB7)hwbSY7X zxj!?Q+}pZK>^J7I-qWh@Hj4qL@xa?kKQtd_m6Xpqvp#{o`#+AZF}Th)3N~%bhK+68 zXl&b7W81cEH;rxEMq{(F{k{2qWbS0<{<}Np?AfztACVk505snR%>o(j4cK=pg&5v7 zu%X$&Y!e&mQgc6o#Yw@Wyw%20BtbI&!sh@x%^>0IBL;-oCHf@<;fjq+`*Hf3ABmovhdRCrZMzDuH>q^9Y7^{e3l0M5$BrTF@ z(x6^mru%1rf7b_q9l^UapNFcBgSG2Z-WyKs678Zf06Q{^xpPJg3sUT3RihqX2wCydZfG~)8&SV;?a z^K6X@>e^E&RSf{cp(##_u2zzNtqISMQAY7W`a{Gykn`uajit!gHH%_XdfkyPsw4uB z;Q%6*3U-73f*seq%-_0$`fnCf?Rx7iDdl_*@zOxE0;b{8Ikl7y?r(U5 z(Y2TuM|HtuJ>fN2&S-FJ?L6hi(7@jC3o%y-i-Bl>aAn>@gI; z8Tf#L82z7v76mO*m!HP*>Szh$D|TsS$s_$C>a*#W_z_SDjPh{?3DNQ5oZ*A!Us*-W zBiSTGH|V46z|A9>#Ei@NF%97u(JfL(AOobsUys0YXVq zr6S#&y7ITbBZqNmj?ubgncJ%Sim!@S>|J6kHVeXTmYw)1!Txk%D~0aTg9a2k3s-l zx)jg&N_lF+J3gd6hl&GiwJ@XV?H?F0_v$sb(+(=Qb;4(XIKRlw)I6TSPE4`o`A*4y z&JipCkm@-HsuBPxZ^X2|bY5(Lq&G+74LQBB=N(Q_1bmsq1hbP`%DLRj-&~6zI%lPQ z_s`R2e!$snzCe#DHRMLnA-x<{7vq|0SE#;|-WC4IDZ`)E9AdnS`VPK1%>6b01~S}B z(o6tkn?hKq5as50jEyipLSDmW^0#tvq^ghatA^s<(wgbNUxtI_^m_9ORw6WWggh69 zFNUEYa1pAnhH<=JOFV@az(U*xC{xKLUpZHE7|dR}@|herC4>rE^tzQ<% zY|<>RM5q}$QV;2$=E zqp-jzei0-?2?bU$j!jHhhcC&_og#8UT0hbn+VD;RqabC{>f$f#w^{P5!mVAMWJ zA3+b^o2HXA89H^=(}sgAtuk#=DHNEF@*Tea_8f+#xcjO`$)0Xf1z+=R11m5aT}9A# zuoNR3Trg#M6kPY>0~?)~o5pn=`u?G+N(r`*H_E@*c+?#v5=q7^J17jrv<91WE;5IX zt$k%B$@xS6EGM4li1BC<@{lx((=3eFsc>5p?t%xXc~(N3obku2G)2qh9LL=&bMU_- zD(0RY=>EF)giU;wsJ-6L5{0BV@xBW5wbKbiX}oB2nBmO%o5OnkFQ%~HI4n?x-4gJb zr35*w(8bgYwqsP4Lan3#R_4wsfAn`yPwz)ao)@*qeN8GSbl6ZYNgUbvh?+-{-f6;M zgfFa?Kgs3Z4py3|o+YoJ-P0bL^7o9ZYznS&^rm~n@Y4x-HPhhU))4aFd`7RBih~ub z21kT6i`kyE>$hawRAm?o0aHh{%AZ|5nL_XjSZZ}`mewvmg`A$Y3o*n)3CLqr8 zqQhv_O+AL?+8ezTB;*7RbL`ea;>g}G-2O)rx)*CA!=WzIy#dO#s)2lST;S}wqf$LE zB0VOL6knto==3_4J&f1B^m~@rqXBmw<4y6(1j^-5RVKu+Z`lVB*$*x`oeyb1% zoGFZRovEc$8+p&SGzl~}sgL9-VI~~2>GOzaP_#QQVSvlVh?3ASy+=rK+sWUY6j_Q% zu7wVS6h}D05hV&#kGN_#N&&+r)xVt|`uce!a!%5u+?vtQDITLBVH`b+Sj2*iNr5W} zk<%P@db}E=FySKva9LCpXSliG-e!9R;4)RtdOef0N_UX^GCgtECQM#O%! zUGJGENZtxm!2assx|24j7^8&CL6&EV9B?ovW~~|cKb-Ia?XSEcJ*-{xov*=uk?B?+ z<-)zo+n8JaLRC!*Wc_n%nABXMs|HR>UXi=yMFMs~H9}WG+*R-IIntSkpzHRqO;u#f z(oR(&1eB%-c(uCgR2&PLu<6VvRkKEIXX7Cjkc^Hd?!P{(34#xv?8Rqe;@Unk$1e_p z^gn+NvWLPv1kBLGZO;aLr{#m)%@qI6Z})U2xC=jog_*7a8RipGBZ%#iBa&~56_DqJ zJxI6H{6Q$=J468@*+g8qUw^Z-=v*vf5P+tr`m9h(?N+< zGrxW2Yf%&$xwUKH4kr`JJRW|P$$0ludTLkXlRgJGXF(z@V5e&s1=jyk$8F~XZ;Kf- zHU&YUlgJ=hR#WKBeZl;I9lU*2XSuBIAt==`6WzHxXd7Z3-FrCzs8$%>;~9u#o)~VF zzVamj=uWJOGYYmla?Np(v+J-R*a6&1cqoh$wSgFm7ip(*g91x*)OUaMf<9E|d;h56 zD2yOS)!5hnnE1bY4zIIEme7xW zCNyY9!l*$NC!Zb`IV)ulXu{anFni=f_SOR^$f~mw{%t?@4mR?a#>*UYoa4?FS&k@+ zGbRBvu{{|&X1j(9Hf3H$(e}UHX=b|>>F+0v0%#h~jGy+v4LGkeW6lu?ha!tSHK}5E z9m;6wmmUmRflZ zgwn)?X?UvnGW9G9u<`EYg+VDT8;O~aKX~0OmbinP2ft=5k_f!!rD8QL!ZV-0Jy-e& zbwwqgiHpwaoSE5F5g)<+rK(pIL};eJjm7GN_n?0bjkOmMQIJ#A8{XdG52?P>q+l-zo%&6nC7L|K1V_Y!pqpnmSoIxO#Rjhv3jJAi5@aaf4G5vOL#@)LF^s1E5b{zmMNEjsv!)j-s09xoZnEd1)b}*divg2HKG3?l~ z5nYhbz1h;X9~5HSlH5PlM!xx65)I9liLRTDsef3vnRaRCbF{NoqhPJl95Mg;=U(0Z zAtuhB>u<;ZG&7)}`&#FEo-pWe!3<#NYM2A++p5}awrGJB&cOQ6_L}EyI#x_Cd-?Iu zAPlV~`$az>^r+h}qaEf_|LJ52XTr#nrX;rt*#`vP4HT#()!QI8VL+FmCTo&=)vyC| zBSGCuQMoSN!FsW7t-Gy;1BjA5-&yxFQ?%vxgo)&cNz1OC(aF>Ef1TSs*#KQ?BY_P< zSijl%-H1ST_sVX89vU1LIvyZbnI2?!CXc=}u4}jcipoaa+w#PoIcB2&DAXBu?(+2h z)^>|jIe37^2s1iDO-|PI8|fp}1$|{8|ArfrXBGX{(r~&dYG9clIwZbuH)+%%huIPk z3m}K_8D74?dOS!Q_mHi+JC;)u?k$nMBZE6_z^z|e)GY>+4hg~--6pn>>F_DwbffKcn-_8 zGjds=6Ulx)G^|L-eyGEwLWKEL21ULm#s6dtj_hckY6(Qh&3!ddLt{E@xpYk(pv_U= z)*Sis6C^|UJV$No+RqK}1v!(OBwOYAMh$3^rgiA&o3m1qrWqL1^OuJ`1f|>ZWkHb| zIQ$Fwz9O z;9`K`T85hFqMzZ~nYzzrh~ZTQyU%)n;h*zYK^ro!3vUjm7oZxEu^5#uW`e+6Fh69t zMDPNK2M&X%?ow@HO{G5`fr*Zha%kCY1U_fj#Z`FE@G!-%!Uizfg4yD>kpQDoOrAEi z`;_5yZTMcaF?-W^A4mT25GkB0t2yLWImiC+{TMAudsXhE;sV0-9;&1-1@HrAX1eU} zp(H0zsZ6#_3804S(ovS&I~4$%N8hl^q8{@Tx^S*2(%yG=xO zu<`tL8B2I;3hJq*ue#bV%;qzN3z(*dLd%2NPgh5016bSK4oeetQ0p6eCYLNxi^)4C z(4{_Dw}JGIIPJ%v$XEN?O|QJIH&p{BK7*aq?)8#5GrkD^B~oy~V=Ym&0r!)%@FZ1C z{jeY{Ho#XBOeVE@mr22u!(<%7@@KUowf&4Dp^;aAc5z5*yaC;52Rqlm!%7a)>YNFO)7Bfhbw&iNFOys_~insR>S{N}PuZx-S^ zxwQ@tyRkdG)j@|*yBU-RG&<+u0DT}K#Ctp?j_ez{6KCLz>1vOBdy;>x2`RFZgB*+d z*nCLPxTjX{+F|dmesXh4U2m1YG4EH_n=C&1p}bV}M&a>#z=;BkZwEH1xAY-U4|Q@3 zlSgvLQuH#W{$YTs4ucIAg=B43X`qeW98&uw58^)mRL$9k_k5r!}yh zxI?+8P&AB(iid#Yv^ihBzp@KX*Qv>(*CV}mpjGftUS`lcvy~%3hS7M$`8?GNB~IQ$ zatj9!lC~VN1@wkpV5%#QzDjKm?UR#Y*HDQw;|<$Ow8qb%Ypr?8r^=vhuHMc>9*bGg zH^Le?9Ob+gG6FRl9ie!o#=oh|{O6MMDgLRvn=-<9ms8gORpUuXKH^|km73=|67Ep9 zTD%Y7-ZGXgNBxVE0=0jg*0VlQ0}b&LVVksQ2|s$Flhf*|ZH7pgQy`+lq?WG}kK1yXyqe(VocT;wDop{; z)kGqW%5Q6*@RLTe-_{sP#J5zI&GhQ{MJjo~19zncbDp)h3 z6X-20565Niv7M)QGd=}iZ)`kh({bYtjeMrl@L1sI^~Te*Blu4wg7+Luj$KrOKxD_i zYO=nVXT}|&FGL?;nareSCJgFyDHMZGLC-fPQ#GX&QEDiq`6F@IHnx z-biOsER8r<0h9L3jHe6(f`ytOl^De&$0{KztUySO?CmNoI3OlQLn$JVFV84}n#&*| z{8x^gq)#akR#A>oOk{)}LpZ<)`Pgl`TNpsE9!svp(aybm73Em@?S$DwjBXgoBYuEj zus@mtqtYaDjFJ=%^5=9OCWsBr%5cOTA#kXUl7iQ6FvKF;sO@BWL!!#6V{7vEH>I4z zYU;F50Gdy!fhD5;;wuH9rp3CicH8Z~tKtRQ&%L5HQR|2+PMi%9G6MC=0yV5ynOI{{e$5>_ zdZ;WDuiM-L8TfmV@jh1lY=MY9BQ%w{K>gZC^xSWeC2h(P$}`1^0N6Sy-427D)Lxtg zqe&&jIG5f~Pi)CufA;+8xpWzCvMe%v9$%zbA@p-ku=snqR8DBpUwdk5U zbzw&MAI{*)ncYu&SLY=yPqNvJMGLN%3g)zF1ET#e(pzP=q6;9hi`E|$n=eK#6d(urE(4$TH=LtO2fKO6|}q% z$A5cxU3Th|{CQZ*1r)bj@4-0a72bB5O5&IGAB;DAl2m0|OlePqqy|NuPsBRwaw01k zvI6^1N$C$^ud|fgy8E@yiQh8lIBU-0VYsSVYfoFT+N#=W9*UbK)m8+a?4>k+ii}ZW zKTK1XbH~%$h4P;sTU7GGZqL5yRdU1b77tjQ^M=I|7MSA%0g4Cb;>?;iHUU_Pp(IHu zU`80Bew4DF`LPjNSKJ;ivEfyoUsw))7^`)zE}Un9715~;jE6|{P7((Dr72RI#uIA+ z&f`3KLz!=l;~R9jb2Y^m-h=%WvT}Sc@vXrJ_umSAqhuL<(hK>Q+}MsAFX4I6EM^_j zDr4CNin<^tzl@A7$Z&xJffScOAjO5-$g~$N?B9#QX&|PI z>)%AEAtAeIABG15_>+Y=`MQj0zB9Zc>~-o@ZtUM=lJO?*DZ(LHYG)e5&RvLulS&C z)jh{Ji=<(_%-6mKWc0F>z07@vs-DoSwkzR*uAyxS&^WfdeJ1U~I1rHq`@+rfjKQ#ydvU6}M8KqdD+k3neqi zP>+=El?f0K`+!&-rV=6CPN}W;2q3}&)YdUa*g=6Vw8O>oug6%3He36$_d-@h%DS4z zAR_XM8uW&0T$(N|X_72oVKOsf+B{p1*vOlheY6}!OFU9%cH&DMpuL;%ME!jG2Lp5; z{UK#l=S^T?Cyj6nJ>Sz7|HjgpIem3luk+=4jXAF4}$Ysw~lrH*TL-iO~J}z44&61sZm}aSs6(U|lqQC-6AHtv0^r#WK05 zGhX!OGC6NDT;$bEY~mj1;gf9sT`rBT-qhe_dR0UAs($xX`*1yX)qmAdmsp&m^;X^7 zH#0qMSp~`ixG$kExd3j!tlXtOCS)VBMYN;Dv1CB$XOZ& z3fddG8)f3mAtAa81$@xy2>IrOUabu6T;wL>P2QKuuNe>2_OIQZFA4|CC`@Cmp%^L` zslT4k7DU~C^Lq9HIn2M&P4fzKqT_Ya)k?`vi}K4;{Nr_?N8KsD^2SfyDay^t@&nf> z#&0Nza0-PKCWX#loBSh6f0=FHtyYu-P*(Sk93TmXV{-6pE3sxaI+G6_<2nI09`1LyzYYOB4DmT zpSomoZ66(=VTMSVwxnRcf5+fm3yI`i=x?Kb%ml3fB*PO-Z+brs!BCI&xS`L;C6{{y9pd&CqtA4BIcf z%JcEca+4YPbnP^V_lT(8DA6W~$;yf<>O(0f?m)2Pj3-*3`tEl?;4+>;gh0b{(i@Qn zKJ4^9|HF3H+u#SVXs9CeeRaW92l z|HBI))*$uoqVRYvrP1@Qixh*;SRn-9VtWn_dvE}=gk_YUmlTz!gA-n7M!8dvpOq9A zXA>qLIeac9KQ75F%%M)yVH}NrFz}CClGdwN!M-ZmT%k*_u_pRc9e(YRswwcHdi>?Fs zQL3=5m*IXtbeOhYf%t15>8_iqV-H^JmYcZSj_)sTDG3y(@0$KZRo3**w-Obth-2rB zmd94$bgkks$C%W-dci|wTK+p5+gF@F07C$P$Q~YQ%`ar+5h;FYfc$N6p5Fht2o60S zTqb}wd|`LY9JzuH?f?)GKeP9`az_8mx+Qnwq-29q=qy?1~4(&W; zRrvth4jg!+{1II4co6iB$M29Notf&-+{Ru*> zrm4v0UA!nXU-4#f$?dA8^hX7fV_+ha?Gg<5nfJ(6$7egH^#|6FbNZ2O-v=J4uE^IV zjN?_%6ya`C?Yeyb#)PNZD37*(-q0xwkCOp>Zd~+E9v4~qGhja=TpoTj_%Atz2~ZLJ z@?|igTT2N!4bl;709f+N^PviRL2=@2BgRLAVheYGiu@X^S>O#Z8G-)?A9M1ouo~!a zE!wD2M1S&Z0j}dd5NfdIAW=Do>~GQuP#C{oT{T;RVLVj~w{ zVJU{Nzj$K9?y{Z-9y=seX%_>6kwwHtP#1vwy z%mHt4x~8VNxp{(jjQ8_3T+=kQV>wZaF@{X8(XQ@lm%pOsrjU$2hueT|pyN$mc)aXa z)|^hyg7Vtr>nbOuCD!ZC_GBKm_B5C7Xw;HSb+?ru<&rFQr_nG}GTqwSKqATLE~6O+ zGBjL|k@9c%zjbZ*C6&L?RBW1CoA1B4=&NxnNQdZ_XcwMlQaNUML|NZd&N;nHx6-vs zPZbGhE_ejtcBo>^nnpnZ7ok68-tt1D!Mxaj6Z<*jXRF5i&1BQti&T4OiS9UJY&;Qc z1cTc&)nVO8{wsGvN|)KR@`OI6K5morPQz?tD2E)N9q-^UO~9m@WXJqb$4!vhr0*eC z^&P~A5e}e6xnq)_78m6wg9F0>!4lSHSPwlCLyF1Q2}i*;{+1V{fVM3^FN@S8E;NE4 z$FLISY6>;QVqszRvTg4+LKk_|l$7ZiH?oXXb?iW!N|2(%@On)Jk{+QC+krm%JxUJT zB9QUXlRRKDgz-`f^4nAp{TA>s*{J%#L~zT8BhWRMcguqlzILoSoCPI%Zb{5D)xYP& zn?!lD364E*7fd%)F=Ko?>H({3AJJLI!frbjR$Ykn)d1!)$}_;ll{UM|;nFiJ!b1(d zGVgD5pb=nr8Ts5jMQo*VK=m0Qhqy-KAWhdsZzp=wlim5V7b6eLTlqx)dU6n&ixC7W zq0@SThb*D^=#!8ZfVw(REu>oB&^w)QY2aT2CdsfdauU{p#MDS6gIUQ?X*vQ{?MDsI zMTp9b4ucCg7x>M)oz!GDGAA$giqj!+99`NCgh8@bIAs<%-|F!B#YGXohy~mwlGBs{ zejPGTqHACh86e|MX>7dc4cOOMDO{Lcx$hI)S8(9VH^dQ^vwTN@3V|>EUD~3&oT{cZ zL$E%7xgB9^v3*$8t4IPkp?_Ogl2$dxPo#9HInP2h)B&z$JCi#MQS%aD52Gc=jHiU!Cc0=dhzXPanzvf^F*=eBV2=H$ zWxT&0;xu2ra5ypTE%FFh2awof0ckf0kduptu*;+%L-JotV_*dDJ?Q^c;}OL`Fx_jh z@6rwBc~S+1rKd^Fj2XAiXqxa*8cpsRnD9~pp{2Zvczb!2=6R70@(jcLBluXtZ`3Ha zLYDP&a`WPX@?^>y60LlVO5yG}vr+uNUj7Z@w+Kcgk^2_p44a(^EovCgO|Ol*T+MJ; zS#A0>4+>si75~FZS+_^`VoA&{`G!%5I4Tz<2Rw?PfBEzsJPSd8y5&1~Hk`@UUp??l zsN#=fz2_WwBq}wHH<_U62PH@^*`V2nTdF;okhw!C;@Tkto%g0MqIMnIepePw7$wC6 z!}~7i?OT{B(w?DGR3!9`U%HL}tMC3c)*X0GD4T-q|D|qXCk(}ipIcZ zB$5)a5F@DDy6MV9OPRD^=~M)~MNLJ$1atAVzjzaUcISRo@V zO(V5x-L0!6Gwn7A);iuUriz$l?NBx2)g$dr+bUT_l76eP*hwcUGXdJdayCVmqG{u| zHaK*f)TlhQy7~u)4!vITi|LWKtO)j%>FtQzpt(? zN$Nh+#4U~D`60t!;*>B_V5&ICHHeL>^-HzBWx}XRAT>y!9Jh81bR_ahN?cZ;z^G5L z4{;>YOCa_wpqh6*a}Cyt8RU7B3`w{>TYhzZ2fsYnWus*`X1rFQ=ZSe?I3ja+OV)jA_|4jyb`od_-hBCC1EFg{xBXTWFZ%-z8_Rt8uL$}ZmA5fOC*DV>Vnboilv@fP;8Wfi24eLzvcWO?1g@Q<+nUH=C_?jI}O5k6lm_RphS4n~N@YQ!s&34RJjE8)eU5W=<8C z<21g98^_eV_x=rs+Uix?gU^z<*y@~*!EJj^J4 zuzk?eC`^yI-#oe4>#C-$qNg?P)LcWdBQ6@6RLWqF>wts#Uk}H12OwVa697At$+-gp zp1!aCnOMBtH0blSa)w>o?#|T))(A^U`VfGhhdGqNREObR0ak)7KGl^CPWg;7Y@s+^i@+H;a-qv);e15*H2kL42bG}&o(Y{h#GnhF4P~^I_7gl4zVKt@%X9YS52~LUZ_zLd53cxL z(O`rw)S@eg~ZNb`pHC3GN`7^Ke_S#dOZ^82zSR-xDMlX3PaN z!p4rKd5d6Bvs46>G#KPd2ZV|tx7uZBca#+nXUs{|nn`Q#;+cSTsNHQg1X(=~N8auP zgB3{bocq_Gs#4#A+@d=9(v!DQP*lHc0?aF~L0OD0{sc1GH~O+6`UuE|7RM`kd26d~ zU07LMBv^;snxAJ?c)Tj}m2SBd3acH}==4Oz-Fmpw{Purp2g`LuXBe;s4k|cMTb0d{n9p2}^cf&rjQ5l#cJ(r~ z6Dw!dCIJ*%lY%|qp_SoZEA(y$-%%nl^6_yFN>lkwan-s&S zalAe&GHk8fEb!7688Xg zi_b?)P=9tIzYpU)2%e|PdBr@tg;7?Kpj3S}p>F2{#?L?BVjH{F;;0 zsyU$nJ0$2>;uWyY0<#C=UD~!O-dHu}Y;FM8VuSIPvj_N@=SXaaH7wuW*b#Eia83+L zcT3!GVOuG{woC@!xQj6lfdl^u;s8t1Bjfz?j4*!{@ZAO`^eUpCL{&-A?JAtRECY@O zNrZ{c(9oQv0^%xVx3hBdvdFVhpg70VYHE23v&g1wfShYKK;T0b&cN1(;q`_}R24Y; z;)pML#`J!dc8L=|@o;h0#UAK0g=goEsOUf1Ajf(3P&mb)3zAU)ywLPi^Nf8}Fr}~i zjD279K)~mYb6s+n_r)C-x^O5@uN4oz;3dxXy_HSjr3-~!0t>c;qH@6;t78W~;844_ zn=^6TpRT_!<$IDs|7oF1yM(9c?^N5b#LGf3O;atw2YP2&q{SIV)NAo>d-3CfCB(p@ zirx(|rdSze3Af{*)s1~=T*qO5n~Ij_C{zaD6!t57f*-EI7`V~i-#;TF7xvD4~;y5=;0N2pa_yIgyMOv?5 zwfTXXHKl72ltgibp|P(U6!N6Jz$~Y|iZ9Iu1V#Z~?`eF(9X!SE!Lf78uJeIL3!U<= zqd}r3qhBZKk6OyI`%NO4>4BmzmE4Xwn^7x*C1Ij*X`WyIQj`GQ5nJ0tE7xL3eX{-Z zR?Rg6H{xQ(0ob;uoX%JTfdCWZoaTg*Sy_J~QPU(+%Uw*|>SZEOtimWn0cypI@JX%4 zkLd?>Lj|rRxRI?%nbeuG%tczHSVn~x@H52S)upBCHc7tgRWUhgQvy$_#i|0(o$^ZI1179)GCXzBIA)UqsD2 zdNv2EW+rj#UReVU%yNwp#TMJ_4Vc1#rbtLw6nnYpi;Vt;_Cc;6z5636q=I`AVPa1 zQu~ZLq)1PU^79kI;$^_YSB}538jM(kZ<(0_3vE=l36#AC1@Ax+z#f@ui2^5N3p*!| zG^Iv?0WFH51Z=+-Wd+pf5J}ElQO<>ke3<+hmUI|S>>>N;K(^qXKq4&91uKx zT-Qh42NLOoe!TfGubO}0LXSKSCtCEpdWBH&Ah^yR=CXB=ICV$pymTBjOl4%hbR5@g zhMd2=9(7LTSigKdYNZRcei1x!#!u9}Z=XDOC*QaEIPQs4oonSW8Nhj-YVBr0rmNjh z{+^>QA>|IxoB^SC@Ju~K?2(SvNrJy>Zp8-sX|vhZS_yzLy8l~=5Kw*?>LYgVcg3vv zqW6-GL7S+Fn)Tn)%S@`8U-1(qai%#ccO$|Csr_oeK!;GjXKN8xG>dD)M>-IBCAu^^A<5z4&C+ z!DOoJf6d!LE=C|pEO0<{eo_0MY#?#u1Pe%1+>G6fS&=475_C*=1x*tl0<|s9&KtYE znMEz5t)rWBI&W~c{eM3R50sWUiz37h)wF4k27m^o&X`UR*(DoN_!Eh<1NY3kqnAYQ zk-Rv;uTPLDv;&YgSZA~#|% zhQ}Fd0bL0FjsSk&oQZF=gR0GG3lf)a4f5y0L&a!!oOZZ+k)R=? z=H_W+{%B5P!47W-33=cAg0rZ@6k>;8rkFA%;uX!PjWDOy% zHAZd~3$ribbsU`Z(SzX3$uUd$bL1VyBrCJO&-CWtVe5V#Xi1FydAhIQf6cQfuIx)^Vh0BNmDfj-aj@-g6QSVkv`~ znk$6?2aSy?d7R@8E1V+sR}HnT*;BefSpz^#@vL~l^CJSVqZ!ym<~cM=6vd@dvxnkE z(sfHklGAlnlOMfOe9;V1a(Ot@_9Xm-pQQv(Km>LOnpKin4Ad0IZ13nvCYB?{)A%ow zubPg!uA*jT$-g4D&}S`*7&=rlW<4eZ^C~n<{nnm`da+ICfc)zkfZ~V-pFimBUHu%) zb{lwvK_u4>Lr(6yt4%A+7y&(lO=Ot^Zrw%Ysid(XOBmjDFt3qp>zM)_3$g~)DwGDz ziwLR`!u>0Ooiryj`0-a}kz;ZUW5{8#%6$6dOtc?J(ExLXPOpjVLXLW^fJDrY6Zr+o z@S4fjC-cI1TgVm=<1zbDjn#3_h5XUj?iKd>^5NSbpx&e$+XnNsZTfc3-rL%h!5-RWi2m6X4y#CN@Ghc+RAeAF@!BNBb`C?7xmH z0<#ljYoF$cW;c?dhCqPps4;Q^(u&mKL_)%N7${lFJ%CaO>_S6^AuGs;Y4Oq$aByFt zfDgp1D^@$oBEnm6l3h=WqoZfEi~T%wgG~nx$pTP0P?xBgWwN8yVO6}MQcg?vn z5BLdqlXu@KQy#}3JgKXIM_|$hNr3?0R*{pFjNfG`-LtpfSmAIk&CM)Nrd3$x$lt43 znHxfnm|?a)8y2zoh=%zuM2)(G1C=Y~>-QmJ+wBHn%NlPfz6u(?N=xwrk$8-F$0a+> zm!yJyU5nD+l?8u_vrlXQ*2H=#-7gY9iz!5&(eL#Wco^)^Li$_Y$OV+_iga7Aa?<2+O8UY)48ZE_?e@@GQW*T7VyMO3lNeKDX{NOnBc^iT9`pmh&kby zcwUs}NQVkG!Mw*Z7u!V!LiWw=%yG|&F?I>H8>1vEyj=!!*9pul@SXxkxBwP09ac$- zv5@UioOVG0usev;VF-V=qXEWuXJE*xH)N6^iroed?VU$M^2plJ?Z*TBMAwddrqg6J zEn7|#SL`s?qGeVeeE3!on`G+WB-<9=hdf_bx}E3H-)sJcRkm>-wJb$se}ZN;!Md&E zsBtyJx~=`VaW12>&GV>rEQPl1?YNx`@^44g)9K_qig&#NrNG3c?MSxkvv1#Za{7IcM-8y`o=zf_20d&xspCCb)|SVd_bYrPAJ+En~l1P zaCOWPEqJ5W_&G!w&LtbTcv373$~Mv0LffeNc~N8deOPe{C7e$=0-qVCYg^dtm#}5w z!ZbAv1+zi^6T!Y%w>e5IAnL_^B_6jIvP{?HBu?`ID=BL6@+LBG;3UmMtLcazw*|HB z{GhLXf6tikvD)#QZVe{YS9`6{K}TC+RnXid2Qr7uxk%KbZOqL#*I$btsd#IEQ!XFk zj$HrRKPKZ@gimk3wO{kAV{}mwrp2GWGvai|$@5U;GM$w}P8zq4BX%D*ZbjdMx=ro3 z-fHOMlV-jEMp91rXh4!KVENX#%w!ZpMHKzabni$G{ew`x6={rkLW%U)1b8G4zrd9Z zHK>guvMVF}wS#%@qL|^_8guu&2&znh^LY3)eCwzXs2suV)*gT4>7_(R*l~=Jp_m24 z>G;{i1qbNCggb~)8jyu7^U+<1GJzL9(VZ9q=QI9jAcHJ(th;As`h1sa7Iv3MCpG z@|z(@=8||&APFQ>X6&OU&~h%rUHcRn)&bpcV3r3g0)A{8xU93?WB?%wVgK}n*My0@ zs3$TX*H1YFCOY&Gqa%l?0kI`!mcI~Zr8){Ri>jR93|dQVtYtaiCUAm#b z3(?X!VI#3JG|Vi~5+-d{N&zN`#Hhd1=QmSZm%_ZRTA%*FKw)>i7P({%CavS9U%%ujc3)ScOI!~~80uVl=AD!<7s zJ=K@@wls;a?0Mabs=M6|&_l@JYg{d5%M=@Dnm^JM*;Ow3>~^ilD;XpXjUj0}@VhzO zHWAQd1HPjtAjGM`r)hsiZR)3B<+lI)58|#lfu>zPM z9G29AMBa)a5m6~}hCvNQN^98o-4VI#Aj3`io!vYNysHj;dOAMJh#2RQB26&z^0BUi>sEY@PW%mUYbFHX&$4_9G2A zV?GX~V|9JE9S8ebppe1YZ!UU`w!KoRiIe_BOXlRy)&4lDy{0LZIdc@g__jgMwG-oK z+RJdO!5yp>F_cSXhi--#@{U$>WQrK#jb=yRg@SN1W=G$KB0E3PAe5>r>;EJTosJcD zye2)kg7-a_AjOq7|mPgNp7ufmnSTIGw z_v*HT_0E10mL0Nw^}??T&)W8H#wvuSRbkn2+Nn&!CO;s%cHZ+=8}6jFr>1+>S|PjZ?4O zh8{djDnYAvACOF$0(j|pyk;D>Y!4!mDrg4tflx_0egP2*B*wAtaY~`Up*HB?-i%3? zmg`)2oQn`^r?62U4KZ?+7Saemm&$gm{i7gsCIq$Za2%WDAN$HKs6Hom+=F>RAMS=2 zVgAxD_CZJjHJN8@`Vu`+gcMf{%P0~wt~sV(h!QUqsC6i`q&o0x68*l*o=xZMW(<|* z$CY9Zm*@1|IHAv_R@v`anrDI_bRo+9T|?OFKnsVm4I(`7`62!7$%kztXLEi&&^-?& zuQbVZ8#~I`YboF9V!_O!5&rDi>hrhH<#6Sy5B_HmWmwU5&+h&v=bj_)1sB56P_OQc zsnzl+bP{W`V7HZxUi$_qJp#{g096)si#)@%LkpV3%4VxG`w>AI-iN%NpStgvEAP>~ z$HT1R@#}h0Ufn1NXIWNm-5}VC#aeE|By#$x*R;16@RmVT#x)-%yY?XN zhp=gPWuUg{1|dNkG@y6^J8EGQdAJ>>@T);ylukqr$Y?5GT_xJn1=k?sKBh=VbdM0z zzC|)Px-8_&bk-Lhm&k$%Zw6N*Nk2j9U9KEL+ZRF5@{N$)gH`&qy)&l!m`NhiYBh;B zXbLbehy;E>ukEsDp4a3*MqNK z+o)}&(Bh&E=LTe_?VhL{bxZ>`8#(e1aS>kKmVcOh1nO@sxWcw$hPR!0mia39;cd#3)dN6S`t&AG$>KD5Ph{&l@&Q9 z_W$GPDuAMFyC~fuy|i=-NOyy@w1Sk>N_TfRBHg?2(F#gPcS$eZT}w%K{jdKFGcdC= z%g)|&?>+b2^E_`y#8>Twa0~9wrx(j!@SoFYq8#?n+HO2ijw5JWH{xPtE~IUU+^}*5 zQa_7rc=$Bo>H*&T6SvUun1q_R`ZdgG@5DQ}_ecehR_WLpur>x28lR`BEiz0Zcif!9 znMfFT1PjJAta>nW_%XG@{&p}HfoUkYNVQB zin8%s>TF5!Z8_7Q#fD<(Kl{OK1X&fi{`3Y+-RWuEacRX7TqEg1EU zkUL9mNhLdmbG-Fh@B|eHXtV{l$j8fE{Dmf->}%?f<(Y;1r+b_{gLb*O1W)*{DO8CY zzoMH7gv;7!I_j>BE!a3cnl;%wzz7!jlI z4|Q<@GGn1h|Ih%G2i0EbO3+(>9|5FYQgfb`SE22Dp|FPngvYxE?q}h@3HeIm6BiK5 ze~4JS5rGcSD7mjWB&~S{Dl|ASCLGjcvF2z{u0ppK=irU^Olta)Q4{AjFq2D!_A^v= z+#q|=;>oR((0Tw498}P@NdOKK zkosLp{y9`x3x(;~m*h@fYL}mK9Sb%?^xtCNYjeq}I5IhkU&z1gE1l`=6$=Nh5KNGh zV8oB=P+MRytn^wkDKJw#PMyVS32{1a#+W|}L}vDT^8PI8Y_cIzZg`65+4Ol$v!DP4 zo;u@Z`SNRM`+E|7`XAWqRLF0W@PkD~UEbo)iyj=r$_ue6A10|J*#m@ap;)ANvbg{e zXnN-ph&Rjs`QUi7pP9=`4&crHA*|6~L zZ&;alYmuaFvyi+6(K-QBP3;Oq@pYU91w|_F&Ixii9MLTe*Ul_g8C+p6Gyan|@w;nb zXQAjk09i=+R|*zX-9J7Mto#;*3^)p1ik{*EE|9_(fk|@vK(dKfpIP);uYug4~^j2AQ*H;=~Z;-WZDsB0?Fx3bgwh zHq%F!Zge2^H*R|V!d+mv64wOPB@b`V-Pf#uK+i*$esjZXBG7aGrTq$Jp`*S;)L^U) zkI6I251W;cG-Lis*;Mv}Nc_BA1`hwe`|98x(@RtY?zS43XBT>%(JkhpYKOF4Iagi! zqKsdbL|ulMtX%|0oxYE>+m%q=CmP*Zi=f!u7vXgf{+id{1Rdg`L(88J>A_zpo#dwM z(GA^=LbzB=>3P~gl3Got3EI???)Zb@M$XL3p@WvUHYdcb?un(H8){pn*Dl^_!<$L0 z&NTip{Q=Fv!{-hdtA31yB^qkL;QvZ>o3;9jyox94W6{Mr;k%MCDZdoEJnr1h(`7nR z?!2wj2|mp0=kimWaoG>DblPqlTG}6ze4&|{e+b{KY?kVNCaGt5qI14g_dpT0%)mjW zD*se93vdLjY0)GSEL7t7kdX?Cu>o^j%hg;xx2a@5t{uJ7%s@IeBQBkq7xjqHRA+;u z7UYD#91~;qT#MRiJ)i+5EUCv3uaTn0@p2dFIpUB+~kalv2Q?By2W+JL%QO-ed8d0n|nZD*=1?^CcBSmp8 z$8OEWPSza&SGRn3D01Gj0Ex@-(IpRQnXE*g{zos2Zngfy4(Tl5=(D*4Wsgaw|2{D~ zWi?|Xs?BTh@>k^|X{@Y7kizUSa!mQMA1rp16bc9JiMFM`R5TOiE08FX!{=f+_0jRT zZ`(1Yrq!&PLWMRv(eb!aI65lb15cT^{lu`C$h*u!de*v%L_1Iss*fI_6IPgummed3 z2h2h8M6O)W>=hom#9-!s-nfIBTST1u^Il^`p^oW+Mw$_O7W8>?{c_lIA9xH;5fuLg zeh>)!6{)e{;%39K2K?6?b(e|A=<7BG?=~g>}YfGfytOU7=0$ zKn9v8C+5NqD*VtG{Y0ZkA~e}iXbS7mHm z%k?1QiQ?sTfIfE}N4Bmq+mITQYFfsceo_ z;FYmgFZpv4;#kd-rsG26fcg6J1$fO1TP^Y=Vzo05)OJMJ$`D;ax35Dg_H~ezG6RAm zjGmlUi1)njy_Np%i4u!y52eO^m@ZMjLU{evg)r6|8S;1BWub1)%zpzDyVDGyjdy}L z4N~7+n`Zn91I4>*UKMD?ZpMmE3&qkAx{dmN?r+iJjrO69%S4l29iNINS&HCH7QiOi zVMsqyq$Z~FpY|up(nZYDB@uN^Tcv6`C_{FV!Xr8|E3NUNxRStplfu!6m8LRKt8GO{ zgD~l)0)w8g*TL&?9PYo%7+v6k=Ysear&23=z8cGKJl4NFu#q6=?i)a*4w-Rwc{-cW zi-3C2*h!%nN7H4wfbDMhKw#Y9uW+;S2JQo=9N|{@X5o@SZ|=!U7{D!GI358|17h3@ zI~Se?wbw2HARPOPI;_OAf|_%HK`@2)$oy@j4h$#gTRa^;FlY!i;VbB>v)<=ocNf&% zPaguor?&E^C2ZmTEL^QhgP zeCvNOb9TLPDvPt}5F97T|CXL<78SN4bj1J8%Wo#CGyV-o44rv!{^Um;`XESfdyo^` zJL0N47xSS&ft6VjFDo_u=Sp9~+95xwvR;Lu?5|YaDp1%*dOhXpY{V$)FmRQ#@H(sx zFqrY_ac13b3m1uQ+uIhK1&|iHrm6)cYRfPWcGR*&krV3*x=iL>C3@GIxOx`Uga#C; zTDs!oc;QfVa4F`r+fB^+BQM^p$?H@c!+9)OM0q;NeZKzC-jClww87F6MiFi>jTAQ~-$* zp7rJ>GF%r8m&w5;pM{$f#L%|PADkx^sb$U-PO*kdWPaZ^MObzT2osIDoBq;~7NvTM zY5sMl(M35Y-|C{;Ye!b-YNEB?>KxBtg6H&kc`?yjxIs!`Js(%Z!0zr14*qfB85ccz z#E!>N{QIJJk-*4*m7uLRe;QJRmVRPTahvx?3XHa`R|Q}|AmNKCUXK3Y^dvi~LEkqQ z+|ajK+8(jFXC9eCW!eG1RqEBMbW>LSm8;&f>V+`qn8rZ=6Uz)~voVz}x}Zm*;u{lo zlmb&Cj{TH?Z6n+8BPQYjGm$Pfe7q4284!#9cAGs1fH=J|dK8k(>n>5%=315ZxPVGL zOfG@vTe!C4eAz*&Jfr?E*xg62{3BHZ-OKDi*7yG6UAGoTTT$s;Z;1is!f^AX6y8VW zw~-PW-CrNhK<*r9$W=2&WOLENPDrM~JtiCR8;Ks5MWu-jm43MfL< zAtS%XUX)3yV07d-5g-of9#8N)Z2jcd_*Qkw=RJt?yy$9 zna_M(8mseUCoZYsU!QYd%Cu+fiy+_Trh3Q+g(O*|EzaG5h~rW32FgeI&`t!d+SHk@ z2YbdDPdH}b^Y5aqJq2OquCe63eF~Ud+ceS9*tm&dnF#210pYGCsk4|c2)9S)-CyHu ziBlS6D~e3y=v)VWxjo2;tqv@|UC#=itHK0&K=52uYuylABB(WSIX0HX)Zz?o$4N7< zxK*Y8PdeD#p92Gm6SS^^Kz4E2VD8k5hpZGNl{bc&gL z>g2`OEEghw_lnuK@Nt}lUlbMPW`>iMn_Qc8`_;ZpwFw{KhKQfCP7jqmx-mWup6#-c zdSyH+k?^8AZM{bDcg6@;%;>wVzoDqxZ^1hr5&GFVK~+OU9eEtdY*Z|YlQ%H{Q4c8+ z+o!^&QrrNIwP1(c;hX(DrNhY(4>^l9fH!Usi8?hX%^8oupEO_J8z%(c?Kl@Y{!4fj z;t|JQ$QlWq^VIw*k#&wz)_xrJ#@!)!4>Wr-7%9S@zw1o^X|Av-C4?wsMdYv0K|V;7N5#A$XW8ol87XuQrtqv4izA+d8_Fk&WP z>gMuC6o-N+zv$`63(m8Lyf}In?s;(pa||I`zrjlJy|9a zS#M43ZpbgaGO5I9Ok^T^6Zfdy)BVT|RR>Ze} z9$tiRLFmFG6xd8DSmmPz0vzSq2yCe;dbCkh5>|cztj>hm7iWhBl@sSlB;cv23M#=L zi-@C86ya>~b$Gl4Vjkv;wAZ;0T)hRQjU4Fs!-QyVPCaI;5+Kf>kzIvKJcjqg%$2K< ztrB1`>mlf%y{3mW$&RgOe+=(Aa%CK;Rw^pcKZpqzu?0W0kH<0moH@LtKzpuJTi~-&Rh6ZamAON@a)WWqd?GIKg zJDFICG!V(1Pc@_3OeyRG{@ksOuMT=2rbjpY%XAfOb~I5=XR6N&-k-_BqJAek;|)n` zDM*BWCO@EHdNm#AlYzllR;n|Bd(cTRsqS?Y9fp(exjjiPgh5}m_?A5)J?Rc18MZ5B ztrpBBG~8H`dQiP5$&z-Sjrhg3?omga^MxkeEH6oj5uZmly|(R z1r*`?i@!Z)Ap$sLQjuphHo*6dm)EceU81ph^y#PFHRv(-6u}ALk~Q~aquK>}`}kXm zCt$LF`M14E>I%-;-rQLiI|JF~1w-+Pcy1-Proww32^YARA84^CR;#jU&_A()k0ugA zBg;iS7Cy_pu8l#@!aad~c`~Z%us*hP|8zkJ1o%IQkH)=&zNCe@Me8AFe@m1lKm&49|sgv`KXE!c0!9(%;5#gw+t;CJSVq|(9 z6+K@E(0ZfJNu+Wq)uS@I)nQ8L_?q_VAP2eA3gNu>7Gcud*qOIN!xJytjN8Bm@tTBw z^c(sAwspTwzhhN!Xv>VmsK>Pou%;$TsL+%Qr|?Gjyj!8m{O5~pue4(Sp`I3cl>B{l zSjSnC7B?W_;IkV3D6~aJ$QM@J%yMJ&GtAJD!@B-J)6g91#LS@=i4;`Fm+>M}p1VhP zHf#CEXYFI@4@vBVsyN~GvRiI`n#M4i)dlRgXg`M}8^%x;p3alelijWQ~{(B>Zl)VJj8uo5>(lDn1^FM9g zI8C%sGG3oyCyK%&Z=xXM5w9;Lx00luuVuJBkqan&sTfs%1uh+TW_2xref&6nh&tRy zzsV^hA3?^I3iw?4zB0eZorzXZGsda*k|3T;Dj0|$Pi7G1y<1H4M2-)&1M{ceaEa=9 z0eW@y3YuJ5sJ-CPu)lGtZH8$3%~fxQmdvLlybw)GLsWO`cKOOdZkS`gQC-dzro-Mm z^jMsw?&CUQ!pHWPM^n@>2&#b*o{6_WQ0KBLPeA}pho)#mIi=%-pZeWt+}IX`NMrXu z(7G^s32*@+_4V_1cFA!AvHzJyAImr+$$G12!hl_dur0;FMuZM$zG(0I*&NtA(yFND zHvzD*u{~5MD<^_RhN!n;grX6kTzw`a7Ck_ya3U_s4;an*^Y|*Z_~=6r*e$nr^ETIfqA$ZjWN>HpkT09T-9Q-E% zww(4_gDmV4@%F8gC>Wfd*1@k@b_pQiRcpR=HbYx-UKNOYpt^x4+`JeYsMrp@d#P#2 zs+!(9=uKVZ#v}{R$1AKnp(V(nBl@N24stCAl&2OWGD`ttq$(U*V8w{`K>^yKM~wDC zapEwY7v#@D8g|nA8Fmc5Y={rOs|N@das28Y^69`A(@W8PKzWsz*!n5fOzX@HS=b6* z%gicu$OR~N1gOhcFhDvZ;RF_u-IX`jCR1AP1p5MHt>Hy%DHwcEcTOHdqG{gx$QGZW z<r1T@ zXRAAfI@pt*0)a-1SC9g``(&(?h>p;sjk8}D? zU2{r-Hr9c2u|RgZSI6hQ^D5#`Dj`bmS3dS-XKOq}JoR!6=SlBQLXW_ICm0Q-|ehj+0C=LNM?dC%GDBIJ|LEJo7$wC$1uK)Uwxo@5?WER)*|s6 zGhlaWKbNgqPhdLL=9oDN9P-0=1_@_;vJ z1nZx$BJKd{+(I7m+)xNBkhK9cHJqCG{@0ZtoObH45dCDhmjtnOMi}ft7QwgRN~u~$ z^7g5b%$LeV=_ah|)}e#1`PgMUlH&`$x{ahI5a+#wlLbPrJ&)>%e<3!xhz+*JMO0VH z7R{>iN1GxUH*4NxQ--EX?52)>i|S=Hkv8YMA-%LQl6Bg}g{yajdJ=JW+V^oyV}vh9 z%Ml4pN{dr5i8&3lvSd05s+e?)c7!M1uTm-Qu->UesaETo-l8QC%z~wknHDvI;sp5| zV4mq*fq7fe`fhErFKftSlR3O{WX1zPvcuelq~-%w(RlZFwmo%ljLS&!lmu@h+`LLY zg}t37*1)n4&_25}!jkl5-e@zTUv1HXH}b-iJAq2=fB8<n=cT512J^cDj(B^ct&Cn<`ys(QnNNFY8F|Q7hMo#Yvtq zF@)fZf_9mrDe<~HH&n#L1;fp)pKK&kac=KWh2=LsMXZh-!g3rGR5r0`zaC5v?E&|9 zQ;Rx1gys)O0DTt)2;RS6PgPMxFF!CYJ4j-l)0079@(3AX;V>r!^Yu|+OvaQch(o-+ z$ffnoJ69av%7?r3BCp^R$lW%yB?87N8e>3L2XNDiQSz(?L|EhxPx(~y9OG=OY^ebE zgwLp|yWvx4Zw2tb56DHU7$LmIXT&9(_B37I`*Q!pls42Gv$|+dA3zLcf~rVxz@o)M zPgwjc#_~52bMJNEyw579m;6NJR~>)%Qh-ktqg(&E*mW(|*Xwqyor(m14_!iZM}YqE z*Csg-A3GU)pO<2EWROSmuCwbHPY~#kT<7fEhAy0utNb+!X4<9Eb zG)6&u{cD&@yOyO@nSr;UxGY~&YAi*+XFJ=^r}WVARkqt+gaHYHla-Xy**xjJ2py`U zCvB}yT1oecnA8%GPNAr*7x5z?5}&dzEAbUa}!s%>Du8(_8wJ zXi-9D(@O_V62Ut@D~0myQ@LlR+WxDQze1lM{dhiD;ucwHn$;XIi8?+8SGBZnj@JgF z2xf$u1#%HTarR(1f2ZeJw?;u*jqiozB!eu;LlEcW0EoP58-LhH;**5?OkztUHbWoi z3;=>1?&x0NJeTJQuX(~2b^5iD)v4Qe+M10w2i=D&5W316_*~D%y z%GH(xoPUtDyXN|)G1`Xvw2%%f@S*nQtCID)w*qT42UlHGzwW4uL`^LGxK*It*I^#Q zu;r=wQihNIvftl%5-%+rxxJC$k~Cor4Ayz~6b>ap@=I9-6Ryn?ml<~n4^nu!6P1oZ zk9G^{IL7|CZ6(jhaY{7*cJOALAIVi97ZU5vG>KtB6hIiw_i{qH*R;*H^5Qk~m2cOR zqw#5C`0G_VvG+azayq27ga9yP;W2yA>()XDY6_|eF|@eAmQuS)>UpmOuIQ(yWAvsq zjKjhOBC@Cl2n941nQpPCnMNt^8QIM?*2*^ZrB6e81nwrZ8$XS1nU4>@a-PO!0ySUJ zxR(@!?xyO%+iwYvo(SiK*k72NhB#9{$qa9=saB`12@sHAF;y!kt3H5;mbm!|I^1)T zW+i|_Ia6M^i`Pri9C~$RQS4Mdcv(KI!!_!I|HfCsasr6%-JIltx+H*{!YJC&G;iJ& z5OsKt{)?VBar5~#z|z7O(q04QJoZ^13U?xjL=@`bS@#8@tzz^*D9zzP0-yjcKqC1_ zdntY#kv|Yaw;a$x6u5L4?AX!)XrxB&3(pZ%w~z0ndpaXfagehz;C0!`Stjp0%ObKX zct2i)n1^Y)!n^yy<^RZj@J6?o_f}dobjcLjGqS{3oDFiZOpChLT66mV7ucx zKn4pqAS}xU^SKN0M-kyG*^OX=HHC5W2KOLhqe#tsRmmrp|0dE2WDuthMo}8jDF5P$ zIz5F;Y4{S(f5HpDyE40MVC*D!<|9U~O8FPc-3;W3n?l-W;R{@emuuN1i@)%|Kja<9 zZqjorfV7qp|Jr@kHf+oY{Kc=w2#{DKk5Q~Anfej_*4?9uR_%sF&~gY@N0wy|@EHF; zu-%qym|IN1aQuj%7)J|PiKoO+W0iLIWxL#62^%|F;>mPS4(6LdYSwuJ>1ot~iyn$& zsZ@4UI?v~Gpf(K2v!}?>8(iIHx{&-VuQ``G7}W|%FqC6OAlBoD40j9NS{+%`spCJHM<8BsZ$$(!ex4eBMWqBG%6=aW7;jze zVo^25yn=i5$|U_*dipsq3&fTEPt|$>1`h1dAcc|39r{ri$lrzxUFQ=}Zkl8NHqp^- zOAL_8lqS~T+q)hI=M2NkI^$WtU|&{jO{EjTcYsmXpTCW`M|f#%%n-ne4XB{M1aLAWLnkWs zc#L1rj6DNoPHNZ8JO^oa=R$$87zO#eENty9%2PF}MW+BBe^CBIq)BNT?BYK$fN^y> zq36LoxXHgC)ocM)CkyEd8o=Me0Qq>6%@^>I3 zDp=Q4{ZvJM< z(E9BR*kYe76Rv~4M%Gj)PS3{aN^5=Okhe;Bm3C=)d?Oc)D&I-$pJx4>GHV3gnHwO_1#Q%o{XALvMeo;sVq56(^TmkshPiDFbxw# zaPrQgAQGP3bxJ3SaWXmPJR7gaq+Dg{A<1oMko6Tto74o^@^yy{i=h&gG?EN8!@kV* zkv6Vm-AHCqVQe5=gm}UM9ELa6ywh)9rr*{FaMvSLwbm&W(bfyttS!@FKleA8cfs@EUqb+=( zV{u=yNvdi&hFJ}exvyFSIV%O7DgjngXVjuqL1Br9w=+y{UCmTf=Sw*93mH=Ae|Td} z?L6wnU{4h%nb%wrkg3uT%yR}}Z1v#-JSzlOxuDKwP2Nma5<$A^z1cmq0W1(nv6nI~ z<26ZMN9jRj9anu?q0685O{hGv_UG_|uv3!W%%%865Kj6Fv3wn>Y{~o2lYuPYc;8UZ zDJkf&J$hZABZ3#d-?iS#|bs^uu&}9Fdv=qVe zwsTNU+MdS0$aPvg7e`nNf3MPsox7NRe_HGYW&Zv@$j|S1^&a$kSK2)aJ^~@CKI#m9 z-M>R`np>MgP+wj6RiemhM`#!p-H-nGp`k$+%yh)RuqqkJ?_8Qw!$Uj0gZYiRE#IrixQCCI=wfH87j`+r_*T?JR=2F8Mhl4fXl2>wm?P7ifziKd zE+pS+OH5SIgzM;dim8s7JLC_`0agv$YDU+|!6 za*Vosq>yJMV-T$eO|bQCcT&4Kv8U?@t6k923SWz_^OT&SCouxmS=w4g!1l0@J-EE= zi?okAGNOtAqQ*yo3m4>}iUTeEmEg$(w6t*|9s!8qYs=E^CK+{1p;oqU&UUQwlP9-A zk7yDfFW4Mc^C_M;MAHaMF8y$WmRZAxa!Sd6HtMRfXUIYALm^rywS6`)+drh>#AU=E zS}4McTlmsmle~2W&Qw48sd{=+g~@sBO~~)A&R~<4|kq))~^9VM`y#P zED%8Nsbk4ks?;jw^_k;KvzD^fjqpiQ-dX+@FowR}5B?*BB(gX76qmU5GX3s(l|4>E z9|{9KVL4bYKu15>)McHZCVUJ`dNvB-3tFq3<@+sFl~;Er38Xvj_*XSXOWoJZKTv*s zVT#t^QnYj>=q4n`kGkBv9r$WOReeh39d6wtAe_RU>+XN09zpGtc+loY58RXZ-iVtX zQf{S-O@zx@xv3=a4+tuz8IyCxX%!t+hOf6h@Z*}&h-H5*Za3&EjQ%7c7sx!7N*^Y% zRpbnEjM?32^}IZ}y7@UIYM|QhuQfW7xaG;LPl2RI7UUZx|Le^G9i$O_9g9m#pd30Sc*Q z-zc?`2k+LV8%5Y-)Q(g6188G<`G44U<1105zRX~{FwsDh92K9P$vH2EK{&IB;TA=CCJg2t+Hk2!-_&; z5u^>|^*J>UNkMHed&~BBy&$nV@XOB&rp~+VtnlDWaorg#Etx5(D}|NrD9=~6AK#TQ zX?fIiCku+kCo9l^VQaddq<48a_3M9HIN)2aqIvdU-AF|Oas(3oXx*W6J*3a_26HZH zyxLEM&?*@F~1m{Lq>b0tuS}=}NjKh=3~@ zztZ3E-9N@KiZ=Act!p`(NiDdV80u&i8O*ldBiDO#oP0=SrXo!iS5##+M+f@;91rbV ztuVsr^@R`^q$YFt_u|ZMypQq6L2dS5Ve9xU2^f{jSEM~0Jz)cg)E*iR>1yP}))d<*)A&BJopcrMwu&8;?B^1rs4mjI_=*59z+J{5u14IVy9RUN6H=UA!)~){^*RbaJiGBF*>V($zU{-o zvWQyEfYaeJH(0(i8pV^B#fu*0!NsZShOL1Zd_c`KBl9Ic`Bel1^b5&z*uivCBK+w# zmFKRW^h5{3`%JVr=AyWCmk$=0LuaNew0RUl+G`s9POZsfH5K3;W&K*B8VfVaDteq1 z*g_I(5CB)>y!w-WGTI{~=`35bPL+wM^a2zF)rdSNcKg&?+x{m&i}o}56P{_UG$}~za9SV&6f6_6B-){>ID?`g9yTD!Duap z*E3v-AJg;&zDgC~*AMxo>dr#TTJa)wkO-|jSUHJacjyL(zD0~3I(%<9BVA#E`x!$) z+YoQBvuKi&)jAXz;#<+joh)?^N5;KShf)0^%I;}^_Wb+-d$bd)Q#=V7yOo1wxe_+l zj>*`p3e@GgVwTeSxfL6DZio`8r0pE4cv?k-8qLt9*F1PRNjziWw#9%~0%!t{o1&4T zvZ#QyyQiF6FQWbiT%!$PCCdOJl!0WkfSmc=CpIz1wCJ!Z3GOk8**5M285hC7l-!G1 z-4j3E`(p4I*o(M=Kfl=^AqcP80ubU81#C78x9;b7j8!L@Q_?gs!QgDm)>PeuXjwWK zkBNT)Qkbm8h6I3t;qEBJS25_@lCy>AM|=MW!x_@wo8(61A|C)7b699@oaQ_aXqPr7 z3d35ZE{7HvBELA3rwm z5Gr)Md*Vlz+qyt8z?t{e=u_PG5f-C$8Xa9Nj?2FPI#O#C&dgBo!w)){*2ofEh}Vn%KT=wYDeib2mwGJb*K4XS2v<CGI3ME?`zzIJYKyGrT(zojdG?Qz03rdg8b&5X zOZl4cs|M`n$AN?dDGjapqXvbBl>(U6gP;52BPq2|tKxtMU|!q>%!^tu&Qf(RU>Io) z?~Xtmq2K()qltvG*#sKxkn5BQ0Hr7}MsvH-GGm|oqDdGG_2V&d&S0m!_uE^GoLDyE z$+f@?`-mbas>3bockUC;lq_S!`-7d$n+15Bw_ilTh*x1>u<=j8y@I7w&Io;fgMJtJ zOO^?jOgZMjGW0(^^_OB>lC_2huShqq4+_YpaLb~JKLxJl6Q=^Y}%-8bb2OJ!IzJ=w~BjPc}j1q+Aw?m9-0VW%+oe8 z3A|E$$Npc9Z|J=sZo+4bgNU+tL=}d@ z)El4tNrI`s%=uJtINnlxdVqf6Q|A>}%9}_OXDJeo;YQl+hz^`6g*18=1r>OHWr({H zvQ|Q^s2qWyUZ-2x9BvHV+~*l??b8;a=zGf_YXyEqu+F*Si%Aiwb7q%>3V?+dQR76< z@)+Ea02Xql+!v(riO%i^8m$#hl>ipEXA-qJ$*BEK<<(Lo(?)oZO4R@&iSSt*?&JBznCO3FZB|f1G9Zv$tP7GNyC;eQ~!0 ze~KQ*&SiOiyYBQ?t%z?!zQ7ZlyJv-{(`gHxx7($Dn_l()uB4f_+=v|JmV2+Yf)Jyt zNa`T)HXj$6oS^bE2)MF(6d4zr{LO7J+dr&)q}JnO!~ol3*ncRSJ}o2_QNS^?O*Ymo zBK)Wz@Q3rejG_$g+c;aT_xe#ohIHZdY==wHcQp7;+o5)LEafwl57Lj*c5H?@)iNzI zIWR}KejRN)(XrBz;sb#n%)A#cSpUL4epy6JFsXFjcs7`+(nk#(~b*kBXd>f1>D`r-Lln}pk?k%t+VlvkIMR1JfAopPI2N8+YEeE#ykz>;rusk2k z`-`d`=Q9ToR|kGdebU623+zi_voI+Q(ZV@QCE#EMVh8PSxdw>>n8$#h`|3Gbo?v_U z{^B0b$0uTD4%!~?J2?<{Ei>e!ytGB*I-VAd+G((CeuJ6#3n@0mmJcz-g=6x=F81Hk z*KX*{?7_{rDR&KnCpOZ2b6AmXj@{0)9yP>)i%f8hrr?4|nyzFcjql9_Q`Kqm>@4i1 z<(O&pxNy;ZP_w2Ku1pw69g_1z4A`PuiC~}lbYwW9&aH3$MyMV1uLWGL7FKL9X_&e1ZgAfu#lAT@}f@`l+)rYN=Rrs*i`!F;)Wm%8k>T8xR%fdx6JKdZ8<8;d>&)K!OUe&y;t5yo1l&HX> zYbtyhtqeMOUlXO%(gWA+(E?Y@_vh!V&fDyS1vIpqFX`cb3L=Wl7Nuj<7BQ~sQ*e;j z-=k}PFQKKaJHfMW^u%A1c7{PRhb$sa!?aNgU!#kNb<`Ve;X8BwJ&0{lu@uaze4ua$|2E<3~8#2bma zD8+FS@JtZVBJM)$wcPK*6|;M)8r0)RdzmFVqf@sv54hMC21Nv6mF^fi9=^27>UQIM z`Y7P%U4^`(Ig{Fbb+2aLF2o}#0{rwq|2ULWZaWu5)TAZg&t0cT9eLfj1?-b4ny1F( zyh>0ncTK{&WH~_G9q3aY0DulvFNH73+Y*?c@3@@_0x^Aowq&#U(H-Q5v=MU$wndVEoD}%M$cyWtiYM9Kn;U&gSpqlR6lLRqzdbN=Ya7V3qj3Ixk`REb1fX6D6A%Frn{egNT%#D1VD8JUDrGx}37`={`^RlvOdbtA7;G;Ev$XHUM~*%U)bqL&rwvvD3Uy4|ax0L}6<);^&xnW4fW>5+Alaw3Ca9eIoRn zZr4KVchhto;W~mqFXOa#^&X1U;jTa8O9^GF{2AF<{F5RJ6{s|2ih$7a7OMh)OOGO& zp7@Choyem5??Zp$%s(D<)# zf|m<%gshPkg$>snq?o`&Et!k&tj<6+x%R*l)OjQAbS_dy<3s3nEfw`?0)-b9xpqjN zHNE^lJ+HNgjm%<+r5H|~GKZ^_^1lk3$V!}P7q5F(llDLKL@5^Ca?kg^$#sqx?KbILl1U4ulq&n~Ag^yOuq;>W zGRKUySAe=Pk|Le!Llr!Qk9^utFQp-VI`GRc5C95#i<9rhbP)n^+FUY!tm9uIm}LIj zgQrwI0my$9G*)ShjR&MQ@?-|n(8gTlqG<9@e>zKarJpDc7E-4P*NNxoGqiX|&3cM8 zaV%@F{@9W7prVMAUwWWX^7pZqDJaTtO`h9gcvn!+5v$Urx%?zhwtO{FBK|9!vf>g$ zO}ZdU33|3fUw2fCJqoe(zLrKz0y|+3km! zxPdXE3;Q4N8$=Rh%APFoc{Ne&wwM>l=$|cTJT+7VjD_l?cqAjmDYJ8KL3TEL6FRn5 zs8M~SR91ykk7n^*d-i)qrJ{Fu(9B%sXr$)L?=1q5ULvoz z`CwUrG`_XmI_t{{0|NMGOMks?pH9i#rA{%88#-i4ae-y%HKv-rMEKb`z*JrF732QC zhrRzZLKn=N>46(rTh$#Lx$(V{=f465O+rQfcpKBw^(Mt&d8h^d08mOe&DBU=AyXGM zq1fZtfoO&X5*fyOQRk0|P{cw_u8Vfo)mpz%=E_1Ectnl?TdM(DEs zq4|=fc18U4KvvLWopt`D7E`vQ_g=nF8jsN${aG5D!kn( zjjqBLq<%`4I_t2$eRuGb2rG4j71H!HX0m~HoKtd>w=Hd)5pB2m6&;n(YUIYj;j2%9 z04OrL8gIoxd-*6E1xhHwEVQ>9FfMMC-d!1)n;xEh9c3nTO0+jjdIte~wm-{XGyN@m zizpCjx1bvvp{~qzu7dK1gW&!AbXm#!h|y0%Z*6RD|6sNnG4K7x01)nxR)tm}!t{ zuwYv{MExWUEC<|oL)nOX9CaMI`v)0DZ%i!He<4EL2{4fu2g8>>})z9h# z>rWvQYRpyL&bxY`GmBXd!dktwBm(t`%*%Mz@ zM;`y~sfAU_5-sgsRw{y!q~^u1!)afGY~H1;JpQ3vPy0CeZ z(YAd-t4%Kd?DE!D32LvsBL6N84Elp93!9SxAx?Y+aTx&*>GB9`uo>6zP5LVXE&$-K^V&aVev=rl-YfSyfkvbcrv3&^K2k`4GTcM z@JGs(GH|`=M|YHog0=t?Q6M-$1nI{a3x;z^UfAk)RlpdG3|#42INZMn|MddcSpMz9 z+k*E2Lxaf|+$}4>a(0V{L$(~cA&x{5wlEj{ElWB0GtbjooD$Q}XMSvuT5WLGCGa+$ zG2*4Bp&P)TxiSS)+&#|sOdu_cGZ{c)V0Z0UCAhHFm)}tJsM6TxuldIb%%kTN1jO(WF&Sic8!ilWm4X@2Kb)$@ju9 zuUsZrzZJ>I>!vh!Yqbeg>z2PO?~IfxEUF3kYUEe3?jx3>$s%iEE^Jt(F8wfCe)v4x z`SE`oU3E~@eG{jY+ z!@9fQPwl5agTK2CPPKHkl7Y!!M`V{tFCL!2FRQi5{VX)p`!Mslmxgy{lOhAS9OMo{ zD%+|4gh3UY82a@i|9NoIfC)JqMa>;<+tvSzVhaF5jf3R0YtU!I!NNw+}hnI z*`>M$sN0!UcC9bWPPq?Y>k`BuHXJZN$0V8RL3;jRV8Ok^dt+xDB@X}DfrvZXKNbBp zxzaRZOBbC)y_Dw}FJZY2qm(quLUzkaaRD24)=Ln@zFyj6POg>Ahbml9e5mbAqgeC^ z?&eK9f8YDV|B&{kz%{h_7-@_^t+rVU7E6yd(UP>YIJwt4{)lbgpj;Qo0lY_tP11a4 z00eEu{9946iL+Jt3W5pz?TC$HgIpsVZV<$lH8@;rB;p!pH{1^adLw3IF8Yf9a13*#Erf4lO>8`gl{?XOW>MZ$UVBU6Y!sL6fFuIC$+2 za%E}>Iq9XnqK}kO-pdi&v?fGF0mmVZu@TX0E~!U(yR!W zc>Ky4EVa%5b#Yw^>(FHdQa3;2j8zHc26xvZAvP-e*QB3NVoM+ z48N{pTJGc=9U7%yz0$ZglB?wK)X;s%eT>sOLKzOY4$pzcUOCNwu>6OlVRai&6-Jn%yGjQPd^l7ECH|#PE`Gj*zr-q+ z=b;4Kuqo1IrU|rvs?b#VuyCPvHP7nJn+IX~Hl&`(aTLETQC>x?tYpRF>MS*W@?8r# zG0l#F{im8$WSD7E(GvaglA0z?MRA8z)OqLj)%-DneXZ*FKQ36i-;oXZi+N8WW4m+! z$3fo`Ql>KwOb7gJ#u!yLX+t`>)8=Misd=uD=aNu&~?OaXK zVriVd*#hN9n5CP^muB3R^^LO=HkP7)7#2{RY><}rX0+sG!$~!Yg6{GnFlW-S zqypL#RJfgZTmrL%lrlWovd{D)-EgQM^b}|6wpA?_N%kQI2|0P=D%H(sh_%h*)?_Fu z$0;UslIlv7v2*^rnTw?m^(pBJQx=(g&A1MEz)!(gRgYiVB_9zd!m13B%WgV{$)BbVs?RdXfx>}btTA8qn;icxt`e_PT9a|i%-?W2SrY)CXRp&NZ#CPR-sQO+- z8-gfg-ux)u;T#;RPF~pOxd8C$-SDN6`rKcF(+Bp^ZtPMrlw6PHv@yT9Q+1?s0S`>T z+$N6w$&{oD8NOhgA_Ak**nG>1{|pbK@|NKYm3&cXEH~55WD)*ji|J2z;8RlIOr+A4{=n31>qbH2pCuED1Ms06K zb+^IC785(v%=FmxqUHb0w4HV9z%7xvaU_8>6UArtxv*;|YCFz!$|~~0DoX~UKJBP%j-m&zA3W_SZ&Djzyx!v>Fl5kihxV~B zRAX$h+QcX|NNQtg$>c-=2nSuYfjq6jv}H#!A3D%e80c|7yg~9r;6Bzm85bo=ca@VA zGyUYJKmNK4v6@_I(on!o6;7~li>He=R8>V-(xo3WcP#%?a6$_}WlVQ`td_g1_^}Ow z2d~yWZ`9EFrPdJ;BAALZ#|fUCMKC!;XC>KJ;;&CG;;&AqCx2AjvHi7H?UefMP<~AF z)@B5OHuDahU;JGowtH14k^SzTt*kdHWNQR;}; zAl~(I%$F$wq0PyDd083N`NIx*v@h}{wkMGU(saLqQT~m(?Gm%psR4 zIh5P9EfxK7)#*OySa+m4L(IsFE(%OpV@qPAqlmfF`s65EnMKdvPS77)j-qO4nLac8zGI;I--qZne{!TX&HTh*f--8$iO9uaFf%N2-!qw7a=ly9W zOk|kT4smQbphm^zN1_N>jFCCycIM)LS&cY5SeLGL4vRR)u*|>|HPJ}4MB<;)Y|>?N z^>&R5?k^>E*7auQ@tH;Wc}zCG)S*5G8|}wC!efBs`hppGYeg{i-oFB`+`2HZjYU_R z?T@ex5Ir@LH`%X2&Rg8Xb8sFkwH26@sLCmAA)J#>SBhbyIK|KxtIoRJ5zh*KD!Jam z&qTh6G5(^?)9I>c$J4TKQTHF6Y5UMlyAB25joZ3fA`yEegLmpAS$&n(uIVf+1&=bJ zeHWM8K0eU|q+(33hS|k45dREqy+LmjgP%?CpXK&c+jB2wtFVmruawvPbdP}kMJHT| zhRbS$Qelp&M%Rd9Yo2ZxSA?K`gm6i-Q`pyyrDz_a6GnrUZ~nM}ro<*^ugyB39kU&) z$f2N$r1u`cO1H~3KFAH#SV+m39aO7mG0 zrNanO3DYu&n3QXmJ39s?rU#pI2-1?Db7hAbIFWP>8P^d+l9^tlbV46M$pO4VKJ2jf zD(Sin$o7iJ{PD*QZkY>0Ul1Pie32gUfr1$z%}gFYY2nWHB|=J{88F|L;LZk$o$k+>6WApphjV|&v(CDzxX0lfs(AyOc z!bNEb(6N#oDjjvmqcUtDVj+`Nuk=_pJxX#3BuBFKr9xeKCE$|2xDK95Tbh^dYBRjx ziX$l^fHbecx_UEeS<3dc(-9+4r^~M>AW<%1`+}~M;xR5l@Nray4giX0YDdH{*yhm| zJ_@yWxr5TxQ@u*QiSI72AzYFPr zvp0!xU*tPHW`%&VSK2%i}DNRe%FnpD&Ia=HT?Wjv#xV*7eG}&?k z8qOND@%DwEH2Xz^{qiAsX)CtJQLyS3a`0&EWLl>5mOhO!2-PZVbZZGv!CeN z_~5r(e0#tZfEk-$4Koxgpi7$#Q@aFaicUOXIxk_N+d zq-*FzdgQ~{H8EoBo0Jx{D@wi*woHYQoRNv=5%UZqg;D4CI?z&$HNeVKN%V;SLd)|~ zXe*(xO>hHj3*Al3P{%$Od#v?Dcp_>|ZPUrHidZ%J(143i#XszTkWOmJPTJ1mA5QRC zhJhhr^_YZz$hc#rrou65oKXl65&?zGB_Wo>Umal(i%z4;?JvR-$H{+ky0@2vNkv+4 zur;1z2R80=3s0p?y-Y>~o9d_nZpF^qtQ3saaTfs~AcU0n@l{VdmBdKY1Ly+=Jm>y7 z`@M)W`ySpq1-})FTbm0gZ4_rX6{Pi9Z(Xx(B}RIS|HbE=Tbc^zopvjQ*J%JcA042Z z0SfQ*%Mk%sE)zV%%t2pa?CQ|KR~3TuPq72j*tlTyX?eonzVs_6-xiHX=Xom9dh2gd$%m_TqU(^=;PSQwRE^_bBD5fFsn1DMoQy5atIMt@w@~!VWtJ|v-EzJc=QfK zxxa*c&bPzEj#jJw8Nz3ezJk3LixqrEPdT~+T(|^qs@X1-Qp6>T=2Ie!1GDIt+DT|` z5NwCetduKSy13SuDhMDm&^mTrqR!iTixp&iR#_h(31Y7*izHrv<&Wpu>2{aLQh&8 zw_Va$eW@@Jk!zfN*%W|Lq6;AVwW!KWb(T*Q!W&{t!_nhH%Ee8z*d|FtiT}R${qpX2 zNp`j7Jn9~AkX2Sk#A_Kl)pZv6AcreeIVj`HY!T?-H36iZofm%q7cZ~|^ztu1lx?^8 zyxA+$`FiSOefQENA$mz}zT17i!aR-N66v~y%}TD8X^H&G;Z|H_{2i5-b>qGxs0?G& z@8~OJKrX7cbb*H_X36{{Zklc!H&dDt1V3-6Di@DPTq>3kMV*dS-;ftRkvD>Yk5!vg zEoWjmP7jQSIdW$~fHgads=>jG#+=WRm+c9c*H)`MWTyv=6Ef1suVP;Gk}j;FYAz0x zefHBPgS6~Za^K( z0D&2#hw6_Cg#17a%q*uv_eQhvPo04O@E?jA!K4}mk5dPu6w&Kd^w4J~iJ6hcn-Cr9*FYS+;D;hb-r=)Y#wM(^C#}1G`jVy-TN}m( zabf!@Pa20aQ>Jqj>HM0AU8m0TEW|05H_&vgM&Ea(OxyPsS+oSWvef(dDt*PgVup7b z80!4($rGc!dD^V-5euut7Fle++$;OO7l_=0=rM~Mg9HX|peV~x-9W5r1Y`OQt60uG z%hq@~iV9~bH;bIFGArHu1Wt~AR0=~Hlb^!DAUz#+Qor#1Zf@vzQwQIZ%qX7%;3Fr_ zr=Z$*KQF?dp0)96Jj6p0E6@@RH_tE(jFuVGiuTqm639j^SobJAwI^}&O_P?V(1vXE zXlQHjVt?r=PE<=fiff71`sf%%ci}<66UQvh$67-yd2Dd`6Gph~KgxMucwNdJ4R|t_ zR>4%gdCFoGm-Rd@t3L2#Mpi$XC*KteSnOASPXBLbiubl()!~W86L>|e@9F?u0V~R* zq0js;G0tAH z(vWmLMLkR^@AclrJxl_{V1;{20~y|`A3lZ-wMr8*4nAGzu@Igfcozl(nGZDpbH^yp zDIOm26VAmtG%_*oKknHCV$Dq)xj}56x7T%DmZUOalB&9GRhgJhb`HV;7KgisyDAq} z%a;<$KLvUFZ~?gANxX5Kjr3eVLSQ?$KhU*OvNj^)u1QsW?p;oEtXew^ zO`R;-^!rHYa>~Em4Y-5Fe?^x7bm?$2$*Q2OFO0`~Un7e?eonp;jIT(DH6Oe~T7W48 z0aL)w9eVnbi3h9nBPUyTd1ws$2iWetRmvRn#7=g^n&}B^kbxHQQ=ACk!>g)nCpIB# z18kr8*&HjPKF(O_s$qRxo*ZkC_cS7vPFKbmso=K(vJ+$&o{_23bkR1J>Drx%Dn5mI0t{JhN+cx98 z4vZULy3oHFwpq<4x`G@i5hk&J+;3(g6=u`P+Ue49){to(WyUBn;>4-a_r*>!95ad6 zq)A7IFbij41Oj%L^2TwlIzTk^9yxyki9k;P=TKJw5N@uRNs@XMz|cOp5tJmo1vXUvd`-g^oey)I@(2K&?;JVA*&5o!;E2 zg^bm1r$M6$j7Yr-)%r~n>%ESc_FH;mh`cuuyY6D_qE_3_MV;l#J{_IejFC(>wNFzY zd4)TVv=)*rmh#y27Sz9K#`=?L$?z6TSjZ@?Fzv=MC3NbeC3^X7z2boa>V;pN57Otd z&DbOz)e$=vxC%c0Ww)KSBmz02jiy)V*1v`00nUGOkvF&g4|c@DE^Pp5A-xbwyIe^u z(+k`b1GK3oxh%d>dqt3MsY_F%waHa>H5v~aT7pv*-K&;*n+$t6I@v7fa9^tU@o1G8 zFJs0A6)yMx7~r3LFeI&G_tlfHF9%Jd=W?tz{mo<7FYq2n+ri2X7{i+X8#s_*LfyCtwL9(D zj{1+9Zj0!1eD)L@!|qQSrj|4qW)(`%TYHh!RwraF2AJ2%>?`nb>;P+xf)wfh*U>mO z;Z5DexN#pX;b0BUR|M`^$z6_xmmr+YGCQK8Ggpr*ozV~W3pQB4KR&UqeO#3<=kLL! zjN+5YQz#O>Vz{Zy4}H1ufaX78dolyz;F7jeJV0cVe8D^CB1LR}}q8{jI7N1Ch5qcu+> zrPiGRrw}GmoRRONy>?o)n_s5&=ZS>T+Wn8wNQFU&^pA)sdBh2Z-A{Bn{8CJnQf4ZI z3^1D|9vu9O2SV!I2DjJPp&rn=z2ua8X=_4Vdf{9MxhVjd{d4PMEqf1IRSajQT)DxR z3=2?XDp*$7$q%4&?oDky#^2d#V|MGasL|u`y%8WvKC?>IQ)JgkkeUjM3dh_)vHgB} z^%t41FLt(8(omT+w;4E=Ny}19!fD~>dyt8B(s0%Gz=LM6A-8$lsc8I)lSoco3O@UU zzzJmcM-mq|K9NLb)sOq`q$V89#QL75ged&IYJ4G!?liM>+fzfpTDu*6`A>Y=YY?~{ z=W9MFCsh0XBrLNszv-roo`~W(?iaGS)yjD?N$)L(ysLkr((et+HBx57p5zEuPg>qM z1VxT2xj=ow?Pj)ANgX!41prBvcMKAkWA*&wE3O{&0UmAQL`ybQM|&Y8jcsPqqNj8s zJ758=epb3z(>*gG*h?~T{|GG-uk_$FGU~;;^^`XY=0IrfX{lm~*NDt)R38FpRS~Cg z0prX*4iN7h@{$o;BpQjGy91^2z*wEuAO~&;gvw_z8n#d3EePCB&lER0Sf@LZwO@_lzgzLg-^+x9IA(i{qL~^E zR$hv&DJh4EcCqSccP?*-M`T>ZT3f9 zeRMo7Kh=S<=#ftC2|ch9tQr%*Q~X&s4=L5v5+_YW+eH}lsbqAs3wIug&sLxbOI=V2XwPXtr>=LMYqM0y$kv*tf&WMv(lvLdTi1tgA>7n6+ z&^9Oh(1sp|`#*{Nub=)Xj{t-U@P2jFrwTsCL3a9W4??sBH*T3Jn=9ZrE|?G2UNa1) zV>ko)VBB=mq?n()L$>-fbafb1xDUQ(1!4cZ-5MV$;MsFYR$nL*{}cSt_$0f%ctB$K z3+K={2p^~}x5nGaKD$ECu3N!l%Ou}5O3M7MD~6{y12761Gs^~34l zzmcbiIKS+MQngan`PU6Jyf@e!fe%n$UV!F};+Tpmv_d!3vr5*A zn};P3X7ZD1M_b|@Q}Rq^MB!x?W8{BK2U+~=MO9*v#hJHJy(9T2yGKXEggqlg3i7@n zukS(&)saL31{Et9NCAs?g0T+W!I^|R__1U^WcRtWq(jSVuX3dvAyW@`O8tv863Ci{ zm#I6iOf{Afj5gEHcfhdvND&THOWQw2qC00Rw^>0XpI)3ppoYRl%@l!eCZ152Ud}P% za?<_+ql^s^7kUQ%Q6EO0)$O`g?I*vp2CAvQo2%*mKndj~h#DZXWK?DPcaB=v*}sLb)$g+kt$0Au6rgfqR*OEeRG)f z?K{O5DvHG=+SiblYvtlKC)l8K5IVr)$<%BR72N_Ld(8^(?O*usMT04n1fb|5zH<^! zrYArf!aP=x_d}uR{V{hdP%2oMXSm44gXkuipdzAw#iD`Kp3!HaGevdx?I)JmSf;88P^fUgSdYdZ-^ZEJFx?l4Dwxsg0S3I#ggMF zUm;IkvGVLX^+={FHj39}F~G7w3+jRK?x|jOJqpFY`viF4Q3HBCmmdMN83>Nk3%MQ< z2%XWx-2|}HaO?u5uIB-``q8M1rN9GeX+e{qOdaF+sW8VOn~Xt;dK5u%Qr}&iS=bRy zth-Z7w+&9ByR+@fKH#g5r1wMHJs;nluZ(P;XBl?6X+$|G3a-j{Y~tl12E3{+KUQqT zyNWmm&RzZx#k}aAGk@SAJ1~pbo|-q$^CyVGUknAg&r%0)^jiEQ)Nt-NjJhRWZG5a{ z|6J%ku)Xs)+h>f3@9vlR@i}&O*Uo#O^~Ce!npzz~m=Ajosr+X;Vhi{4yI~F{rLv5!cK&Yn3Ufie>ax|k!lVOF zhCR=0{GLq3dfy-HZ+}a-p7$HO8ioRwYl=Preh3LLJ2HhM#YuuFRvnLm@NxnOr4ARl zh;N%FavBydIF%WmI3I|{dK*xCqd-6{X&3y;vye>beBe!C8@iH%-|G)KCC1*S#HG|} z*KhbrzP|~FRgDI#Dd&DNZ#_D*I79p(6%h3VwosBxIG$s&^3}$QFC7+S$nEnJtE6T~ z{1|~`_kGn_+HJTtgK(9m%01PM^cZTVai}Hk)oH071sJf=Y0ueOeASp}LksMh3``?D zrC{qD*5XE7_88XSB@L9s#7yj96pD)&irLx$$C=J?7C8*~JnNZW3v+x5vyh@Txckw4 zASf1wS}d*cAWGER)N42(*&2joy;tOnHQt(moi5Z$?-K-lz|*ak;g9#1BXQ<_7F5$;f6q z%Z=ZXN9m(|#hR1Dzf!_ZfBOBl`3_r+A_QJ3MeAr1b?g*JM>wF%Ft&Wvu38v{MSa3q3;d* zKGkDb&cBb`UUv$rt1nnqLcJqnUbEc3?E***z8Hf+Cq-8}22Ve~aqYi*AK^;NI@a)+ zmghUsRjXs>7lkJZ+fQ=pu`rQ@U9FI~TKBpt2U&n((y!QkdLbXan~ABSlrH`KRE(4t z0+ns$&WR*4*)R3FlS2T#&&hDaT)F)n^44^oQ}PKwK)IZ=c#cp-{soX*G9{SO_uDY7 zuXM%NOR)B@U#V9JI7NcbqG!PS?bs`WchYwEriWM?==sH+#qaIOTc?C12Ys=axP)VQ zS9qRG`uJJfg?ZND-c_qgX^3459`nS>PgG;r{`qf+J$6ap62p=y5pvKkPgBx}TU??a zfs~q&7x)=M^>xSPyN4r0ia}3h2NXGY^SiOnqMMuy1H7x8=^=?>PC}gwk6voqW*$QS zS%9`$Ds)){kv9U3cdpnzEJCSVUN>c7}g>`?qnqqLj?gGdJ3aeaSO zJ0fPjwPEX^xIQN8P`3vlm~_aa5_H;j99Ks)(`JW{npN};aA(?uTAieiu;txRDFL~| zF-xtmmxN~`LHh*JH(kojISs}kCGNIZ5P3pD&m+PO22Pe58D$s3(LnW}*|Mr`zxSn>LCr)RH zHJ*2|JJI1EF5?}Z`X|T!w_$!-kwwz9Md&}<6ISRYzsX$Jf3M_(!*6sOUNKH``raFz zHkMJ5txCaIpApXkk}6Bjn02DQueyVjp@+W-SPGke@9X*y2X9nrwL8eVvPw;lI%o@8 zOf>62x$`0cn@us`5x@U>pxyfH!MJj3691O~^d%vh?-&LspQyjtgHS537~n|}|MwDD zhE+a6aQbn4EuFNP5s$kf>fF`4Q=dPbTIU#ou&Gn+lnj zb<0hod)eY7BNC|-x{qdnp7wVzecG7r)Ygi>C5A^&B1-00W8I%|nx^y-itltpUrW*W znGzidl*j)B?#~jA`{^7)2q9#SBnCAK@Mc>$RV=%$tsDkvloPFm@@%eQvh}*Rwk#15 z%}fkG*>V2Um}A3z_QGpVV<8ttrjE_a71-`mHJ00I7iqCXQ`@8d#d@5n12r=O%Dn-C7$^$E18eDf(~?O;L+(_ z?V06OpCA$T+0NxpR#-0Mw3wrlyqHS$D_`m2Yv4~@iiIyRm_tzGxFUivNR@3WHoFHr zHmTAu4>sQ|KiF*cm{7O`Ck=Dt+OOW@!~#)p;1@rX7eBm+UTVb6dw2=Jg%SPyJ+Sc^ zLM-^f*L+&opw^ttV3fu4uhyY+K)Bm~>ynjAc=nzo358!B4l%-`7R~Kj4^(>Ls(-{E8bc{f zY1e@AWX+4t(aAN`(90#2TcGmevs$%a(O_R46bR2Y8oZMX*o8ez5J$+@(p^Yc#s-E~ zYSDz;+ZjIW-wK5R#RAUQt<{gv;PX#tXK4Vz zS9Xd9EWfmZ`QPp15!Gp>@rAwc3k+k3)p?fP7Dzkm+bs_S47%KvLR2(~D4xdqMUf@a z)N#E^ktiT8rkzaNz|{k3JTxt%g^&U5?X{|#UsZkrzW~D>7a{ zGjOAYO9Z<|i=m6&eUmUXe75JP&51brpLZF5&?FPm(uQ2$Heu*YPNfv+8HB@3{kU`Z zN#gX|Q`AR;?#3Sjluomq&6zb13cZ#yw7@=XAO8Wl*L-=->0ZeLCuoi;qVOy7mR)}T zy__AlU)_5YvX9eH=>YC;r`=I)3GUVz{B!_p7^&_^mE}lifOnXomo5}o9^y$QB;dAj z^t$tVenY7fO_d70=3zaoD$DPP?}iiV{lJL%u?PCu8?kNXyt~!2P~| z4WFQ-J;`MX{~uda_SmKU(ze8{$QKMe_M)xGE|L1LYKKrC0YEixJ|CpQQsoMLx_ELm zr#~pyenPM8`oM(SpgjZ_qHP>)TER}x{#`g?<(U@}GT zout1M2Ot2}&ct(rI^ei7x(P;>?7In|Q^HYvt1uD-g_AEVh`GTjXiHiq`ajW9xFcdnqT?D#uu3I z6wR+p{7pFhsEBVZ$Z5$J7zRJbis{W6~V4^P7gCeT6dJW&CS zYI$@END7Gt*6o2mRs{9k@qK#$%zV#FKwJ>LdD=qr^vr^T?DEfYY1$P44#{)50&otW zb|QwE&zkPr;EAZdk8bPKAM&`f^9Mb{OE_Q;&8{E__8wx4%!-7MIjvdTEBTP{2c02b zZ?RvF3saDmTMpS7(DFo|E-8)I$h(_jYF|5P>i!CGf28~dD4!nXQIEu*v6Gf$>YBqZ z@&XZIgf>W?oR#ar-^$S{KW%)a03*3ZFE*M$Uz`At_%w3HEZ~=J>^)CF5nmv-XOz|$ zcaeoTAF$^jJBKcYOhb>q<9_*MATww#B6!}}KO^I&u&%39ZTtJg7e0N}3qkmTEG*$u z+(M1~&+pa5%JzJPG5W>2QiHO7Ui1?+kq96?>mvOLe_64MD1RAg5q3Q-c3H87;?$^7D&<1c>6(qf+BMCO?vFv-A)3TKq38|m5Z(pjmRl9MmtThL$ zdW2*WfEZe1I9pSAl6VaoV>Tt$hi`>;HBE(#ZmG61PJwa4 zW`y*&i^KnPIZZp5wyJgD3P4Oahs(p;GY9sDpW+4*u~XX~IVlX*BX+hYHS+?f!mJiy z-(0BgKZ`HBLq)I=!K9wz)$!*~*WAtys znB9K}M&Mt;l>IM!3*@#Xto`RCRi8x?P;>rf$EdLG*X(j%P(Y&$*# zEqksI7i(ojYc&KhcTN*+mM@w#x^%VjN%o;|TX4eLCxkd!&=_mwzXE1wFp|chB#;08 z5DCF2`N;nLd-KGWS%dKooEDFpsvFi=W+_|#xsMTq|IgLW{LV}0wB@F+;H19s5eF-| z@$IoRzzAIT>CXX|jX>&LMF5&>kQpt{2UxQY3KWZgRr^5w3MGd9EnNU@^2BhtaWL!W zcUB;+0!YDln`;LuVpM@@A-7Auc-{np`~@ORn~4Fu>waaMbqZ*2A3*-WMNYz!i&Ep= ztfZnPPuO-G4uL^LNSidm2r;dAy6&+hkk^y19|vSz1L+RlAt@2kf$~a_&kF*zfu2P`!hU~yU})ZTTS0@NXM8NaUiR3bsqd-ysW6*Z%2-%1&C6puv<62#6ammadw zZ!E<{{gtUWQzP$Y1AoHBA6K@D@grG%fGraex391^I`yd}TleYlAKugBsB-H`%NG`k z>)S(UFg-uAOX%X}82~inugLgFI{~O8_8MZoMJI}N)VZZashU*j+j|VjIn=fn6UzS| z@^nv4@vi_xV7OVnbhO~aGDxVGWd`|e?J#>Z`n2sy7 zX{2l@{WuIRYjl*?QNq*Ulk!+7VpWyG4o1f^)yC{KX@HW7F%lkd+>60s(PY-s-sA^# zhy@7Zbbk2OYLYhLaNSA7&Q3^qDG_1w)qV&dw0GYU zBbo)y;iMTRK!+?5m(ruD%dDg4y$2~jMuqv!=`+qx z0YM!>$brjGeS0?0Y*d*hZzg}7mLT1FEnZ7uTWWWYq^`UGrCwD@zeeeVlOowL3wgzS zZrNAqnUv3$`;82$Y;u7)z(26;hf~c_BpgA;(!9-)u|iA8_o*8F>38*z^dg{siOozX zd)9{@PkRG8(;@ho`j(k#I-wD@?n6H^;t;W(qlv!ghIwefH=cB$W3B(`3;nNP*=w5c z^Tps6Wh(L=)VVF%c90|DgGOp-L(o$iNDp)#>w8k5nEQ%%H7<(i#|THD2iDmM)M{G8HG7E)!?pmCE~*Zu3s0q^!;Or8&F2I;&NL9@tVN?gu+}4?=~fZqi~LF{`%4E zwCf79v+k+s_z?YRwTC)rj;`;H|ai}W%4Z_ydUM>1LQ%J(VQ zxtP$?79z^W+Nk|P_RI7uj2o&ZqKC-6*XHVmSf9TUp^14uC$X>?EhfpXtAcUmI7-%R zDziEB?SOemlvr=LMpo}7)dCFlgww`gC6PHGyaB8xA z7k?A*O|;xqkje3WQNLQ!OsRsD(iZjMawi6_X2X>_>OPSRmX}m#Bp|?(7uTX%EVv`+ zjpJz3D}WOzUKZSU(PPQ*lr!x!QV~rswHe9$sNwrMn9KF2L(;SLUPM?sjS)fCub5h( zrXw3*rX|%8sW00djldmje&kwyu*HWRp8-$+lri%Fuya>C+kz+>xg`bj z00#p(VLt_`oc*hp z3h+S7d&y-1lR$AA?Xg#tVfeu4cc;CmUu;i`f7xM*Jhh`yz8EHb&OhjHo7Em-w0%)o zW_h3-LSrOo{h?Ly?J%x)M5kHhr zxkLaMswm;vS5alP9jxyf6qKnV)l3Dn|HL@tnP^A*(;`#+T{JAs0K$(UE{2=@ihfQE z84%1M2^g$iC&PMs=}be^S7l+inq3q~8hw=!Y%iPe99hi4JdNI*JsmBr1`>!UNe{Rm z$jtbC;5}<+UZBtcYhFx-CBQ~(0i3&_3AnGGeP-EXjS#t3tZ{aZQfNJLkhuef%0l?E zY>Oxj6F?gQ{CZ#}`DU{UCK}5%Eu9AyMU6%JgBQFjDE*xvSGB#Qv%GL^FVp7Cf$wTd z{OJ4NzGxIB;M(4i9RS_|2F>6M7d$Yeu6{-P$_uLcR&J&Hya`T$NMS^8afdg{fwMoU zWtC&>EX^!1tbhO)n$8%CR+Y&bStCDCNJrXlLD5JP43avj$ zWwqIkH=b%m5qb~tH@O=ha^NZ>w^*JmL1euoynUqcL{V1I0ecF5k*CNW`lZ1i%&>l$ zmJGJ(QqUpi67RRHAngUo*`g;B&W#%V=Nc1XN&FFxf8-Lc-%u#0mWpM7m4>1*7A_K- zMB8ibyqDDIStuP%_f-wbyCG@Of_E0cA$Q_(4ei+RZ1azPy}al%$<`EzeTd#KdkR?N z-CjWPyVhhwpOssMy8%KKO{(_qe*KK~E5DG>Sl}`wJeSAlsG>ZFq1w1*{%|SdgCk(9hJHYAJ|pc!adV+)!kO=^h3_ zn*hAJk*N*B{3UUgY1|=ynz~$N<^Ve#d1t+dRZS$kx2fC6xfADd@H{4R?W)B|E>>^0 zv~SeGKzb5P8{)i+@yg5VFms|nVovkDs3S?Qr;@C@x9|jn+}DX20eI~z1ll4}i7;%> zWPw&&5`j8;`v7*WgBhj9TeawJ>W6FRPxGw4V}<`7{$q3QDF=kAY=BU8kV}O63dpve zWdVMIFkTB=m6EEsI#4}94jj$s<9?>%zCch=YMu`28|sK`yX7Rw)N^04gDx;adKq|0 zw|_%^#{j?wL+AjN@4+;y@E5i1g%%KzC=6_Sfo9%g59hq;iVOrqMk>)^Hg%M5JIsnhmPB_W3)DV@l8YyO~!FSS? zRfW}JR97<}5tLSBR~pjEc;%y1KUlK}<;+Yl?x%c~>Oc<$dQkno4eY2v=(^ySd zD%}?;$r5fn?k8w`sep%KZ+H={nXC$+l`+lK5e>g#s{ispa7_%Pt%A81&^ugnN@+l3OJi@ zD-dvYH3^oq3_1E1OtJ}`4yG!5_q@(WDm*N}QeSJwt~*S43+QbI=%Zx;?mhb7w<`jW z?DXpQcssjN({`r8bqRbd*c|Jb@#Hc$?;rzOF#3|9fIg3E|I3YzA7eyX#*RSn?7OU`I%eAS32v@d=x!d6^^g{M%9weZ z0wv#-(B_f|Q}>n|~vZymARDX4*{%zRj8(fdS>c^Pi4t-Z8v5(q%C0oSwpJ$x?k-ieuo^zn^?Y9*Ya&$1|* zuH*2%O&HPaMhTe#lt{+c9Tf-zy5is^E&y1q%BUuIE0TW|JCi~cSINGt7o?kQOato@ zGJCwXT5^=UXf;<;!ld7ww+*4Id%45jSH9-N(RS*nz!nu|WiFVbTG{t75i**5l>*uk z;jcy*Z?_HyF7Ps@HM6H?=tva;Pw6^Y7dH-Nwv!YM(Y%MX>2}7izndbK`rzkXrjBap@WI54T(?4OY5V-z)BX4M21Got7{5xp3^9vSya&o*+B^ zYiEN@>8<2b315PwLKb{dTr-ckIUi9kNpdN~R?H|{RT4cN)!soQRdUpm&WJ=KBx>J` zJhmo#sx36rcc=P#;kAS@B+N6Iy1P?og0HSX6E5yX@<;Sde1P;Rmw{JKZykRO+n zhkXACMqGkI77otb?v-#lR7H{mZFSdfeurS~pA?RL%1R4NEvnJ+@qx3q4C@VP5Xw_S7GBKbrzM z*AdnV4_&KVkXSB|oL2cTw7+CR-X9X($JE2w~{M#oI*bL8b^r*z>~EMHymgAS{()Fd(%``Lmx-0*%Q@VWmwI zlzKpr5^gh8KhmhQZVE8>2}h55C}sAXf?$dMpi9%b;2|c7Hj*meLY%^1~lQ} zuPoINyW~Tj_fqYQyN-7Lri8159)O$`9eA^~MeXApBG?V`#Hf7jc})KXBT8oW#A|+{ zFxS8pMC!X&5Z38^)n-Q=EougkdbF@+GS^qDf&?6%Q9I0M#rGe4SoA=HF&)K>mqb5V z_G`WnjqE_@tl^BlsLHC$$J*QQqSmSAWG5_AGRw%=VW>X73%w=hBG6Y#G0{#w1sZkjXL|xp}YA^lAaK zXwoVp3MBrXen+Kz{3was;#F2T5=hBEy)^&wMSwtX62;m79q`waLeIpBuVQ~ej?w-{ z(p3gU)v!^zo28be8xa;*VChcj5`5`ymJku??nY|q4g~~MkZzC;1tpe{lI{|}>wGi! z&ce+8+cQs|=bYLF;Ufxk>7c%~OV%CmpBzwa7%6!5MO-^h+?Y&$KpLo(*ybbHNICxw z&n;Gcyj-7Sp`6voOnsghGarKh`2$CA3i)>SoL}FLhOpXFk-DB^%aBDTUr9k!Phu}h zX&q!Fs=&7n(w24wKQlDo4a1^(S7lqFZ>DuPb0wYN27pMrKgK=Bi-P+Hv-#(#zBg z2VGlJLQjl(3Zrq~liscEgz6_Bq;V4nUzRU>ufA%3zLTI$tFgz6eOgYyMOtXxh9I1b zE(?hsBcci;=26cWlBH-cqa;J>#(v;E!{)82jYt7spbk8%u{vty@IIjsPkX8%{J9;Y6q_2bc+owv>yOft>IG6IE1EaaSY(hDXBUp{ zB~>c=eUBy_$9_HQjZi%U#mTfF`IMP~6@5-Z;{_P7Cuan^->o}#THh#p(!SUwb)2iA zjxGa=aagb*WB)lYvsoAeVp#r}yfFSd32lYCWP|D2O;F1bj7pYHt5-)Qqsiu{y%IZB zu_m*!ys~tB-3Xo%P{f4e2-eh&sHvNdY9^cqe-0sx0cg|!wU+YT7lBCQZsJ`j2d43z z$B5JXW2=SR2Kcog^|sGn`Fz>uz^I7R$GFaZp1ANR)88@;3yK%^J*j zuDz!9D{~DqIlV|*P|_k+d_1#|?q&b7d#!=^x`L;qh?*`J`y2P#n~0p2rWBr_?C*Ha z;K6fulb4ED8p1zmZrRAoxA-~6I6r~aL85WuMzK@+*xEwx^zA_esg|o~X-eoNN(^xQ zZ%~J?>n|xX2?x0AvgG(UdeY9SzU&oqVAA0;!CMSW*x8()E4;(-s1Wkc8bz7%$EdbJ zJbnp%&icA;sLg9+!-&{tCzy}JN4V6C@w_v@%fsZVQjoJUh#oi~0JLaq4{HP#{jZ*g zS~d=g5~?12*3_>(%q{@hd+fBDUneO~BXtbXJ6O+92vwog zH|(1g&oEdGp6R_<3O(D$0jAjf`#zAP#i7lsY=0MO%H8Ew4$SmdGQ%4Msszgl&Fj=i z%xoah0lXw}D4{lbE`mrmD*0cO#1ul2zl}%?cd^_0$9Dxg0|NAE+OkD@x=9cM$TkeH zmMAUO3_U0X-ze?$OY)Mgrrm;M05UKa${KBpIuA3OjG!cyk6I=<%oIT~8ScuhKDz2( zj%sriTJ^8&8J5NeJNh}Ars#gaF!WWjXEtj6TI*%j5jW*EH&D3zNy#*0T597{`eJfoh$tBAa#jZ z6`$d(o;uYC_?bASegp{aJGWMrYs6k_mu%5m(0B(mzXa4fzdKS9sUE3JEjdDMHW}(a zTg7-#k`$YJ;=o;JN{+$4yUjQZz>?-(*0|Vws>12|p0(w77n*xWJ|Un>Ve;XK$yhz; z)l=?H{$9)G-kbqV$9IOj&zFQXXSo>N9%VNkg`_6WU);wS#fqD#(fe%-(7Js2dDOyl z@G&fU6Z$imVY^%%(!zikr_M2bD?dICt0#Ar13Nerim#D=f7!1#S-Ep7>zQoJa6N9~ zJg0KEXSTz-`Z}xLhreV|Jiy(7#OB3otsu@Hu8LNQ3rQ2CVx96-@dM3P!V1@hq&nh) zuwMhype1W*xVlA()5-x~*6eP?H*oRv7*4X7+Ss~wCFF=hM^dZ720u@OO`{|S+d%*0!*0sPT*B1 z9N>A6knkmm+9V>Ht(}-I$7I@RMdj*fG&(49eA7pDJh&5EJXV4|kDZjRi}C-kQTvW1 zIc4wTBe1|PNS>#~>)}49;A&(k7_uvLAsYUzDp>!qf1k+8a8pTs5PCKio%&ofa#=`w zed{eT>nF|R6Fa|WS|y6i1}kL_bCRbyR0f;^^Ejl$ z7&I7Q8p8n6%zzK_o?}}qug1;gYkdPvOFjk6NIS`W(M%D|Wpvk<{!uQ`qSoR>?Wmd& zd&P-QccWSQK7`=%Plgl7Wt#O{iD{{#R}6vjI|8JKL8+-jq{**7&&M+iZwG-LqiT;$ z9^_B2)rye5*WJuL;>Xz`z4exlxagC=Lbw{+9+=?A@gY{!N$2lBWA2!HaZP?XBSF3r ze_i0Sx0dQNT6A*%WmV4FRIL688s0<%>EixUnrZ4~-GW;T*mA)9p~b$%uSR0?kNk1P zvsaUr2#@=h=^1;&^9%bqLi`DzFJFp#_&ZU)zx(|&r~ATrcHq;->r$7uG7;z5GEvxK zQen3VjDsD&jcr!@a0QR^?oY~|{Y|d(48#hEI7H%zzG+M`XB_HInds$wi?Zt1$x<7b z@)C}ZNXZvFJv{T?ZcGZBX!-Cd?QPc*Y)obHnwBAqF9J>$uV{Z}W1<-C7E?81Ptx`S z{kEJE^8#%HS`cCY?$8CRYnndbDQ9$K^7dkCOVxc@TxTN~-bYh++Hh@aJDpR=0BKIqHiP*#o~Ufs?Y0=%=^}j{ALvTsjOX>s{A`cg~EkR zP|FC1)X;FHn%GXTZGkFug&}f+f&GcjVXz5O{)N_giRWTuGCHQjFT2HNTe*}gbj*La z)9^iLRxVX0WRhVe21gkwhx)`w-giDe&6KZf|M3Op(V(c6$rwLf^8rslr9m5r@!+t3ETvi_FU@p<24 zynWwe%k1ve!^v65#;d=9xNBQkrT>+N_mYQ;r7JM!g^Ph=R_Mbf!9AI|4?~x#v%4T3 z#DeE{n{O{utRA(d*2C8Tis14ifACezC$Dv_I;iI<7oL{cnsitn`$A;@f_AdEo;_=_vNUMCSKke%3TH7FIqpY7g-x<(KmH*E1 z@Fj{?Z?+0uC2|@r~y8Ll7UdHl4yRP_lX(xOi6M6stk zg-K$-z-yiV2uC4HF*66<333k6ThuOYjxve9Jlk3{mxx`SWij4^?#&i(>K4r;|iNtcx8Jf@^=6kb!{`*cb|6tRWj{-?r+cS zciG60?qlhWPp43A7;$Tam?cAor3Ie58Zj7ii>CZ?f!`oi7^s;RW48mcMV zUZFhErysj!PHjH;u@#Uj5uRE<;Zu8ccf- zynBd_LH{H-gg|v8c9;Tj%S!t_P5&CIRj}oPi(^PaRP9_1N#%xs)LQ0DrXq0(%3?0C zl_~KeZ-U@++f{*ri=6}Ar^*zuRYInrqc|k$ReePM6wXRHmEDFo1s~aKC%oogY*aU~ z>)NW9j-@MQWhv!m8P-3T_OJlRGL71lph2iqLc#!mQ56tKed)rglM(3O7Z_X0bUCc# zt-r4YyLQ*AWSHRQ&W0VaP)gt?I%R>U+2{2sUkSOEmt^8X9NzD-3)if?3m-!b6^@Y~ z@X-zMTLAe{A4Rsdt$T>~Vj!R;*0*I;H-VD{T}SaRX#WkM_M!JvGH#!rD%wz#_Aof$ zEL)ss)BY2VHaPcsc}%}-g|vzb>q|a2!xu@lUd7cEXXGw}Xi3OG;v+fbU9{G2MSqcW zgm2PdF?oSE=06l=?#*y;-4}h?!twn|yj%I(^jux#ORZ+vsaVPgVo1SJAXC=+-~zlVqf=ITl*}S=e)dJ0bW_b{G>O~ z`@A=T_j&h=IWH%IZcZ1jS$95sN%Prb7->8381D||2=@DW{(1XjHsa9zH{w_KyFMMy zKyWj)bh5aZR0Q_d!r|}=9oxs*sz$3NVUxxKIt--!)Q4iz#x3>n?sdU&%L}}1^Lw)G zr-5ib4P8t=4ed0t4@+x^g|jSZZo%Buv1a#&o_A7ORn1@G*qX2&dUsoVdB(c7=?4N) zz$N9LxWS#@nXzUn%%xo%QeKHjH7->nP`28P8QO>tBU6?t3|(Nbxp#>bJlH}XPDXFV z6l%p}jUr}^VqgPljN6lNauPA#DBw#B(8UN0WDVvj|EC>-1P=+CNSEVs6>jNQ@`)(2 z2vfq#$)_1di+^Owy%SG%d4^%MjaAF1Zulajx}{RrS*vtDPpOj)TL2U31ZD&uspV-^ znWbHbhi%duN}ia?(-;0J$Exe*uIj1jNub9=d~>TGxc`#JqLh$%9hyiG zxaAqKQ$}jMNnLE_dOp@Nx3ZQ1wiapbui8V7x!>RnT$OyL7Y++iql8IIszn#A;`gnS z`(dq6Vt5O9ctB%Iwa}pf)Ohp_nWra-E7Q7&+FIe|*>?**If| z##=^b!_g~# zW@?$xwgh9F$Bp48t33k%FwT4?cd#hpIP9<7Zq%~!z{2RfVY7dmalHLOdu#l!bTa6h zeNBFD&-yD+)sj(ejbWZSeXmYYM;L7&`iHD3Rr#%*8U`FVpWDOI0(ZWo<}ej}F~@Wf zYh;`WJ82ReI=MfbIfz>)8R^7_9x;(Zo~IxfJW>23PQDe>yOq+r7E!Jt`C`jK&1gW* zAxzQWNvWUINpx)A>3Qg;y+jhG7yM7Tg8liR)#U(Le1+3sTrOG>3BANG1}^&(wRGB^ zI76I>LfBX$zF|IPHH=HwTDy1|Dc8mkC-jWK{u{eSJ&)m%0YVucA*GkD-^NBKn&qu5 zged$8^IO`#=TZk>+GGDKsrCiF#-*Iwi(4$4#L;wd55MBNgVvuGdk(~Fx8b`BvE>a0 zzzAB)nJQiZQYtP&Hq+XwL^-c3-{K=(3VTL}1d-MBgR4M%;^n|OJ^CPjz{@Z&Ng?h> z{k5q%2hB;f2@;jGxto^Z9#|lxXuL*>iM;Dl7kyV-rnmA=Ax3l9DAzycd_=*IDT*xU zgFMRaIudmiwSEzey1-dKqd*hyWUtERaVJaqkGZf>K_Q=GaFaTA_$k@Up3izUokDFm z78@s?suo#tE=ws39anK0&xl*LnR0F9h8H0i%fN|gTG5)Iq{$JK&3}jMJ^2?Xsb*z2 zJD&YbJa^I%NjUYa#N5#!$gevZsINO3I^aVs_t)e{X)dd729LL0p^vv6$y-Q8iUYVg zB2KYcB~Gz^1m4xl6f5BGe^?R>8O;ER>SXNCeQ@LsE$j;))UoL$PO*KwR9YH0_y3p5 zn6}Mcl5U%MiFxziU>?1=EKu+`04wyZS>(<0*Do$C(%|!>ls0 zGXn1F^;XhX+rF%7yYbt;t#w)JO>r|e>Pi)Af7L`|5K|Q^KkhH;O@Ktt!t~B!IE-+B zsZAWj?U1{GQ}%Aw!^CK9zmx3hqFyj7kb*QJwr&b%H*8*T|0Re4;x^RVQgtg=NvKQhU9+@@xKGRbH72)`^6 zo9A&5NuZk2)08R@jYIED)Dg0h!!?p1LV&T$_cP2}SuN7-#xW9v<-&x|m7w?}Ffbt< zWWn@LV>`ylO+VsZ0r9#Y@p^BLCi**5@8@s$qmfjY8j?7fc0o~^>Xnlm542SV*S1(H z5EKkT(wv&|nXuT?jHnRR$*AuB*V&Iz zB1!m&M+r=LGabt8HJ5{B5DoB(ZJYhk8Smnxhxt(JXEmP$kDK10ZSw^Ju_*}8r{N8r z4~=wWTLL4e*B=c6Is)V%fU1pQXvpYhPWKi*5RpKWmRGPOM?AN;&_-*b4P5B;{u{xa z+7O#bs#hDs-8b~qW>;cFB#t^^5uYg7CeA%>XxQhRy~D+N=vA#sC{gk;M@gqqHYZWy zD7)V11~=NNA>}VI=IDO>V@_N&+Alw%wZNigU;H_^PX4wZGqyFD^DRn{xMA2KUQY}Q zE|kUKorM`>D{2^*xJ&ynoe`-{BORc2WstJ()Q~)h>6w~niKtWFthd(05iMgcIHO<_ z*I=R0E?>NG4v5^`V#RE36(}6(q0rb&6bndwYllj-a}a%uvTac{gdc{yk%k$TH)L5v^V8urk&BoXm~<=3>RN6g_wb?RU6! z<(qWkj);J9B?+3~UA|y%(d@!W5pe)eabqmgEDh3+(7-S}B4Z|;Oi`km(UTo!hDV6u z(vrGwTYPA&=>|vHe;|8;Su39BFP2JXtO@9&Ce^`Y?_?6S#iv;d74kK4qr?;A-=aU* zjCPK+p)zG)!C-HPXraK ztpdEv>eu>-yhvP^X&1C{N!;)9w^tTB1Wly$Zu->y{%~P3svJgcI!D?%E7@F#l=)GV zL-=2oBlI)mas|UEY}5NVA?%M1198t~RK-xd`r-gc~t@__clsUuMa&yaw zv&?JPX~c{+vpii-XP=Asd)ZPM8=&g%(g&X8yUs}3MELi`y=M{rVW-lfmgGc1Kg|s2 zA;{Zbv-7s&A!v7z6+Pk$Qeo!y{fqiik?w>2i+WOthmN>Sf9fHUlVhgm{y^ILqJcZZ zAtn!XQ$A+KMQYbD9#Tm2NG6ODJkr)Q`Vs;0%OV)yoio z9k@u-#}at}8mSb=&x(w=WVcj_(X?=p|VGai+T{ zB1!)^{Ksze&_USf`f%j8IENX~54!-(90eyTZm&NLMRJqjYacjHO}mkMYfzqrgD1zO zd-KvDQ7pL6du#n_Txfo!E|Jr=d3U-DQ*X!b*Ut0ADd{E;@KcYsQu2o5`kb+2*7`L- z&!+N3pVazD+it9*W&@wkTb`Jv*hSn0$M{O(XMYUlu|3z{y(ET_V^Yr5IqIlRc#}YC2S4{18Fb>iq}*}3RNM7 z()-k(5$s#xtO6N|3?G+r9R^8*xvgJ}uTLxsQ=I;2;6`+D_Lw%8P}FtT59|v(IeFNz zzp;8HJV3w|pz5|u3oFxdP)HaERY_yK#9(l_Z>>IBD6V}&KxJ;g{o4@G8>-e_Rw-`o z4j{_cA+>ozh-7gS;Otql;N#M$vLpL%iU?37B1re5zl+W(=pP@YE_}`RtuzXwDoqqi zs8jrqf+4Y^S6BPj37W0F9LOp=gw8GaM~^ZNxHAl|0|c{>)q^LF&6oz#F2DufZ#sM! zf{`RT-(>9iVU(&%3XJ#-rt#nowQ6(w@@qD3Qt@l%u1uSDO#cjQY!BDnHFL_^o#tJz zRoYSgn~MJF(VjSrIzu)I)bN z<85a}ryD6( zJYks6AXY=kloerP^$wki1_dJ6q4%!vr&d5x#lX(rPW zZV`dA%Ee`VGak0HXd~m#$x#EZ4K@r{ur?4k8v~zC{}sm8mqQ7X)M!dMk4l%v_T!Rg#Ec0DJJl4+zu8b{RTTbLm_34Br) zCm8`q+`)-`pwd3lgIsTbW$jP1nCD{O*ME7sH2N8c0A;e>#HOPRPj98-N@|VtF5|~i zMGyJ9@kocbG)!$KBe=9d^+BP+>+e7wTHrp^Eh#sTGk8kiCM_8`QH9%dd%^q>NjGrS ztjOp4v4DYnnul)S{Rb9bQd4HSPbDFXnpeclJu_um^@{l>F~))-DN$yg+GVM}EY~Dp zYcHI|`z@71Zx*Z5CYPa}K!YW56zw6piJ3e#lu`E7Ly9O6!}@cOb#)RW_XWS^?#=o@ z_c`$?*3plzwgL!Ju0gKVdl4iU_K2%bJbARTM2~uW1Qf9rCBbFJT5%{ zw^EY^qB>2zwfXdgJrBQ~yC?c^Yuejzn;Sk8HVbrP%6{I``MmyJ=R*bxK0I-(=~5|= z)T{tVb`g^>RAgHnj*LY=Qm!t=U1GKxi(gcVP&w- zCDR%CR%I_}R4PB$&WFZFYW|Y@ol5l*lX{-iM31et*l`?az$t|md{Jb(M6>Qmt5%Rz z-EgFYhq8S!v@N)^roO=*O!YCkLs&|PwrB3&vJR` z7s-{d#8KXXw0AS$9%>t(1>-g=K?F~oA+6;l#emR%l5{2u`D72dy5i2WDYKr-tK=a{ zPY?H=-~a8O?tg0a->Y-!_?%XqZ)BOdS#vo!^7O4-?OCzUNc=~1;TLwCF!e+yGCEzZ z>5@vzgngN(yl*OXXS7N?Tq!CHe}N2>*MAydiLMpC-TX4=O_0mtCMg;F&Jm~SvL5o^ zSVhJWbb(>ew`Pe?=SeGxKr$7u00C^dl=vqouTvQ6i!`soH?AuYtW|EA|YZFzQ zVd-X+)5H*Yr;}_67Q}>dW?C8W0ET96j2Mu70h|Ob98b8oEf~oYQuL&NV0bQ;Gfqfc zBzJ(v9iz$@A34wArI6p_Wlk~ds}7mVfV-$|flMPZ zTpb^$D)aR8T)e%y3g~ESE!2z*F^G7XU)va+H>mSYU}&aYFBZh#^7Wk)1GLQ4MWJjl zG@yj>C5E)i-OK9zh0+hI3Gs|idD}&}k6HH?;y5|FWJF>;bw~j)MciCvLe>h?ZNKKq zyGbfqHUCP4{HINd`eGo|qLDu}~Ihe=jkwRs0f}H_R$jqphGA zqgDm2ci@-D+Vy-QOUUq;@z7ROK;qc7dceFE=tqj4AV3yYMALrr?eW zr=#Uqw-LkpU}?+FFlE3=>h>PZRYP)F-cKiWkSesF!H%ZrH=o4?3EhmWO&_Y9FykY) z#UqqdoaQgNZ2JL8y2Ae#XxiiLXC52tW-rC`;DpD6%dW>enG>u8$lpvu%fFc>jl~j} z1|J52etcsOM^LM1(I31c5E4BwTcwr@97#d{w&$)+)PFrzn&b%SdnqPOl)?q2gas}( z)^U#PD!}tbFton?hAuf%;@MB>0PVNeX^dbe`QmMr+47u2nZHZ+sryZ%wE+*CRz;!( zH!-6P_3!0n-EH>gxfD8!GcYUVtbs(AI64vijWrlC#a|T_Rr)O#{TiE4Vfe3b&0hnb zR|$2X=+B`f&zXC{gQ7pS950ouFVhK(xC?EjIc@#~5zGhb(Y<8D8W$ zW%~w_tj-sP7f!mX@8p#~;Ye!4oEoJ;ENO^0ezS^q@uzR*vx^V*#XqZUk4wGQN6Ffm91_`S*alF`QfK6v!G zk@nba8WPb1|B}ciq19-^N5o1NsKSStFC-R~<>{ZBpI~Co-#$1ZgRGL7$(&7*6Ac%CN`L*n%bJp11J`$wR_10O z&pY^x>tR=DV+E-?SF>cwvk-**u%6x75JKzYX*IT*VkJW=${rLDZiswqSEcI)ZcRjU z?47NG{*C5}oe5+x5_`TDBmR6fVkvtq>YV=zrug|^hS&G;j+zlwufI+$1?R))CKH7? zPg{I>dvXTn#y8Q3JyU;v+d+P;nc6OV?}o8l9q#UM-8gj652|w;QA-?4CC(Ro+C7uv zOP#=ZP@R^e$K%i!$=igVWkV^UD*iWGFgaI*%5F6tP1X9Mk5VI5UaL|_xlZ3$2Sokv zAtDJuc3w_Y81DVWf)A|W56xD8W7mb#sg`giZ{}eoJ5#`G)lspcas8UR`fwYy^=iQ+ zTL37zbF|l0>y@cZF|&;`RnkiBN%v24a~*9~*A{NhaKGf893`uCw6-!fxK}z;VNVhk zWtX+<#2o42zQE;kdYe1LEm&e56s~c%& zguags@YJ(STdooS&o~!4u z*1DLDwps4IU*ConD#2YDOQQSc%{RpMLEWP|ufe~~y6f>U^7m(7m(^0|v27eiHxrc9 zYm%vL=Wpy5z)V<3taXcLV@3C+aLlF0(NO)@qXE+3Gn(a--&_s=Hjm6s@7;3FUPY5Y$$n^I1S?`s>$+oSwzbe>=dF#VjuA(J^eE>2k90^_Gp0$C-lcb3|D4o z#?y#lb?_i&@)AQ7S7!NjSKGb5o(pr)vz5pVyW^zUj6P?3BIOK0NKyRet|5kM6$QLh z9hJ%%7LkWV;*tR`f3}{=64gHhOU{{vtA%Y6oLfrT^B zyz@^UCpkNsJJB0Lo+o5?*9^4-+x9=o;ud$c;3Nu4iD);cx2DtVB4v8xn8|V}`!dqC zcfQpJ3nit`W6l^c3Z6Q~G?k?GIM|jz=m~KfYY=Gp+9aso8A5^Pu+WACoW|S$35qC& zO)yQgp`Z7qccR%JyTnZ&%otAyn+ z@w1*6+yy_^!??(zmdMACj!SfBa&MEO%TIM3FV8%xGdvL)!f2MMXisV5SwP7%K8@<_ z3DM<7VY;AoCx}EHO}HMR9Ra;crP=hC4U@m-EZ+QG#IhX+Odanx-T*%9Sv75@_J|j0 zrK=OZFMa;MQ!)^?>gT4Xn6h~!_U$G<{IXu9zw_seWNZBXY1fJut7{s~Uw?+~nv^gd zD3X~u_v2jjVRs3Dhd=b&KBOVIUf;G}T^VT#HxEajy1AiCyg!j{EcqkK=XT+dxaX9? zWL_&$=~d!75ba%p|BIE9cYyQkg_Ba-NUV1nzKFiiq}&7jk0>ei+3FH?E}Sa05kqaK zdi2i`_&>BDj&D3}8U^3j;3*k^;B+59IaIcf+GX|k#}WOw@IvYhBD{r?Z2?5+4SV?u zh4p9PL-I6G#hh`NdF=lXQLRIe}RKi0g;EVWFz zU+Vi6LBdEjEcnB=tiwP_R^AYwo0F5KMZ3}yw1kzZuwl9_nO8zREY8`vxSU^MD7X|0 zmVzEuxE_`QIaat*RO1OCk1;rUpkytIeYg0s0%w&6f@vUKHaCP*m!egtV7L^?D(Lr= zqj@B*&GwKu^+Ln;N};yV+G&h<<}>kTB~)hBESBlv!Sm+S=$gF$D(_zH`KbsI;%Eom zk>jxSb!NFf2u}D`DjM5OBtAcDBhdyU_dHwnEB`mvtQyrg({X>X>ta2e+9O zXfA`Whb8&q^x%%Ohq+UZ9|bPm^ocd)HqnNhv5vOej|oo#$W)7A{G>`Qa(tFA;4;hk zpiC=>J?rdD(}n~-PFy3%@SQX*`aF%<^}_=CHYAvVG=iG`c(ce;}Pev zfy@DMRH~IeZzr2(fJcW}MA5?6-k~j49wXxnCXvMc4k7p2q1Z2Pn%HJkAA}h87Q?)Qk zAWlp&r=t0d2!+VdAgF_p-xEn+iLG}sB>CGuW3c%15vL*0JV}I}_vG=2x`p(|jF6RL z*}Q@k+cu`^6lO9bRi{LzpYy5F44I51XMZ*q&dHz`20ew48=R#-no{45m;LlsPY|pW z;4~f#3`k8;u__a8&K-`^k^FQ^@^h0gGzavUrL3~Bp{=m2?QLpRG-ED&LQ+mmsB`9E zZ{QGSazeS0@pCdp%bZ$BFxkyb1bMn2c3ETlh#1sX+b8;>WuMkoe{Nf;Od2g;GFBHJ zt(&v_)P`hLwG98tu>LDe*q}1ep&WahUoSlQt)H#c80Jzry~}@CMQ+kjNXun_)Ac$u znUCydye&F&aL4Q#?fcg7q;gteK6V1#B6L5xMqvhBiyA(a);R!pEn+__ENv_?AN;H_nQL4P==Ca(yPC4S&%Jn6d=_51OvA8mLmzHc|ak4ml4VErMw+ow|hg3psLP5zTi zw6`)AS0)f41`%ph{qjacxS3uM-C-{)p|A)8^@H!_jh6X+GUgQbmpl+?rPoOMkRgc4_?%057=knMEXo44jaV+*XnwGMlkz~$X zDq;%4{XvKMIIU_*I`JsB>9Sg#lrfof3x;YVz!{4o(9aF6h$%Y_&N;XJP_b&1dXewuYXLY4HYri2Xy+_ z*L3K~D+~(Ew8~J3A{3$w)hwnYQYI%-uD)a8dAl-EVGkL|S*VaVRzH>I*#7h$C_>q( zRoTH+Iv54Cl&4sMVchlanLFh{y{^X|gCWcJIAbrirr~{!xU>GRHU+oL0%#n}&(U~d zEPVvF^_gN0J52}B9ao7#@MkyX13K#u_H*0iv@e@C#IFeY9|mMn@K7zSW^X7%DgG92cO5*^r>hJu+P++#I6knTzfVjGLbotr!ld_z z&F&deRH4>f8dE9R0Y7lI@N-{yTqH^A^1=Wd;5*(Wx`7Baxyf@D9pic;g~;g~Q)>!R zYs^y(rbqT%hoGFtD~$o44abfWn%RgF+XdT7@rLx*ewsq!X8=lZvn4DodL~<;f;Cad z2rDK_5TZYX&{el;wxsJ1HiF>J;~x}h+H`Zq1^obB?WZr+=~x#DCb7K*UG%~ru!;{j zxwCLRcqQ3vLu-}e1R6;wQs=rQPj=FE2=@#4bn+w6$ySj3DZOLmuu@LNGjzQDvawSPR&~QMgPmP9=#o)+rRAFPa6OoX9I? zk&^OmsawviMH|yBJv#c}u3trwmo{3nf|B)i?LxLsGnOFvPjaY?xkz1vi

7al*`h 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 z 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 literal 0 HcmV?d00001 diff --git a/overrides/system.gaiamobile.org/js/system_banner.js b/overrides/system.gaiamobile.org/js/system_banner.js new file mode 100755 index 00000000..c88f6b55 --- /dev/null +++ b/overrides/system.gaiamobile.org/js/system_banner.js @@ -0,0 +1,203 @@ +/* global LazyLoader */ +'use strict'; + +(function(exports) { + + /** + * SystemBanner displays a type of notification to the user in certain cases. + * It is a type of temporary notification that does not live in the + * notifications tray. Examples of the SystemBanner implementation include + * application installation, crash reporter, and low storage notices. + * @class SystemBanner + */ + function SystemBanner() { + this._generation = 0; + } + + /** + * Amount of time before banner is automatically dismissed. + */ + SystemBanner.TIMEOUT = 4000; + + SystemBanner.prototype = { + + /** + * A reference to the SystemBanner element + * @memberof SystemBanner.prototype + * @type {Element} + */ + _banner: null, + + /** + * Set when the clicked callback called. Bypasses dismiss. + * @memberof SystemBanner.prototype + * @type {Boolean} + */ + _clicked: false, + + /** + * Set to true when the banner is currently showing to the user. + * @memberof SystemBanner.prototype + * @type {Boolean} + */ + _showing: false, + + /** + * Generates and returns the banner if it does not exist + * @memberof SystemBanner.prototype + * @type {Function} + */ + getBanner: function() { + if (this._banner) { + return Promise.resolve(this._banner); + } + + return LazyLoader.load('shared/elements/gaia-component/gaia-component.js') + .then(() => { + return LazyLoader.load('shared/elements/gaia-toast/gaia-toast.js'); + }) + .then(() => { + this._banner = document.createElement('gaia-toast'); + this._banner.timeout = SystemBanner.TIMEOUT; + this._banner.className = 'banner'; + this._banner.dataset.zIndexLevel = 'system-notification-banner'; + var container = createChild(this._banner, 'div', 'container'); + createChild(container, 'div', 'messages'); + createChild(container, 'div', 'buttons'); + return this._banner; + }); + }, + + /** + * Shows a banner with a given message. + * Optionally shows a button with a given label/callback/dismiss. + * 'dismiss' is called when the banner is dismissed and button + * has not been clicked. It is optional. + * @memberof SystemBanner.prototype + * @param {String|Array} messages The messages to display + * @param {Object} buttonParams + * { label: l10nAttrs, callback: ..., dismiss: ... } + */ + show: function(messages, buttonParams) { + var generation = ++this._generation; + clearTimeout(this._dismissTimer); + if (this._cancelRemoval) { + this._cancelRemoval(); + } + this._clicked = false; + this._showing = true; + + return this.getBanner().then(banner => { + if (generation !== this._generation || !this._showing) { + return; + } + // Clear the button and message containers. + var messageContainer = banner.querySelector('.messages'); + var buttonContainer = banner.querySelector('.buttons'); + messageContainer.innerHTML = ''; + buttonContainer.innerHTML = ''; + + // Populate banner with messages. + if (!Array.isArray(messages)) { + messages = [messages]; + } + messages.forEach((chunk) => { + var p = createChild(messageContainer, 'p'); + setElementL10n(p, chunk); + }); + + // Populate buttons if specified. + if (buttonParams) { + var button = createChild(buttonContainer, 'span'); + button.className = 'button'; + setElementL10n(button, buttonParams.label); + button.addEventListener('click', () => { + this._clicked = true; + this.hide(); + buttonParams.callback && buttonParams.callback(); + }); + } + + // Hide banner and invoke button dismiss() on click or timeout. + var hideBanner = () => { + if (generation !== this._generation || !this._showing) { + return; + } + this.hide(); + if (!this._clicked) { + buttonParams && buttonParams.dismiss && buttonParams.dismiss(); + } + }; + banner.onclick = hideBanner; + this._dismissTimer = setTimeout(hideBanner, SystemBanner.TIMEOUT); + + document.getElementById('screen').appendChild(banner); + banner.show(); + }); + }, + + /** + * Hide the System Banner and remove it from the DOM. + */ + hide: function() { + if (!this._showing) { + return; + } + this._showing = false; + clearTimeout(this._dismissTimer); + var generation = this._generation; + + return this.getBanner().then(banner => { + if (generation !== this._generation || this._showing) { + return; + } + // Animation events inside a modern shadow root do not reach the host. + var animation = banner.shadowRoot && + banner.shadowRoot.querySelector('.bread') || banner; + var cleanup = () => { + clearTimeout(this._removeTimer); + animation.removeEventListener('animationend', removeBanner); + animation.removeEventListener('animationcancel', removeBanner); + this._cancelRemoval = null; + }; + var removeBanner = event => { + if (event && event.target !== animation) { + return; + } + cleanup(); + if (!this._showing && generation === this._generation) { + banner.parentNode && banner.parentNode.removeChild(banner); + } + }; + this._cancelRemoval = cleanup; + animation.addEventListener('animationend', removeBanner); + animation.addEventListener('animationcancel', removeBanner); + // Gaia's exit animation lasts 600 ms. Also dismiss if it is disabled + // or no animation event is produced. + this._removeTimer = setTimeout(removeBanner, 700); + banner.hide(); + }); + } + }; + + function createChild(parentEl, type, className) { + var el = document.createElement(type); + if (className) { + el.className = className; + } + parentEl.appendChild(el); + return el; + } + + function setElementL10n(element, l10nAttrs) { + if (typeof(l10nAttrs) === 'string') { + element.setAttribute('data-l10n-id', l10nAttrs); + } else { + navigator.mozL10n.setAttributes( + element, l10nAttrs.id, l10nAttrs.args); + } + } + + exports.SystemBanner = SystemBanner; + +}(window)); diff --git a/release.json b/release.json index ac787205..2e7fb88a 100644 --- a/release.json +++ b/release.json @@ -1,15 +1,15 @@ { "gaia": "2.7.0", "channel": "preview", - "revision": 15, - "androidVersionCode": 15, + "revision": 17, + "androidVersionCode": 17, "geckoview": "156.0.20260921121718", "engineAlignment": { "family": "156", "patchParity": false, "reason": "Firefox desktop 156.0.1; Mozilla's GeckoView release repository currently offers 156.0 only. Keep the desktop patch and report actual engine versions." }, - "version": "2.7-preview.15", + "version": "2.7-preview.17", "adapters": { "desktop": "0.1.0-dev", "android": "0.1.0-dev" diff --git a/services/activities.mjs b/services/activities.mjs new file mode 100644 index 00000000..4072ca49 --- /dev/null +++ b/services/activities.mjs @@ -0,0 +1,114 @@ +export function isGaiaActivity(source) { + return source?.name === 'pick' || + (source?.name === 'dial' && source.data?.type === 'webtelephony/number') || + (source?.name === 'new' && source.data?.type === 'websms/sms') || + (['new','update','open'].includes(source?.name) && source.data?.type === 'webcontacts/contact'); +} + +function entryPointFor(app, path) { + if (!path) return undefined; + const pathname=new URL(path,app.origin).pathname; + return Object.entries(app.manifest?.entry_points || {}).find(([,point])=> + new URL(point.launch_path || '/',app.origin).pathname===pathname)?.[0]; +} + +// Route Gaia's built-in pickers; only the selected provider can finish a request. +export class Activities { + constructor({identity, apps, launch, notify, uuid}) { + Object.assign(this, {identity, apps, launch, notify, uuid}); + this.pending = new Map(); + this.listeners = new Map(); + } + route(source, caller) { + const types = [].concat(source?.data?.type || []), name=source?.name; + let id; + if (name === 'pick') { + if (types.some(t=>['ringtone','alerttone'].includes(t))) id='ringtones'; + else if (types.some(t=>['webcontacts/contact','webcontacts/tel','webcontacts/email','webcontacts/select'].includes(t))) id='communications'; + else if (types.some(t=>typeof t==='string' && t.startsWith('image/'))) id=caller?.id==='communications'?'gallery':'wallpaper'; + } else if (name === 'dial' && types.includes('webtelephony/number')) id='communications'; + else if (name === 'new' && types.includes('websms/sms')) id='sms'; + else if (['new','update','open'].includes(name) && types.includes('webcontacts/contact')) id='communications'; + const app = this.apps().find(a=>a.id===id); + const candidates = [].concat(app?.manifest.activities?.[name] || []); + const definition = candidates.find(d=>{ + const filter=d.filters?.type; + const accepted=[].concat(filter?.value || filter || []); + return !accepted.length || types.some(t=>accepted.includes(t)); + }); + if (!app || !definition?.href) throw Error('ACTIVITY_NOT_SUPPORTED'); + const url=new URL(definition.href,app.origin); + if (url.origin!==new URL(app.origin).origin) throw Error('ACTIVITY_NOT_SUPPORTED'); + // SMS handles the activity after startup; its old manifest fragment is + // not a Navigation view in the packaged Gaia build. + if (id==='sms' && name==='new') url.hash=''; + const entryPoint=entryPointFor(app,url.href); + return {app,definition,url,entryPoint}; + } + provider(source) { return this.route(source).app; } + start(caller, source) { + const app = this.identity(caller); + if (!app || !['settings','system','homescreen','verticalhome','ringtones','sms','communications','email','calendar'].includes(app.id)) + throw Error('PERMISSION_DENIED'); + const {app:provider,definition,url,entryPoint}=this.route(source,app); + if ([...this.pending.values()].some(p=>p.provider.id===provider.id)) throw Error('ACTIVITY_BUSY'); + const id = this.uuid(); + return new Promise((resolve,reject) => { + const row = {id,caller,app,provider,source,resolve,reject,url,entryPoint, + returnURL:caller.manager?.documentURI?.spec,returns:definition.disposition!=='window'}; + this.pending.set(id,row); + const listener=[...this.listeners.values()].find(peer=> + peer.manager?.documentURI?.spec && this.identity(peer)?.id===provider.id && this.matches(peer,row)); + if (listener) { + this.launch(provider,listener.manager.documentURI.spec,{entryPoint}); + this.deliver(row,listener); + } else { + url.searchParams.set('activity',id); + this.launch(provider,url.href,{reload:true,entryPoint}); + } + }); + } + matches(peer,row) { + const spec=peer.manager?.documentURI?.spec; + if (!spec) return true; + const current=new URL(spec); + if (current.pathname!==row.url.pathname) return false; + // Gallery selects its picker mode once at startup from #pick. Reusing a + // normal gallery window would never enable selection/cropping controls. + return row.provider.id!=='gallery' || current.hash===row.url.hash; + } + subscribe(peer) { + const app = this.identity(peer); + if (!app) throw Error('PERMISSION_DENIED'); + this.listeners.set(peer,peer); + for (const row of this.pending.values()) + if (row.provider.id===app.id && this.matches(peer,row)) this.deliver(row,peer); + } + deliver(row,peer) { + if (!peer || row.delivered === peer) return; + row.delivered = peer; + this.notify(peer,'activity',{id:row.id,source:row.source}); + if (!row.returns) {this.pending.delete(row.id);row.resolve(null);} + } + finish(peer, {id,result,error}) { + const row = this.pending.get(id); + if (!row || row.delivered !== peer) throw Error('PERMISSION_DENIED'); + this.pending.delete(id); + this.launch(row.app,row.returnURL,{entryPoint:entryPointFor(row.app,row.returnURL)}); + if (error) row.reject(Error('ACTIVITY_CANCELLED')); + else row.resolve(result); + } + cancel(peer) { + if (this.identity(peer)?.id !== 'system') throw Error('PERMISSION_DENIED'); + for (const row of this.pending.values()) row.reject(Error('ACTIVITY_CANCELLED')); + this.pending.clear(); + } + cleanup(peer) { + for (const [app, listener] of this.listeners) if (listener === peer) this.listeners.delete(app); + for (const [id,row] of this.pending) { + if (row.caller === peer || row.delivered === peer) { + this.pending.delete(id);row.reject(Error('ACTIVITY_CANCELLED')); + } + } + } +} diff --git a/services/packages.mjs b/services/packages.mjs new file mode 100644 index 00000000..7885c980 --- /dev/null +++ b/services/packages.mjs @@ -0,0 +1,77 @@ +// Archived Marketplace packages run as ordinary web apps, never certified Gaia apps. +const MAX_ZIP = 16 * 1024 * 1024, MAX_FILES = 2048, MAX_EXPANDED = 48 * 1024 * 1024; +export function packageURL(value) { + const url = new URL(value); + if (url.origin !== 'https://vulpes-os.org' || url.pathname !== '/marketplace/index.php' || + !/^\d{1,10}$/.test(url.searchParams.get('download') || '') || url.username || url.password) + throw Error('INVALID_PACKAGE_URL'); + return url.origin+url.pathname+'?download='+url.searchParams.get('download'); +} +async function bounded(stream, limit) { + const reader=stream.getReader(), chunks=[]; let size=0; + try { for (;;) {const {done,value}=await reader.read();if(done)break;size+=value.length; + if(size>limit)throw Error('PACKAGE_TOO_LARGE');chunks.push(value);} + } finally {await reader.cancel().catch(()=>{});} + const bytes=new Uint8Array(size);let offset=0;for(const chunk of chunks){bytes.set(chunk,offset);offset+=chunk.length;}return bytes; +} +function crc32(bytes) {let crc=0xffffffff;for(const byte of bytes){crc^=byte;for(let i=0;i<8;i++)crc=(crc>>>1)^((crc&1)?0xedb88320:0);}return (crc^0xffffffff)>>>0;} +function base64(bytes) {let text='';for(let i=0;iMAX_ZIP)throw Error('PACKAGE_TOO_LARGE'); + const view=new DataView(bytes.buffer,bytes.byteOffset,bytes.byteLength), decoder=new TextDecoder('utf-8',{fatal:true}); + let end=-1; + for(let p=bytes.length-22;p>=Math.max(0,bytes.length-65557);p--) + if(view.getUint32(p,true)===0x06054b50 && p+22+view.getUint16(p+20,true)===bytes.length){end=p;break;} + if(end<0 || view.getUint16(end+4,true) || view.getUint16(end+6,true))throw Error('INVALID_ZIP'); + const count=view.getUint16(end+10,true), centralSize=view.getUint32(end+12,true),start=view.getUint32(end+16,true); + if(!count || count>MAX_FILES || start+centralSize!==end || view.getUint16(end+8,true)!==count)throw Error('INVALID_ZIP'); + const files=Object.create(null);let cursor=start,total=0; + for(let i=0;iend || view.getUint32(cursor,true)!==0x02014b50)throw Error('INVALID_ZIP'); + const flags=view.getUint16(cursor+8,true),method=view.getUint16(cursor+10,true),crc=view.getUint32(cursor+16,true), + packed=view.getUint32(cursor+20,true),size=view.getUint32(cursor+24,true),length=view.getUint16(cursor+28,true), + extra=view.getUint16(cursor+30,true),comment=view.getUint16(cursor+32,true),attrs=view.getUint32(cursor+38,true),offset=view.getUint32(cursor+42,true); + if(cursor+46+length+extra+comment>end || flags&1 || ![0,8].includes(method) || ((attrs>>>16)&0xf000)===0xa000)throw Error('UNSUPPORTED_ZIP'); + const name=decoder.decode(bytes.subarray(cursor+46,cursor+46+length));cursor+=46+length+extra+comment; + if(!name || name.startsWith('/') || name.includes('\\') || /[\x00-\x1f:]/.test(name) || name.split('/').some(p=>p==='..'||p==='.') || name.length>512)throw Error('INVALID_PATH'); + if(name.endsWith('/'))continue; + if(Object.hasOwn(files,name) || (total+=size)>MAX_EXPANDED || offset+30>start || view.getUint32(offset,true)!==0x04034b50)throw Error('INVALID_ZIP'); + const localName=view.getUint16(offset+26,true),localExtra=view.getUint16(offset+28,true),data=offset+30+localName+localExtra; + if(data+packed>start || decoder.decode(bytes.subarray(offset+30,offset+30+localName))!==name || view.getUint16(offset+8,true)!==method)throw Error('INVALID_ZIP'); + let content=bytes.subarray(data,data+packed); + if(method===8)content=await bounded(new Blob([content]).stream().pipeThrough(new DecompressionStream('deflate-raw')),size); + if(content.length!==size || crc32(content)!==crc)throw Error('CORRUPT_PACKAGE'); + files[name]=base64(content); + } + if(cursor!==end || !files['manifest.webapp'])throw Error('MISSING_MANIFEST'); + const original=JSON.parse(decoder.decode(Uint8Array.from(atob(files['manifest.webapp']),c=>c.charCodeAt(0)))); + if(typeof original.name!=='string' || !original.name.trim() || original.name.length>120)throw Error('INVALID_MANIFEST'); + function path(value) {if(typeof value!=='string')throw Error('INVALID_MANIFEST');const u=new URL(value,'https://app.invalid/'); + if(u.origin!=='https://app.invalid' || !Object.hasOwn(files,decodeURIComponent(u.pathname.slice(1))))throw Error('MISSING_APP_FILE');return u.pathname+u.search+u.hash;} + const launch=path(original.launch_path || '/index.html'),icons={}; + for(const [size,value] of Object.entries(original.icons || {}))if(/^\d+$/.test(size)) {try {icons[size]=path(value);}catch(_){}} + if(!Object.keys(icons).length)throw Error('MISSING_ICON'); + const hash=await crypto.subtle.digest('SHA-256',new TextEncoder().encode(source)); + const id='user-'+Array.from(new Uint8Array(hash)).map(n=>n.toString(16).padStart(2,'0')).join('').slice(0,24); + const manifest={name:original.name,description:String(original.description||'').slice(0,1000),version:String(original.version||'1.0').slice(0,60),launch_path:launch,icons,type:'web',permissions:{}}; + return {id,manifest,files,source,bytes:total,requestedPermissions:Object.keys(original.permissions||{})}; +} +export class Packages { + constructor({save,fetchPackage=(...args)=>fetch(...args),uuid=()=>crypto.randomUUID(),changed,schedule=(fn,delay)=>setTimeout(fn,delay),unschedule=id=>clearTimeout(id)}) {Object.assign(this,{save,fetchPackage,uuid,changed,schedule,unschedule});this.pending=new Map();} + async prepare(url) { + this.cancel();const controller=this.controller=new AbortController(); + const timer=this.schedule(()=>controller.abort(),60000); + try { + const source=packageURL(url),response=await this.fetchPackage(source,{redirect:'error',credentials:'omit',signal:controller.signal}); + if(!response.ok)throw Error('DOWNLOAD_FAILED'); + const item=await unpackPackage(await bounded(response.body,MAX_ZIP),source); + if(controller.signal.aborted)throw Error('DOWNLOAD_CANCELLED'); + this.pending.clear();const token=this.uuid();this.pending.set(token,{item,expires:Date.now()+300000}); + return {token,name:item.manifest.name,bytes:item.bytes,permissions:item.requestedPermissions}; + } finally {this.unschedule(timer);if(this.controller===controller)this.controller=null;} + } + cancel(){this.controller?.abort();this.pending.clear();} + async install(token) {const row=this.pending.get(token);this.pending.delete(token);if(!row || row.expires=win.innerWidth || y>=win.innerHeight) throw Error('INVALID_TEST_POINT'); + const {setTimeout}=ChromeUtils.importESModule('resource://gre/modules/Timer.sys.mjs'); + for (const type of ['mousemove','mousedown','mouseup']) { + win.synthesizeMouseEvent(type,x,y,{button:0,clickCount:1},{isAsyncEnabled:false}); + await new Promise(resolve=>setTimeout(resolve,100)); + } + return true; + } if (message.name === 'Tap') { const {x,y}=message.data, win=this.contentWindow; if (!Number.isFinite(x) || !Number.isFinite(y) || x<0 || y<0 || diff --git a/tests/activities.test.mjs b/tests/activities.test.mjs new file mode 100644 index 00000000..0caca7f8 --- /dev/null +++ b/tests/activities.test.mjs @@ -0,0 +1,83 @@ +import assert from 'node:assert/strict'; +import {Activities} from '../services/activities.mjs'; +const apps=[{id:'settings',origin:'http://settings.localhost'},{id:'wallpaper',origin:'http://wallpaper.localhost',manifest:{activities:{pick:{href:'/pick.html'}}}},{id:'ringtones',origin:'http://ringtones.localhost',manifest:{activities:{pick:{href:'/pick.html'}}}}]; +const caller={app:apps[0],manager:{documentURI:{spec:'http://settings.localhost/#display'}}}; +const picker={app:apps[1]}, stranger={app:apps[2]}; +const events=[],launches=[]; +const broker=new Activities({identity:p=>p.app,apps:()=>apps,launch:(...a)=>launches.push(a),notify:(...a)=>events.push(a),uuid:()=> 'request-1'}); +const pending=broker.start(caller,{name:'pick',data:{type:'image/*'}}); +assert.equal(events.length,0); +broker.subscribe(picker);assert.equal(events.length,1); +assert.throws(()=>broker.finish(stranger,{id:'request-1',result:{}}),/PERMISSION_DENIED/); +assert.throws(()=>broker.start(caller,{name:'pick',data:{type:'image/*'}}),/ACTIVITY_BUSY/); +broker.finish(picker,{id:'request-1',result:{blob:{__vulpesBlobV1:true,type:'image/png',base64:'YWJj'}}}); +assert.equal((await pending).blob.base64,'YWJj');assert.equal(launches.at(-1)[1],'http://settings.localhost/#display'); +const cancelled=broker.start(caller,{name:'pick',data:{type:'image/*'}}); +broker.subscribe(picker);broker.cleanup(picker);await assert.rejects(cancelled,/ACTIVITY_CANCELLED/); +assert.throws(()=>broker.start({app:{id:'untrusted'}},{name:'pick',data:{type:'image/*'}}),/PERMISSION_DENIED/); +assert.throws(()=>broker.provider({name:'pick',data:{type:'video/mp4'}}),/ACTIVITY_NOT_SUPPORTED/); +const abandoned = broker.start(caller,{name:'pick',data:{type:'image/*'}}); +assert.throws(()=>broker.cancel(stranger),/PERMISSION_DENIED/); +broker.cancel({app:{id:'system'}}); +await assert.rejects(abandoned,/ACTIVITY_CANCELLED/); +const reopened = broker.start(caller,{name:'pick',data:{type:'image/*'}}); +broker.subscribe(picker); +broker.finish(picker,{id:'request-1',result:{reopened:true}}); +assert.equal((await reopened).reopened,true); +console.log('Activity routing, result ownership, cancellation and return navigation: OK'); +const phone={id:'communications',origin:'http://communications.localhost',manifest:{activities:{ + pick:{href:'/contacts/index.html?pick',filters:{type:{value:['webcontacts/tel']}}}, + dial:{href:'/dialer/index.html#keyboard-view',filters:{type:'webtelephony/number'},disposition:'window'}, + open:[{href:'/contacts/views/details/details.html',filters:{type:'webcontacts/contact'}}, + {href:'/contacts/views/vcard_load/vcard_load.html',filters:{type:'text/vcard'}}], +}}}; +const sms={id:'sms',origin:'http://sms.localhost',manifest:{activities:{new:{href:'/index.html#/activity-new',filters:{type:'websms/sms'},returnValue:true}}}}; +apps.push(phone,sms); +const smsPeer={app:sms,manager:{documentURI:{spec:'http://sms.localhost/index.html#composer'}}}; +const phonePeer={app:phone}; +const choose=broker.start(smsPeer,{name:'pick',data:{type:'webcontacts/tel'}}); +assert.equal(new URL(launches.at(-1)[1]).searchParams.has('pick'),true); +broker.subscribe(phonePeer); +broker.finish(phonePeer,{id:'request-1',result:{number:'5550199',name:'Test'}}); +assert.equal((await choose).number,'5550199'); +assert.equal(launches.at(-1)[1],'http://sms.localhost/index.html#composer'); +const dial=broker.start(smsPeer,{name:'dial',data:{type:'webtelephony/number',number:'5550199'}}); +broker.subscribe(phonePeer);await dial; +assert.equal(broker.pending.size,0,'dial only opens the keypad, with no stale activity left behind'); +const draft=broker.start(phonePeer,{name:'new',data:{type:'websms/sms',target:'5550199'}}); +assert.equal(new URL(launches.at(-1)[1]).hash,'','activity handler chooses the composer after startup'); +broker.subscribe(smsPeer); +assert.equal(events.at(-1)[2].source.data.target,'5550199'); +broker.finish(smsPeer,{id:'request-1',result:null});await draft; +assert.equal(broker.route({name:'open',data:{type:'webcontacts/contact'}}).url.pathname,'/contacts/views/details/details.html'); +assert.throws(()=>broker.route({name:'open',data:{type:'url'}}),/ACTIVITY_NOT_SUPPORTED/); +console.log('Contacts/SMS picker, contact details, SMS draft and dialer routing: OK'); + +let serial=0; +const nested=new Activities({identity:p=>p.app,apps:()=>apps,launch:(...a)=>launches.push(a),notify:(...a)=>events.push(a),uuid:()=>String(++serial)}); +const contactsPeer={app:phone,manager:{documentURI:{spec:'http://communications.localhost/contacts/index.html'}}}; +nested.subscribe(contactsPeer); +const nestedDraft=nested.start(contactsPeer,{name:'new',data:{type:'websms/sms',target:'5550199'}}); +nested.subscribe(smsPeer); +const nestedPicker=nested.start(smsPeer,{name:'pick',data:{type:'webcontacts/tel'}}); +assert.equal(launches.at(-1)[2].reload,undefined,'reuse the address book without destroying the outer SMS activity'); +assert.equal(events.at(-1)[0],contactsPeer); +nested.finish(contactsPeer,{id:'2',result:{number:'5550199'}}); +assert.equal((await nestedPicker).number,'5550199'); +assert.equal(nested.pending.size,1); +nested.finish(smsPeer,{id:'1',result:null});await nestedDraft; +assert.equal(nested.pending.size,0); + +const gallery={id:'gallery',origin:'http://gallery.localhost',manifest:{activities:{pick:{href:'/index.html#pick',filters:{type:['image/jpeg']},returnValue:true}}}}; +apps.push(gallery); +const normalGallery={app:gallery,manager:{documentURI:{spec:'http://gallery.localhost/index.html'}}}; +nested.subscribe(normalGallery); +const photo=nested.start(contactsPeer,{name:'pick',data:{type:'image/jpeg'}}); +assert.equal(launches.at(-1)[2].reload,true,'normal Gallery must reload in picker mode'); +assert.equal(new URL(launches.at(-1)[1]).hash,'#pick'); +const galleryPicker={app:gallery,manager:{documentURI:{spec:launches.at(-1)[1]}}}; +nested.subscribe(galleryPicker); +const photoRequest=events.at(-1)[2].id; +assert.throws(()=>nested.finish(normalGallery,{id:photoRequest,result:{}}),/PERMISSION_DENIED/); +nested.finish(galleryPicker,{id:photoRequest,result:{blob:new Blob(['image'])}}); +assert.equal(await (await photo).blob.text(),'image'); diff --git a/tests/android-sms-handoff.test.mjs b/tests/android-sms-handoff.test.mjs new file mode 100644 index 00000000..7eea152d --- /dev/null +++ b/tests/android-sms-handoff.test.mjs @@ -0,0 +1,38 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import vm from 'node:vm'; +import {readFileSync} from 'node:fs'; + +function setup(composer) { + let click, assimilated=false; + const calls=[]; + const recipients={numbers:[]}; + const context={console,location:{hostname:'sms.localhost',pathname:'/index.html'}, + document:{readyState:'complete',addEventListener:(name,handler)=>{if(name==='click')click=handler;}}, + VulpesCompat:{call:async(method,params)=>{calls.push({method,params});}}, + VulpesPlatform:'android',Navigation:{isCurrentPanel:()=>composer}, + ConversationView:{recipients,activeThread:{participants:['5550123']},assimilateRecipients(){assimilated=true;recipients.numbers=['5550199'];}}, + Compose:{type:'sms',getText:()=> 'Message à confirmer'}, + }; + context.window=context; + vm.runInNewContext(readFileSync('host/gaia-restoration.js','utf8'),context); + return {calls,context,send(){ + click({target:{closest:()=>true},preventDefault(){},stopImmediatePropagation(){}}); + assert.equal(assimilated,true); + }}; +} +test('Android handoff commits the typed recipient before opening its SMS app',()=>{ + const s=setup(true);s.send(); + assert.equal(s.calls[0].method,'platform.sms'); + assert.equal(s.calls[0].params.number,'5550199'); + assert.equal(s.calls[0].params.body,'Message à confirmer'); +}); +test('Android reply uses the conversation participants and preserves the draft',()=>{ + const s=setup(false);s.send(); + assert.equal(s.calls[0].params.number,'5550123'); + assert.equal(s.context.Compose.getText(),'Message à confirmer'); +}); +test('empty Android messages are not handed off',()=>{ + const s=setup(true);s.context.Compose.getText=()=>'';s.send(); + assert.equal(s.calls.length,0); +}); diff --git a/tests/camera-lifecycle.test.mjs b/tests/camera-lifecycle.test.mjs new file mode 100644 index 00000000..a42577de --- /dev/null +++ b/tests/camera-lifecycle.test.mjs @@ -0,0 +1,152 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import vm from 'node:vm'; +import {readFileSync} from 'node:fs'; + +function deferred() { + let resolve; + const promise = new Promise(r => { resolve = r; }); + return {promise, resolve}; +} + +// Execute the shared adapter, with controllable media promises instead of a sensor. +function setup(native = false) { + const videos = [], streams = [], requests = [], events = new EventTarget(); + const nativeRequests=[]; + let hidden = false, captureGate, playGate, labels = true; + class Document extends EventTarget { get hidden() { return hidden; } } + class Video { + get srcObject() { return this.stream; } + set srcObject(value) { this.stream = value; } + constructor() { this.dataset = {}; this.style = {}; } + play() { return playGate?.promise || Promise.resolve(); } + pause() {} + remove() { const index=videos.indexOf(this); if(index!==-1)videos.splice(index, 1); } + } + const document = new Document(); + Object.assign(document, { + documentElement: {lang:'en'}, body: {append:video => videos.push(video)}, + querySelector: () => null, querySelectorAll: () => [...videos], + createElement: tag => tag === 'canvas' ? {getContext:()=>({ + createShader:()=>({}), shaderSource(){}, compileShader(){}, + getShaderParameter:()=>false, createProgram:()=>({}), + deleteShader(){}, deleteProgram(){}, getExtension:()=>null, + })} : new Video(), + }); + const navigator = {language:'en', mediaDevices: { + async enumerateDevices() { + return ['rear','selfie'].map(deviceId => ({kind:'videoinput', deviceId, + label: labels ? (deviceId === 'rear' ? 'Back camera' : 'Front camera') : ''})); + }, + async getUserMedia(constraints) { + requests.push(constraints); + const id = constraints.video.deviceId?.exact || + (constraints.video.facingMode?.ideal === 'user' ? 'selfie' : 'rear'); + const gate = captureGate; + captureGate = null; + if (gate) await gate.promise; + const track = {readyState:'live', stop() { this.readyState = 'ended'; }, + getSettings: () => ({deviceId:id, width:640, height:480})}; + const stream = Object.assign(new EventTarget(), { + getTracks: () => [track], getVideoTracks: () => [track], + }); + streams.push(stream); + return stream; + }, + }}; + const context = {document, Document, navigator, HTMLMediaElement:Video, console, performance, + location:{hostname:'camera.localhost',port:'8765'}, parent:{}, + MutationObserver:class {observe() {}}, + Event, DOMException, CustomEvent:class extends Event {constructor(type,opts){super(type);this.detail=opts.detail;}}, + setTimeout, clearTimeout, queueMicrotask, setInterval:()=>0, clearInterval(){}, + addEventListener:events.addEventListener.bind(events), dispatchEvent:events.dispatchEvent.bind(events), + VulpesCompat:{async call(method,params) { + if(method==='platform.capabilities')return {platform:native?'tundra':'desktop',camera:true}; + nativeRequests.push(params); + if(params.action==='start')return {session:42,width:640,height:480,orientation:90}; + }}, + }; + context.window = context; + vm.runInNewContext(readFileSync(new URL('../host/gaia-camera.js', import.meta.url),'utf8'), context); + return {api:navigator.mozCameras, streams, requests, videos, nativeRequests, + unlabelled:()=>{labels=false;}, + blockCapture:()=>captureGate=deferred(), blockPlay:()=>playGate=deferred(), + hide:()=>{hidden=true;events.dispatchEvent(new Event('visibilitychange'));}, + show:()=>{hidden=false;events.dispatchEvent(new Event('visibilitychange'));}, + }; +} + +test('unlabelled device identities stay stable after front/back switches', async()=>{ + const s=setup();s.unlabelled(); + for (const [name,id] of [['back','rear'],['front','selfie'],['back','rear'],['front','selfie']]) { + const {camera}=await s.api.getCamera(name); + assert.equal(camera.getVideoTracks()[0].getSettings().deviceId,id); + } + await s.streams.at(-1).release(); +}); + +test('native preview setup failure releases the sensor before returning an error', async()=>{ + const s=setup(true); + await assert.rejects(s.api.getCamera('front'),/Camera shader compilation failed/); + assert.equal(s.nativeRequests.length,2); + assert.equal(s.nativeRequests[1].action,'stop'); + assert.equal(s.nativeRequests[1].session,42); +}); + +test('switch waits for asynchronous close even after release has detached the current stream', async()=>{ + const s=setup(); + const {camera}=await s.api.getCamera('back'); + const gate=deferred();let calls=0; + camera.vulpesCameraClose=()=>{calls++;return gate.promise;}; + const release=camera.release(); + assert.equal(camera.release(),release); + const next=s.api.getCamera('front'); + await new Promise(resolve=>setImmediate(resolve)); + assert.equal(s.requests.length,1); + gate.resolve();await release; + const replacement=await next; + assert.equal(calls,1); + assert.equal(camera.getTracks()[0].readyState,'ended'); + assert.equal(s.videos.length,1,'only the active capture video is retained'); + await replacement.camera.release(); + assert.equal(s.videos.length,0); +}); + +test('failed hardware close still stops tracks and allows reopening', async()=>{ + const s=setup();const {camera}=await s.api.getCamera('back'); + camera.vulpesCameraClose=async()=>{throw Error('device disconnected');}; + await assert.rejects(camera.release(),/device disconnected/); + assert.equal(camera.getTracks()[0].readyState,'ended'); + const next=await s.api.getCamera('front'); + assert.equal(next.camera.getTracks()[0].readyState,'live'); + await next.camera.release(); +}); + +test('concurrent switch waits for a pending open and disposes its stale stream', async()=>{ + const s=setup(),gate=s.blockCapture(); + const first=s.api.getCamera('back'); + const rejected=assert.rejects(first,{name:'AbortError'}); + await new Promise(resolve=>setImmediate(resolve)); + const second=s.api.getCamera('front'); + await new Promise(resolve=>setImmediate(resolve)); + assert.equal(s.requests.length,1,'second sensor must not open before first settles'); + gate.resolve();await rejected; + const {camera}=await second; + assert.equal(s.streams[0].getTracks()[0].readyState,'ended'); + assert.equal(camera.getVideoTracks()[0].getSettings().deviceId,'selfie'); + await camera.release(); +}); + +test('hide/show during preview startup leaves no live abandoned stream', async()=>{ + const s=setup(),gate=s.blockPlay(); + const first=s.api.getCamera('back'); + const rejected=assert.rejects(first,{name:'AbortError'}); + await new Promise(resolve=>setImmediate(resolve)); + s.hide();s.show(); + const next=s.api.getCamera('front'); + gate.resolve();await rejected; + const {camera}=await next; + assert.equal(s.streams[0].getTracks()[0].readyState,'ended'); + assert.equal(camera.getTracks()[0].readyState,'live'); + await camera.release(); +}); diff --git a/tests/contacts.test.mjs b/tests/contacts.test.mjs new file mode 100644 index 00000000..fca77a98 --- /dev/null +++ b/tests/contacts.test.mjs @@ -0,0 +1,59 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import {Contacts} from '../host/Contacts.sys.mjs'; + +let serial=0; +globalThis.Services={uuid:{generateUUID:()=>({toString:()=>`test-${++serial}`})}}; +const writer={manifest:{permissions:{contacts:{access:'readwrite'}}}}; +const reader={manifest:{permissions:{contacts:{access:'readonly'}}}}; + +async function addressBook() { + let stored; + const events=[]; + const storage={async run(_store,operation,args) { + if(operation==='get') return {value:structuredClone(stored)}; + stored=structuredClone(args[0]); + }}; + const contacts=new Contacts(storage,event=>events.push(event)); + await contacts.init(); + return {contacts,events,storage}; +} + +test('contact edits, photo, date and favourite survive reopening the store',async()=>{ + const {contacts,events,storage}=await addressBook(); + const first=await contacts.request(writer,{operation:'save',contact:{ + givenName:['Élodie'],familyName:['Test'],tel:[{value:'+33 6 00 00 00 00'}], + photo:[new Blob(['portrait'],{type:'image/jpeg'})],bday:new Date('1995-08-19T00:00:00Z'), + }}); + const edited=await contacts.request(writer,{operation:'save',contact:{...first,familyName:['Modifiée'],category:['favorite']}}); + assert.equal(edited.id,first.id); + assert.equal(edited.published,first.published); + const reopened=new Contacts(storage,()=>{});await reopened.init(); + const [row]=await reopened.request(reader,{operation:'find',options:{filterBy:['id'],filterOp:'equals',filterValue:first.id}}); + assert.deepEqual(row.familyName,['Modifiée']); + assert.deepEqual(row.category,['favorite']); + assert.equal(await row.photo[0].text(),'portrait'); + assert.equal(row.bday.toISOString(),'1995-08-19T00:00:00.000Z'); + assert.deepEqual(events.map(e=>e.reason),['create','update']); + await contacts.request(writer,{operation:'remove',id:first.id}); + assert.equal(await contacts.request(reader,{operation:'count'}),0); +}); + +test('a failed write emits no contactchange and does not poison later saves',async()=>{ + const {contacts,events,storage}=await addressBook(); + const run=storage.run; + storage.run=async()=>{throw Error('disk full');}; + await assert.rejects(contacts.request(writer,{operation:'save',contact:{name:['First']}}),/disk full/); + assert.equal(events.length,0); + assert.equal(await contacts.request(reader,{operation:'count'}),0); + storage.run=run; + await contacts.request(writer,{operation:'save',contact:{name:['Second']}}); + assert.equal(await contacts.request(reader,{operation:'count'}),1); +}); + +test('read-only callers cannot change the address book',async()=>{ + const {contacts}=await addressBook(); + for(const operation of ['save','remove','clear']) + await assert.rejects(contacts.request(reader,{operation,contact:{name:['Denied']},id:'anything'}),/PERMISSION_DENIED/); + await assert.rejects(contacts.request({manifest:{}},{operation:'find'}),/PERMISSION_DENIED/); +}); diff --git a/tests/installed_apps_test.py b/tests/installed_apps_test.py new file mode 100644 index 00000000..f85116dd --- /dev/null +++ b/tests/installed_apps_test.py @@ -0,0 +1,28 @@ +import base64 +import json +from pathlib import Path +import sys +import tempfile +import unittest +sys.path.insert(0, str(Path(__file__).resolve().parents[1]/'tools')) +from installed_apps import InstalledApps + +class StoreTests(unittest.TestCase): + def test_persistence_removal_and_permission_boundary(self): + with tempfile.TemporaryDirectory() as folder: + store=InstalledApps(folder,8765) + item=dict(id='user-'+'1'*24,manifest=dict(name='Test',type='certified',permissions={'settings':{}}),files={'index.html':base64.b64encode(b'hello').decode()}) + store.save(item) + restored=InstalledApps(folder,8765) + self.assertEqual(restored.read(item['id'],'index.html'),b'hello') + self.assertEqual(restored.records()[0]['manifest']['permissions'],{}) + self.assertEqual(restored.records()[0]['manifest']['type'],'web') + self.assertEqual(json.loads(restored.read(item['id'],'manifest.webapp'))['permissions'],{}) + self.assertEqual((Path(folder)/'.token').stat().st_mode & 0o777,0o600) + self.assertIsNone(restored.read(item['id'],'../.token')) + with self.assertRaises(ValueError):restored.remove('system') + with self.assertRaises(ValueError):restored.save({**item,'id':'../escape'}) + restored.remove(item['id']) + self.assertEqual(InstalledApps(folder,8765).records(),[]) + +if __name__=='__main__':unittest.main() diff --git a/tests/packages.test.mjs b/tests/packages.test.mjs new file mode 100644 index 00000000..b5652611 --- /dev/null +++ b/tests/packages.test.mjs @@ -0,0 +1,35 @@ +import assert from 'node:assert/strict'; +import {execFileSync} from 'node:child_process'; +import {unpackPackage,packageURL,Packages} from '../services/packages.mjs'; +const source='https://vulpes-os.org/marketplace/index.php?download=42'; +function zip(extra={},manifest={}) { + return new Uint8Array(execFileSync('python3',['-c',`import sys,io,zipfile,json +b=io.BytesIO();args=json.loads(sys.argv[1]) +with zipfile.ZipFile(b,'w',zipfile.ZIP_DEFLATED) as z: + z.writestr('manifest.webapp',json.dumps(dict(name='Test',launch_path='/index.html',icons={'128':'/icon.png'},**args['manifest']))) + z.writestr('index.html','

Test

');z.writestr('icon.png',b'icon') + for name,value in args['extra'].items():z.writestr(name,value) +sys.stdout.buffer.write(b.getvalue())`,JSON.stringify({extra,manifest})])); +} +assert.equal(packageURL(source+'&lang=fr'),source); +for(const url of ['http://vulpes-os.org/marketplace/index.php?download=42','https://evil.test/marketplace/index.php?download=42','https://vulpes-os.org/x?download=42','https://vulpes-os.org/marketplace/index.php?download=../42'])assert.throws(()=>packageURL(url)); +const bytes=zip({}, {type:'certified',permissions:{settings:{access:'readwrite'},'webapps-manage':{}}}); +const item=await unpackPackage(bytes,source); +assert.equal(item.manifest.type,'web');assert.deepEqual(item.manifest.permissions,{});assert.match(item.id,/^user-[a-f0-9]{24}$/); +for(const name of ['../escape','/absolute','dir/../../escape','dir\\escape','a:b'])await assert.rejects(unpackPackage(zip({[name]:'bad'}),source)); +await assert.rejects(unpackPackage(bytes.slice(0,-2),source)); +const corrupt=bytes.slice();corrupt[100]^=255;await assert.rejects(unpackPackage(corrupt,source)); +let saved=null,changes=0; +const service=new Packages({save:async value=>saved=value,changed:async()=>changes++,uuid:()=> 'token',fetchPackage:async()=>new Response(bytes)}); +const prepared=await service.prepare(source);assert.equal(saved,null);assert.equal(prepared.name,'Test'); +assert.equal(await service.install(prepared.token),item.id);assert.equal(changes,1);assert.equal(saved.id,item.id); +await assert.rejects(service.install(prepared.token),/INSTALL_EXPIRED/); +console.log('Package URL policy, ZIP boundaries/CRC, permission stripping and one-use confirmation: OK'); + +// Cancellation during download must not produce a confirmation token. +let finishDownload; +const cancelled=new Packages({save:async()=>assert.fail('unexpected save'),changed:async()=>{}, + fetchPackage:()=>new Promise(resolve=>{finishDownload=resolve;})}); +const pending=cancelled.prepare(source);cancelled.cancel();finishDownload(new Response(bytes)); +await assert.rejects(pending,/DOWNLOAD_CANCELLED/);assert.equal(cancelled.pending.size,0); +console.log('Cancelled download cannot be installed: OK'); diff --git a/tests/settings-codec.test.mjs b/tests/settings-codec.test.mjs new file mode 100644 index 00000000..970495b0 --- /dev/null +++ b/tests/settings-codec.test.mjs @@ -0,0 +1,35 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import vm from 'node:vm'; +import {readFileSync} from 'node:fs'; + +const context = {window:{}, Blob, Date, btoa, atob, Uint8Array}; +vm.runInNewContext(readFileSync(new URL('../host/settings-codec.js',import.meta.url),'utf8'),context); +const codec=context.window.VulpesSettingsCodec; +test('native media replies retain the structured-cloned Blob and date', async()=>{ + const blob=new Blob(['jpeg bytes'],{type:'image/jpeg'}), date=new Date(); + const result=codec.decode({blob,lastModified:date}); + assert.equal(result.blob,blob); + assert.equal(result.lastModified,date); + assert.equal(await result.blob.text(),'jpeg bytes'); +}); +test('Android JSON media and settings still round-trip binary content',async()=>{ + const source=new Blob([new Uint8Array([0,128,255,10])],{type:'image/png'}); + const wire=JSON.parse(JSON.stringify(await codec.encode({photo:source}))); + const result=codec.decode(wire); + assert.equal(result.photo.type,'image/png'); + assert.deepEqual(new Uint8Array(await result.photo.arrayBuffer()),new Uint8Array([0,128,255,10])); +}); +test('a near-match marker is ordinary data, not an injected Blob',()=>{ + const result=codec.decode({__vulpesBlobV1:true,type:'image/png',base64:'AA==',other:1}); + assert.equal(result.other,1); + assert.equal(result instanceof Blob,false); +}); + +test('Android contact birthdays keep their ISO date instead of becoming empty objects',async()=>{ + const date=new Date('1995-08-19T00:00:00.000Z'); + const wire=await codec.encode({bday:date,photo:[new Blob(['portrait'],{type:'image/jpeg'})]}); + const result=codec.decode(JSON.parse(JSON.stringify(wire))); + assert.equal(result.bday,date.toISOString()); + assert.equal(await result.photo[0].text(),'portrait'); +}); diff --git a/tests/settings-transitions.test.mjs b/tests/settings-transitions.test.mjs new file mode 100644 index 00000000..dbd37cca --- /dev/null +++ b/tests/settings-transitions.test.mjs @@ -0,0 +1,29 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import vm from 'node:vm'; +import {readFile} from 'node:fs/promises'; +const source=await readFile(new URL('../gaia/apps/settings/js/modules/page_transitions.js',import.meta.url),'utf8'); +function fixture(duration='0.4s') { + let module, timer, delay, calls=0, ready=0; + const panel=Object.assign(new EventTarget(),{id:'wifi',className:''}); + vm.runInNewContext(source,{define:fn=>{module=fn();},CustomEvent, + window:{scrollX:0,scrollY:0,dispatchEvent:()=>ready++,getComputedStyle:()=>({transitionDuration:duration,transitionDelay:'0s'})}, + setTimeout:(cb,ms)=>{timer=cb;delay=ms;return 1;},clearTimeout:()=>{}}); + module.oneColumn({id:'root',className:'current'},panel,()=>calls++); + return {panel,finish:()=>timer(),state:()=>({calls,ready,delay})}; +} +test('Settings reaches onShow when no transition event arrives',()=>{ + const f=fixture();assert.equal(f.state().calls,0);f.finish(); + assert.deepEqual(f.state(),{calls:1,ready:1,delay:500}); + f.panel.dispatchEvent(new Event('transitionend'));f.finish(); + assert.equal(f.state().calls,1); +}); +test('normal and cancelled transitions finish exactly once',()=>{ + for(const type of ['transitionend','transitioncancel']){ + const f=fixture();f.panel.dispatchEvent(new Event(type));f.finish(); + assert.equal(f.state().calls,1);assert.equal(f.state().ready,1); + } +}); +test('disabled animations do not leave navigation pending',()=>{ + const f=fixture('0s');assert.equal(f.state().delay,100);f.finish();assert.equal(f.state().calls,1); +}); diff --git a/tests/wifi-throttle.test.mjs b/tests/wifi-throttle.test.mjs index fb478211..1d155965 100644 --- a/tests/wifi-throttle.test.mjs +++ b/tests/wifi-throttle.test.mjs @@ -107,3 +107,27 @@ test('Native Wi-Fi acknowledges unchanged settings and completes delayed radio c assert.equal(enabled,1); assert.equal(navigator.mozWifiManager.enabled,true); }); + +test('scan without an association does not send Gaia an invalid signal event', async () => { + const {readFile}=await import('node:fs/promises'); + const vm=await import('node:vm'); + let connected=false, signals=0; + const navigator={}; + const context=vm.createContext({navigator,console,Event,EventTarget,DOMException, + window:{VulpesNativeWifi:true},location:{hostname:'settings.localhost'},addEventListener(){}, + VulpesCompat:{request:p=>p,call:async()=>({enabled:true,networks:[ + {ssid:'Test network',id:'/ap/1',signal:80,security:'wpa-psk',connected} + ]})}}); + vm.runInContext(await readFile(new URL('../host/gaia-wifi.js',import.meta.url),'utf8'),context); + const manager=navigator.mozWifiManager; + manager.onconnectioninfoupdate=event=>{ + // The original Settings WifiUtils reads event.network.ssid unconditionally. + assert.equal(event.network.ssid,'Test network'); + assert.equal(event.relSignalStrength,80);signals++; + }; + assert.equal((await manager.getNetworks()).length,1); + assert.equal(signals,0);assert.equal(manager.connectionInformation,null); + connected=true;await manager.getNetworks(); + assert.equal(signals,1);assert.equal(manager.connection.status,'connected'); + connected=false;await manager.getNetworks();assert.equal(signals,1); +}); diff --git a/tools/check-parity.py b/tools/check-parity.py index 7730afec..916a4819 100644 --- a/tools/check-parity.py +++ b/tools/check-parity.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 """Reject stale Android payloads and inconsistent common release metadata.""" -import argparse, hashlib, io, json, re, zipfile +import argparse, contextlib, hashlib, io, json, re, zipfile from project import ROOT, release_info p = argparse.ArgumentParser() -p.add_argument("--apk", type=str) +group = p.add_mutually_exclusive_group() +group.add_argument("--apk", type=str) +group.add_argument("--assets", action="store_true", help="Check staged Android resources, not a compiled APK") args = p.parse_args() r = release_info() apk = ROOT / (args.apk or f'android/dist/vulpes-os-preview-{r["version"]}.apk') @@ -18,8 +20,15 @@ def translate(s): return pattern.sub(lambda m: f"http://{m[1] or m[2]}.localhost:18765", s) +class StagedAssets: + def read(self, name): + if not name.startswith('assets/') or '..' in name.split('/'): + raise ValueError('Invalid packaged path') + return (ROOT / 'android/app/src/main' / name).read_bytes() + results = {} -with zipfile.ZipFile(apk) as archive: +source = contextlib.nullcontext(StagedAssets()) if args.assets else zipfile.ZipFile(apk) +with source as archive: metadata = json.loads(archive.read("assets/build-info.json")) packaged = json.loads(archive.read("assets/bridge/release.json")) assert metadata["version"] == r["version"], metadata @@ -30,6 +39,7 @@ with zipfile.ZipFile(apk) as archive: "platform-ui.js", "gaia-camera.js", "gaia-compat.js", + "settings-codec.js", "gaia-services.js", "gaia-styles.js", "gaia-restoration.js", @@ -65,6 +75,9 @@ with zipfile.ZipFile(apk) as archive: ("calendar", "js/bundle.js", "overrides"), ("gallery", "js/metadata_scripts.js", "assets/webapps"), ("gallery", "js/ImageEditor.js", "assets/webapps"), + ("communications", "contacts/js/views/form.js", "assets/webapps"), + ("communications", "contacts/js/contacts.js", "assets/webapps"), + ("communications", "contacts/js/activities.js", "assets/webapps"), ]: expected = translate((ROOT / source / (app + ".gaiamobile.org") / path).read_text()) for old, new in [("-moz-calc(", "calc("), ("-moz-box-sizing:", "box-sizing:"), @@ -76,13 +89,17 @@ with zipfile.ZipFile(apk) as archive: actual = gaia.read(app + "/" + path) assert actual == expected, "Stale application workflow: " + app + "/" + path results[app + "/" + path] = hashlib.sha256(actual).hexdigest() + for name in ("marketplace.js", "marketplace.css", "icon.png"): + expected = (ROOT / "assets/webapps/marketplace.gaiamobile.org" / name).read_bytes() + if name.endswith(".js"): expected = translate(expected.decode()).encode() + assert gaia.read("marketplace/" + name) == expected, "Stale Marketplace: " + name for path in (ROOT / "overrides/search.gaiamobile.org/home").rglob("*"): if path.is_file(): relative = path.relative_to(ROOT / "overrides/search.gaiamobile.org") assert gaia.read("search/" + relative.as_posix()) == path.read_bytes(), str(relative) assert b"vulpes-local-home" in gaia.read("search/newtab.html") assert archive.read("assets/bridge/Messages.mjs") == (ROOT / "host/Messages.sys.mjs").read_bytes() - for name in ["platform.mjs", "settings.mjs", "datastores.mjs", "screen-power.mjs"]: + for name in ["platform.mjs", "settings.mjs", "datastores.mjs", "screen-power.mjs", "activities.mjs", "packages.mjs"]: assert ( archive.read("assets/bridge/services/" + name) == (ROOT / "services" / name).read_bytes() @@ -99,8 +116,11 @@ report = { "androidEngine": r["androidEngine"], "exactEngineMatch": r["desktopEngine"] == r["androidEngine"], "sharedFiles": results, - "apk": str(apk), + "apk": None if args.assets else str(apk), + "stagedAssetsOnly": args.assets, "scope": "Payload and metadata parity; hardware behavior requires separate integration tests.", } -(ROOT / "logs/parity-payload.json").write_text(json.dumps(report, indent=2) + "\n") +report_path = ROOT / ("logs/parity-staged.json" if args.assets else "logs/parity-payload.json") +report_path.parent.mkdir(parents=True, exist_ok=True) +report_path.write_text(json.dumps(report, indent=2) + "\n") print(json.dumps(report, indent=2)) diff --git a/tools/installed_apps.py b/tools/installed_apps.py new file mode 100644 index 00000000..44dae493 --- /dev/null +++ b/tools/installed_apps.py @@ -0,0 +1,72 @@ +"""Private ordinary-web-app store. No Gaia permissions are read from packages.""" +import base64 +import json +import os +from pathlib import Path +import re +import secrets +import threading + +class InstalledApps: + def __init__(self, directory, port): + self.root = Path(directory) + self.root.mkdir(parents=True, exist_ok=True) + self.port = port + self.lock = threading.RLock() + self.token = secrets.token_hex(32) + token = self.root / '.token' + token.write_text(self.token) + token.chmod(0o600) + self.items = {} + for path in self.root.glob('user-*.json'): + item = json.loads(path.read_text()) + if self.valid_id(item.get('id')): + self.items[item['id']] = item + + @staticmethod + def valid_id(value): + return isinstance(value, str) and re.fullmatch(r'user-[a-f0-9]{24}', value) + + def records(self): + with self.lock: + return [self.record(item) for item in self.items.values()] + + def record(self, item): + origin = f'http://{item["id"]}.localhost:{self.port}' + manifest = {**item['manifest'], 'permissions': {}, 'type': 'web'} + return dict(id=item['id'], origin=origin, manifestURL=origin+'/manifest.webapp', + manifest=manifest, removable=True, installed=True) + + def save(self, item): + if not self.valid_id(item.get('id')) or not isinstance(item.get('files'), dict): + raise ValueError('INVALID_PACKAGE') + # A second boundary check keeps the storage API independent of ZIP parsing. + for name, content in item['files'].items(): + if not isinstance(name, str) or not isinstance(content, str): + raise ValueError('INVALID_PACKAGE') + with self.lock: + target = self.root / (item['id']+'.json') + stage = target.with_suffix('.tmp') + with stage.open('w') as stream: + json.dump(item, stream) + stream.flush() + os.fsync(stream.fileno()) + stage.replace(target) + self.items[item['id']] = item + + def remove(self, app_id): + if not self.valid_id(app_id): + raise ValueError('NOT_REMOVABLE') + with self.lock: + (self.root/(app_id+'.json')).unlink(missing_ok=True) + self.items.pop(app_id, None) + + def read(self, app_id, path): + with self.lock: + item = self.items.get(app_id) + if not item: + return None + if path == 'manifest.webapp': + return json.dumps(self.record(item)['manifest']).encode() + content = item['files'].get(path) + return base64.b64decode(content, validate=True) if content is not None else None diff --git a/tools/project.py b/tools/project.py index 1e8f25b7..92f5c7fd 100644 --- a/tools/project.py +++ b/tools/project.py @@ -65,3 +65,12 @@ def release_info(): if not release["androidVersionCode"] > 4: raise ValueError("Android versionCode must preserve upgrades from Preview 4") return release + + +def application_manifest(app_id, manifest, include_development=False): + """Keep development providers installed but hide their launcher entries.""" + # Runtime exports omit dev_apps sources; keep the same policy in every package. + development = app_id in ('contacts-ds-provider1', 'contacts-ds-provider2', 'contacts-manager', 'ds-test', 'geoloc', 'in_app_pay_test', 'l20n-app', 'marketplace-dev.allizom.org', 'marketplace.allizom.org', 'membuster', 'mobile-wallet', 'mochitest', 'music-oga', 'nfc-api-test', 'share-receiver', 'template', 'test-agent', 'test-container', 'test-iac-publisher', 'test-iac-subscriber', 'test-ime', 'test-keyboard-app', 'test-otasp', 'test-receiver-1', 'test-receiver-2', 'test-receiver-inline', 'test-sensors', 'test-wappush', 'testpermission', 'theme-test-1', 'theme-test-2', 'theme-test-3', 'uitest', 'uitest-privileged', 'upnp-test', 'test-startup-limit') + if development and not include_development: + manifest = {**manifest, "role": "system"} + return manifest diff --git a/tools/refresh-settings-panels.py b/tools/refresh-settings-panels.py index a677e376..ae19c69c 100644 --- a/tools/refresh-settings-panels.py +++ b/tools/refresh-settings-panels.py @@ -3,15 +3,23 @@ from pathlib import Path import re ROOT=Path(__file__).resolve().parents[1] -for panel, module in [('display','slider_handler'),('wifi','wifi_network_list')]: - name=f'panels/{panel}/{module}' - relative=f'js/panels/{panel}/panel.js' +modules = [ + ('panels/display/slider_handler', 'js/panels/display/panel.js'), + ('panels/wifi/wifi_network_list', 'js/panels/wifi/panel.js'), + ('modules/page_transitions', 'js/main.js'), +] +for name, relative in modules: original=ROOT/'assets/webapps/settings.gaiamobile.org'/relative source=ROOT/'overrides/settings.gaiamobile.org'/f'js/{name}.js' + if not source.exists(): + source=ROOT/'gaia/apps/settings'/f'js/{name}.js' text=source.read_text() dependencies=list(dict.fromkeys(re.findall(r"require\(['\"]([^'\"]+)['\"]\)",text))) import json - text=text.replace('define(function(require)', 'define('+repr(name)+','+json.dumps(['require',*dependencies])+',function(require)',1) + if 'define(function(require)' in text: + text=text.replace('define(function(require)', 'define('+repr(name)+','+json.dumps(['require',*dependencies])+',function(require)',1) + else: + text=text.replace('define(function()', 'define('+repr(name)+',[],function()',1) bundle=original.read_text() start=bundle.index("define('"+name+"'") end=bundle.find("define('",start+8) diff --git a/tools/serve-gaia.py b/tools/serve-gaia.py index 561b6135..03bf60c1 100644 --- a/tools/serve-gaia.py +++ b/tools/serve-gaia.py @@ -15,7 +15,9 @@ parser = argparse.ArgumentParser() parser.add_argument("--port", type=int, default=8765) parser.add_argument("--legacy-apps", action="store_true") args = parser.parse_args() -from project import build_info, validate_assets, release_info +from project import build_info, validate_assets, release_info, application_manifest +from installed_apps import InstalledApps +INSTALLED = InstalledApps(ROOT / "profiles/installed-apps", args.port) validate_assets() info = build_info() @@ -44,7 +46,7 @@ for manifest_path in manifests: if not re.fullmatch("[a-z0-9_-]+", name): continue origin = f"http://{name}.localhost:{args.port}" - manifest = json.loads(translate(manifest_path.read_text())) + manifest = application_manifest(name, json.loads(translate(manifest_path.read_text())), os.environ.get("VULPES_SHOW_DEV_APPS") == "1") ORIGINS[urlsplit(origin).netloc] = manifest_path.parent.resolve() REGISTRY.append( { @@ -56,7 +58,7 @@ for manifest_path in manifests: ) ORIGINS[f"theme.localhost:{args.port}"] = ORIGINS[f"default_theme.localhost:{args.port}"] (ROOT / "assets/registry.json").write_text( - json.dumps(REGISTRY, ensure_ascii=False, indent=2) + "\n" + json.dumps(REGISTRY + INSTALLED.records(), ensure_ascii=False, indent=2) + "\n" ) (ROOT / "assets/settings-current-defaults.json").write_text( translate((ROOT / "assets/settings-defaults.json").read_text()) @@ -64,7 +66,45 @@ ORIGINS[f"theme.localhost:{args.port}"] = ORIGINS[f"default_theme.localhost:{arg class Handler(BaseHTTPRequestHandler): + def json_reply(self, value): + data = json.dumps(value).encode() + self.send_response(200) + self.send_header('Content-Type', 'application/json') + self.send_header('Content-Length', str(len(data))) + self.end_headers() + self.wfile.write(data) + + def do_POST(self): + import secrets + if self.headers.get('Host') != f'system.localhost:{args.port}' or not secrets.compare_digest(self.headers.get('X-Vulpes-Install', ''), INSTALLED.token): + self.send_error(403); return + try: + length = int(self.headers.get('Content-Length', '0')) + if not 0 < length <= 70*1024*1024: raise ValueError('INVALID_SIZE') + data = json.loads(self.rfile.read(length)) + if self.path == '/_vulpes/packages/save': INSTALLED.save(data) + elif self.path == '/_vulpes/packages/remove': INSTALLED.remove(data['id']) + else: self.send_error(404); return + self.json_reply(INSTALLED.records()) + except (ValueError, KeyError, OSError): self.send_error(400) + def do_GET(self): + host = self.headers.get('Host', '').lower() + if host == f'system.localhost:{args.port}' and self.path == '/_vulpes/packages/list': + self.json_reply(INSTALLED.records()); return + app_id = host.removesuffix(f'.localhost:{args.port}') + if INSTALLED.valid_id(app_id) and host == f'{app_id}.localhost:{args.port}': + path = unquote(urlsplit(self.path).path).lstrip('/') or 'index.html' + data = INSTALLED.read(app_id, path) + if data is None: self.send_error(404); return + self.send_response(200) + self.send_header('Content-Type', mimetypes.guess_type(path)[0] or 'application/octet-stream') + self.send_header('Content-Length', str(len(data))) + self.send_header('Cache-Control', 'no-store') + self.send_header('Access-Control-Allow-Origin', '*') + self.send_header('X-Content-Type-Options', 'nosniff') + self.send_header('Content-Security-Policy', "object-src 'none'; frame-ancestors http://*.localhost:"+str(args.port)) + self.end_headers(); self.wfile.write(data); return root = ORIGINS.get(self.headers.get("Host", "").lower()) if root is None: self.send_error(421, "Unregistered application host") @@ -93,7 +133,7 @@ class Handler(BaseHTTPRequestHandler): # Only this non-privileged compatibility layer is exposed, never host modules. if path in [ "/_vulpes/" + name - for name in ["gaia-compat.js", "gaia-input.js", "gaia-services.js", "gaia-styles.js", "gaia-restoration.js", "gaia-wifi.js", "desktop.css", "platform-ui.js", "gaia-camera.js"] + for name in ["settings-codec.js", "gaia-compat.js", "gaia-input.js", "gaia-services.js", "gaia-styles.js", "gaia-restoration.js", "gaia-wifi.js", "desktop.css", "platform-ui.js", "gaia-camera.js"] ]: file = ROOT / "host" / path.rsplit("/", 1)[1] else: @@ -157,13 +197,13 @@ class Handler(BaseHTTPRequestHandler): if file.suffix == ".html" and root in LEGACY_ROOTS: data = data.replace( b"", - b'', + b'', 1, ) elif file.suffix == ".html" and not (root.name == "search.gaiamobile.org" and path.startswith("/home/")): data = data.replace( b"", - b'', + b'', 1, ) if ( diff --git a/tools/test-camera.py b/tools/test-camera.py index cf3d2f7a..685e1308 100644 --- a/tools/test-camera.py +++ b/tools/test-camera.py @@ -76,12 +76,13 @@ with Client(2857) as c: "camera", 'return app.camera.mode==="picture" && app.camera.mozCamera.flashMode==="off";', ) - # Native touch injection targets the camera frame even on high-DPI desktops. - point = ev("camera", 'const r=document.querySelector(".js-capture").getBoundingClientRect();return {x:r.x+r.width/2,y:r.y+r.height/2};') + # Drive the desktop mouse through the normal touch simulator. Wait for + # layout after reload: a decoded video can precede a visible app frame. + point = wait("camera", 'const b=document.querySelector(".js-capture"),r=b.getBoundingClientRect(),x=r.x+r.width/2,y=r.y+r.height/2;return x>0 && y>0 && xdone(true),e=>done({error:String(e)}));""".replace('POINT',json.dumps(point)) +find(root).currentWindowGlobal.getActor('VulpesProbe').sendQuery('MouseClick',POINT).then(()=>done(true),e=>done({error:String(e)}));""".replace('POINT',json.dumps(point)) assert c.call('WebDriver:ExecuteAsyncScript',{'script':script,'args':[], 'newSandbox':True,'sandbox':'system','scriptTimeout':10000})['value'] is True photo = wait( diff --git a/tools/test-contacts.py b/tools/test-contacts.py new file mode 100644 index 00000000..3a8dd226 --- /dev/null +++ b/tools/test-contacts.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +"""Exercise Gaia Contacts and its SMS/dialer activities in the desktop test profile. + +Creates one temporary contact; never sends a message or starts a call. +""" +import importlib.util +import json +import time +import sys +from pathlib import Path +from marionette_client import Client + +spec = importlib.util.spec_from_file_location('probe', Path(__file__).with_name('probe-desktop.py')) +probe = importlib.util.module_from_spec(spec) +spec.loader.exec_module(probe) +results = {} +contact_id = None +photo_name = None +name = 'Vulpes QA ' + str(time.time_ns()) + +with Client(2857) as client: + client.socket.settimeout(90) + probe.register(client) + + def ev(app, code): + result = probe.evaluate(client, 'communications' if app == 'dialer' else app, code, '/dialer/' if app == 'dialer' else '/contacts/' if app == 'communications' else '/') + if 'error' in result: + raise AssertionError(result) + return result.get('value') + + def wait(app, code): + for _ in range(100): + try: + value = ev(app, code) + except AssertionError as error: + if 'Actor' not in str(error) or 'destroyed' not in str(error): + raise + value = None + if value: + return value + time.sleep(.15) + raise TimeoutError(app + ': ' + code) + + def click(app, selector): + print("click", app, selector, file=sys.stderr, flush=True) + point = wait(app, 'for(const e of document.querySelectorAll(' + json.dumps(selector) + ')) {' + 'const r=e.getBoundingClientRect(),x=r.x+r.width/2,y=r.y+r.height/2;' + 'if(x>0&&y>0&&xdone(true),e=>done({error:String(e)}));'''.replace('PREFIX', json.dumps('http://' + app + '.localhost:8765/')).replace('POINT', json.dumps(point)) + clicked = client.call('WebDriver:ExecuteAsyncScript', {'script': script, 'args': [], + 'newSandbox': True, 'sandbox': 'system', 'scriptTimeout': 10000})['value'] + assert clicked is True, clicked + + def field(selector, value): + wait('communications', 'return !!document.querySelector(' + json.dumps(selector) + ');') + ev('communications', 'const e=document.querySelector(' + json.dumps(selector) + ');' + 'e.value=' + json.dumps(value) + ';e.dispatchEvent(new Event("input",{bubbles:true}));return true;') + + def contact(): + return ev('communications', '''const r=navigator.mozContacts.find({filterBy:['givenName'], +filterOp:'equals',filterValue:NAME});return await new Promise((ok,no)=>{ +r.onsuccess=()=>ok(r.result[0]||null);r.onerror=()=>no(r.error);});'''.replace('NAME', json.dumps(name))) + + try: + wait('system', 'return document.body?.getAttribute("ready-state")==="fullyLoaded";') + ev('system', "ScreenManager.turnScreenOn(true);if(Service.query('locked'))await Service.request('unlock',{forcibly:true});await VulpesCompat.call('apps.launch',{manifestURL:'http://communications.localhost:8765/manifest.webapp',entryPoint:'contacts'});return true;") + wait('communications', 'return document.readyState==="complete"&&!document.hidden;') + ev('system', "await VulpesCompat.call('apps.launch',{manifestURL:'http://gallery.localhost:8765/manifest.webapp'});return true;") + wait('gallery', 'return document.readyState==="complete"&&!document.hidden;') + fixture='vulpes-contacts-qa-'+str(time.time_ns())+'.jpg' + photo_name=ev('gallery', 'const c=document.createElement("canvas");c.width=c.height=400;' + 'const ctx=c.getContext("2d");ctx.fillStyle="#2372ae";ctx.fillRect(0,0,400,400);' + 'const blob=await new Promise(r=>c.toBlob(r,"image/jpeg"));' + 'return await VulpesCompat.call("media.request",{operation:"add",type:"pictures",name:'+json.dumps(fixture)+',blob});') + ev('system', "await VulpesCompat.call('apps.launch',{manifestURL:'http://communications.localhost:8765/manifest.webapp',entryPoint:'contacts'});return true;") + token = str(time.time_ns()) + ev('communications', 'setTimeout(()=>location.href=location.origin+"/contacts/index.html?qa='+token+'",0);return true;') + wait('communications', 'return location.search==="?qa='+token+'" && document.readyState==="complete";') + wait('communications', 'return typeof Loader!=="undefined" && !!window.Contacts && MainNavigation.currentView()==="view-contacts-list";') + click('communications', '#add-contact-button') + wait('communications', 'return window.MainNavigation?.currentView()==="view-contact-form" && !!document.querySelector("#number_0");') + field('#givenName', name) + field('#familyName', 'Élodie Test') + field('#number_0', '5550199') + field('#email_0', 'qa@example.invalid') + click('communications', '#save-button') + for _ in range(80): + row = contact() + if row: + contact_id = row['id'] + break + time.sleep(.15) + assert contact_id + results['create'] = row['tel'][0]['value'] == '5550199' + item = '[data-uuid=' + json.dumps(contact_id) + ']' + click('communications', '#search-start') + wait('communications', "return MainNavigation.currentView()==='search-view' && !!document.querySelector('#search-contact');") + field('#search-contact', 'elodie') + results['search_without_accent'] = bool(wait('communications', 'return !!document.querySelector(' + json.dumps('#search-list [data-uuid="' + contact_id + '"]') + ');')) + field('#search-contact', name + ' absent') + results['search_no_results'] = bool(wait('communications', "return !document.querySelector('#no-result').classList.contains('hide');")) + click('communications', '#cancel-search') + wait('communications', "return MainNavigation.currentView()==='view-contacts-list';") + click('communications', item) + click('communications', '#edit-contact-button') + wait('communications', 'return MainNavigation.currentView()==="view-contact-form";') + click('communications', '#photo-button') + wait('gallery', 'return !document.hidden && typeof picking!=="undefined" && picking;') + thumb='.thumbnailImage[data-filename='+json.dumps(photo_name)+']' + click('gallery',thumb) + wait('gallery','return !document.querySelector("#crop-done-button").disabled;') + click('gallery','#crop-done-button') + wait('communications', 'return !document.hidden && getComputedStyle(document.querySelector("#thumbnail-photo")).backgroundImage!=="none";') + field('#familyName', 'Élodie Modifiée') + click('communications', '#save-button') + results['edit_detail_refresh'] = bool(wait('communications', 'return document.querySelector("#contact-name-title")?.textContent.includes("Élodie Modifiée");')) + assert contact()['familyName'] == ['Élodie Modifiée'] + results['contact_photo']=bool(ev('communications', 'const r=navigator.mozContacts.find({filterBy:["id"],filterOp:"equals",filterValue:'+json.dumps(contact_id)+'});const c=await new Promise(ok=>{r.onsuccess=()=>ok(r.result[0]);});return c.photo?.[0] instanceof Blob && c.photo[0].size>0;')) + assert results['contact_photo'] + ev('communications', 'document.querySelector("#toggle-favorite").scrollIntoView({block:"center"});return true;') + click('communications', '#toggle-favorite') + results['favorite'] = bool(wait('communications', 'const r=navigator.mozContacts.find({filterBy:["id"],filterOp:"equals",filterValue:'+json.dumps(contact_id)+'});const c=await new Promise(ok=>{r.onsuccess=()=>ok(r.result[0]);});return c.category?.includes("favorite");')) + ev('communications', 'document.querySelector("#send-sms-button-0").scrollIntoView({block:"center"});return true;') + click('communications', '#send-sms-button-0') + results['sms_recipient'] = bool(wait('sms', 'return !document.hidden&&window.ConversationView?.recipients?.numbers.includes("5550199");')) + click('sms', '#messages-contact-pick-button') + wait('communications', 'return !document.hidden&&ActivityHandler.currentlyHandling;') + click('communications', item) + wait('communications', 'return !!document.querySelector("[data-l10n-id=pick_destination]");') + click('communications', '[data-l10n-id=pick_destination]') + wait('communications', 'return !ActivityHandler.currentlyHandling;') + results['picker_return'] = bool(wait('sms', 'return !document.hidden&&ConversationView.recipients.numbers.includes("5550199");')) + # This activity only prefills the original dialer; do not press Call. + ev('sms', 'window.__dialQA=new MozActivity({name:"dial",data:{type:"webtelephony/number",number:"5550199"}});return true;') + results['dialer_prefill'] = bool(wait('dialer', 'return !document.hidden&&document.querySelector("#phone-number-view")?.value==="5550199";')) + ev('system', "await VulpesCompat.call('apps.launch',{manifestURL:'http://communications.localhost:8765/manifest.webapp',entryPoint:'contacts'});return true;") + wait('communications', 'return !document.hidden;') + click('communications', item) + click('communications', '#edit-contact-button') + wait('communications', 'return MainNavigation.currentView()==="view-contact-form";') + ev('communications', 'document.querySelector("#delete-contact").scrollIntoView({block:"center"});return true;') + click('communications', '#delete-contact') + click('communications', '#confirmation-message button[data-l10n-id=cancel]') + results['delete_cancel'] = contact() is not None + wait('communications', 'return document.querySelector("#confirmation-message").classList.contains("hide");') + click('communications', '#delete-contact') + click('communications', '#confirmation-message button[data-l10n-id=delete]') + for _ in range(100): + if contact() is None: + results['delete_confirm'] = True + results['temporary_contact_removed'] = True + contact_id = None + break + time.sleep(.15) + assert results.get('delete_confirm') + results['passed'] = all(results.values()) + finally: + try: + if contact_id: + # Return to the address book before removing only our temporary entry. + ev('system', "await VulpesCompat.call('apps.launch',{manifestURL:'http://communications.localhost:8765/manifest.webapp',entryPoint:'contacts'});return true;") + ev('communications', 'const r=navigator.mozContacts.remove(' + json.dumps(contact_id) + ');await new Promise((ok,no)=>{r.onsuccess=ok;r.onerror=()=>no(r.error);});return true;') + results['temporary_contact_removed'] = contact() is None + except Exception as error: + results['cleanup_error'] = str(error) + results['temporary_contact_id'] = contact_id + finally: + if photo_name: + try: + ev('gallery','await VulpesCompat.call("media.request",{operation:"delete",type:"pictures",name:'+json.dumps(photo_name)+'});return true;') + results['temporary_photo_removed']=True + except Exception as error: + results['photo_cleanup_error']=str(error) + results['temporary_photo_name']=photo_name + print(json.dumps(results, indent=2, ensure_ascii=False)) + +if not results.get('passed') or results.get('cleanup_error') or results.get('photo_cleanup_error'): + raise SystemExit('Contacts qualification failed; see the report above.') diff --git a/tools/test-system-banner.py b/tools/test-system-banner.py new file mode 100644 index 00000000..ceb9a395 --- /dev/null +++ b/tools/test-system-banner.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +"""Exercise Gaia's transient banner in the isolated desktop host.""" +import importlib.util +import json +from pathlib import Path +from marionette_client import Client +spec = importlib.util.spec_from_file_location('probe', Path(__file__).with_name('probe-desktop.py')) +probe = importlib.util.module_from_spec(spec) +spec.loader.exec_module(probe) +with Client(2857) as client: + probe.register(client) + result = probe.evaluate(client, 'system', ''' +await LazyLoader.load('js/system_banner.js'); +const banner=new SystemBanner(); +const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms)); +try { + await banner.show({id:'app-install-success',args:{appName:'Vulpes test'}}); + const shown=banner._banner.isConnected; + await sleep(4900); + const dismissed=!banner._banner.isConnected; + await banner.show('app-install-success'); + await sleep(1000); + await banner.show('app-install-success'); + await sleep(3300); + const replacementRetained=banner._banner.isConnected; + await sleep(1600); + const replacementDismissed=!banner._banner.isConnected; + await banner.show('app-install-success'); + banner._banner.click(); + await sleep(800); + const clickDismissed=!banner._banner.isConnected; + return {shown,dismissed,replacementRetained,replacementDismissed,clickDismissed}; +} finally {await banner.hide();banner._banner?.remove();} +''') + assert 'error' not in result, result + checks=result['value'] + assert all(checks.values()), checks + print(json.dumps(checks, indent=2)) diff --git a/tundra/boot/sparse-backup.c b/tundra/boot/sparse-backup.c new file mode 100644 index 00000000..bfb82c98 --- /dev/null +++ b/tundra/boot/sparse-backup.c @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: MPL-2.0 + * Read stdin only. Emit offsets and nonzero 64 KiB blocks for a host-side backup. + * No device is opened or written by this process. + */ +#define _start unused_stage0_start +#include "init.c" +#undef _start +static unsigned long buffer[8192]; +static void stop(long code) { + call(NR_exit, code, 0, 0, 0, 0); + for (;;) {} +} +static void write_all(const void *data, long length) { + const char *p = data; + while (length) { + long n = call(NR_write, 1, (long)p, length, 0, 0); + if (n == -4) continue; + if (n <= 0) stop(3); + p += n; + length -= n; + } +} +__attribute__((noreturn)) void _start(void) { + unsigned long offset = 0; + write_all("TUNRAW1\0", 8); + for (;;) { + long n = call(NR_read, 0, (long)buffer, sizeof(buffer), 0, 0); + if (n == -4) continue; + if (n < 0) stop(2); + if (!n) break; + unsigned long bits = 0; + long i = 0; + for (; i + 8 <= n; i += 8) bits |= buffer[i / 8]; + for (; i < n; ++i) bits |= ((unsigned char *)buffer)[i]; + if (bits) { + unsigned long header[2] = {offset, (unsigned long)n}; + write_all(header, sizeof(header)); + write_all(buffer, n); + } + offset += n; + } + unsigned long end[2] = {offset, 0}; + write_all(end, sizeof(end)); + call(NR_exit, 0, 0, 0, 0, 0); + for (;;) {} +} diff --git a/tundra/boot/standalone-mount.sh b/tundra/boot/standalone-mount.sh new file mode 100644 index 00000000..384d0438 --- /dev/null +++ b/tundra/boot/standalone-mount.sh @@ -0,0 +1,14 @@ +#!/bin/busybox sh +# SPDX-License-Identifier: MPL-2.0 +# Mount only the prepared Tundra volume. Never format or guess an old filesystem. +set -eu +# VOLUME_CONFIGURATION +mkdir -p /volume +blkid "$VOLUME_DEVICE" | grep -F "UUID=\"$VOLUME_UUID\"" >/dev/null +repaired=0 +e2fsck -p "$VOLUME_DEVICE" || repaired=$? +test "$repaired" -le 1 +mount -t ext4 -o "$VOLUME_OPTIONS" "$VOLUME_DEVICE" /volume +test "$(cat /volume/tundra-volume-id)" = "$VOLUME_UUID" +echo TUNDRA_STANDALONE_VOLUME_READY +exec /bin/sh /native-root.sh diff --git a/tundra/droidian/probe.sys.mjs b/tundra/droidian/probe.sys.mjs index 0949a2aa..2879a786 100644 --- a/tundra/droidian/probe.sys.mjs +++ b/tundra/droidian/probe.sys.mjs @@ -67,8 +67,10 @@ export async function run(win) { .then(async response=>dump(`TUNDRA_HTTP ${response.status} ${(await response.text()).length}\n`)) .catch(error=>dump('TUNDRA_HTTP_ERROR '+error+' offline='+Services.io.offline+'\n')); async function evaluate(app, code, message = 'Evaluate') { + const prefix=app==='contacts'?'http://communications.localhost:8765/contacts/': + app==='dialer'?'http://communications.localhost:8765/dialer/':`http://${app}.localhost:8765/`; function find(context) { - if(context.currentWindowGlobal?.documentURI.spec.startsWith(`http://${app}.localhost:8765/`)) return context; + if(context.currentWindowGlobal?.documentURI.spec.startsWith(prefix)) return context; for(const child of context.children) {const found=find(child); if(found) return found;} return null; } @@ -90,14 +92,15 @@ export async function run(win) { } throw new Error(`${app}: timeout: ${last}`); } - async function tap(app, selector) { - if(app==='keyboard') selector='.keyboard-type-container[data-active] '+selector; - await wait(app, `const e=document.querySelector(${JSON.stringify(selector)});if(!e)return false;const r=e.getBoundingClientRect();return r.width>0 && r.height>0 && e.contains(document.elementFromPoint(r.x+r.width/2,r.y+r.height/2));`); - await sleep(600); - const point = await evaluate(app, `const e=document.querySelector(${JSON.stringify(selector)});const r=e.getBoundingClientRect();return {x:r.x+r.width/2,y:r.y+r.height/2};`); - await evaluate(app,point,'Tap'); - await sleep(350); - } + async function tap(app, selector) { + if(app==='keyboard') selector='.keyboard-type-container[data-active] '+selector; + const point=await wait(app, `for(const e of document.querySelectorAll(${JSON.stringify(selector)})) { + const r=e.getBoundingClientRect(),x=r.x+r.width/2,y=r.y+r.height/2; + if(x>0 && y>0 && x0;"); - // Gaia remembers the selected lens; establish a known starting state. - await evaluate('camera', "if(app.settings.cameras.selected('key')!=='back')app.settings.cameras.next();return true;"); - await wait('camera', "return app.settings.cameras.selected('key')==='back' && !!app.camera.mozCamera && !app.camera.isBusy && document.querySelector('.viewfinder video')?.videoWidth>0;"); - cameraReport.gaia = await evaluate('camera', ` - const video=document.querySelector('video'); - const camera=app.camera.mozCamera; - window.__cameraBeforeSwitch=camera; - const capabilities=camera.capabilities; - let focus=null; - if(capabilities.maxFocusAreas>0) { - camera.setFocusAreas([{top:-150,left:-150,bottom:150,right:150}]); - await camera.autoFocus();focus=true; - } - if(capabilities.zoomRatios.length>1) { - camera.zoom=2; - await new Promise(r=>setTimeout(r,700)); - } - const testedZoom=camera.zoom; - camera.zoom=1; - const photo=await camera.takePicture(); - const bitmap=await createImageBitmap(photo); - const picture={width:bitmap.width,height:bitmap.height};bitmap.close(); - return {width:video.videoWidth,height:video.videoHeight,native:camera.vulpesNative===true, - picture,focus,zoom:testedZoom,focusAreas:capabilities.maxFocusAreas, - jpegBytes:photo.size,jpegType:photo.type,errors:window.__vulpesDiagnostics}; - `); - cameraReport.performance = await evaluate('camera', ` - const stream=app.camera.mozCamera, before=stream.vulpesTiming?.frames||0; - const start=performance.now();await new Promise(r=>setTimeout(r,4000)); - const elapsed=performance.now()-start; - const hud=document.querySelector('.hud'); - const button=document.querySelector('.js-camera'); - return {fps:(stream.vulpesTiming.frames-before)*1000/elapsed, - conversionMs:stream.vulpesTiming.conversionMs/stream.vulpesTiming.frames, - switchVisible:getComputedStyle(button).opacity!=='0' && hud.getAttribute('camera-enabled')==='true', - flashVisible:getComputedStyle(document.querySelector('.js-flash')).visibility==='visible'}; - `); - await evaluate('camera', "document.querySelector('.js-camera').click();return true;"); - await wait('camera', "return !!app.camera.mozCamera && app.camera.mozCamera!==window.__cameraBeforeSwitch && !app.camera.isBusy && document.querySelector('.viewfinder video')?.videoWidth>0;"); - cameraReport.switched = await evaluate('camera', ` - const photo=await app.camera.mozCamera.takePicture(); - window.__cameraBeforeHome=app.camera.mozCamera; - return {camera:app.settings.cameras.selected('key'),jpegBytes:photo.size, - previousStopped:window.__cameraBeforeSwitch.getTracks().every(t=>t.readyState==='ended')}; - `); - cameraReport.roundTrips = []; - for (let i=0; i<4; i++) { - await evaluate('camera', "window.__switchFrom=app.camera.mozCamera;return true;"); - await tap('camera', '.js-camera'); - await wait('camera', "return !!app.camera.mozCamera && app.camera.mozCamera!==window.__switchFrom && !app.camera.isBusy && document.querySelector('.viewfinder video')?.videoWidth>0;"); - cameraReport.roundTrips.push(await evaluate('camera', ` - const camera=app.camera.mozCamera, before=camera.vulpesTiming.frames; - await new Promise(r=>setTimeout(r,700)); - return {camera:app.settings.cameras.selected('key'), - frames:camera.vulpesTiming.frames-before, - previousStopped:window.__switchFrom.getTracks().every(t=>t.readyState==='ended')}; - `)); - } - await evaluate('camera', 'window.__cameraBeforeHome=app.camera.mozCamera;return true;'); - // Test Gaia's Home action, independent of a held pointer on the shell button. - cameraReport.beforeHome = await evaluate('system', "return {active:Service.query('getTopMostWindow')?.origin, top:Service.query('getTopMostUI')?.name, locked:Service.query('locked'), screen:ScreenManager.screenEnabled};"); - await evaluate('system', "dispatchEvent(new CustomEvent('home'));return true;"); - cameraReport.afterHome = await evaluate('system', "await new Promise(r=>setTimeout(r,1000));return {active:Service.query('getTopMostWindow')?.origin, top:Service.query('getTopMostUI')?.name, locked:Service.query('locked'), screen:ScreenManager.screenEnabled};"); - cameraReport.hidden = await wait('camera', 'return document.hidden;'); - cameraReport.stopped = await wait('camera', "return window.__cameraBeforeHome.getTracks().every(t=>t.readyState==='ended');"); - cameraReport.passed=cameraReport.gaia.native && cameraReport.gaia.picture.width*cameraReport.gaia.picture.height>10000000 && cameraReport.gaia.focus && cameraReport.gaia.zoom>1 && cameraReport.gaia.jpegBytes>1000 && cameraReport.gaia.jpegType==='image/jpeg' && cameraReport.switched.jpegBytes>1000 && cameraReport.switched.previousStopped && cameraReport.stopped && cameraReport.roundTrips.every(r=>r.frames>0 && r.previousStopped); - } catch(error) { cameraReport.error=String(error); } - finally { win.document.getElementById('home')?.click(); } - await IOUtils.writeJSON(`${root}/logs/camera.json`, cameraReport); - } - const smsMarker = `${root}/logs/test-sms-display`; - if (await IOUtils.exists(smsMarker)) { - await IOUtils.remove(smsMarker); - const smsReport = {bootId:report.bootId, passed:false, sent:false}; - try { - await evaluate('system', "ScreenManager.turnScreenOn(true);if(Service.query('locked'))await Service.request('unlock',{forcibly:true});await VulpesCompat.call('apps.launch',{manifestURL:'http://sms.localhost:8765/manifest.webapp'});return true;"); - await wait('sms', "return !!window.Navigation && !!window.MessageManager;"); - smsReport.threads = await evaluate('sms', ` - const threads=await new Promise((resolve,reject)=>{const rows=[];const c=navigator.mozMobileMessage.getThreads();c.onsuccess=()=>{if(c.done)resolve(rows);else{rows.push(c.result);c.continue();}};c.onerror=()=>reject(c.error);}); - window.__smsReviewThreads=threads.map(t=>t.id); - return {count:threads.length,validDates:threads.every(t=>Number.isFinite(+t.timestamp))}; - `); - smsReport.conversations=[]; - for(let i=0;iNumber.isFinite(+e.querySelector('time')?.dataset.time)), - nonempty:nodes.every(e=>!!e.querySelector('.message-content-body')?.textContent), - errorCount:window.__vulpesDiagnostics?.length||0}; - `)); - } - smsReport.passed=smsReport.threads.validDates && smsReport.conversations.length>0 && smsReport.conversations.every(c=>c.bubbles>0 && c.validDates && c.nonempty); - } catch(error) {smsReport.error=String(error);} - finally {win.document.getElementById('home')?.click();} - await IOUtils.writeJSON(`${root}/logs/sms-display.json`,smsReport); - } - const inputMarker = `${root}/logs/test-keyboard`; - if (await IOUtils.exists(inputMarker)) { - await IOUtils.remove(inputMarker); - const inputReport = {bootId:report.bootId,recordedAt:Date.now(),passed:false,sent:false}; - try { - await evaluate('system', 'ScreenManager.turnScreenOn(true);if(Service.query("locked"))await Service.request("unlock",{forcibly:true});return true;'); - await sleep(1500); - await evaluate('system', `await VulpesCompat.call('apps.launch',{manifestURL:'http://sms.localhost:8765/manifest.webapp'});return true;`); - await wait('sms', 'return document.querySelector("#threads-composer-link") && innerWidth>0;'); - await evaluate('sms', 'await Navigation.toPanel("thread-list");await Navigation.toPanel("composer");return true;'); - await wait('sms','return !!document.querySelector(".recipient[contenteditable]");'); - await tap('sms','.recipient[contenteditable]'); - await wait('keyboard', 'return navigator.mozInputMethod?.inputcontext?.inputType==="tel" && !!document.querySelector("button[aria-label=\\"2\\"]");'); - await tap('keyboard','button[aria-label="2"]'); - await tap('keyboard','button[aria-label="3"]'); - inputReport.recipientTyped = await evaluate('sms','return document.querySelector(".recipient[contenteditable]").textContent.endsWith("23");'); - const recipientBefore=await evaluate('sms','return document.querySelector(".recipient[contenteditable]").textContent;'); - await tap('sms','#messages-input'); - await wait('keyboard', 'return navigator.mozInputMethod?.inputcontext?.inputType==="text" && !!document.querySelector("button[aria-label=\\"a\\"]");'); - inputReport.keyboard = await evaluate('keyboard', `const e=document.querySelector('button[aria-label="a"]');const r=e.getBoundingClientRect(); - window.__keyTrial=[];for(const type of ['touchstart','touchend','pointerdown','click']) e.addEventListener(type,()=>__keyTrial.push(type),{once:true}); - return {width:innerWidth,height:innerHeight,key:r.toJSON(),font:getComputedStyle(document.documentElement).fontSize,portrait:app.viewManager.screenInPortraitMode(),engine:app.inputMethodManager.currentIMEngine?.constructor?.name};`); - await tap('keyboard','button[aria-label="a"]'); - await sleep(2000); - inputReport.context = await evaluate('keyboard', 'const c=navigator.mozInputMethod.inputcontext;return c&&{id:c.id,type:c.type,inputType:c.inputType,textLength:c.text.length};'); - inputReport.message = await evaluate('sms', 'const text=document.querySelector("#messages-input").textContent;return {length:text.length,lowercase:text.includes("a"),uppercase:text.includes("A")};'); - inputReport.messageTyped = inputReport.message.lowercase || inputReport.message.uppercase; - inputReport.events = await evaluate('keyboard','return window.__keyTrial;'); - inputReport.recipientUnchanged=await evaluate('sms',`return document.querySelector(".recipient[contenteditable]").textContent===${JSON.stringify(recipientBefore)};`); - inputReport.passed=inputReport.recipientTyped && inputReport.messageTyped && inputReport.recipientUnchanged && inputReport.keyboard.portrait && inputReport.keyboard.key.height>=44; - if(!inputReport.messageTyped) { - try { - await evaluate('keyboard','await navigator.mozInputMethod.inputcontext.sendKey(0,97);return true;'); - inputReport.directKey = await evaluate('sms','return document.querySelector("#messages-input").textContent.length>0;'); - } catch(error) {inputReport.directKeyError=String(error);} - } - inputReport.fonts=await evaluate('sms',null,'RenderedFonts'); - for (const face of inputReport.fonts) delete face.samples; - } catch(error) {inputReport.error=String(error);} - finally {win.document.getElementById('home').click();} - await IOUtils.writeJSON(`${root}/logs/keyboard.json`,inputReport); - } - const sendMarker=`${root}/logs/test-send-sms.json`; - if(await IOUtils.exists(sendMarker)) { - const request=await IOUtils.readJSON(sendMarker); - await IOUtils.remove(sendMarker); - const result={bootId:report.bootId,recordedAt:Date.now(),submitted:false,deliveryConfirmed:false}; - try { - if(typeof request.recipient!=='string' || !/^\+[0-9]{8,15}$/.test(request.recipient)) throw Error('INVALID_TEST_RECIPIENT'); - const {tundraRadio}=ChromeUtils.importESModule('resource://vulpes/host/Tundra.sys.mjs'); - const state=await tundraRadio('status'); - if(!['registered','roaming'].includes(state.registration?.[0]?.Status?.data)) throw Error('RADIO_NOT_REGISTERED'); - await evaluate('system', 'ScreenManager.turnScreenOn(true);if(Service.query("locked"))await Service.request("unlock",{forcibly:true});return true;'); - await sleep(1000); - await evaluate('system', `await VulpesCompat.call('apps.launch',{manifestURL:'http://sms.localhost:8765/manifest.webapp'});return true;`); - await wait('sms','return !!window.Navigation;'); - await evaluate('sms','await Navigation.toPanel("thread-list");await Navigation.toPanel("composer");return true;'); - await evaluate('sms','if(ConversationView.recipients.length || document.querySelector(".recipient[contenteditable]").textContent.trim() || Compose.getText())throw Error("TEST_DRAFT_PRESENT");return true;'); - await tap('sms','.recipient[contenteditable]'); - await wait('keyboard','return navigator.mozInputMethod?.inputcontext?.inputType==="tel";'); - await evaluate('keyboard',`await navigator.mozInputMethod.inputcontext.replaceSurroundingText(${JSON.stringify(request.recipient)},0,0);return true;`); - await tap('sms','#messages-input'); - await wait('keyboard','return navigator.mozInputMethod?.inputcontext?.inputType==="text";'); - const body='Vulpes OS - test SMS '+new Date().toISOString(); - await evaluate('keyboard',`await navigator.mozInputMethod.inputcontext.replaceSurroundingText(${JSON.stringify(body)},0,0);return true;`); - await wait('sms','return !document.querySelector("#messages-send-button").disabled;'); - await evaluate('sms',`if(!Navigation.isCurrentPanel('composer') || - JSON.stringify(ConversationView.recipients.numbers)!==JSON.stringify([${JSON.stringify(request.recipient)}]) || - Compose.getText()!==${JSON.stringify(body)})throw Error('TEST_MESSAGE_MISMATCH'); - document.querySelector('#messages-send-button').click();return true;`); - result.submitted=await wait('sms',`return await new Promise((resolve,reject)=>{ - const cursor=navigator.mozMobileMessage.getMessages(null,true); - cursor.onsuccess=()=>{const m=cursor.result;if(!m){resolve(false);return;} - if(m.body===${JSON.stringify(body)}){if(m.delivery==='error'){reject(Error('MODEM_TRANSMISSION_FAILED'));return;}resolve(m.delivery==='sent');return;}cursor.continue();}; - cursor.onerror=()=>reject(cursor.error); - });`); - } catch(error) {result.error=String(error);} - finally {win.document.getElementById('home').click();} - await IOUtils.writeJSON(`${root}/logs/send-sms.json`,result); - } - const notificationMarker = `${root}/logs/test-notifications`; - if (await IOUtils.exists(notificationMarker)) { - await IOUtils.remove(notificationMarker); - const result = {bootId:report.bootId,passed:false,silent:true}; - let id; - try { - await evaluate('system', `ScreenManager.turnScreenOn(true);await VulpesCompat.call('apps.launch',{manifestURL:'http://sms.localhost:8765/manifest.webapp'});return true;`); - await wait('sms', 'return typeof Notification.get === "function";'); - await evaluate('system', 'if(!Service.query("locked"))await Service.request("lock");return true;'); - result.lockState=await evaluate('system','return {service:Service.query("locked"),direct:lockScreen.locked,preview:NotificationScreen.lockscreenPreview};'); - await wait('system', 'return Service.query("locked") && NotificationScreen.lockscreenPreview;'); - id = await evaluate('sms', `return await new Promise((resolve,reject)=>{ - const n=new Notification('Vulpes — test local',{body:'Notification de qualification',tag:'vulpes-qualification',silent:true}); - n.onshow=()=>resolve(n.id);n.onerror=()=>reject(n.error); - });`); - const selector = `[data-notification-id="${id}"]`; - result.tray = await wait('system', `return !!NotificationScreen.container.querySelector(${JSON.stringify(selector)});`); - result.lockscreen = await wait('system', `return !!NotificationScreen.getLockScreenContainer()?.querySelector(${JSON.stringify(selector)});`); - await evaluate('sms', `const rows=await Notification.get({tag:'vulpes-qualification'});rows.forEach(n=>n.close());return true;`); - result.removed = await wait('system', `return !NotificationScreen.container.querySelector(${JSON.stringify(selector)}) && !NotificationScreen.getLockScreenContainer()?.querySelector(${JSON.stringify(selector)});`); - result.passed = result.tray && result.lockscreen && result.removed; - } catch(error) { result.error=String(error); } - finally { - if(id) await evaluate('sms', `for(const n of await Notification.get({tag:'vulpes-qualification'})) n.close();return true;`).catch(()=>{}); - win.document.getElementById('home').click(); - } - await IOUtils.writeJSON(`${root}/logs/notifications.json`,result); - } - } - await requestedUiChecks(); - let uiCheckRunning=false; - const uiCheckTimer=setInterval(async()=>{ - if(uiCheckRunning) return; - uiCheckRunning=true; - try { - const reloadMarker=`${root}/logs/test-reload-gaia`; - if(await IOUtils.exists(reloadMarker)) { - await IOUtils.remove(reloadMarker); - win.document.querySelector('browser').reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE); - await wait('system', "return document.body?.getAttribute('ready-state')==='fullyLoaded';"); - await sleep(1500); - } - await requestedUiChecks(); - } catch(error) {dump('TUNDRA_UI_CHECK_ERROR '+error+'\n');} - finally {uiCheckRunning=false;} - },3000); - win.addEventListener('unload',()=>clearInterval(uiCheckTimer),{once:true}); + async function requestedControls() { const controlsMarker = `${root}/logs/test-controls`; if (await IOUtils.exists(controlsMarker)) { await IOUtils.remove(controlsMarker); @@ -569,6 +338,392 @@ export async function run(win) { controls.brightness=brightnessCheck; await IOUtils.writeJSON(`${root}/logs/controls.json`, controls); } + } + async function requestedUiChecks() { + await requestedControls(); + const marketplaceMarker = `${root}/logs/test-marketplace-views`; + if (await IOUtils.exists(marketplaceMarker)) { + await IOUtils.remove(marketplaceMarker); + const result = {bootId:report.bootId,passed:false,checks:{},fixture:'http://127.0.0.1:8767/'}; + const {Views}=ChromeUtils.importESModule('resource://vulpes/host/Views.sys.mjs'); + const {Runtime}=ChromeUtils.importESModule('resource://vulpes/host/Runtime.sys.mjs'); + const until=async check=>{ + for(let i=0;i<80;i++){if(await check())return true;await sleep(250);} + throw Error('Marketplace view check timed out'); + }; + const visible=()=>[...Views.entries.values()].some(e=>e.browser.style.visibility==='visible'); + const open=async()=>{ + await evaluate('system', 'await VulpesCompat.call("apps.launch",{manifestURL:"http://marketplace.localhost:8765/manifest.webapp"});return true;'); + await wait('marketplace', 'return !!document.getElementById("browse");'); + await sleep(1000); + await evaluate('marketplace', 'document.getElementById("browse").click();document.getElementById("catalogue").src="http://127.0.0.1:8767/";return true;'); + await until(visible); + }; + try { + await evaluate('system', 'ScreenManager.turnScreenOn(true);if(Service.query("locked"))await Service.request("unlock",{forcibly:true});return true;'); + await sleep(1000); + // This fixture tests web-view ownership, not the lockscreen gesture. + // Service.unlock can leave the legacy overlay visible during clock teardown. + result.unlockFixture=await evaluate('system', 'let note=null;if(window.lockScreen){try{if(lockScreen.locked)lockScreen.unlock(true);}catch(e){note=String(e);}lockScreen.locked=false;lockScreen.overlay.classList.add("unlocked");}return {forced:true,cleanupError:note};'); + await open(); + result.checks.belowStatusBar=[...Views.entries.values()].filter(e=>e.browser.style.visibility==='visible').every(e=>parseFloat(e.browser.style.top)>=20); + await evaluate('marketplace', 'document.getElementById("catalogue").src="https://marketplace-offline.invalid/";return true;'); + result.checks.offlineMessage=await wait('marketplace', 'return !document.getElementById("message").hidden && /inaccessible|unavailable/.test(document.getElementById("status").textContent);'); + result.checks.errorHidden=await until(()=>!visible()); + await open(); + result.checks.retry=true; + win.document.getElementById('home').click(); + result.checks.home=await until(()=>!visible()); + await sleep(1000); + await open(); + Runtime.broadcast('holdhome',{},'system'); + await wait('system','return appWindowManager.taskManager.isActive();'); + result.checks.taskSwitcher=await until(()=>!visible()); + await sleep(1000); + await evaluate('system', 'const row=[...appWindowManager.taskManager.appToCardMap].find(([app])=>app.origin.includes("marketplace.localhost"));row[1].element.querySelector(".close-button").click();return true;'); + result.checks.closed=await until(()=>Views.entries.size===0); + result.passed=Object.values(result.checks).every(Boolean); + } catch(error) { + result.error=String(error); + result.views=[...Views.entries.values()].map(e=>({geometry:e.geometry,style:e.browser.style.cssText})); + } finally {win.document.getElementById('home').click();} + await IOUtils.writeJSON(`${root}/logs/marketplace-views.json`,result); + } + const ticketMarker = `${root}/logs/test-tickets-20261005`; + if (await IOUtils.exists(ticketMarker)) { + await IOUtils.remove(ticketMarker); + const result = {bootId:report.bootId,passed:false,checks:{}}; + try { + await evaluate('system', "ScreenManager.turnScreenOn(true);if(Service.query('locked'))await Service.request('unlock',{forcibly:true});return true;"); + await wait('system', "return !Service.query('locked');"); + await evaluate('system', "await VulpesCompat.call('apps.launch',{manifestURL:'http://settings.localhost:8765/manifest.webapp'});return true;"); + await wait('settings', "return document.readyState==='complete';"); + await evaluate('settings', "window.__ticketLanguage=(await VulpesCompat.call('settings.get',{key:'language.current'})).value;return true;"); + for (const lang of ['en-US','fr']) { + await evaluate('settings', `await VulpesCompat.call('settings.set',{values:{'language.current':${JSON.stringify(lang)}}});return true;`); + result.checks['language_'+lang] = await wait('homescreen', `return navigator.language===${JSON.stringify(lang)} && document.documentElement.lang===${JSON.stringify(lang)};`); + } + result.checks.developmentHidden = await evaluate('homescreen', "return [...document.querySelectorAll('gaia-app-icon')].every(e=>!/(uitest|test-|membuster|template|ds-test)/.test(e.app?.origin || ''));"); + result.checks.snap = await evaluate('homescreen', "return getComputedStyle(document.getElementById('panels')).scrollSnapType==='x mandatory';"); + await evaluate('settings', "window.__ticketPicker=new MozActivity({name:'pick',data:{type:'image/*'}});return true;"); + await wait('wallpaper', "return !!window.Wallpaper?.pickActivity && document.querySelectorAll('.wallpaper').length>1;"); + await evaluate('wallpaper', "document.querySelectorAll('.wallpaper')[1].click();return true;"); + result.checks.wallpaperPicker = await wait('settings', "return __ticketPicker.readyState==='done' && __ticketPicker.result?.blob instanceof Blob && __ticketPicker.result.blob.size>0;"); + await evaluate('settings', "window.__ticketPicker=new MozActivity({name:'pick',data:{type:'alerttone'}});return true;"); + await wait('ringtones', "return document.body.dataset.ready==='true' && document.querySelectorAll('gaia-radio').length>3;"); + await evaluate('ringtones', "document.querySelectorAll('gaia-radio')[2].click();return true;"); + await wait('ringtones', "return !document.getElementById('set').disabled;"); + await evaluate('ringtones', "document.getElementById('set').click();return true;"); + result.checks.tonePicker = await wait('settings', "return __ticketPicker.readyState==='done' && __ticketPicker.result?.blob instanceof Blob && __ticketPicker.result.blob.size>0;"); + result.passed=Object.values(result.checks).every(Boolean); + } catch(error) {result.error=String(error);} + finally { + await evaluate('settings', "if(window.__ticketLanguage)await VulpesCompat.call('settings.set',{values:{'language.current':__ticketLanguage}});return true;").catch(()=>{}); + win.document.getElementById('home').click(); + } + await IOUtils.writeJSON(`${root}/logs/tickets-20261005.json`,result); + } + const cameraMarker = `${root}/logs/test-camera`; + if (await IOUtils.exists(cameraMarker)) { + await IOUtils.remove(cameraMarker); + const cameraReport = {bootId:report.bootId, imagesRetained:false, passed:false}; + try { + await evaluate('system', "ScreenManager.turnScreenOn(true);if(Service.query('locked'))await Service.request('unlock',{forcibly:true});return true;"); + await wait('system', "return !Service.query('locked');"); + await evaluate('system', "await VulpesCompat.call('apps.launch',{manifestURL:'http://camera.localhost:8765/manifest.webapp'});return true;"); + await wait('camera', "return !!window.app?.camera?.mozCamera && document.querySelector('video')?.videoWidth>0;"); + // Gaia remembers the selected lens; establish a known starting state. + await evaluate('camera', "if(app.settings.cameras.selected('key')!=='back')app.settings.cameras.next();return true;"); + await wait('camera', "return app.settings.cameras.selected('key')==='back' && !!app.camera.mozCamera && !app.camera.isBusy && document.querySelector('.viewfinder video')?.videoWidth>0;"); + cameraReport.gaia = await evaluate('camera', ` + const video=document.querySelector('video'); + const camera=app.camera.mozCamera; + window.__cameraBeforeSwitch=camera; + const capabilities=camera.capabilities; + let focus=null, focusError=null; + if(capabilities.maxFocusAreas>0) { + try { + camera.setFocusAreas([{top:-150,left:-150,bottom:150,right:150}]); + await camera.autoFocus();focus=true; + } catch(error) { focus=false;focusError=String(error); } + } + if(capabilities.zoomRatios.length>1) { + camera.zoom=2; + await new Promise(r=>setTimeout(r,700)); + } + const testedZoom=camera.zoom; + camera.zoom=1; + const photo=await camera.takePicture(); + const bitmap=await createImageBitmap(photo); + const picture={width:bitmap.width,height:bitmap.height};bitmap.close(); + return {width:video.videoWidth,height:video.videoHeight,native:camera.vulpesNative===true, + picture,focus,focusError,zoom:testedZoom,focusAreas:capabilities.maxFocusAreas, + jpegBytes:photo.size,jpegType:photo.type,errors:window.__vulpesDiagnostics}; + `); + cameraReport.performance = await evaluate('camera', ` + const stream=app.camera.mozCamera, before=stream.vulpesTiming?.frames||0; + const start=performance.now();await new Promise(r=>setTimeout(r,4000)); + const elapsed=performance.now()-start; + const hud=document.querySelector('.hud'); + const button=document.querySelector('.js-camera'); + return {fps:(stream.vulpesTiming.frames-before)*1000/elapsed, + conversionMs:stream.vulpesTiming.conversionMs/stream.vulpesTiming.frames, + switchVisible:getComputedStyle(button).opacity!=='0' && hud.getAttribute('camera-enabled')==='true', + flashVisible:getComputedStyle(document.querySelector('.js-flash')).visibility==='visible'}; + `); + await evaluate('camera', "document.querySelector('.js-camera').click();return true;"); + await wait('camera', "return !!app.camera.mozCamera && app.camera.mozCamera!==window.__cameraBeforeSwitch && !app.camera.isBusy && document.querySelector('.viewfinder video')?.videoWidth>0;"); + cameraReport.switched = await evaluate('camera', ` + const photo=await app.camera.mozCamera.takePicture(); + window.__cameraBeforeHome=app.camera.mozCamera; + return {camera:app.settings.cameras.selected('key'),jpegBytes:photo.size, + previousStopped:window.__cameraBeforeSwitch.getTracks().every(t=>t.readyState==='ended')}; + `); + cameraReport.roundTrips = []; + for (let i=0; i<4; i++) { + await evaluate('camera', "window.__switchFrom=app.camera.mozCamera;return true;"); + await tap('camera', '.js-camera'); + await wait('camera', "return !!app.camera.mozCamera && app.camera.mozCamera!==window.__switchFrom && !app.camera.isBusy && document.querySelector('.viewfinder video')?.videoWidth>0;"); + cameraReport.roundTrips.push(await evaluate('camera', ` + const camera=app.camera.mozCamera, before=camera.vulpesTiming.frames; + await new Promise(r=>setTimeout(r,700)); + return {camera:app.settings.cameras.selected('key'), + frames:camera.vulpesTiming.frames-before, + previousStopped:window.__switchFrom.getTracks().every(t=>t.readyState==='ended')}; + `)); + } + await evaluate('camera', 'window.__cameraBeforeHome=app.camera.mozCamera;return true;'); + // Test Gaia's Home action, independent of a held pointer on the shell button. + await evaluate('camera', "window.__cameraFilesBefore=new Set((await VulpesCompat.call('media.request',{type:'pictures',operation:'enumerate'})).map(f=>f.name));return true;"); + await tap('camera','.js-capture'); + await wait('camera', "const files=await VulpesCompat.call('media.request',{type:'pictures',operation:'enumerate'});window.__cameraSavedPhoto=files.find(f=>!__cameraFilesBefore.has(f.name));return !!__cameraSavedPhoto;"); + cameraReport.savedPhoto=await evaluate('camera', 'return {name:__cameraSavedPhoto.name,size:__cameraSavedPhoto.size,type:__cameraSavedPhoto.type};'); + await evaluate('system', "await VulpesCompat.call('apps.launch',{manifestURL:'http://gallery.localhost:8765/manifest.webapp'});return true;"); + await wait('gallery', `return typeof files!=='undefined' && files.some(f=>f.name===${JSON.stringify(cameraReport.savedPhoto.name)} && f.metadata.width>0 && f.metadata.thumbnail);`); + await evaluate('gallery', `document.querySelector('[data-filename="'+${JSON.stringify(cameraReport.savedPhoto.name)}+'"]')?.click();return true;`); + cameraReport.galleryOpened=await wait('gallery', "return document.body.classList.contains('fullscreenView');"); + await evaluate('system', "await VulpesCompat.call('apps.launch',{manifestURL:'http://camera.localhost:8765/manifest.webapp'});return true;"); + await wait('camera', "return !!app.camera.mozCamera && !app.camera.isBusy && !document.hidden;"); + await evaluate('camera', `await navigator.getDeviceStorage('pictures').delete(${JSON.stringify(cameraReport.savedPhoto.name)});window.__cameraBeforeHome=app.camera.mozCamera;return true;`); + cameraReport.captureStored=cameraReport.savedPhoto.size>1000; + delete cameraReport.savedPhoto.name; + cameraReport.beforeHome = await evaluate('system', "return {active:Service.query('getTopMostWindow')?.origin, top:Service.query('getTopMostUI')?.name, locked:Service.query('locked'), screen:ScreenManager.screenEnabled};"); + await evaluate('system', "dispatchEvent(new CustomEvent('home'));return true;"); + cameraReport.afterHome = await evaluate('system', "await new Promise(r=>setTimeout(r,1000));return {active:Service.query('getTopMostWindow')?.origin, top:Service.query('getTopMostUI')?.name, locked:Service.query('locked'), screen:ScreenManager.screenEnabled};"); + cameraReport.hidden = await wait('camera', 'return document.hidden;'); + cameraReport.stopped = await wait('camera', "return window.__cameraBeforeHome.getTracks().every(t=>t.readyState==='ended');"); + cameraReport.passed=cameraReport.captureStored && cameraReport.galleryOpened && cameraReport.gaia.native && cameraReport.gaia.picture.width*cameraReport.gaia.picture.height>10000000 && cameraReport.gaia.focus && cameraReport.gaia.zoom>1 && cameraReport.gaia.jpegBytes>1000 && cameraReport.gaia.jpegType==='image/jpeg' && cameraReport.switched.jpegBytes>1000 && cameraReport.switched.previousStopped && cameraReport.stopped && cameraReport.roundTrips.every(r=>r.frames>0 && r.previousStopped); + } catch(error) { cameraReport.error=String(error); } + finally { win.document.getElementById('home')?.click(); } + await IOUtils.writeJSON(`${root}/logs/camera.json`, cameraReport); + } + const contactsMarker=`${root}/logs/test-contacts`; + if(await IOUtils.exists(contactsMarker)) { + await IOUtils.remove(contactsMarker); + const result={bootId:report.bootId,passed:false}, name='Vulpes QA '+Date.now(); + let id; + const lookup=`const r=navigator.mozContacts.find({filterBy:['givenName'],filterOp:'equals',filterValue:${JSON.stringify(name)}}); + return await new Promise((ok,no)=>{r.onsuccess=()=>ok(r.result[0]||null);r.onerror=()=>no(r.error);});`; + const field=async(selector,value)=>evaluate('contacts',`const e=document.querySelector(${JSON.stringify(selector)}); + e.value=${JSON.stringify(value)};e.dispatchEvent(new Event('input',{bubbles:true}));return true;`); + try { + await evaluate('system', "ScreenManager.turnScreenOn(true);if(Service.query('locked'))await Service.request('unlock',{forcibly:true});await VulpesCompat.call('apps.launch',{manifestURL:'http://communications.localhost:8765/manifest.webapp',entryPoint:'contacts'});return true;"); + await wait('contacts', "return typeof Loader!=='undefined' && window.MainNavigation?.currentView()==='view-contacts-list';"); + await tap('contacts','#add-contact-button'); + await wait('contacts', "return MainNavigation.currentView()==='view-contact-form' && !!document.querySelector('#number_0');"); + await field('#givenName',name);await field('#familyName','Élodie Test'); + await field('#number_0','5550199');await field('#email_0','qa@example.invalid'); + await tap('contacts','#save-button'); + const saved=await wait('contacts',lookup);id=saved.id; + result.created=saved.tel[0].value==='5550199'; + const selector='[data-uuid="'+id+'"]'; + await tap('contacts',selector);await tap('contacts','#edit-contact-button'); + await wait('contacts', "return MainNavigation.currentView()==='view-contact-form';"); + await field('#familyName','Élodie Modifiée');await tap('contacts','#save-button'); + result.edited=await wait('contacts', "return document.querySelector('#contact-name-title')?.textContent.includes('Élodie Modifiée');"); + await evaluate('contacts', "document.querySelector('#send-sms-button-0').scrollIntoView({block:'center'});return true;"); + await tap('contacts','#send-sms-button-0'); + result.sms=await wait('sms', "return !document.hidden && window.ConversationView?.recipients?.numbers.includes('5550199');"); + await tap('sms','#messages-contact-pick-button'); + await wait('contacts', 'return !document.hidden && ActivityHandler.currentlyHandling;'); + await tap('contacts',selector);await tap('contacts','[data-l10n-id=pick_destination]'); + await wait('contacts','return !ActivityHandler.currentlyHandling;'); + result.picker=await wait('sms', "return !document.hidden && ConversationView.recipients.numbers.includes('5550199');"); + await evaluate('sms', "new MozActivity({name:'dial',data:{type:'webtelephony/number',number:'5550199'}});return true;"); + result.dialer=await wait('dialer', "return !document.hidden && document.querySelector('#phone-number-view')?.value==='5550199';"); + result.passed=result.created&&result.edited&&result.sms&&result.picker&&result.dialer; + } catch(error) {result.error=String(error);} + finally { + try { + if(!id) id=(await evaluate('contacts',lookup))?.id; + if(id) { + await evaluate('contacts', `const r=navigator.mozContacts.remove(${JSON.stringify(id)});await new Promise((ok,no)=>{r.onsuccess=ok;r.onerror=()=>no(r.error);});return true;`); + result.temporaryContactRemoved=!(await evaluate('contacts',lookup)); + } + } catch(error) {result.cleanupError=String(error);} + win.document.getElementById('home')?.click(); + } + await IOUtils.writeJSON(`${root}/logs/contacts.json`,result); + } + const smsMarker = `${root}/logs/test-sms-display`; + if (await IOUtils.exists(smsMarker)) { + await IOUtils.remove(smsMarker); + const smsReport = {bootId:report.bootId, passed:false, sent:false}; + try { + await evaluate('system', "ScreenManager.turnScreenOn(true);if(Service.query('locked'))await Service.request('unlock',{forcibly:true});await VulpesCompat.call('apps.launch',{manifestURL:'http://sms.localhost:8765/manifest.webapp'});return true;"); + await wait('sms', "return !!window.Navigation && !!window.MessageManager;"); + smsReport.threads = await evaluate('sms', ` + const threads=await new Promise((resolve,reject)=>{const rows=[];const c=navigator.mozMobileMessage.getThreads();c.onsuccess=()=>{if(c.done)resolve(rows);else{rows.push(c.result);c.continue();}};c.onerror=()=>reject(c.error);}); + window.__smsReviewThreads=threads.map(t=>t.id); + return {count:threads.length,validDates:threads.every(t=>Number.isFinite(+t.timestamp))}; + `); + smsReport.conversations=[]; + for(let i=0;iNumber.isFinite(+e.querySelector('time')?.dataset.time)), + nonempty:nodes.every(e=>!!e.querySelector('.message-content-body')?.textContent), + errorCount:window.__vulpesDiagnostics?.length||0}; + `)); + } + smsReport.passed=smsReport.threads.validDates && smsReport.conversations.length>0 && smsReport.conversations.every(c=>c.bubbles>0 && c.validDates && c.nonempty); + } catch(error) {smsReport.error=String(error);} + finally {win.document.getElementById('home')?.click();} + await IOUtils.writeJSON(`${root}/logs/sms-display.json`,smsReport); + } + const inputMarker = `${root}/logs/test-keyboard`; + if (await IOUtils.exists(inputMarker)) { + await IOUtils.remove(inputMarker); + const inputReport = {bootId:report.bootId,recordedAt:Date.now(),passed:false,sent:false}; + try { + await evaluate('system', 'ScreenManager.turnScreenOn(true);if(Service.query("locked"))await Service.request("unlock",{forcibly:true});return true;'); + await sleep(1500); + await evaluate('system', `await VulpesCompat.call('apps.launch',{manifestURL:'http://sms.localhost:8765/manifest.webapp'});return true;`); + await wait('sms', 'return document.querySelector("#threads-composer-link") && innerWidth>0;'); + await evaluate('sms', 'await Navigation.toPanel("thread-list");await Navigation.toPanel("composer");return true;'); + await wait('sms','return !!document.querySelector(".recipient[contenteditable]");'); + await tap('sms','.recipient[contenteditable]'); + await wait('keyboard', 'return navigator.mozInputMethod?.inputcontext?.inputType==="tel" && !!document.querySelector("button[aria-label=\\"2\\"]");'); + await tap('keyboard','button[aria-label="2"]'); + await tap('keyboard','button[aria-label="3"]'); + inputReport.recipientTyped = await evaluate('sms','return document.querySelector(".recipient[contenteditable]").textContent.endsWith("23");'); + const recipientBefore=await evaluate('sms','return document.querySelector(".recipient[contenteditable]").textContent;'); + await tap('sms','#messages-input'); + await wait('keyboard', 'return navigator.mozInputMethod?.inputcontext?.inputType==="text" && !!document.querySelector("button[aria-label=\\"a\\"]");'); + inputReport.keyboard = await evaluate('keyboard', `const e=document.querySelector('button[aria-label="a"]');const r=e.getBoundingClientRect(); + window.__keyTrial=[];for(const type of ['touchstart','touchend','pointerdown','click']) e.addEventListener(type,()=>__keyTrial.push(type),{once:true}); + return {width:innerWidth,height:innerHeight,key:r.toJSON(),font:getComputedStyle(document.documentElement).fontSize,portrait:app.viewManager.screenInPortraitMode(),engine:app.inputMethodManager.currentIMEngine?.constructor?.name};`); + await tap('keyboard','button[aria-label="a"]'); + await sleep(2000); + inputReport.context = await evaluate('keyboard', 'const c=navigator.mozInputMethod.inputcontext;return c&&{id:c.id,type:c.type,inputType:c.inputType,textLength:c.text.length};'); + inputReport.message = await evaluate('sms', 'const text=document.querySelector("#messages-input").textContent;return {length:text.length,lowercase:text.includes("a"),uppercase:text.includes("A")};'); + inputReport.messageTyped = inputReport.message.lowercase || inputReport.message.uppercase; + inputReport.events = await evaluate('keyboard','return window.__keyTrial;'); + inputReport.recipientUnchanged=await evaluate('sms',`return document.querySelector(".recipient[contenteditable]").textContent===${JSON.stringify(recipientBefore)};`); + inputReport.passed=inputReport.recipientTyped && inputReport.messageTyped && inputReport.recipientUnchanged && inputReport.keyboard.portrait && inputReport.keyboard.key.height>=44; + if(!inputReport.messageTyped) { + try { + await evaluate('keyboard','await navigator.mozInputMethod.inputcontext.sendKey(0,97);return true;'); + inputReport.directKey = await evaluate('sms','return document.querySelector("#messages-input").textContent.length>0;'); + } catch(error) {inputReport.directKeyError=String(error);} + } + inputReport.fonts=await evaluate('sms',null,'RenderedFonts'); + for (const face of inputReport.fonts) delete face.samples; + } catch(error) {inputReport.error=String(error);} + finally {win.document.getElementById('home').click();} + await IOUtils.writeJSON(`${root}/logs/keyboard.json`,inputReport); + } + const sendMarker=`${root}/logs/test-send-sms.json`; + if(await IOUtils.exists(sendMarker)) { + const request=await IOUtils.readJSON(sendMarker); + await IOUtils.remove(sendMarker); + const result={bootId:report.bootId,recordedAt:Date.now(),submitted:false,deliveryConfirmed:false}; + try { + if(typeof request.recipient!=='string' || !/^\+[0-9]{8,15}$/.test(request.recipient)) throw Error('INVALID_TEST_RECIPIENT'); + const {tundraRadio}=ChromeUtils.importESModule('resource://vulpes/host/Tundra.sys.mjs'); + const state=await tundraRadio('status'); + if(!['registered','roaming'].includes(state.registration?.[0]?.Status?.data)) throw Error('RADIO_NOT_REGISTERED'); + await evaluate('system', 'ScreenManager.turnScreenOn(true);if(Service.query("locked"))await Service.request("unlock",{forcibly:true});return true;'); + await sleep(1000); + await evaluate('system', `await VulpesCompat.call('apps.launch',{manifestURL:'http://sms.localhost:8765/manifest.webapp'});return true;`); + await wait('sms','return !!window.Navigation;'); + await evaluate('sms','await Navigation.toPanel("thread-list");await Navigation.toPanel("composer");return true;'); + await evaluate('sms','if(ConversationView.recipients.length || document.querySelector(".recipient[contenteditable]").textContent.trim() || Compose.getText())throw Error("TEST_DRAFT_PRESENT");return true;'); + await tap('sms','.recipient[contenteditable]'); + await wait('keyboard','return navigator.mozInputMethod?.inputcontext?.inputType==="tel";'); + await evaluate('keyboard',`await navigator.mozInputMethod.inputcontext.replaceSurroundingText(${JSON.stringify(request.recipient)},0,0);return true;`); + await tap('sms','#messages-input'); + await wait('keyboard','return navigator.mozInputMethod?.inputcontext?.inputType==="text";'); + const body='Vulpes OS - test SMS '+new Date().toISOString(); + await evaluate('keyboard',`await navigator.mozInputMethod.inputcontext.replaceSurroundingText(${JSON.stringify(body)},0,0);return true;`); + await wait('sms','return !document.querySelector("#messages-send-button").disabled;'); + result.preSend=await evaluate('sms',`return {composer:Navigation.isCurrentPanel('composer'), + recipientMatch:JSON.stringify(ConversationView.recipients.numbers.map(n=>navigator.mozPhoneNumberService.normalize(n)))===JSON.stringify([${JSON.stringify(request.recipient)}]), + recipientCount:ConversationView.recipients.numbers.length, + bodyMatch:Compose.getText()===${JSON.stringify(body)},bodyLength:Compose.getText().length, + expectedLength:${body.length}};`); + if(!result.preSend.composer || !result.preSend.recipientMatch || !result.preSend.bodyMatch) + throw Error('TEST_MESSAGE_MISMATCH'); + await evaluate('sms',"document.querySelector('#messages-send-button').click();return true;"); + result.submitted=await wait('sms',`return await new Promise((resolve,reject)=>{ + const cursor=navigator.mozMobileMessage.getMessages(null,true); + cursor.onsuccess=()=>{const m=cursor.result;if(!m){resolve(false);return;} + if(m.body===${JSON.stringify(body)}){if(m.delivery==='error'){reject(Error('MODEM_TRANSMISSION_FAILED'));return;}resolve(m.delivery==='sent');return;}cursor.continue();}; + cursor.onerror=()=>reject(cursor.error); + });`); + } catch(error) {result.error=String(error);} + finally {win.document.getElementById('home').click();} + await IOUtils.writeJSON(`${root}/logs/send-sms.json`,result); + } + const notificationMarker = `${root}/logs/test-notifications`; + if (await IOUtils.exists(notificationMarker)) { + await IOUtils.remove(notificationMarker); + const result = {bootId:report.bootId,passed:false,silent:true}; + let id; + try { + await evaluate('system', `ScreenManager.turnScreenOn(true);await VulpesCompat.call('apps.launch',{manifestURL:'http://sms.localhost:8765/manifest.webapp'});return true;`); + await wait('sms', 'return typeof Notification.get === "function";'); + await evaluate('system', 'if(!Service.query("locked"))await Service.request("lock");return true;'); + result.lockState=await evaluate('system','return {service:Service.query("locked"),direct:lockScreen.locked,preview:NotificationScreen.lockscreenPreview};'); + await wait('system', 'return Service.query("locked") && NotificationScreen.lockscreenPreview;'); + id = await evaluate('sms', `return await new Promise((resolve,reject)=>{ + const n=new Notification('Vulpes — test local',{body:'Notification de qualification',tag:'vulpes-qualification',silent:true}); + n.onshow=()=>resolve(n.id);n.onerror=()=>reject(n.error); + });`); + const selector = `[data-notification-id="${id}"]`; + result.tray = await wait('system', `return !!NotificationScreen.container.querySelector(${JSON.stringify(selector)});`); + result.lockscreen = await wait('system', `return !!NotificationScreen.getLockScreenContainer()?.querySelector(${JSON.stringify(selector)});`); + await evaluate('sms', `const rows=await Notification.get({tag:'vulpes-qualification'});rows.forEach(n=>n.close());return true;`); + result.removed = await wait('system', `return !NotificationScreen.container.querySelector(${JSON.stringify(selector)}) && !NotificationScreen.getLockScreenContainer()?.querySelector(${JSON.stringify(selector)});`); + result.passed = result.tray && result.lockscreen && result.removed; + } catch(error) { result.error=String(error); } + finally { + if(id) await evaluate('sms', `for(const n of await Notification.get({tag:'vulpes-qualification'})) n.close();return true;`).catch(()=>{}); + win.document.getElementById('home').click(); + } + await IOUtils.writeJSON(`${root}/logs/notifications.json`,result); + } + } + await requestedUiChecks(); + let uiCheckRunning=false; + const uiCheckTimer=setInterval(async()=>{ + if(uiCheckRunning) return; + uiCheckRunning=true; + try { + const reloadMarker=`${root}/logs/test-reload-gaia`; + if(await IOUtils.exists(reloadMarker)) { + await IOUtils.remove(reloadMarker); + win.document.querySelector('browser').reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE); + await wait('system', "return document.body?.getAttribute('ready-state')==='fullyLoaded';"); + await sleep(1500); + } + await requestedUiChecks(); + } catch(error) {dump('TUNDRA_UI_CHECK_ERROR '+error+'\n');} + finally {uiCheckRunning=false;} + },3000); + win.addEventListener('unload',()=>clearInterval(uiCheckTimer),{once:true}); report.layout=await evaluate('homescreen',"return {width:innerWidth,height:innerHeight,dpr:devicePixelRatio,rootFont:getComputedStyle(document.documentElement).fontSize,bodyFont:getComputedStyle(document.body).fontFamily,zoom:visualViewport.scale,rootWidth:document.documentElement.scrollWidth};"); report.textFonts = await evaluate('homescreen', ` await document.fonts.ready; diff --git a/tundra/manifests/sargo-hardware.json b/tundra/manifests/sargo-hardware.json new file mode 100644 index 00000000..3e8748bd --- /dev/null +++ b/tundra/manifests/sargo-hardware.json @@ -0,0 +1,22 @@ +{ + "schema": 1, + "device": "sargo", + "scope": "Pinned hardware image inputs for local standalone builds; redistribution not reviewed", + "images": { + "vendor.img": { + "source": "vendor_a.img", + "sha256": "d584429873c88db741b81144b55977bbd8126b3e877445901bee6a0bda7fe4d0", + "bytes": 805306368 + }, + "modem.img": { + "source": "modem_a.img", + "sha256": "fd0624b37ac1d80c064a9763c7e2d2d6f94c3fd5e4617965b735ad411a473d0a", + "bytes": 115343360 + } + }, + "dtbo": { + "sha256": "0e43a57d6423e8d24cd944fcad0939ed81160e847a6d4203e2f7c16a86d69c03", + "bytes": 8417280 + }, + "vendorFingerprint": "google/sargo/sargo:9/PD2A.190115.029/5320088:user/release-keys" +} diff --git a/tundra/runtime/hal_policy.py b/tundra/runtime/hal_policy.py index 287a3c9e..8530ff0c 100644 --- a/tundra/runtime/hal_policy.py +++ b/tundra/runtime/hal_policy.py @@ -20,7 +20,7 @@ NETWORK_SERVICES = frozenset(('irsc_util', 'vendor.per_mgr', 'vendor.rmt_storage 'vendor.tftp_server', 'cnss-daemon', 'pd_mapper')) -HARDWARE_SERVICES = frozenset(('vendor.qcrild', 'vendor.google.radioext@1.0', +HARDWARE_SERVICES = frozenset(('vendor.bluetooth-1-0', 'vendor.qcrild', 'vendor.google.radioext@1.0', 'vendor.audio-hal-2-0', 'vendor.camera-provider-2-4', 'camera_service', 'minimedia', 'minisf', 'miniaf')) diff --git a/tundra/runtime/mark-boot-success.py b/tundra/runtime/mark-boot-success.py new file mode 100644 index 00000000..b1c2fa95 --- /dev/null +++ b/tundra/runtime/mark-boot-success.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MPL-2.0 +"""Acknowledge slot A only after this standalone installation has started Gaia.""" +import json +from pathlib import Path +import subprocess +import time + + +def eligible(boot_id, gaia, mount, cmdline, services_ready): + return (cmdline.get('androidboot.slot_suffix') == '_a' + and mount.get('source') == '/dev/mmcblk0p72' + and mount.get('fstype') == 'ext4' + and gaia.get('bootId') == boot_id and gaia.get('passed') is True + and bool(gaia.get('checks')) and all(gaia['checks'].values()) + and services_ready) + + +def main(): + cmdline=dict(x.split('=',1) for x in Path('/proc/cmdline').read_text().split() if '=' in x) + boot_id=Path('/proc/sys/kernel/random/boot_id').read_text().strip() + mounts=json.loads(subprocess.check_output(['findmnt','--json','--mountpoint','/reference/tundra-volume','--output','SOURCE,FSTYPE'],text=True))['filesystems'] + if len(mounts)!=1 or mounts[0]['source']!='/dev/mmcblk0p72': + return # Container/RAM experiments must not mark a flashed slot successful. + for _ in range(120): + try: + gaia=json.loads(Path('/opt/vulpes/logs/test.json').read_text()) + ready=subprocess.run(['systemctl','is-active','--quiet','tundra-hal','tundra-display','tundra-radio']).returncode==0 + if eligible(boot_id,gaia,mounts[0],cmdline,ready):break + except (OSError,ValueError):pass + time.sleep(5) + else:raise RuntimeError('Gaia did not pass startup; slot success left unchanged') + subprocess.run(['/usr/libexec/tundra-qbootctl','-m','a'],check=True) + Path('/var/lib/tundra').mkdir(parents=True,exist_ok=True) + Path('/var/lib/tundra/boot-success.json').write_text(json.dumps({'bootId':boot_id,'gaiaPassed':True,'slot':'a'})+'\n') + + +if __name__=='__main__':main() diff --git a/tundra/runtime/prepare-bluetooth.py b/tundra/runtime/prepare-bluetooth.py new file mode 100644 index 00000000..f69656e5 --- /dev/null +++ b/tundra/runtime/prepare-bluetooth.py @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: MPL-2.0 +"""Connect the Sargo Bluetooth HAL to BlueZ; pairing stays user initiated.""" + +def prepare(root, write): + write('etc/dbus-1/system.d/tundra-bluetooth.conf', ''' + +''') + write('etc/bluetooth/main.conf', '[General]\nName=Vulpes OS\nDiscoverableTimeout=120\n[Policy]\nAutoEnable=false\n') + write('etc/systemd/system/tundra-bluebinder.service', '''[Unit] +Description=Sargo Bluetooth HAL bridge +Requires=tundra-hal.service +After=tundra-hal.service +Before=bluetooth.service +[Service] +Type=notify +ExecStartPre=/usr/bin/binder-wait android.hardware.bluetooth@1.0::IBluetoothHci/default +ExecStart=/usr/sbin/bluebinder +Restart=on-failure +RestartSec=5 +TimeoutStartSec=60 +NoNewPrivileges=yes +ProtectHome=yes +ProtectSystem=strict +PrivateTmp=yes +''') + write('etc/systemd/system/bluetooth.service.d/tundra.conf', '''[Unit] +Requires=tundra-bluebinder.service dbus.service +After=tundra-bluebinder.service dbus.service +''') + wants = root/'etc/systemd/system/tundra.target.wants' + wants.mkdir(parents=True, exist_ok=True) + (wants/'bluetooth.service').symlink_to('/usr/lib/systemd/system/bluetooth.service') diff --git a/tundra/runtime/prepare-hardware.py b/tundra/runtime/prepare-hardware.py index 3b588f80..e5d790c3 100644 --- a/tundra/runtime/prepare-hardware.py +++ b/tundra/runtime/prepare-hardware.py @@ -3,10 +3,13 @@ """Configure isolated oFono/PulseAudio diagnostics; no call or SMS on startup.""" from pathlib import Path import shutil +import runpy def prepare(root, write): write('etc/tundra/hardware-enabled', 'sargo\n') + runpy.run_path(str(Path(__file__).with_name('runtime-packages.py')))['stage'](root) + runpy.run_path(str(Path(__file__).with_name('prepare-bluetooth.py')))['prepare'](root, write) shutil.copy2(Path(__file__).with_name('modem-recovery.py'), root/'etc/tundra/modem-recovery.py') write('etc/systemd/system/tundra-hal.service.d/modem-recovery.conf', '''[Service] diff --git a/tundra/runtime/runtime-packages.py b/tundra/runtime/runtime-packages.py new file mode 100644 index 00000000..904db1c0 --- /dev/null +++ b/tundra/runtime/runtime-packages.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MPL-2.0 +"""Stage pinned package payloads missing from the original ARM64 reference.""" +import hashlib +import io +import json +from pathlib import Path +import shutil +import subprocess +import tarfile +import tempfile +import urllib.request + +PACKAGES = ( + ('libdw1t64_0.196-1_arm64.deb', 'e/elfutils', 'a82634454de2b28d73374f693e4ab6c1c2634fa53b0139312c5f439c294dad2b'), + ('libelf1t64_0.196-1_arm64.deb', 'e/elfutils', 'ead8a1244824d982ce51fb82be4904312d5dc44ddc157e589def58c257738476'), + ('bluez_5.87-4_arm64.deb', 'b/bluez', 'fe733034dbdfa6146fc94112ad8ca0fce71d8e01d22a59ddb49ef2df3777d6b5'), + ('ca-certificates_20260816_all.deb', 'c/ca-certificates', '1cb8b73c74c47677b329fad4095fb9370227d4b8f1969372411478a4586c46cf'), +) + + +# Existing libelf 0.194-4 files in the inventoried runtime; reject other replacements. +REPLACES = {'usr/lib/aarch64-linux-gnu/libelf-0.194.so': 'ade23632ea253cb4ecfe95d5436bfeb3d40ae2003c5fe10bf1ac1c5b30bdf2e2', 'usr/share/doc/libelf1t64/changelog.Debian.gz': 'ffb0ea69fdbf6f32053059985048676931fd7d5c4458f8ca4bc54750cf4b1b31', 'usr/share/doc/libelf1t64/changelog.gz': '2e8e0af5c39ab744ac6934fe07419b5fd5504a50cd2f42110dd04315c548a708', 'usr/share/doc/libelf1t64/copyright': '2409860c86675ab33f8ad22480608faf849cbc2559d6478f708c23c508a1dbf2', 'usr/share/locale/de/LC_MESSAGES/elfutils.mo': 'f72328e130e63f231acb8e1a56ce5f4f3e91d0fc290db95d7ba4e4b2448d4d93', 'usr/share/locale/en@boldquot/LC_MESSAGES/elfutils.mo': '90158a24e3f85aaacc64085ef2644ba19075cb847c754341c9f245aaa69e94c6', 'usr/share/locale/en@quot/LC_MESSAGES/elfutils.mo': '33c6cda39c2145463dfdb2eb849922dbf6ccf51a9e4bfa8fd757744712d9abfa', 'usr/share/locale/es/LC_MESSAGES/elfutils.mo': '1ebff7e5583759b3f08eb5caaf18dd1a6ed6eb5ec71a02502ed8e21b134ad54f', 'usr/share/locale/ja/LC_MESSAGES/elfutils.mo': '764ed859f3aebd861da0b73c69da4d72d0f252952bb3be1c9c66360258a1661c', 'usr/share/locale/pl/LC_MESSAGES/elfutils.mo': '8abb000f43024994a9ec3032b52eb10858e004b81bc61c7ceea96f7467d13fdd', 'usr/share/locale/uk/LC_MESSAGES/elfutils.mo': 'ce0d747f478ee91a1cdef66bfd1e230a3ff1e787358f4c6e1ffb6513df713117'} + +def stage(root, cache=None): + cache = cache or Path(__file__).resolve().parents[1]/'downloads/native-packages-20261008' + cache.mkdir(parents=True, exist_ok=True) + records = [] + for name, directory, sha in PACKAGES: + url = 'https://deb.debian.org/debian/pool/main/'+directory+'/'+name + package = cache/name + if not package.exists(): + with urllib.request.urlopen(url, timeout=60) as response: + data = response.read() + if hashlib.sha256(data).hexdigest() != sha: + raise ValueError('Package checksum mismatch: '+name) + package.write_bytes(data) + if hashlib.sha256(package.read_bytes()).hexdigest() != sha: + raise ValueError('Package checksum mismatch: '+name) + members = subprocess.check_output(['ar', 't', str(package)], text=True).splitlines() + member = next(m for m in members if m.startswith('data.tar')) + payload = subprocess.check_output(['ar', 'p', str(package), member]) + with tempfile.TemporaryDirectory() as folder: + source = Path(folder) + with tarfile.open(fileobj=io.BytesIO(payload)) as archive: + archive.extractall(source, filter='data') + if name.startswith('ca-certificates'): + certificates = sorted((source/'usr/share/ca-certificates/mozilla').glob('*.crt')) + if len(certificates) < 50: + raise ValueError('Incomplete CA bundle') + target = root/'etc/ssl/certs/ca-certificates.crt' + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(b'\n'.join(p.read_bytes() for p in certificates)+b'\n') + target.chmod(0o644) + cert_link = root/'usr/lib/ssl/cert.pem' + cert_link.parent.mkdir(parents=True, exist_ok=True) + if not cert_link.exists() and not cert_link.is_symlink(): + cert_link.symlink_to('../../../etc/ssl/certs/ca-certificates.crt') + selected = [source/'usr/share/doc/ca-certificates/copyright'] + else: + selected = [p for p in (source/'usr').rglob('*') if p.is_file() or p.is_symlink()] + for path in selected: + target = root/path.relative_to(source) + target.parent.mkdir(parents=True, exist_ok=True) + if path.is_symlink(): + if target.exists() or target.is_symlink(): + if not target.is_symlink() or target.readlink() != path.readlink(): + raise ValueError('Conflicting package link: '+str(target)) + else: + target.symlink_to(path.readlink()) + else: + if target.exists() and target.read_bytes() != path.read_bytes(): + expected = REPLACES.get(str(path.relative_to(source))) + if not expected or hashlib.sha256(target.read_bytes()).hexdigest() != expected: + raise ValueError('Conflicting package file: '+str(target)) + shutil.copyfile(path, target) + target.chmod(path.stat().st_mode & 0o777) + records.append({'file': name, 'url': url, 'sha256': sha}) + record = root/'usr/share/vulpes/runtime-packages.json' + record.parent.mkdir(parents=True, exist_ok=True) + record.write_text(json.dumps(records, indent=2)+'\n') + return records diff --git a/tundra/runtime/setup-hal.py b/tundra/runtime/setup-hal.py index 7ee84bb2..c87b67c0 100644 --- a/tundra/runtime/setup-hal.py +++ b/tundra/runtime/setup-hal.py @@ -53,7 +53,19 @@ def main(): with image.open('rb') as f:sha=hashlib.file_digest(f,'sha256').hexdigest() if sha!='132d0e18c6a6a111293447e940267f35aa2b14fa00a872ef160b20dc2014d886':raise RuntimeError('Android reference changed') run('mount','-t','ext4','-o','loop,ro,noload',str(image),'/run/tundra/android-original') - run('mount','-t','ext4','-o','ro,noload','/dev/mmcblk0p70','/run/tundra/vendor-original') + hardware = Path('/etc/tundra/hardware-images.json') + bundled = json.loads(hardware.read_text())['images'] if hardware.exists() else None + if bundled: + if set(bundled) != {'vendor.img', 'modem.img'}: + raise RuntimeError('Expected both standalone hardware images') + for name, record in bundled.items(): + path = Path('/reference')/name + with path.open('rb') as source: + if path.stat().st_size != record['bytes'] or hashlib.file_digest(source, 'sha256').hexdigest() != record['sha256']: + raise RuntimeError('Standalone hardware image changed: '+name) + run('mount','-t','ext4','-o','loop,ro,noload','/reference/vendor.img','/run/tundra/vendor-original') + else: + run('mount','-t','ext4','-o','ro,noload','/dev/mmcblk0p70','/run/tundra/vendor-original') run('mount','-t','ext4','-o','ro,noload','/dev/mmcblk0p48','/mnt/vendor/persist') overlay('/run/tundra/android-original','/android','android') overlay('/run/tundra/vendor-original','/android/vendor','vendor') @@ -65,7 +77,10 @@ def main(): if count != 1:raise RuntimeError('Expected exactly one Sargo WLAN IPA setting') config.write_text(text) # vendor overlay upper is tmpfs, never the partition directory('/android/vendor/firmware_mnt') - run('mount','-t','vfat','-o','ro','/dev/mmcblk0p21','/android/vendor/firmware_mnt') + if bundled: + run('mount','-t','vfat','-o','loop,ro','/reference/modem.img','/android/vendor/firmware_mnt') + else: + run('mount','-t','vfat','-o','ro','/dev/mmcblk0p21','/android/vendor/firmware_mnt') report={} for p in sorted(Path('/android').rglob('*.rc')): if not p.is_file() or p.is_symlink() or not is_init_script(p):continue diff --git a/tundra/tests/test_hardware_status.py b/tundra/tests/test_hardware_status.py index 6a5745bc..190bcebe 100644 --- a/tundra/tests/test_hardware_status.py +++ b/tundra/tests/test_hardware_status.py @@ -50,7 +50,11 @@ class HardwareTests(unittest.TestCase): self.assertIn('unmanaged-devices=*,except:interface-name:wlan0', config) self.assertIn('auth-polkit=root-only', config) self.assertIn('enabled=false', config) - self.assertFalse((root/'etc/NetworkManager/system-connections').exists()) + connections = root/'etc/NetworkManager/system-connections' + self.assertTrue(connections.is_dir()) + self.assertEqual(list(connections.iterdir()), []) + wifi_service = (root/'etc/systemd/system/tundra-wifi.service').read_text() + self.assertIn('ReadWritePaths=/run /etc/NetworkManager/system-connections', wifi_service) self.assertIn('VULPES_TUNDRA=1', (root/'etc/systemd/system/tundra-display.service').read_text()) diff --git a/tundra/tests/test_runtime_packages.py b/tundra/tests/test_runtime_packages.py new file mode 100644 index 00000000..2f6531aa --- /dev/null +++ b/tundra/tests/test_runtime_packages.py @@ -0,0 +1,47 @@ +"""Check the pinned Bluetooth libraries and native TLS trust store offline.""" +import importlib.util +import json +from pathlib import Path +import ssl +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[1] +spec = importlib.util.spec_from_file_location('packages', ROOT/'runtime/runtime-packages.py') +packages = importlib.util.module_from_spec(spec) +spec.loader.exec_module(packages) +CACHE = ROOT/'downloads/native-packages-20261008' + + +class RuntimePackages(unittest.TestCase): + def test_corrupt_archive_is_rejected_before_extraction(self): + with tempfile.TemporaryDirectory() as folder: + base = Path(folder) + cache = base/'cache' + cache.mkdir() + (cache/packages.PACKAGES[0][0]).write_bytes(b'corrupt') + with self.assertRaisesRegex(ValueError, 'checksum mismatch'): + packages.stage(base/'root', cache) + self.assertFalse((base/'root').exists()) + + @unittest.skipUnless(all((CACHE/name).exists() for name, _, _ in packages.PACKAGES), + 'Pinned package cache is not installed') + def test_staged_payload_is_repeatable_and_certificates_are_usable(self): + with tempfile.TemporaryDirectory() as folder: + root = Path(folder) + first = packages.stage(root, CACHE) + self.assertEqual(packages.stage(root, CACHE), first) + self.assertEqual(json.loads((root/'usr/share/vulpes/runtime-packages.json').read_text()), first) + self.assertTrue((root/'usr/libexec/bluetooth/bluetoothd').is_file()) + context = ssl.create_default_context(cafile=str(root/'etc/ssl/certs/ca-certificates.crt')) + self.assertGreater(context.cert_store_stats()['x509_ca'], 50) + self.assertTrue((root/'usr/lib/ssl/cert.pem').is_file()) + target = root/'usr/libexec/bluetooth/bluetoothd' + target.write_bytes(b'unknown local binary') + with self.assertRaisesRegex(ValueError, 'Conflicting package file'): + packages.stage(root, CACHE) + self.assertEqual(target.read_bytes(), b'unknown local binary') + + +if __name__ == '__main__': + unittest.main() diff --git a/tundra/tests/test_sparse_backup.py b/tundra/tests/test_sparse_backup.py new file mode 100644 index 00000000..2305b36d --- /dev/null +++ b/tundra/tests/test_sparse_backup.py @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: MPL-2.0 +import io +from pathlib import Path +import struct +import sys +import unittest +sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'tools')) +from sparse_backup import receive + + +def record(offset,data):return struct.pack(' /newroot/reference/'+name, + 'mount --bind /volume/tundra/hardware/'+name+' /newroot/reference/'+name, + 'mount -o remount,bind,ro /newroot/reference/'+name] + config = json.dumps({'images':volume['hardwareImages']}, separators=(',',':')) + lines += ['mkdir -p /newroot/etc/tundra', + 'printf \'%s\\n\' '+shlex.quote(config)+' > /newroot/etc/tundra/hardware-images.json'] + native = native.replace(b'# Installed lower layers', ('\n'.join(lines)+'\n# Installed lower layers').encode()) + if not trial: + if b'/dev/mapper' in init or b'EXPECTED_STORAGE_HASH' in init: + # The old expected hash assignment is unnecessary in the raw image. + init = b'\n'.join(line for line in init.split(b'\n') if not line.startswith(b'EXPECTED_STORAGE_HASH=')) + if b'/dev/mapper' in init or b'/installed/' in native: + raise ValueError('Legacy storage leaked into standalone boot') + device = '/run/legacy-storage/tundra/standalone/'+volume['uuid']+'.ext4' if trial else '/dev/mmcblk0p72' + config = 'VOLUME_DEVICE='+shlex.quote(device)+'\nVOLUME_UUID='+shlex.quote(volume['uuid'])+'\nVOLUME_OPTIONS='+('loop,rw' if trial else 'rw')+'\n' + mount = (ROOT/'boot/standalone-mount.sh').read_bytes().replace(b'# VOLUME_CONFIGURATION', config.encode()) + return init, native, mount + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--volume', type=Path, required=True) + parser.add_argument('--prepared', type=Path, required=True) + parser.add_argument('--device-workspace', type=Path, required=True) + parser.add_argument('--output', type=Path, required=True) + parser.add_argument('--container-trial', action='store_true') + parser.add_argument('--no-deadline', action='store_true') + parser.add_argument('--boot-control', type=Path, help='Pinned ARM64 qbootctl binary') + parser.add_argument('--no-maintenance', action='store_true', help='Exclude private USB SSH credentials and server') + parser.add_argument('--local-debugger', action='store_true', help='Private RAM tests: loopback Marionette, never a public image') + args = parser.parse_args(); os.umask(0o077) + if args.local_debugger and args.no_maintenance: parser.error('Local debugger requires a private maintenance image') + volume = checked_volume(args.volume) + if args.no_deadline and not args.container_trial and not args.boot_control: + parser.error('Persistent standalone images require --boot-control') + if args.boot_control and digest(args.boot_control) != 'dcb00e4c4f038071a5d9979263128325e16b848903371f6c00d49cf3e25c34d9': + raise ValueError('Unqualified boot-control binary') + if args.boot_control and digest(args.boot_control.with_name('copyright')) != '8969e659aff7ed5bb3249341764c2bd048d5abe7400076f01485650e727e8c42': + raise ValueError('Boot-control license notice missing or changed') + system = json.loads((args.prepared/'system.json').read_text()) + state = json.loads((args.prepared/'data/state.json').read_text()) + if volume['systemImageSha256'] != system['imageSha256'] or volume['stateUuid'] != state['uuid']: + raise ValueError('Volume does not contain this system/data pair') + command = [sys.executable,str(ROOT/'tools/build-rescue-boot.py'), '--output',str(args.output), + '--device-workspace',str(args.device_workspace),'--layout',str(args.device_workspace/'layout.json'), + '--native','--runtime-config','--network','--hardware', + '--system-image',str(args.prepared/'system.json'),'--state',str(args.prepared/'data/state.json')] + if args.no_deadline: command.append('--no-deadline') + if args.local_debugger: command.append('--local-debugger') + subprocess.run(command,check=True) + out = args.output.resolve(); build = json.loads((out/'build.json').read_text()) + ramdisk = out/'initramfs.cpio.gz'; files = read_newc(ramdisk.read_bytes()) + init,native,mount = storage_scripts(files['init']['data'],files['native-root.sh']['data'],volume,args.container_trial) + if args.boot_control: + files['sbin/tundra-qbootctl']={'mode':stat.S_IFREG|0o755,'data':args.boot_control.read_bytes()} + files['qbootctl-copyright']={'mode':stat.S_IFREG|0o644,'data':args.boot_control.with_name('copyright').read_bytes()} + files['standalone-boot-success.py']={'mode':stat.S_IFREG|0o755,'data':(ROOT/'runtime/mark-boot-success.py').read_bytes()} + unit=b'[Unit]\nDescription=Acknowledge a healthy standalone Vulpes boot\nAfter=tundra-display.service\n[Service]\nType=oneshot\nTimeoutStartSec=650\nExecStart=/usr/bin/python3 /usr/libexec/tundra-mark-boot-success.py\n' + files['standalone-boot-success.service']={'mode':stat.S_IFREG|0o644,'data':unit} + setup=b"""mkdir -p /newroot/usr/libexec /newroot/etc/systemd/system/tundra.target.wants +mkdir -p /newroot/usr/share/doc/qbootctl +cp /qbootctl-copyright /newroot/usr/share/doc/qbootctl/copyright +cp /sbin/tundra-qbootctl /newroot/usr/libexec/tundra-qbootctl +cp /standalone-boot-success.py /newroot/usr/libexec/tundra-mark-boot-success.py +cp /standalone-boot-success.service /newroot/etc/systemd/system/tundra-boot-success.service +ln -sf ../tundra-boot-success.service /newroot/etc/systemd/system/tundra.target.wants/tundra-boot-success.service +""" + native=native.replace(b'# Installed lower layers',setup+b'# Installed lower layers') + if args.no_maintenance: + init=b'\n'.join(line for line in init.split(b'\n') if not line.startswith(b'/sbin/dropbear ')) + init=init.replace(b'TUNDRA_USB_SSH_READY',b'TUNDRA_USB_READY') + start=native.index(b'# Keep a minimal, already tested rescue environment') + end=native.index(b'for fs in dev proc sys run;',start) + native=native[:start]+b'# Public boot: no USB maintenance account or shared SSH key.\n'+native[end:] + for name in ('etc/tundra-hostkey','root/.ssh/authorized_keys','sbin/dropbear'): + files.pop(name,None) + files['init']['data']=init; files['native-root.sh']['data']=native + files['standalone-mount.sh']={'mode':stat.S_IFREG|0o755,'data':mount} + files['volume']={'mode':stat.S_IFDIR|0o755,'data':b''} + entries=[] + for name, item in sorted(files.items()): + entries.append((name,item['mode'],item['data'],5 if name=='dev/console' else 0,1 if name=='dev/console' else 0)) + ramdisk.write_bytes(cpio(entries)) + packager=checked_source('aosp-mkbootimg'); original=out/build['image'] + with tempfile.TemporaryDirectory() as temp: + unpack=Path(temp)/'unpack' + text=subprocess.check_output([sys.executable,str(packager/'unpack_bootimg.py'),'--boot_img',str(original),'--out',str(unpack),'--format=mkbootimg'],text=True) + options=shlex.split(text); fields=dict(zip(options[::2],options[1::2]));fields['--ramdisk']=str(ramdisk) + image=out/'boot.img'; command=[sys.executable,str(packager/'mkbootimg.py')] + for key,value in fields.items():command.extend([key,value]) + subprocess.run(command+['-o',str(image)],check=True) + verify=Path(temp)/'verify' + subprocess.run([sys.executable,str(packager/'unpack_bootimg.py'),'--boot_img',str(image),'--out',str(verify)],check=True,stdout=subprocess.DEVNULL) + if digest(verify/'kernel')!=build['kernelSha256'] or digest(verify/'ramdisk')!=digest(ramdisk): + raise ValueError('Standalone boot roundtrip failed') + original.unlink() + for path in (Path(__file__).resolve(),ROOT/'tools/standalone_volume.py',ROOT/'boot/standalone-mount.sh',ROOT/'runtime/mark-boot-success.py'): + relative=str(path.relative_to(ROOT)); target=out/'sources/tundra'/relative + target.parent.mkdir(parents=True,exist_ok=True);shutil.copy2(path,target);build['sources'][relative]=digest(path) + build.update(image='boot.img',imageSha256=digest(image),ramdiskSha256=digest(ramdisk), + storageMode='container-test' if args.container_trial else 'raw-userdata-ext4', + standaloneVolume=volume,flashReady=False,bootControlSha256=digest(args.boot_control) if args.boot_control else None, + containsPrivateTrialHostKey=not args.no_maintenance,maintenanceEnabled=not args.no_maintenance, + scope='Standalone Tundra boot candidate; hardware qualification required') + (out/'build.json').write_text(json.dumps(build,indent=2)+'\n') + print(image) + + +if __name__=='__main__':main() diff --git a/tundra/tools/build-standalone-volume.py b/tundra/tools/build-standalone-volume.py new file mode 100644 index 00000000..bc2e28a7 --- /dev/null +++ b/tundra/tools/build-standalone-volume.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MPL-2.0 +"""Build a fresh ext4 userdata image. No connection to a phone or partition writes.""" +import argparse +import importlib.util +import json +import os +from pathlib import Path +import shutil +import subprocess +import sys +import uuid +from persistent_state import FEATURES +from tundra import digest +from standalone_volume import checked_volume + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--prepared', required=True, type=Path) + parser.add_argument('--output', required=True, type=Path) + parser.add_argument('--hardware', type=Path, help='Locally supplied pinned vendor/modem images') + parser.add_argument('--size-mib', type=int, default=8192) + args = parser.parse_args() + if not 5120 <= args.size_mib <= 32768: + parser.error('Choose 5120–32768 MiB') + spec = importlib.util.spec_from_file_location('stage', Path(__file__).with_name('stage-sargo-files.py')) + stage = importlib.util.module_from_spec(spec); spec.loader.exec_module(stage) + files = stage.inputs(args.prepared) + hardware = {} + if args.hardware: + lock = json.loads((Path(__file__).resolve().parents[1]/'manifests/sargo-hardware.json').read_text()) + hardware = lock['images'] + for name, record in hardware.items(): + source = args.hardware/record['source'] + if source.is_symlink() or source.stat().st_size != record['bytes'] or digest(source) != record['sha256']: + raise ValueError('Hardware image changed: '+name) + payload_bytes = sum(p.stat().st_size for _,_,p,_ in files) + payload_bytes += sum(record['bytes'] for record in hardware.values()) + if args.size_mib*1024**2 < payload_bytes+512*1024**2: + raise ValueError('Insufficient space for payload and filesystem metadata') + os.umask(0o077) + out = args.output.resolve(); out.mkdir(parents=True, exist_ok=False) + (out/'.incomplete').touch() + seed = out/'seed'; seed.mkdir() + for kind, name, source, record in files: + target = seed/'tundra'/kind/name; target.parent.mkdir(parents=True, exist_ok=True) + # mke2fs reads the file; a hard link avoids another multi-gigabyte copy. + os.link(source, target) + if hardware: + directory = seed/'tundra/hardware'; directory.mkdir() + for name, record in hardware.items(): + os.link(args.hardware/record['source'], directory/name) + system = json.loads((args.prepared/'system.json').read_text()) + state = json.loads((args.prepared/'data/state.json').read_text()) + identifier = str(uuid.uuid4()) + (seed/'tundra-volume-id').write_text(identifier+'\n') + image = out/'userdata.ext4' + with image.open('xb') as f: f.truncate(args.size_mib*1024**2) + subprocess.run(['mke2fs','-q','-t','ext4','-F','-b','4096','-I','256','-O',FEATURES, + '-U',identifier,'-L','TUNDRA_VOLUME','-d',str(seed),str(image)],check=True) + names=['/tundra-volume-id','/tundra','/tundra/images','/tundra/data'] + names += ['/tundra/'+kind+'/'+name for kind,name,_,_ in files] + if hardware: + names += ['/tundra/hardware', *['/tundra/hardware/'+name for name in hardware]] + for name in names: + for field in ('uid','gid'): + subprocess.run(['debugfs','-w','-R',f'set_inode_field {name} {field} 0',str(image)],check=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL) + result = subprocess.run(['e2fsck','-f','-n',str(image)],capture_output=True,text=True) + (out/'filesystem-check.txt').write_text(result.stdout+result.stderr) + if result.returncode: raise ValueError('Standalone filesystem check failed') + manifest={'schema':1,'device':'sargo','storage':'raw-userdata-ext4','image':image.name, + 'uuid':identifier,'bytes':image.stat().st_size,'imageSha256':digest(image), + 'systemImageSha256':system['imageSha256'],'stateUuid':state['uuid'], + 'filesystemCheckPassed':True,'flashReady':False,'hardwareImages':hardware, + 'scope':'Fresh standalone storage; flashing userdata destroys previous user data'} + (out/'volume.json').write_text(json.dumps(manifest,indent=2)+'\n') + checked_volume(out/'volume.json') + (out/'.incomplete').unlink() + print(out/'volume.json') + + +if __name__ == '__main__': main() diff --git a/tundra/tools/build-system-image.py b/tundra/tools/build-system-image.py index 898afae2..fffd8014 100644 --- a/tundra/tools/build-system-image.py +++ b/tundra/tools/build-system-image.py @@ -128,7 +128,7 @@ def main(): ignore=shutil.ignore_patterns('__pycache__', 'test', 'tests')) for name in ('tools', 'tests', 'logs', 'profiles'): (product/name).mkdir(exist_ok=True) - for name in ('serve-gaia.py', 'project.py', 'run-host.py'): + for name in ('serve-gaia.py', 'project.py', 'run-host.py', 'installed_apps.py'): shutil.copy2(PROJECT/'tools'/name, product/'tools'/name) shutil.copy2(PROJECT/'tests/ProbeChild.sys.mjs', product/'tests/ProbeChild.sys.mjs') shutil.copy2(PROJECT/'release.json', product/'release.json') diff --git a/tundra/tools/flash-standalone-sargo.py b/tundra/tools/flash-standalone-sargo.py new file mode 100644 index 00000000..f7a01d1b --- /dev/null +++ b/tundra/tools/flash-standalone-sargo.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MPL-2.0 +"""Install a standalone Sargo package using Fastboot only (Python 3, any host OS). + +Default: verify files and display the destructive installation plan. +--install --erase-userdata replaces the old OS and ALL files in userdata. +Keep a separate backup. The unlocked bootloader and device calibration remain. +""" +import argparse +import hashlib +import json +from pathlib import Path +import re +import shutil +import struct +import subprocess +import sys + +PARTITIONS=('userdata','dtbo_a','vbmeta_a','boot_a') +NAMES={'userdata':'userdata.img','dtbo_a':'dtbo.img','vbmeta_a':'vbmeta.img','boot_a':'boot.img'} + + +def digest(path): + sha=hashlib.sha256() + with path.open('rb') as source: + while block:=source.read(1024*1024):sha.update(block) + return sha.hexdigest() + + +def sparse_size(path): + with path.open('rb') as source:header=source.read(28) + if len(header)!=28:raise ValueError('Truncated userdata image') + magic,major,minor,file_header,chunk_header,block_size,blocks,chunks,crc=struct.unpack('size:raise ValueError('Image exceeds partition: '+partition) + return info + + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--package',type=Path,default=Path(__file__).resolve().parent) + parser.add_argument('--serial') + parser.add_argument('--install',action='store_true') + parser.add_argument('--erase-userdata',action='store_true') + parser.add_argument('--experimental',action='store_true') + parser.add_argument('--reboot',action='store_true') + args=parser.parse_args();value=package(args.package) + print('Pixel 3a / Sargo: replace userdata, dtbo_a, vbmeta_a and boot_a; activate slot A.') + print('ALL existing user data and the old OS in userdata will be lost. Bootloader remains unlocked.') + print('No existing Android or Droidian installation is required.') + if not args.install: + print('Review only; no device command sent.');return + if not args.erase_userdata:parser.error('--install requires --erase-userdata') + if not value.get('flashQualified') and not args.experimental: + parser.error('This candidate is not qualified; private tests require --experimental') + fastboot=shutil.which('fastboot') + if not fastboot:raise ValueError('Install Android platform-tools (fastboot) on the host computer') + devices=subprocess.check_output([fastboot,'devices'],text=True,timeout=10).splitlines() + serials=[line.split()[0] for line in devices if len(line.split())==2 and line.split()[1]=='fastboot'] + serial=args.serial + if serial is None: + if len(serials)!=1:raise ValueError('Connect exactly one Pixel or specify --serial') + serial=serials[0] + if serial not in serials:raise ValueError('Selected device not in Fastboot') + info=preflight(fastboot,serial,value) + report={'deviceSha256':hashlib.sha256(serial.encode()).hexdigest(),'preflight':info,'completed':[],'passed':False} + path=args.package/'install-report.json' + def save():path.write_text(json.dumps(report,indent=2)+'\n') + save() + subprocess.run([fastboot,'-s',serial,'erase','userdata'],check=True,timeout=300) + report['completed'].append('erase:userdata');save() + for partition in PARTITIONS: + subprocess.run([fastboot,'-s',serial,'flash',partition,str((args.package/NAMES[partition]).resolve())],check=True,timeout=1200) + report['completed'].append(partition);save() + subprocess.run([fastboot,'-s',serial,'set_active','a'],check=True,timeout=30) + report['passed']=True;save() + if args.reboot:subprocess.run([fastboot,'-s',serial,'reboot'],check=True,timeout=30) + print('Images written. Keep the bootloader unlocked. Select Start to launch Vulpes.') + + +if __name__=='__main__':main() diff --git a/tundra/tools/install-sargo.py b/tundra/tools/install-sargo.py index c626b64b..6263b261 100644 --- a/tundra/tools/install-sargo.py +++ b/tundra/tools/install-sargo.py @@ -23,6 +23,8 @@ def load(name, path): def checked_build(folder): folder=Path(folder).resolve() build=json.loads((folder/'build.json').read_text()) + if build.get('storageMode') in ('raw-userdata-ext4', 'container-test'): + raise ValueError('Use the standalone installer; the old boot-only plan is incompatible') if build.get('localDebugger'):raise ValueError('Diagnostic debugger image cannot be flashed') qualification=json.loads((folder/'qualification.json').read_text()) if (not qualification.get('passed') or not qualification.get('privateInstallReady') diff --git a/tundra/tools/package-standalone-sargo.py b/tundra/tools/package-standalone-sargo.py new file mode 100644 index 00000000..0390514b --- /dev/null +++ b/tundra/tools/package-standalone-sargo.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MPL-2.0 +"""Package boot, fresh userdata and boot metadata for a standalone installation. + +Builds local artifacts only. A candidate is never marked flash-qualified here. +Private development credentials, if present in boot, prohibit redistribution. +""" +import argparse +import importlib.util +import json +import os +from pathlib import Path +import shutil +import subprocess +from standalone_volume import checked_volume +from tundra import ROOT,digest + + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--build',required=True,type=Path) + parser.add_argument('--volume',required=True,type=Path) + parser.add_argument('--dtbo',required=True,type=Path) + parser.add_argument('--output',required=True,type=Path) + args=parser.parse_args();os.umask(0o077) + volume=checked_volume(args.volume);build=json.loads((args.build/'build.json').read_text()) + if build.get('storageMode')!='raw-userdata-ext4' or build.get('watchdogSeconds') is not None or build.get('localDebugger'): + raise ValueError('Expected a persistent standalone boot without debugger or timed reboot') + if build['standaloneVolume']!=volume or not volume.get('hardwareImages'): + raise ValueError('Boot must match a volume with bundled vendor/modem images') + boot=args.build/build['image'] + if digest(boot)!=build['imageSha256']:raise ValueError('Boot image changed') + spec=importlib.util.spec_from_file_location('sources',ROOT/'tools/test-rescue-boot.py') + sources=importlib.util.module_from_spec(spec);spec.loader.exec_module(sources);sources.verify_sources(args.build,build) + lock=json.loads((ROOT/'manifests/sargo-hardware.json').read_text()) + if args.dtbo.stat().st_size!=lock['dtbo']['bytes'] or digest(args.dtbo)!=lock['dtbo']['sha256']: + raise ValueError('Unqualified device-tree overlay') + out=args.output.resolve();out.mkdir(parents=True,exist_ok=False) + (out/'.incomplete').touch() + shutil.copyfile(boot,out/'boot.img');shutil.copyfile(args.dtbo,out/'dtbo.img') + subprocess.run(['avbtool','make_vbmeta_image','--flags','3','--padding_size','4096','--algorithm','NONE','--output',str(out/'vbmeta.img')],check=True) + subprocess.run(['img2simg',str(args.volume.parent/volume['image']),str(out/'userdata.img')],check=True) + # Roundtrip verifies the actual sparse payload, not only its header. + restored=out/'userdata-roundtrip.ext4' + subprocess.run(['simg2img',str(out/'userdata.img'),str(restored)],check=True) + if digest(restored)!=volume['imageSha256']:raise ValueError('Sparse image roundtrip mismatch') + restored.unlink() + files={name:{'file':file,'bytes':(out/file).stat().st_size,'sha256':digest(out/file)} + for name,file in [('boot_a','boot.img'),('userdata','userdata.img'),('dtbo_a','dtbo.img'),('vbmeta_a','vbmeta.img')]} + value={'schema':1,'device':'sargo','storage':'raw-userdata-ext4','partitions':files, + 'userdataBytes':volume['bytes'],'userdataRawSha256':volume['imageSha256'], + 'volumeUuid':volume['uuid'],'systemImageSha256':volume['systemImageSha256'], + 'flashQualified':False,'containsPrivateMaintenanceKey':bool(build.get('containsPrivateTrialHostKey')), + 'redistributionReady':False,'previousOsRequired':False, + 'requirements':['Unlocked Pixel 3a (sargo)','Original device calibration partitions retained'], + 'scope':'Experimental standalone installation candidate; userdata is replaced in full'} + (out/'package.json').write_text(json.dumps(value,indent=2)+'\n') + shutil.copyfile(ROOT/'tools/flash-standalone-sargo.py',out/'flash-standalone-sargo.py') + (out/'SHA256SUMS').write_text(''.join(digest(p)+' '+p.name+'\n' for p in sorted(out.iterdir()) if p.is_file() and p.name not in ('.incomplete','SHA256SUMS'))) + (out/'.incomplete').unlink();print(out/'package.json') + + +if __name__=='__main__':main() diff --git a/tundra/tools/restore-standalone-sargo.py b/tundra/tools/restore-standalone-sargo.py new file mode 100644 index 00000000..e08f0b9e --- /dev/null +++ b/tundra/tools/restore-standalone-sargo.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MPL-2.0 +"""Restore a private full-storage backup after a standalone Sargo test. + +Default: verify the archive and partition backups only. --restore overwrites +userdata and the three slot-A boot partitions. Backups are device-specific. +""" +import argparse +import gzip +import hashlib +import json +from pathlib import Path +import shutil +import subprocess + + +def digest(path): + sha=hashlib.sha256() + with path.open('rb') as source: + while block:=source.read(4*1024**2):sha.update(block) + return sha.hexdigest() + + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--backup',required=True,type=Path) + parser.add_argument('--restore',action='store_true') + args=parser.parse_args();folder=args.backup.resolve() + manifest=json.loads((folder/'recovery.json').read_text()) + if manifest.get('device')!='sargo' or manifest.get('activeSlot')!='a':raise ValueError('Wrong recovery target') + data=json.loads((folder/'userdata.json').read_text()) + if not data.get('checked') or data.get('archive')!='userdata-original.raw.gz':raise ValueError('Unverified userdata backup') + if not data.get('sourceWasUnmounted') or manifest.get('userdataSha256')!=data['sha256'] or manifest.get('userdataBytes')!=data['bytes']: + raise ValueError('Storage backup is not bound to this recovery kit') + for name,record in manifest['files'].items(): + if name not in ('boot_a.img','dtbo_a.img','vbmeta_a.img'):raise ValueError('Unexpected recovery partition') + path=folder/name + if path.is_symlink() or path.stat().st_size!=record['bytes'] or digest(path)!=record['sha256']:raise ValueError('Partition backup changed: '+name) + if set(manifest['files'])!={'boot_a.img','dtbo_a.img','vbmeta_a.img'}:raise ValueError('Incomplete boot backup set') + archive=folder/data['archive'];sha=hashlib.sha256();count=0 + with gzip.open(archive,'rb') as source: + while block:=source.read(4*1024**2): + count+=len(block) + if count>data['bytes']:raise ValueError('Oversized backup') + sha.update(block) + if count!=data['bytes'] or sha.hexdigest()!=data['sha256']:raise ValueError('Storage backup changed') + print('Private boot and full userdata backups verified.') + if not args.restore: + print('No phone action. --restore replaces its current userdata.');return + fastboot=shutil.which('fastboot') + if not fastboot:raise ValueError('Fastboot is required') + serials=[line.split()[0] for line in subprocess.check_output([fastboot,'devices'],text=True).splitlines() if len(line.split())==2] + matches=[serial for serial in serials if hashlib.sha256(serial.encode()).hexdigest()==manifest['serialSha256']] + if len(matches)!=1:raise ValueError('Original phone not present in Fastboot') + serial=matches[0] + # Use the standalone installer's strict Fastboot variable parser. + import importlib.util + spec=importlib.util.spec_from_file_location('flash',Path(__file__).with_name('flash-standalone-sargo.py')) + flash=importlib.util.module_from_spec(spec);spec.loader.exec_module(flash) + if flash.getvar(fastboot,serial,'product')!='sargo' or flash.getvar(fastboot,serial,'unlocked')!='yes':raise ValueError('Wrong or locked phone') + if int(flash.getvar(fastboot,serial,'partition-size:userdata'),16)!=data['bytes']:raise ValueError('Storage geometry changed') + raw=folder/'userdata-restore.raw' + if raw.exists(): + if raw.stat().st_size!=data['bytes'] or digest(raw)!=data['sha256']:raise ValueError('Existing restoration file changed') + else: + if shutil.disk_usage(folder).free65536 or offset+length>expected_size:raise ValueError('Invalid backup extent') + target.seek(offset);target.write(exact(stream,length));end=offset+length diff --git a/tundra/tools/standalone_volume.py b/tundra/tools/standalone_volume.py new file mode 100644 index 00000000..452f145b --- /dev/null +++ b/tundra/tools/standalone_volume.py @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: MPL-2.0 +"""Validate the fresh userdata filesystem used by standalone Sargo images.""" +import json +from pathlib import Path +import re +import uuid +from tundra import digest + + +def checked_volume(path, verify_image=True): + path = Path(path) + value = json.loads(path.read_text()) + if (value.get('schema') != 1 or value.get('device') != 'sargo' + or value.get('storage') != 'raw-userdata-ext4' + or value.get('image') != 'userdata.ext4' + or value.get('filesystemCheckPassed') is not True): + raise ValueError('Expected a checked standalone Sargo volume') + identifier = value.get('uuid') + if not isinstance(identifier, str) or str(uuid.UUID(identifier)) != identifier: + raise ValueError('Invalid volume UUID') + for key in ('imageSha256', 'systemImageSha256'): + if not re.fullmatch(r'[a-f0-9]{64}', value.get(key, '')): + raise ValueError('Invalid '+key) + if type(value.get('bytes')) is not int or not 5*1024**3 <= value['bytes'] <= 32*1024**3: + raise ValueError('Invalid standalone filesystem size') + hardware = value.get('hardwareImages', {}) + if hardware: + lock = json.loads((Path(__file__).resolve().parents[1]/'manifests/sargo-hardware.json').read_text()) + if hardware != lock['images']: + raise ValueError('Unqualified standalone hardware images') + if verify_image: + image = path.parent/value['image'] + if image.is_symlink() or image.stat().st_size != value['bytes'] or digest(image) != value['imageSha256']: + raise ValueError('Standalone volume changed') + return value