From f7b8ab263bba10d9124a068c4524a9fdba5e2f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Sun, 2 Nov 2025 21:41:10 +0100 Subject: [PATCH 01/13] auto-dark-light@gihaume: v2.0.0 - Closes #6758 - Closes #7247 - Closes #7923 --- auto-dark-light@gihaume/.editorconfig | 9 + auto-dark-light@gihaume/.env | 3 + auto-dark-light@gihaume/.gitignore | 3 + .../.vscode/extensions.json | 7 + auto-dark-light@gihaume/.vscode/settings.json | 7 + auto-dark-light@gihaume/CHANGELOG.md | 108 +- auto-dark-light@gihaume/CONTRIBUTING.md | 94 + auto-dark-light@gihaume/CREDITS.md | 4 + auto-dark-light@gihaume/README.md | 43 +- auto-dark-light@gihaume/doc/README.md | 21 + .../handlers/Appearance_handler.drawio.svg | 4 + .../handlers/Location_handler.drawio.svg | 4 + .../handlers/Twilights_handler.drawio.svg | 4 + .../doc/schemas/handlers/legend.drawio.svg | 4 + .../auto-dark-light@gihaume/2.2/applet.js | 4 +- .../5.8/Time_change_listener/.gitignore | 2 + .../Makefile | 0 .../Time_change_listener.cpp} | 27 +- .../Time_change_listener.hpp} | 16 +- .../5.8/Time_change_listener/main.cpp | 50 + .../database.json | 1 - .../auto-dark-light@gihaume/5.8/applet.js | 437 +---- .../5.8/applet.js.sha256sum | 1 + .../auto-dark-light@gihaume/5.8/globals.d.ts | 1 - .../auto-dark-light@gihaume/5.8/jsconfig.json | 10 - .../5.8/lib/CLASSES HIERARCHY.drawio.svg | 4 - .../5.8/lib/background_handler.js | 56 - .../5.8/lib/color_scheme_change_listener.js | 31 - .../5.8/lib/commands_launcher/README.md | 28 - .../commands_launcher/commands_launcher.js | 59 - .../lib/commands_launcher/launch_command.js | 61 - .../auto-dark-light@gihaume/5.8/lib/dbus.js | 150 -- .../5.8/lib/event_scheduler.js | 42 - .../screen_lock_checker.js | 34 - .../sleep_wakeup_listener.js | 41 - .../5.8/lib/themes_handler.js | 67 - .../5.8/lib/time_change_listener/main.cpp | 50 - .../time_change_listener.js | 117 -- .../5.8/lib/time_of_day.js | 60 - .../5.8/lib/timer_absolute.js | 16 - .../5.8/lib/timezone_change_listener.js | 28 - .../generate_database.ipynb | 1553 ----------------- .../timezone_coordinates_finder.js | 30 - .../5.8/lib/translator.js | 11 - .../5.8/lib/twilights_calculator/suncalc.js | 172 -- .../twilights_calculator.js | 31 - .../5.8/settings-schema.json | 681 +++++--- .../5.8/widgets/Button_read_only.py | 30 + .../5.8/widgets/Entry_read_only.py | 31 + .../5.8/widgets/Spin_button_read_only.py | 34 + .../5.8/widgets/Switch_read_only.py | 29 + .../auto-dark-light@gihaume/metadata.json | 4 +- .../auto-dark-light@gihaume/po/.gitignore | 1 + .../po/auto-dark-light@gihaume.pot | 515 +++--- .../files/auto-dark-light@gihaume/po/ca.po | 607 ++++--- .../files/auto-dark-light@gihaume/po/es.po | 619 +++---- .../files/auto-dark-light@gihaume/po/fi.po | 603 ++++--- .../files/auto-dark-light@gihaume/po/fr.po | 629 +++---- .../files/auto-dark-light@gihaume/po/hu.po | 615 +++---- .../files/auto-dark-light@gihaume/po/it.po | 616 +++---- .../files/auto-dark-light@gihaume/po/nl.po | 616 +++---- .../files/auto-dark-light@gihaume/po/tr.po | 609 +++---- .../files/auto-dark-light@gihaume/po/vi.po | 611 +++---- .../files/auto-dark-light@gihaume/po/zh_CN.po | 610 ++++--- .../files/auto-dark-light@gihaume/po/zh_TW.po | 601 ++++--- auto-dark-light@gihaume/info.json | 4 +- auto-dark-light@gihaume/package.json | 24 + auto-dark-light@gihaume/pnpm-lock.yaml | 1017 +++++++++++ auto-dark-light@gihaume/pnpm-workspace.yaml | 1 + auto-dark-light@gihaume/requirements.txt | 1 + auto-dark-light@gihaume/screenshot.png | Bin 81810 -> 261107 bytes .../src/app/handlers/Appearance_handler.ts | 55 + .../src/app/handlers/Background_handler.ts | 66 + .../src/app/handlers/Commands_handler.ts | 36 + .../src/app/handlers/Location_handler.ts | 55 + .../src/app/handlers/Themes_handler.ts | 49 + .../src/app/handlers/Twilights_handler.ts | 58 + .../src/app/handlers/initialize_handlers.ts | 308 ++++ .../src/app/initialize_applet_settings.ts | 62 + auto-dark-light@gihaume/src/app/ui/Applet.ts | 17 + .../src/app/ui/Settings.ts | 71 + auto-dark-light@gihaume/src/globals.ts | 50 + .../auto-dark-light@gihaume => src}/icon.svg | 0 .../src/lib/core/Time_of_day.ts | 83 + .../Timezone_location_finder.ts | 39 + .../Timezone_location_finder/database.json | 420 +++++ .../generate_database.ipynb | 78 + .../compute_twilights/compute_twilights.ts | 15 + .../lib/core/compute_twilights/uSunCalc.ts | 97 + .../sys/Event_scheduler/Event_scheduler.ts | 63 + .../lib/sys/Event_scheduler/Timer_absolute.ts | 24 + .../src/lib/sys/Keybinding_handler.ts | 23 + .../Screen_lock_checker.ts | 91 + .../Sleep_events_listener.ts | 76 + .../src/lib/sys/System_background.ts | 34 + .../src/lib/sys/System_color_scheme.ts | 42 + .../src/lib/sys/System_themes.ts | 37 + .../src/lib/sys/Time_change_listener.ts | 147 ++ .../src/lib/sys/Timezone_change_listener.ts | 60 + .../src/lib/sys/launch_command.ts | 107 ++ .../src/lib/sys/system_time.ts | 37 + auto-dark-light@gihaume/src/lib/utils.ts | 4 + auto-dark-light@gihaume/src/main.ts | 37 + auto-dark-light@gihaume/src/types.ts | 28 + auto-dark-light@gihaume/src/vite-env.d.ts | 15 + .../tests/Time_of_day.test.ts | 117 ++ auto-dark-light@gihaume/tsconfig.json | 15 + auto-dark-light@gihaume/vite.config.mts | 64 + 108 files changed, 8289 insertions(+), 6904 deletions(-) create mode 100644 auto-dark-light@gihaume/.editorconfig create mode 100644 auto-dark-light@gihaume/.env create mode 100644 auto-dark-light@gihaume/.gitignore create mode 100644 auto-dark-light@gihaume/.vscode/extensions.json create mode 100644 auto-dark-light@gihaume/.vscode/settings.json create mode 100644 auto-dark-light@gihaume/CONTRIBUTING.md create mode 100644 auto-dark-light@gihaume/CREDITS.md create mode 100644 auto-dark-light@gihaume/doc/README.md create mode 100644 auto-dark-light@gihaume/doc/schemas/handlers/Appearance_handler.drawio.svg create mode 100644 auto-dark-light@gihaume/doc/schemas/handlers/Location_handler.drawio.svg create mode 100644 auto-dark-light@gihaume/doc/schemas/handlers/Twilights_handler.drawio.svg create mode 100644 auto-dark-light@gihaume/doc/schemas/handlers/legend.drawio.svg create mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/.gitignore rename auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/{lib/time_change_listener => Time_change_listener}/Makefile (100%) rename auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/{lib/time_change_listener/time_change_listener.cpp => Time_change_listener/Time_change_listener.cpp} (74%) rename auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/{lib/time_change_listener/time_change_listener.hpp => Time_change_listener/Time_change_listener.hpp} (75%) create mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/main.cpp rename auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/{lib/timezones_coordinates => Timezone_location_finder}/database.json (99%) create mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js.sha256sum delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/globals.d.ts delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/jsconfig.json delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/CLASSES HIERARCHY.drawio.svg delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/background_handler.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/color_scheme_change_listener.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/README.md delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/commands_launcher.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/launch_command.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/dbus.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/event_scheduler.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/sleep_wakeup_listener/screen_lock_checker.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/sleep_wakeup_listener/sleep_wakeup_listener.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/themes_handler.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/main.cpp delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_of_day.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timer_absolute.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezone_change_listener.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/generate_database.ipynb delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/timezone_coordinates_finder.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/translator.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/twilights_calculator/suncalc.js delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/twilights_calculator/twilights_calculator.js create mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Button_read_only.py create mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Entry_read_only.py create mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Spin_button_read_only.py create mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Switch_read_only.py create mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/.gitignore create mode 100644 auto-dark-light@gihaume/package.json create mode 100644 auto-dark-light@gihaume/pnpm-lock.yaml create mode 100644 auto-dark-light@gihaume/pnpm-workspace.yaml create mode 100644 auto-dark-light@gihaume/requirements.txt create mode 100644 auto-dark-light@gihaume/src/app/handlers/Appearance_handler.ts create mode 100644 auto-dark-light@gihaume/src/app/handlers/Background_handler.ts create mode 100644 auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts create mode 100644 auto-dark-light@gihaume/src/app/handlers/Location_handler.ts create mode 100644 auto-dark-light@gihaume/src/app/handlers/Themes_handler.ts create mode 100644 auto-dark-light@gihaume/src/app/handlers/Twilights_handler.ts create mode 100644 auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts create mode 100644 auto-dark-light@gihaume/src/app/initialize_applet_settings.ts create mode 100644 auto-dark-light@gihaume/src/app/ui/Applet.ts create mode 100644 auto-dark-light@gihaume/src/app/ui/Settings.ts create mode 100644 auto-dark-light@gihaume/src/globals.ts rename auto-dark-light@gihaume/{files/auto-dark-light@gihaume => src}/icon.svg (100%) create mode 100644 auto-dark-light@gihaume/src/lib/core/Time_of_day.ts create mode 100644 auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/Timezone_location_finder.ts create mode 100644 auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/database.json create mode 100644 auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/generate_database.ipynb create mode 100644 auto-dark-light@gihaume/src/lib/core/compute_twilights/compute_twilights.ts create mode 100644 auto-dark-light@gihaume/src/lib/core/compute_twilights/uSunCalc.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Event_scheduler.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Timer_absolute.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Screen_lock_checker.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Sleep_events_listener.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/System_background.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/System_color_scheme.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/System_themes.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/Time_change_listener.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/Timezone_change_listener.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/launch_command.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/system_time.ts create mode 100644 auto-dark-light@gihaume/src/lib/utils.ts create mode 100644 auto-dark-light@gihaume/src/main.ts create mode 100644 auto-dark-light@gihaume/src/types.ts create mode 100644 auto-dark-light@gihaume/src/vite-env.d.ts create mode 100644 auto-dark-light@gihaume/tests/Time_of_day.test.ts create mode 100644 auto-dark-light@gihaume/tsconfig.json create mode 100644 auto-dark-light@gihaume/vite.config.mts diff --git a/auto-dark-light@gihaume/.editorconfig b/auto-dark-light@gihaume/.editorconfig new file mode 100644 index 00000000000..f9500e96bae --- /dev/null +++ b/auto-dark-light@gihaume/.editorconfig @@ -0,0 +1,9 @@ +[*.*] +charset = utf-8 +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true +trim_final_newline = true +end_of_line = lf +max_line_length = 80 diff --git a/auto-dark-light@gihaume/.env b/auto-dark-light@gihaume/.env new file mode 100644 index 00000000000..5c9a8af42cc --- /dev/null +++ b/auto-dark-light@gihaume/.env @@ -0,0 +1,3 @@ +# Every of theses keys to be used in `src` must be typed in `src/vite-env.d.ts` + +VITE_KEEP_MAIN_FUNCTION_SENTINEL=__auto_dark_light__ diff --git a/auto-dark-light@gihaume/.gitignore b/auto-dark-light@gihaume/.gitignore new file mode 100644 index 00000000000..3ec40f72dc1 --- /dev/null +++ b/auto-dark-light@gihaume/.gitignore @@ -0,0 +1,3 @@ +node_modules +.pnpm-store +.venv diff --git a/auto-dark-light@gihaume/.vscode/extensions.json b/auto-dark-light@gihaume/.vscode/extensions.json new file mode 100644 index 00000000000..6d1524737e1 --- /dev/null +++ b/auto-dark-light@gihaume/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "EditorConfig.EditorConfig", + "ms-python.python", + "vitest.explorer" + ] +} diff --git a/auto-dark-light@gihaume/.vscode/settings.json b/auto-dark-light@gihaume/.vscode/settings.json new file mode 100644 index 00000000000..7d955dffb7d --- /dev/null +++ b/auto-dark-light@gihaume/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib", + "python.analysis.extraPaths": [ + "/usr/share/cinnamon/cinnamon-settings/bin" + ], + "C_Cpp.default.cppStandard": "c++20" +} diff --git a/auto-dark-light@gihaume/CHANGELOG.md b/auto-dark-light@gihaume/CHANGELOG.md index 98fb947044e..9721f77a53c 100644 --- a/auto-dark-light@gihaume/CHANGELOG.md +++ b/auto-dark-light@gihaume/CHANGELOG.md @@ -1,45 +1,103 @@ -## 1.2.6 - 18.05.2025 +# Changelog -- Corrected commands launching not supporting `;` in the command +The format adheres to [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) and [SemVer 2.0.0](https://semver.org/spec/v2.0.0.html) -## 1.2.5 - 18.05.2025 +## [2.0.0] - 2025-11-02 - [#?](https://github.com/linuxmint/cinnamon-spices-applets/pull/?) -- Corrected `g++` dependancy wrongly verified as `gcc` -- Added explicit notification for not supported versions of Cinnamon +Extensive rewrite to enable new features – some bugs may have been introduced. -## 1.2.4 - 13.05.2025 +### Added -- Added TypeScript checks via `jsconfig.json` -- Renamed a lot of things +- Manual switching schedule per twilight ([#6758](https://github.com/linuxmint/cinnamon-spices-applets/issues/6758)). +- Automatic switching schedule offset per twilight ([#7247](https://github.com/linuxmint/cinnamon-spices-applets/issues/7247)). +- Keybinding to toggle appearance ([#7923](https://github.com/linuxmint/cinnamon-spices-applets/issues/7923)). +- Indicator showing if the actual appearance is unsynced with the current time, also in the settings configure menu (previously only shown in the panel's icon state). +- Indicator of the next appearance update schedule. +- Indicator of the twilights computed from the location as a widget instead of the previous notification triggered from a button. +- Indicator of the current system location. +- **Known limitation**: some indicators are updated with a delay of 2 seconds because of an [issue with Cinnamon's settings](https://github.com/linuxmint/cinnamon/issues/12362). -## 1.2.3 - 28.04.2025 +### Changed -- Background handling feature: - - Corrected applying both file and folder while it should only do one at once - - Added support for non-ASCII URIs +- Every previous "mode" textual reference to be "appearance". +- Themes fields to be read-only. +- Timezone coordinates local database to be the same as the ones used by Cinnamon Settings Daemon's Night Light. + - Note that there can still be a difference in the twilight times as their calculation is done differently. +- Improved logging and notifications types for better look and clarity. -## 1.2.2 - 23.01.2025 +### Changed (internal) -- Added missing import in `time_change_listener/main.cpp` for GCC 14.2 +- Use of MobX for scalable reactive state management. +- Use of Vite transpilation for better imports handling, use of external libraries and bundling. +- Use of TypeScript for better typing expressivity. +- Use of Vitest for unit testing. -## 1.2.1 - 22.10.2024 +## [1.2.6] - 2025-05-18 - [#7257](https://github.com/linuxmint/cinnamon-spices-applets/pull/7257) -- Custom commands launching feature: - - Corrected list's `Active` attribute default to `true` - - Added shell features support +### Fixed -## 1.2.0 - 22.10.2024 +- Custom commands launching to correctly support `;` shell feature. [#6549](https://github.com/linuxmint/cinnamon-spices-applets/issues/6549) -- Added custom commands launching feature +## [1.2.5] - 2025-05-18 - [#7256](https://github.com/linuxmint/cinnamon-spices-applets/pull/7256) -## 1.1.0 - 02.09.2024 +### Added -- Added desktop background support +- Explicit notification for not supported versions of Cinnamon ([#7207](https://github.com/linuxmint/cinnamon-spices-applets/issues/7207)). -## 1.0.1 - 26.08.2024 +### Fixed -- Replaced `DateTime` methods incompatible with `GLib` < 2.80 +- `g++` dependency wrongly verified as `gcc`. -## 1.0.0 - 26.08.2024 +## [1.2.4] - 2025-05-13 - [#7217](https://github.com/linuxmint/cinnamon-spices-applets/pull/7217) + +### Changed (internal) + +- Use of TypeScript checking via JSDoc. +- Renaming of a lot of code things. + +## [1.2.3] - 2025-04-28 - [#7140](https://github.com/linuxmint/cinnamon-spices-applets/pull/7140) + +### Fixed + +- Desktop background to be applied to either file or folder depending if slideshow is enabled ([#7138](https://github.com/linuxmint/cinnamon-spices-applets/issues/7138)). +- Background's file/folder to support non-ASCII URIs. + +## [1.2.2] - 2025-01-23 - [#6797](https://github.com/linuxmint/cinnamon-spices-applets/pull/6797) + +### Fixed + +- Missing import in time change listener's `main.cpp` for `g++` 14.2 ([#6791](https://github.com/linuxmint/cinnamon-spices-applets/issues/6791)). + +## [1.2.1] - 2024-10-22 - [#6524](https://github.com/linuxmint/cinnamon-spices-applets/pull/6524) + +### Added + +- Shell features support for custom commands launching. + +### Changed + +- Custom commands launching's list's `Active` attribute to default to `true`. + +## [1.2.0] - 2024-10-22 - [#6521](https://github.com/linuxmint/cinnamon-spices-applets/pull/6521) + +### Added + +- Custom commands launching. + +## [1.1.0] - 2024-09-02 - [#6361](https://github.com/linuxmint/cinnamon-spices-applets/pull/6361) + +### Added + +- Desktop background support ([#6354](https://github.com/linuxmint/cinnamon-spices-applets/issues/6354)). + +## [1.0.1] - 2024-08-26 - [#6344](https://github.com/linuxmint/cinnamon-spices-applets/pull/6344) + +### Fixed + +- `GLib.DateTime` used methods to be compatible with `GLib` < 2.80 ([#6341](https://github.com/linuxmint/cinnamon-spices-applets/issues/6341)). + +## [1.0.0] - 2025-08-26 - [#6329](https://github.com/linuxmint/cinnamon-spices-applets/pull/6329) + +### Added - Initial release diff --git a/auto-dark-light@gihaume/CONTRIBUTING.md b/auto-dark-light@gihaume/CONTRIBUTING.md new file mode 100644 index 00000000000..d91428a8847 --- /dev/null +++ b/auto-dark-light@gihaume/CONTRIBUTING.md @@ -0,0 +1,94 @@ +# Contributing + +## Prerequisites + +### Global dependencies + +- [pnpm](https://pnpm.io/installation#on-posix-systems) (tested v10.20.0). + +### Local dependencies + +- Install dependencies: + ```bash + pnpm i # shortcut for `pnpm install` + ``` + - It needs to be done after each `git pull` that changes `pnpm-lock.yaml`. + - It creates a `node_modules` folder with symlinks to a global store, so: + - The global store can be pruned after the local `node_modules` folder has been deleted: + ```bash + pnpm store prune + ``` + - Or to have the files installed in this folder instead of the global store, use exclusively: + ```bash + pnpm i --store-dir=.pnpm-store + ``` + +## Development + +- Create a symbolic link pointing to this repository and add it in your user applets folder: + ```bash + ln -s \ + /files/auto-dark-light@gihaume \ + ~/.local/share/cinnamon/applets/auto-dark-light@gihaume + ``` + - Alternatively, it can be created via GUI with the handy Cinnamon Spices' Action [`create-desktop-shortcut@anaximeno`](https://cinnamon-spices.linuxmint.com/actions/view/11). +- Launch the continuous and incremental build of `applet.js` triggered on each source file save: + ```bash + pnpm dev + ``` + - Modify source files in `src/` as wanted. + - Reset Cinnamon with `Ctrl`+`Alt`+`Esc` for loading and testing the applet's new version. + - Debug with: + - Looking Glass logs (`Alt`+`F2`, type `lg`, `Enter`), + - `~/.xsession-errors` logs file. + - Press `Ctrl`+`C` (`SIGINT`) to stop the continuous build. + +## Testing + +- Run all unit tests: + ```bash + pnpm test + ``` + - The VS Code extension [Vitest](vscode:extension/vitest.explorer) can also be used. + +## Committing + +Before any commit: + +- The `applet.js` has to be built via a minification single run with: + ```bash + pnpm build + ``` + - Then it is advisable to E2E test the change again. + - Note that it produces an `applet.js.sha256sum` file using GNU's `sha256sum` command for reproducible integrity verification by a reviewer. +- The change has to be documented as an incremented version in `CHANGELOG.md` accordingly. + - The version number has to be modified in `files/metadata.json` accordingly. +- If some call to gettext `_("…")` has been added or modified, the following command must be run from the root of the repository to update the `.pot` translation template file: + ```bash + ./cinnamon-spices-makepot auto-dark-light@gihaume + ``` + +## Documentation + +Check the [`doc/README.md`](./doc/README.md) file. + +## Linting for Python widgets (experimental) + +### Installation + +- Create environment: + ```sh + python -m venv .venv --system-site-packages + ``` +- Install dependencies: + ```sh + ./.venv/bin/pip install -r requirements.txt + ``` + +### Setting up in VS Code + +- Install the `ms-python.python` extension. +- Select the Python interpreter from the `.venv` folder: + - Launch the Command Palette with `Ctrl`+`Shift`+`P` + - Select `Python: Select Interpreter` + - Select the one from the `.venv` folder. diff --git a/auto-dark-light@gihaume/CREDITS.md b/auto-dark-light@gihaume/CREDITS.md new file mode 100644 index 00000000000..da9d9da964c --- /dev/null +++ b/auto-dark-light@gihaume/CREDITS.md @@ -0,0 +1,4 @@ +# Credits + +- [SunCalc](https://github.com/mourner/suncalc): twilights calculations from geographical coordinates and date +- [MobX](https://mobx.js.org): reactive state management diff --git a/auto-dark-light@gihaume/README.md b/auto-dark-light@gihaume/README.md index 80d665414fd..15162272518 100644 --- a/auto-dark-light@gihaume/README.md +++ b/auto-dark-light@gihaume/README.md @@ -1,35 +1,44 @@ # Automatic dark/light themes -This Cinnamon applet brings the ability to automatically switch between dark and light themes and desktop background at twilight times based on a location. +This Cinnamon applet brings the ability to automatically switch between dark and light appearances at twilights times based on a location or some user set schedules. + +The appearance consists of: +- themes, +- desktop background, +- shell commands to be launched when switching. ## Features -- Dump system themes and desktop background settings as light/dark presets in one click in order to keep using the Cinnamon settings menu. +- Save system themes and desktop background settings as light/dark presets in one click. - Sync location from the system `Region` and `City` settings using a local database to automatically determine the geographical coordinates. -- Enter manually any geographical coordinates if needed. -- Always sync instantaneously with external changes of color scheme, region/city and time (useful in e.g. after a sleep wake up). -- Fully event and scheduling based, zero polling. -- Automatic mode switch can be disabled. -- Dark/light mode can always be switched manually. -- Schedule any amount of commands to launch at twilight times. + - Or enter manually any geographical coordinates if needed. +- Compute twilights times from geographical coordinates and add them some offset or just set them arbitrarily. +- Always sync instantaneously with system changes of color scheme (appearance), region/city and time (useful in e.g. after a sleep wake up). +- Automatic appearance switch can be disabled. +- Dark/light appearance can always be switched manually. +- Everything is fully event-listening and scheduling based (no active polling). ## Applet icons legend
Auto - Automatic mode switch enabled. + Automatic appearance switch enabled.
Auto inverted - Automatic mode switch enabled but the current mode has been set while not in sync with the actual daytime, so any external changes won't update it until the next scheduled mode change or if entering auto mode switch again. + Automatic appearance switch enabled but the current appearance has been set while not in sync with the actual daytime, so any external changes won't update it until the next scheduled appearance change or if entering in automatic appearance switch mode again.
Light - Automatic mode switch disabled and the current mode is light. + Automatic appearance switch disabled and the current appearance is light.
Dark - Automatic mode switch disabled and the current mode is dark. + Automatic appearance switch disabled and the current appearance is dark. +
+
+ Error + The applet is in an error state and is not functional. A notification should have been shown giving more details about the error. If it has disappeared, it is possible to find it in the Looking Glass logs: press Alt+F2 and enter 'lg'.
## Dependencies @@ -38,10 +47,6 @@ This Cinnamon applet brings the ability to automatically switch between dark and ## Feedback -Add a `⭐ Score` on the [Cinnamon spices](https://cinnamon-spices.linuxmint.com/applets/view/397) page if you like this applet. - -Report issues on the [GitHub repository](https://github.com/linuxmint/cinnamon-spices-applets/issues) in mentioning `@guillaume-mueller`. - -## Donate - -[Buy me a coffee](https://buymeacoffee.com/gihaume) +- Add a `⭐ Score` on the [Cinnamon spices page](https://cinnamon-spices.linuxmint.com/applets/view/397)'s top if you like this applet. +- Report issues or request features on the [GitHub repository](https://github.com/linuxmint/cinnamon-spices-applets/issues?q=is:issue+is:open+auto-dark-light@gihaume). +- [Buy me a coffee](https://buymeacoffee.com/gihaume) if you'd like. diff --git a/auto-dark-light@gihaume/doc/README.md b/auto-dark-light@gihaume/doc/README.md new file mode 100644 index 00000000000..79aac4144e2 --- /dev/null +++ b/auto-dark-light@gihaume/doc/README.md @@ -0,0 +1,21 @@ +# Architecture overview + +## Reactive state handlers dependencies graphs + +### Legend + +![Legend](./schemas/handlers/legend.drawio.svg) + +### Location handler + +![Location handler](./schemas/handlers/Location_handler.drawio.svg) + +### Twilights handler + +![Twilights handler](./schemas/handlers/Twilights_handler.drawio.svg) + +### Appearance handler + +(It's actually more complex than that) + +![Appearance handler](./schemas/handlers/Appearance_handler.drawio.svg) diff --git a/auto-dark-light@gihaume/doc/schemas/handlers/Appearance_handler.drawio.svg b/auto-dark-light@gihaume/doc/schemas/handlers/Appearance_handler.drawio.svg new file mode 100644 index 00000000000..92f23498713 --- /dev/null +++ b/auto-dark-light@gihaume/doc/schemas/handlers/Appearance_handler.drawio.svg @@ -0,0 +1,4 @@ + + + +
Twilights
Is state auto
  Handler
  Controls
Is state auto
Update
Time
OS
Manual state
State
Manual state
  Views
Auto state
Compute
Auto state
\ No newline at end of file diff --git a/auto-dark-light@gihaume/doc/schemas/handlers/Location_handler.drawio.svg b/auto-dark-light@gihaume/doc/schemas/handlers/Location_handler.drawio.svg new file mode 100644 index 00000000000..25557d38a57 --- /dev/null +++ b/auto-dark-light@gihaume/doc/schemas/handlers/Location_handler.drawio.svg @@ -0,0 +1,4 @@ + + + +
Manual <coord>
Is location auto
Auto location
  Handler
  Views
  Controls
Auto latitude
Manual latitude
Manual longitude
Auto longitude
Is location auto
Timezone
Timezone
Find
Location
OS
\ No newline at end of file diff --git a/auto-dark-light@gihaume/doc/schemas/handlers/Twilights_handler.drawio.svg b/auto-dark-light@gihaume/doc/schemas/handlers/Twilights_handler.drawio.svg new file mode 100644 index 00000000000..64aabbdb7f8 --- /dev/null +++ b/auto-dark-light@gihaume/doc/schemas/handlers/Twilights_handler.drawio.svg @@ -0,0 +1,4 @@ + + + +
Is <twilight> auto
Manual <twilight>
Auto <twilight> offset
Auto <twilight>
  Views
  Controls
Auto sunrise
Auto sunset
Auto sunrise offset
Auto sunset offset
Manual sunrise
Manual sunset
Is sunrise auto
Is sunset auto
Location twilights
  Handler
Date
Compute
Location
Update
Twilights
OS
\ No newline at end of file diff --git a/auto-dark-light@gihaume/doc/schemas/handlers/legend.drawio.svg b/auto-dark-light@gihaume/doc/schemas/handlers/legend.drawio.svg new file mode 100644 index 00000000000..833ddec3925 --- /dev/null +++ b/auto-dark-light@gihaume/doc/schemas/handlers/legend.drawio.svg @@ -0,0 +1,4 @@ + + + +
State
Task
Push
Pull
\ No newline at end of file diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/2.2/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/2.2/applet.js index 5a2de6db40a..16a190f042a 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/2.2/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/2.2/applet.js @@ -16,8 +16,8 @@ class ThisApplet extends Applet.IconApplet { const _ = text => Gettext.dgettext(applet_name, text); const critical_message = - `${_("Critical error")}${_(":")}` - + `${_("this applet is only supported by")} Cinnamon >= 5.8.`; + `${_("Critical error")}${_(":")} ` + + `${_("this applet only supports")} Cinnamon >= 5.8.`; Main.criticalNotify(applet_name, critical_message); this.set_applet_tooltip(critical_message); diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/.gitignore b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/.gitignore new file mode 100644 index 00000000000..1dc1265edc6 --- /dev/null +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/.gitignore @@ -0,0 +1,2 @@ +build +auto-dark-light-time-change-listener diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/Makefile b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Makefile similarity index 100% rename from auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/Makefile rename to auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Makefile diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.cpp b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.cpp similarity index 74% rename from auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.cpp rename to auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.cpp index 9cf1deaddbf..89525a785ae 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.cpp +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.cpp @@ -1,4 +1,4 @@ -#include "time_change_listener.hpp" +#include "Time_change_listener.hpp" #include #include @@ -30,10 +30,10 @@ int new_timerfd() { Time_change_listener::Time_change_listener(std::function callback) : fd{new_timerfd()}, callback{callback}, - listen_thread{&This::listen, this} + listener_thread{&This::listener_thread_function, this} {} -void Time_change_listener::listen() const { +void Time_change_listener::listener_thread_function() const { do { static uint64_t dull_buffer; if (-1 == ::read(this->fd, &dull_buffer, sizeof(dull_buffer))) { @@ -41,19 +41,19 @@ void Time_change_listener::listen() const { this->callback(); continue; } else { - std::cerr << "Time_change_listener::listen: read failed: " - << std::strerror(errno) << std::endl; + std::cerr << "Time_change_listener::listener_thread_function: " + "read failed: " << std::strerror(errno) + << std::endl; return; } } - } while (!this->end_thread); + } while (this->should_listener_thread_run); } static constexpr struct itimerspec SETTIME_NEVER = {{0, 0}, {0, 0}}; void Time_change_listener::enable() const { - static constexpr auto FLAGS = - TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET; + static constexpr auto FLAGS = TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET; if (-1 == ::timerfd_settime(this->fd, FLAGS, &SETTIME_NEVER, NULL)) throw system_error( "Time_change_listener::enable: timerfd_settime failed" @@ -68,14 +68,11 @@ void Time_change_listener::disable() const { } Time_change_listener::~Time_change_listener() { - this->end_thread = true; + this->should_listener_thread_run = false; - // Unblock the blocked `read` call in the `listen` method - static constexpr struct itimerspec VIRTUALLY_NOW = { - {0, 0}, - {0, 1} // expire once in 1 ns - }; - if (-1 == ::timerfd_settime(this->fd, 0, &VIRTUALLY_NOW, nullptr)) + static constexpr struct itimerspec VIRTUALLY_NOW = {{0, 0}, {0, 1}}; // "Once, in 1 ns" + + if (-1 == ::timerfd_settime(this->fd, 0, &VIRTUALLY_NOW, nullptr)) // Unblocks the blocked `read` call in the `listener_thread_function` method std::cerr << "Time_change_listener::~Time_change_listener: " "timerfd_settime failed: " << std::strerror(errno) << std::endl; diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.hpp b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.hpp similarity index 75% rename from auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.hpp rename to auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.hpp index 7264218c188..c6b094f8a7b 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.hpp +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.hpp @@ -5,8 +5,7 @@ #include /** - * @brief A passive listener for system time changes implementing the kernel's - * `TFD_TIMER_CANCEL_ON_SET` flag feature. + * @brief A passive listener for system time changes implementing the kernel's `TFD_TIMER_CANCEL_ON_SET` flag feature. */ class Time_change_listener { using This = Time_change_listener; @@ -17,10 +16,8 @@ class Time_change_listener { public: /** - * @param callback The function to be called to notify when the system time - * changes. - * @throw `std::system_error` if the internal timer file descriptor failed - * to be created due to any operating system restriction. + * @param callback The function to be called to notify when the system time changes. + * @throw `std::system_error` if the internal timer file descriptor failed to be created due to any operating system restriction. */ Time_change_listener(std::function callback); @@ -39,8 +36,7 @@ class Time_change_listener { private: const int fd; // Linux file descriptor const std::function callback; - const std::jthread listen_thread; - std::atomic_bool end_thread = false; - - void listen() const; + const std::jthread listener_thread; + std::atomic_bool should_listener_thread_run = true; + void listener_thread_function() const; }; diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/main.cpp b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/main.cpp new file mode 100644 index 00000000000..6dda301c45e --- /dev/null +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/main.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +#include "Time_change_listener.hpp" + +int main(int argc, char* argv[]) { + if ( + std::any_of(argv, argv + argc, [](char* arg) { + return std::string_view(arg) == "--help"; + }) + ) { + std::cout + << "Listens for system time changes and prints 'changed' to `stdout` each time it occurs.\n" + << '\n' + << "Commands via `stdin`:\n" + << " 'enable': Enable listening for the system time changes.\n" + << " 'disable': Disable listening for the system time changes.\n" + << " 'exit': Exit the program.\n" + << '\n' + << "Options:\n" + << " --help: Display this help message.\n" + << std::endl; + return 0; + } + + try { + Time_change_listener listener([]() { + std::cout << "changed" << std::endl; + }); + + std::string input; + while (std::getline(std::cin, input)) { + if (input == "enable") + listener.enable(); + else + if (input == "disable") + listener.disable(); + else + if (input == "exit") + break; + } + } catch (const std::exception& e) { + std::cerr << e.what() << std::endl; + return 1; + } +} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/database.json b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Timezone_location_finder/database.json similarity index 99% rename from auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/database.json rename to auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Timezone_location_finder/database.json index 29d0c177fc3..e96f43c9999 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/database.json +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Timezone_location_finder/database.json @@ -225,7 +225,6 @@ "Asia/Beirut": [33.88894, 35.49442], "Asia/Bishkek": [42.87, 74.59], "Asia/Chita": [52.03341, 113.50089], - "Asia/Choibalsan": [46.68056, 113.27917], "Asia/Colombo": [6.93194, 79.84778], "Asia/Damascus": [33.5102, 36.29128], "Asia/Dhaka": [23.7104, 90.40744], diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index 24fdd4f436c..70a3a4ae4f3 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -1,434 +1,3 @@ -const Themes_handler = require('lib/themes_handler.js'); -const Background_handler = require('lib/background_handler.js'); -const Twilights_calculator = require('lib/twilights_calculator/twilights_calculator.js'); -const Event_scheduler = require('lib/event_scheduler.js'); -const Timer_absolute = require('lib/timer_absolute.js'); -const Time_of_day = require('lib/time_of_day.js'); -const Time_change_listener = require('lib/time_change_listener/time_change_listener.js'); -const Timezone_change_listener = require('lib/timezone_change_listener.js'); -const Timezone_coordinates_finder = require('lib/timezones_coordinates/timezone_coordinates_finder.js'); -const Sleep_wakeup_listener = require('lib/sleep_wakeup_listener/sleep_wakeup_listener.js'); -const Color_scheme_change_listener = require('lib/color_scheme_change_listener.js'); -const Commands_launcher = require('lib/commands_launcher/commands_launcher.js'); -const _ = require('lib/translator.js'); - -const Applet = imports.ui.applet; -const GLib = imports.gi.GLib; -const Settings = imports.ui.settings; -const Main = imports.ui.main; -const Util = imports.misc.util; - -class ThisApplet extends Applet.IconApplet { - constructor(metadata, orientation, panel_height, instance_id) { - super(orientation, panel_height, instance_id); - - this.metadata = metadata; - this.settings = new Settings.AppletSettings( - this, - metadata.uuid, - instance_id - ); - - this.set_applet_tooltip( - _("Click: toggle dark/light mode") + "\n" - + _("Middle-click: toggle automatic switch mode") - ); - - this._init_libs(); - this._bind_ui(); - - switch (Themes_handler.get_system_color_scheme()) { - case 'prefer-dark': - this.ui_switch_dark_mode = true; - if (!this.themes_dark.has_detected) - this.themes_dark.detect(); - break; - case 'prefer-light': default: - this.ui_switch_dark_mode = false; - if (!this.themes_light.has_detected) - this.themes_light.detect(); - } - - this.color_scheme_change_listener.enable(); - if (this.ui_switch_auto_mode) { - this.time_change_listener.enable(); - this.sleep_wakeup_listener.enable(); - } - - this.apply_ui_switch_sync_from_timezone(); - this._update(); - } - - _init_libs() { - this.scheduler = new Event_scheduler(); - - this.timer_abs = new Timer_absolute(); - this.settings.bindWithObject( - this.timer_abs, 'timer-absolute-set-timeout', "timeout" - ); - - this.themes_light = new Themes_handler(this.settings, false, { - mouse_pointer: 'light-mode_themes_entry_mouse-pointer', - applications: 'light-mode_themes_entry_applications', - icons: 'light-mode_themes_entry_icons', - desktop: 'light-mode_themes_entry_desktop', - has_detected: 'has-detected-themes-light' - }); - this.themes_dark = new Themes_handler(this.settings, true, { - mouse_pointer: 'dark-mode_themes_entry_mouse-pointer', - applications: 'dark-mode_themes_entry_applications', - icons: 'dark-mode_themes_entry_icons', - desktop: 'dark-mode_themes_entry_desktop', - has_detected: 'has-detected-themes-dark' - }); - - this.color_scheme_change_listener = - new Color_scheme_change_listener(() => { - this.ui_switch_dark_mode = - Themes_handler.get_system_color_scheme() === 'prefer-dark'; - this._update_state(); - }); - - this.background_light = new Background_handler( - this.settings, - { - is_slideshow: 'light-mode_background_switch_slideshow', - background_file: 'light-mode_background_filechooser_file', - slideshow_folder: 'light-mode_background_filechooser_folder' - } - ); - this.background_dark = new Background_handler( - this.settings, - { - is_slideshow: 'dark-mode_background_switch_slideshow', - background_file: 'dark-mode_background_filechooser_file', - slideshow_folder: 'dark-mode_background_filechooser_folder' - } - ); - - this.commands_light = new Commands_launcher( - this.settings, - 'light-mode_commands_list', - this._notify_error.bind(this) - ); - this.commands_dark = new Commands_launcher( - this.settings, - 'dark-mode_commands_list', - this._notify_error.bind(this) - ); - - try { - this.time_change_listener = new Time_change_listener( - `${this.metadata.path}/lib/time_change_listener`, - this._update.bind(this), - this._notify_error.bind(this) - ); - } catch (error) { - this._notify_critical(error.message); - this.settings.finalize(); // somewhat crash cleanly - return; // '' - } - - this.timezone_change_listener = new Timezone_change_listener(() => { - this.apply_coordinates_from_system_timezone(); - this._update(); - }); - - this.timezone_coordinates_finder = new Timezone_coordinates_finder( - `${this.metadata.path}/lib/timezones_coordinates` - ); - - this.sleep_wakeup_listener = new Sleep_wakeup_listener( - () => { - this.time_change_listener.disable(); - this.scheduler.unset_the_event(); - }, - () => { - this._update(); - this.time_change_listener.enable(); - } - ); - } - - _bind_ui() { - this.settings.bind( - 'settings_state_switch_dark-mode', - "ui_switch_dark_mode", - () => { this.apply_ui_switch_dark_mode(); this._update_state(); } - ); - this.settings.bind( - 'settings_state_is-auto-mode-inverted', - "is_auto_mode_inverted" - ); - this.settings.bind( - 'settings_control_switch_auto-mode', - "ui_switch_auto_mode", - () => { this.apply_ui_switch_auto_mode(); this._update(); } - ); - this.settings.bind( - 'settings_location_switch_sync-from-timezone', - "ui_switch_sync_from_timezone", - () => { this.apply_ui_switch_sync_from_timezone(); this._update(); } - ); - this.settings.bind( - 'settings_location_entry_latitude', - "ui_entry_latitude", - () => { this.apply_ui_entry_coordinates(); this._update(); } - ); - this.settings.bind( - 'settings_location_entry_longitude', - "ui_entry_longitude", - () => { this.apply_ui_entry_coordinates(); this._update(); } - ); - this.settings.bind( - 'both-modes_background_switch_enable', - "ui_switch_enable_background" - ); - this.settings.bind( - 'light-mode_commands_switch_enable', - "ui_switch_enable_commands_light" - ); - this.settings.bind( - 'dark-mode_commands_switch_enable', - "ui_switch_enable_commands_dark" - ); - } - - apply_ui_switch_dark_mode() { - this.color_scheme_change_listener.disable(); - this.ui_switch_dark_mode ? this.themes_dark. apply() - : this.themes_light.apply(); - this.color_scheme_change_listener.enable(); - - if (this.ui_switch_enable_background) - this.ui_switch_dark_mode ? this.background_dark.apply() - : this.background_light.apply(); - - if (this.ui_switch_dark_mode) { - if (this.ui_switch_enable_commands_dark) - this.commands_dark.launch_commands(); - } else { - if (this.ui_switch_enable_commands_light) - this.commands_light.launch_commands(); - } - this._update_applet_icon(); - } - - apply_ui_switch_auto_mode() { - if (this.ui_switch_auto_mode) { - this.is_auto_mode_inverted = false; - this.time_change_listener.enable(); - this.sleep_wakeup_listener.enable(); - } else { - this.time_change_listener.disable(); - this.sleep_wakeup_listener.disable(); - this.scheduler.unset_the_event(); - } - } - - apply_ui_switch_sync_from_timezone() { - if (this.ui_switch_sync_from_timezone) { - this.apply_coordinates_from_system_timezone(); - this.timezone_change_listener.enable(); - } else { - this.timezone_change_listener.disable(); - this.apply_ui_entry_coordinates(); - } - } - - apply_ui_entry_coordinates() { - this.latitude = this.ui_entry_latitude; - this.longitude = this.ui_entry_longitude; - } - - apply_coordinates_from_system_timezone() { - const timezone = GLib.TimeZone.new_local().get_identifier(); - [this.latitude, this.longitude] = - this.timezone_coordinates_finder.find_coordinates(timezone); - } - - _update_state() { - if (this.ui_switch_auto_mode && this._update_twilights()) { - this._update_is_auto_mode_inverted(); - this._schedule_auto_switch(); - } - this._update_applet_icon(); - } - - _update() { - if (this.ui_switch_auto_mode && this._update_twilights()) { - if (!this.is_auto_mode_inverted || this.timer_abs.get_if_has_expired()) - this._update_mode(); - this._update_is_auto_mode_inverted(); - this._schedule_auto_switch(); - } - this._update_applet_icon(); - } - - _update_mode() { - this.ui_switch_dark_mode = !this._is_now_day(); - this.apply_ui_switch_dark_mode(); - this.is_auto_mode_inverted = false; - } - - _update_is_auto_mode_inverted() { - this.is_auto_mode_inverted = - this.ui_switch_dark_mode === this._is_now_day(); - } - - _is_now_day() { - return Time_of_day.now().is_between(this.sunrise, this.sunset); - } - - /** - * @returns {boolean} Whether the twilights have been successfully updated. - */ - _update_twilights() { - let sunrise, sunset; - try { ({sunrise, sunset} = - Twilights_calculator.get_today(this.latitude, this.longitude)); - } - catch (error) { - this._notify_error(error.message); - return false; - } - this.sunrise = sunrise; - this.sunset = sunset; - return true; - } - - _update_applet_icon() { - this.set_applet_icon_symbolic_name( - this.ui_switch_auto_mode - ? this.is_auto_mode_inverted - ? 'auto-inverted-symbolic' - : 'auto-symbolic' - : this.ui_switch_dark_mode - ? 'dark-symbolic' - : 'light-symbolic' - ); - } - - _schedule_auto_switch() { - const callback = this.is_auto_mode_inverted ? - () => {} - : this.ui_switch_dark_mode ? - this._apply_light_mode.bind(this) - : this._apply_dark_mode .bind(this); - - const time = this.ui_switch_dark_mode ? - (this.is_auto_mode_inverted ? this.sunset : this.sunrise) - : (this.is_auto_mode_inverted ? this.sunrise : this.sunset); - - this.timer_abs.expiration_time = time; - - this.scheduler.set_the_event(time, () => { - this.is_auto_mode_inverted = false; - callback(); - if (!this._update_twilights()) - return; - this._schedule_auto_switch(); - this._update_applet_icon(); - }); - } - - _apply_light_mode() { - this.ui_switch_dark_mode = false; - this.apply_ui_switch_dark_mode(); - } - - _apply_dark_mode() { - this.ui_switch_dark_mode = true; - this.apply_ui_switch_dark_mode(); - } - - on_applet_clicked() { // built-in method - if (this.ui_switch_auto_mode) - this.is_auto_mode_inverted = !this.is_auto_mode_inverted; - this.ui_switch_dark_mode = !this.ui_switch_dark_mode; - this.apply_ui_switch_dark_mode(); - this._update_state(); - } - - on_applet_middle_clicked() { // built-in method - this.ui_switch_auto_mode = !this.ui_switch_auto_mode; - this.apply_ui_switch_auto_mode(); - this._update(); - } - - on_button_open_os_date_time_settings() { - Util.spawnCommandLine("cinnamon-settings calendar"); - } - - on_button_show_start_times() { - if (!this._update_twilights()) - return; - this._notify( - _("Today's automatic mode switch times") + _(":") + '\n' - + `- ${_("Light mode")}${_(":")} ${this.sunrise.as_string()}` + '\n' - + `- ${_("Dark mode") }${_(":")} ${this.sunset .as_string()}` - ); - } - - on_button_open_os_themes_settings() { - Util.spawnCommandLineAsync('cinnamon-settings themes', null, null); - } - - on_button_detect_themes_light() { - this.themes_light.detect(); - this.ui_switch_dark_mode = false; - this._update_state(); - } - - on_button_apply_themes_light() { this.themes_light.apply(); } - - on_button_detect_themes_dark() { - this.themes_dark.detect(); - this.ui_switch_dark_mode = true; - this._update_state(); - } - - on_button_apply_themes_dark() { this.themes_dark.apply(); } - - on_button_open_os_background_settings() { - Util.spawnCommandLineAsync('cinnamon-settings background', null, null); - } - - on_button_detect_background_light() { this.background_light.detect(); } - - on_button_apply_background_light() { this.background_light.apply(); } - - on_button_detect_background_dark() { this.background_dark.detect(); } - - on_button_apply_background_dark() { this.background_dark.apply(); } - - on_button_launch_commands_light() { this.commands_light.launch_commands(); } - - on_button_launch_commands_dark() { this.commands_dark.launch_commands(); } - - _notify(msg) { Main.notify(this.metadata.name, msg); } - - _notify_error(msg) { - Main.notifyError(this.metadata.name, `${_("Error")}${_(":")} ${msg}`); - } - - _notify_critical(msg) { - Main.criticalNotify( - this.metadata.name, - `${_("Critical error")}${_(":")} ${msg}` - ); - } - - on_applet_removed_from_panel() { // built-in method - this.scheduler .finalize(); - this.time_change_listener .finalize(); - this.sleep_wakeup_listener .finalize(); - this.timezone_change_listener .finalize(); - this.color_scheme_change_listener.finalize(); - this.settings .finalize(); - } -} - -function main(metadata, orientation, panel_height, instance_id) { - return new ThisApplet(metadata, orientation, panel_height, instance_id); -} +const e=imports.gettext,{GLib:t}=imports.gi,n=imports.ui.main,{St:i}=imports.gi,s={uuid:"",name:"",description:"",path:"",force_loaded:!1};function _(t){return e.dgettext(s.uuid,t)}let r="";const a=new i.Icon({icon_name:"dialog-warning",icon_type:i.IconType.SYMBOLIC,icon_size:24}),o=new i.Icon({icon_name:"dialog-error",icon_type:i.IconType.SYMBOLIC,icon_size:24}),u={info(e){global.log(r+`${_(":")} `+e),n.notify(r,e)},warn(e){global.logWarning(r+`${_(":")} `+e),n.warningNotify(r,e,a)},error(e){global.logError(r+`${_(":")} `+e),n.criticalNotify(r,e,o)}};function l(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;ie.length)&&(t=e.length);for(var n=0,i=Array(t);n=e.length?{done:!0}:{done:!1,value:e[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function z(){return z=Object.assign?Object.assign.bind():function(e){for(var t=1;ti&&(i=o.dependenciesState_)}n.length=s,e.newObserving_=null,r=t.length;for(;r--;){var u=t[r];0===u.diffValue&&wt(u,e),u.diffValue=0}for(;s--;){var l=n[s];1===l.diffValue&&(l.diffValue=0,kt(l,e))}i!==nt.UP_TO_DATE_&&(e.dependenciesState_=i,e.onBecomeStale_())}(e),pt(i),s}function ct(e){var t=e.observing_;e.observing_=[];for(var n=t.length;n--;)wt(t[n],e);e.dependenciesState_=nt.NOT_TRACKING_}function ht(e){var t=dt();try{return e()}finally{ft(t)}}function dt(){var e=yt.trackingDerivation;return yt.trackingDerivation=null,e}function ft(e){yt.trackingDerivation=e}function gt(e){var t=yt.allowStateReads;return yt.allowStateReads=e,t}function pt(e){yt.allowStateReads=e}function vt(e){if(e.dependenciesState_!==nt.UP_TO_DATE_){e.dependenciesState_=nt.UP_TO_DATE_;for(var t=e.observing_,n=t.length;n--;)t[n].lowestObserverState_=nt.UP_TO_DATE_}}var bt=function(){this.version=6,this.UNCHANGED={},this.trackingDerivation=null,this.trackingContext=null,this.runId=0,this.mobxGuid=0,this.inBatch=0,this.pendingUnobservations=[],this.pendingReactions=[],this.isRunningReactions=!1,this.allowStateChanges=!1,this.allowStateReads=!0,this.enforceActions=!0,this.spyListeners=[],this.globalReactionErrorHandlers=[],this.computedRequiresReaction=!1,this.reactionRequiresObservable=!1,this.observableRequiresReaction=!1,this.disableErrorBoundaries=!1,this.suppressReactionErrors=!1,this.useProxies=!0,this.verifyProxies=!1,this.safeDescriptors=!0},mt=!0,yt=function(){var e=h();return e.__mobxInstanceCount>0&&!e.__mobxGlobals&&(mt=!1),e.__mobxGlobals&&e.__mobxGlobals.version!==(new bt).version&&(mt=!1),mt?e.__mobxGlobals?(e.__mobxInstanceCount+=1,e.__mobxGlobals.UNCHANGED||(e.__mobxGlobals.UNCHANGED={}),e.__mobxGlobals):(e.__mobxInstanceCount=1,e.__mobxGlobals=new bt):(setTimeout(function(){l(35)},1),new bt)}();function kt(e,t){e.observers_.add(t),e.lowestObserverState_>t.dependenciesState_&&(e.lowestObserverState_=t.dependenciesState_)}function wt(e,t){e.observers_.delete(t),0===e.observers_.size&&Ot(e)}function Ot(e){!1===e.isPendingUnobservation&&(e.isPendingUnobservation=!0,yt.pendingUnobservations.push(e))}function St(){yt.inBatch++}function At(){if(0===--yt.inBatch){Vt();for(var e=yt.pendingUnobservations,t=0;t0&&Ot(e),!1)}function Et(e){e.lowestObserverState_!==nt.STALE_&&(e.lowestObserverState_=nt.STALE_,e.observers_.forEach(function(e){e.dependenciesState_===nt.UP_TO_DATE_&&e.onBecomeStale_(),e.dependenciesState_=nt.STALE_}))}var jt=function(){function e(e,t,n,i){void 0===e&&(e="Reaction"),this.name_=void 0,this.onInvalidate_=void 0,this.errorHandler_=void 0,this.requiresObservable_=void 0,this.observing_=[],this.newObserving_=[],this.dependenciesState_=nt.NOT_TRACKING_,this.runId_=0,this.unboundDepsCount_=0,this.flags_=0,this.isTracing_=st.NONE,this.name_=e,this.onInvalidate_=t,this.errorHandler_=n,this.requiresObservable_=i}var t=e.prototype;return t.onBecomeStale_=function(){this.schedule_()},t.schedule_=function(){this.isScheduled||(this.isScheduled=!0,yt.pendingReactions.push(this),Vt())},t.runReaction_=function(){if(!this.isDisposed){St(),this.isScheduled=!1;var e=yt.trackingContext;if(yt.trackingContext=this,_t(this)){this.isTrackPending=!0;try{this.onInvalidate_()}catch(t){this.reportExceptionInDerivation_(t)}}yt.trackingContext=e,At()}},t.track=function(e){if(!this.isDisposed){St(),this.isRunning=!0;var t=yt.trackingContext;yt.trackingContext=this;var n=lt(this,e,void 0);yt.trackingContext=t,this.isRunning=!1,this.isTrackPending=!1,this.isDisposed&&ct(this),ut(n)&&this.reportExceptionInDerivation_(n.cause),At()}},t.reportExceptionInDerivation_=function(e){var t=this;if(this.errorHandler_)this.errorHandler_(e,this);else{if(yt.disableErrorBoundaries)throw e;var n="[mobx] uncaught error in '"+this+"'";yt.suppressReactionErrors||console.error(n,e),yt.globalReactionErrorHandlers.forEach(function(n){return n(e,t)})}},t.dispose=function(){this.isDisposed||(this.isDisposed=!0,this.isRunning||(St(),ct(this),At()))},t.getDisposer_=function(e){var t=this,n=function n(){t.dispose(),null==e||null==e.removeEventListener||e.removeEventListener("abort",n)};return null==e||null==e.addEventListener||e.addEventListener("abort",n),n[Z]=this,"dispose"in Symbol&&"symbol"==typeof Symbol.dispose&&(n[Symbol.dispose]=n),n},t.toString=function(){return"Reaction["+this.name_+"]"},t.trace=function(e){},$(e,[{key:"isDisposed",get:function(){return B(this.flags_,e.isDisposedMask_)},set:function(t){this.flags_=U(this.flags_,e.isDisposedMask_,t)}},{key:"isScheduled",get:function(){return B(this.flags_,e.isScheduledMask_)},set:function(t){this.flags_=U(this.flags_,e.isScheduledMask_,t)}},{key:"isTrackPending",get:function(){return B(this.flags_,e.isTrackPendingMask_)},set:function(t){this.flags_=U(this.flags_,e.isTrackPendingMask_,t)}},{key:"isRunning",get:function(){return B(this.flags_,e.isRunningMask_)},set:function(t){this.flags_=U(this.flags_,e.isRunningMask_,t)}},{key:"diffValue",get:function(){return B(this.flags_,e.diffValueMask_)?1:0},set:function(t){this.flags_=U(this.flags_,e.diffValueMask_,1===t)}}])}();jt.isDisposedMask_=1,jt.isScheduledMask_=2,jt.isTrackPendingMask_=4,jt.isRunningMask_=8,jt.diffValueMask_=16;var Pt=100,Tt=function(e){return e()};function Vt(){yt.inBatch>0||yt.isRunningReactions||Tt(Dt)}function Dt(){yt.isRunningReactions=!0;for(var e=yt.pendingReactions,t=0;e.length>0;){++t===Pt&&(console.error("[mobx] cycle in reaction: "+e[0]),e.splice(0));for(var n=e.splice(0),i=0,s=n.length;i",s=function(){var e,t=arguments,s=++tn,r=$t(i+" - runid: "+s+" - init",n).apply(this,t),a=void 0,o=new Promise(function(t,n){var o=0;function u(e){var t;a=void 0;try{t=$t(i+" - runid: "+s+" - yield "+o++,r.next).call(r,e)}catch(u){return n(u)}c(t)}function l(e){var t;a=void 0;try{t=$t(i+" - runid: "+s+" - yield "+o++,r.throw).call(r,e)}catch(u){return n(u)}c(t)}function c(e){if(!S(null==e?void 0:e.then))return e.done?t(e.value):(a=Promise.resolve(e.value)).then(u,l);e.then(c,n)}e=n,u(void 0)});return o.cancel=$t(i+" - runid: "+s+" - cancel",function(){try{a&&on(a);var t=r.return(void 0),n=Promise.resolve(t.value);n.then(O,O),on(n),e(new nn)}catch(i){e(i)}}),o};return s.isMobXFlow=!0,s},sn);function on(e){S(e.cancel)&&e.cancel()}function un(e){return!0===(null==e?void 0:e.isMobXFlow)}function _n(e){return function(e){return!!e&&(Xn(e)||!!e[Z]||ee(e)||It(e)||at(e))}(e)}function ln(e,t){void 0===t&&(t=void 0),St();try{return e.apply(t)}finally{At()}}function cn(e){return e[Z]}an.bound=X(rn);var hn={has:function(e,t){return cn(e).has_(t)},get:function(e,t){return cn(e).get_(t)},set:function(e,t,n){var i;return!!A(t)&&(null==(i=cn(e).set_(t,n,!0))||i)},deleteProperty:function(e,t){var n;return!!A(t)&&(null==(n=cn(e).delete_(t,!0))||n)},defineProperty:function(e,t,n){var i;return null==(i=cn(e).defineProperty_(t,n))||i},ownKeys:function(e){return cn(e).ownKeys_()},preventExtensions:function(e){l(13)}};function dn(e){return void 0!==e.interceptors_&&e.interceptors_.length>0}function fn(e,t){var n=e.interceptors_||(e.interceptors_=[]);return n.push(t),w(function(){var e=n.indexOf(t);-1!==e&&n.splice(e,1)})}function gn(e,t){var n=dt();try{for(var i=[].concat(e.interceptors_||[]),s=0,r=i.length;s0}function vn(e,t){var n=e.changeListeners_||(e.changeListeners_=[]);return n.push(t),w(function(){var e=n.indexOf(t);-1!==e&&n.splice(e,1)})}function bn(e,t){var n=dt(),i=e.changeListeners_;if(i){for(var s=0,r=(i=i.slice()).length;s0?e.map(this.dehancer):e},t.intercept_=function(e){return fn(this,e)},t.observe_=function(e,t){return void 0===t&&(t=!1),t&&e({observableKind:"array",object:this.proxy_,debugObjectName:this.atom_.name_,type:"splice",index:0,added:this.values_.slice(),addedCount:this.values_.length,removed:[],removedCount:0}),vn(this,e)},t.getArrayLength_=function(){return this.atom_.reportObserved(),this.values_.length},t.setArrayLength_=function(e){("number"!=typeof e||isNaN(e)||e<0)&&l("Out of range: "+e);var t=this.values_.length;if(e!==t)if(e>t){for(var n=new Array(e-t),i=0;i0&&ai(e+t+1)},t.spliceWithArray_=function(e,t,n){var i=this;this.atom_;var s=this.values_.length;if(void 0===e?e=0:e>s?e=s:e<0&&(e=Math.max(0,s+e)),t=1===arguments.length?s-e:null==t?0:Math.max(0,Math.min(t,s-e)),void 0===n&&(n=v),dn(this)){var r=gn(this,{object:this.proxy_,type:kn,index:e,removedCount:t,added:n});if(!r)return v;t=r.removedCount,n=r.added}if(n=0===n.length?n:n.map(function(e){return i.enhancer_(e,void 0)}),this.legacyMode_){var a=n.length-t;this.updateArrayLength_(s,a)}var o=this.spliceItemsIntoValues_(e,t,n);return 0===t&&0===n.length||this.notifyArraySplice_(e,n,o),this.dehanceValues_(o)},t.spliceItemsIntoValues_=function(e,t,n){var i;if(n.length<1e4)return(i=this.values_).splice.apply(i,[e,t].concat(n));var s=this.values_.slice(e,e+t),r=this.values_.slice(e+t);this.values_.length+=n.length-t;for(var a=0;a=this.values_.length))return this.atom_.reportObserved(),this.dehanceValue_(this.values_[e]);console.warn("[mobx] Out of bounds read: "+e)},t.set_=function(e,t){var n=this.values_;if(this.legacyMode_&&e>n.length&&l(17,e,n.length),e2?n-2:0),s=2;s-1&&(this.splice(n,1),!0)}};function En(e,t){"function"==typeof Array.prototype[e]&&(xn[e]=t(e))}function jn(e){return function(){var t=this[Z];t.atom_.reportObserved();var n=t.dehanceValues_(t.values_);return n[e].apply(n,arguments)}}function Pn(e){return function(t,n){var i=this,s=this[Z];return s.atom_.reportObserved(),s.dehanceValues_(s.values_)[e](function(e,s){return t.call(n,e,s,i)})}}function Tn(e){return function(){var t=this,n=this[Z];n.atom_.reportObserved();var i=n.dehanceValues_(n.values_),s=arguments[0];return arguments[0]=function(e,n,i){return s(e,n,i,t)},i[e].apply(i,arguments)}}En("at",jn),En("concat",jn),En("flat",jn),En("includes",jn),En("indexOf",jn),En("join",jn),En("lastIndexOf",jn),En("slice",jn),En("toString",jn),En("toLocaleString",jn),En("toSorted",jn),En("toSpliced",jn),En("with",jn),En("every",Pn),En("filter",Pn),En("find",Pn),En("findIndex",Pn),En("findLast",Pn),En("findLastIndex",Pn),En("flatMap",Pn),En("forEach",Pn),En("map",Pn),En("some",Pn),En("toReversed",Pn),En("reduce",Tn),En("reduceRight",Tn);var Vn=V("ObservableArrayAdministration",Sn);function Dn(e){return x(e)&&Vn(e[Z])}var In={},Mn="add",Cn="delete",Nn=function(){function e(e,t,n){var i=this;void 0===t&&(t=ie),void 0===n&&(n="ObservableMap"),this.enhancer_=void 0,this.name_=void 0,this[Z]=In,this.data_=void 0,this.hasMap_=void 0,this.keysAtom_=void 0,this.interceptors_=void 0,this.changeListeners_=void 0,this.dehancer=void 0,this.enhancer_=t,this.name_=n,S(Map)||l(18),li(function(){i.keysAtom_=te("ObservableMap.keys()"),i.data_=new Map,i.hasMap_=new Map,e&&i.merge(e)})}var t=e.prototype;return t.has_=function(e){return this.data_.has(e)},t.has=function(e){var t=this;if(!yt.trackingDerivation)return this.has_(e);var n=this.hasMap_.get(e);if(!n){var i=n=new et(this.has_(e),se,"ObservableMap.key?",!1);this.hasMap_.set(e,i),Zt(i,function(){return t.hasMap_.delete(e)})}return n.get()},t.set=function(e,t){var n=this.has_(e);if(dn(this)){var i=gn(this,{type:n?wn:Mn,object:this,newValue:t,name:e});if(!i)return this;t=i.newValue}return n?this.updateValue_(e,t):this.addValue_(e,t),this},t.delete=function(e){var t=this;if((this.keysAtom_,dn(this))&&!gn(this,{type:Cn,object:this,name:e}))return!1;if(this.has_(e)){var n=pn(this),i=n?{observableKind:"map",debugObjectName:this.name_,type:Cn,object:this,oldValue:this.data_.get(e).value_,name:e}:null;return ln(function(){var n;t.keysAtom_.reportChanged(),null==(n=t.hasMap_.get(e))||n.setNewValue_(!1),t.data_.get(e).setNewValue_(void 0),t.data_.delete(e)}),n&&bn(this,i),!0}return!1},t.updateValue_=function(e,t){var n=this.data_.get(e);if((t=n.prepareNewValue_(t))!==yt.UNCHANGED){var i=pn(this),s=i?{observableKind:"map",debugObjectName:this.name_,type:wn,object:this,oldValue:n.value_,name:e,newValue:t}:null;n.setNewValue_(t),i&&bn(this,s)}},t.addValue_=function(e,t){var n=this;this.keysAtom_,ln(function(){var i,s=new et(t,n.enhancer_,"ObservableMap.key",!1);n.data_.set(e,s),t=s.value_,null==(i=n.hasMap_.get(e))||i.setNewValue_(!0),n.keysAtom_.reportChanged()});var i=pn(this),s=i?{observableKind:"map",debugObjectName:this.name_,type:Mn,object:this,name:e,newValue:t}:null;i&&bn(this,s)},t.get=function(e){return this.has(e)?this.dehanceValue_(this.data_.get(e).get()):this.dehanceValue_(void 0)},t.dehanceValue_=function(e){return void 0!==this.dehancer?this.dehancer(e):e},t.keys=function(){return this.keysAtom_.reportObserved(),this.data_.keys()},t.values=function(){var e=this,t=this.keys();return Rn({next:function(){var n=t.next(),i=n.done,s=n.value;return{done:i,value:i?void 0:e.get(s)}}})},t.entries=function(){var e=this,t=this.keys();return Rn({next:function(){var n=t.next(),i=n.done,s=n.value;return{done:i,value:i?void 0:[s,e.get(s)]}}})},t[Symbol.iterator]=function(){return this.entries()},t.forEach=function(e,t){for(var n,i=K(this);!(n=i()).done;){var s=n.value,r=s[0],a=s[1];e.call(t,a,r,this)}},t.merge=function(e){var t=this;return Ln(e)&&(e=new Map(e)),ln(function(){var n,i,s;E(e)?function(e){var t=Object.keys(e);if(!M)return t;var n=Object.getOwnPropertySymbols(e);return n.length?[].concat(t,n.filter(function(t){return p.propertyIsEnumerable.call(e,t)})):t}(e).forEach(function(n){return t.set(n,e[n])}):Array.isArray(e)?e.forEach(function(e){var n=e[0],i=e[1];return t.set(n,i)}):D(e)?(n=e,i=Object.getPrototypeOf(n),s=Object.getPrototypeOf(i),null!==Object.getPrototypeOf(s)&&l(19,e),e.forEach(function(e,n){return t.set(n,e)})):null!=e&&l(20,e)}),this},t.clear=function(){var e=this;ln(function(){ht(function(){for(var t,n=K(e.keys());!(t=n()).done;){var i=t.value;e.delete(i)}})})},t.replace=function(e){var t=this;return ln(function(){for(var n,i=function(e){if(D(e)||Ln(e))return e;if(Array.isArray(e))return new Map(e);if(E(e)){var t=new Map;for(var n in e)t.set(n,e[n]);return t}return l(21,e)}(e),s=new Map,r=!1,a=K(t.data_.keys());!(n=a()).done;){var o=n.value;if(!i.has(o))if(t.delete(o))r=!0;else{var u=t.data_.get(o);s.set(o,u)}}for(var c,h=K(i.entries());!(c=h()).done;){var d=c.value,f=d[0],g=d[1],p=t.data_.has(f);if(t.set(f,g),t.data_.has(f)){var v=t.data_.get(f);s.set(f,v),p||(r=!0)}}if(!r)if(t.data_.size!==s.size)t.keysAtom_.reportChanged();else for(var b=t.data_.keys(),m=s.keys(),y=b.next(),k=m.next();!y.done;){if(y.value!==k.value){t.keysAtom_.reportChanged();break}y=b.next(),k=m.next()}t.data_=s}),this},t.toString=function(){return"[object ObservableMap]"},t.toJSON=function(){return Array.from(this)},t.observe_=function(e,t){return vn(this,e)},t.intercept_=function(e){return fn(this,e)},$(e,[{key:"size",get:function(){return this.keysAtom_.reportObserved(),this.data_.size}},{key:Symbol.toStringTag,get:function(){return"Map"}}])}(),Ln=V("ObservableMap",Nn);function Rn(e){return e[Symbol.toStringTag]="MapIterator",vi(e)}var Bn={},Un=function(){function e(e,t,n){var i=this;void 0===t&&(t=ie),void 0===n&&(n="ObservableSet"),this.name_=void 0,this[Z]=Bn,this.data_=new Set,this.atom_=void 0,this.changeListeners_=void 0,this.interceptors_=void 0,this.dehancer=void 0,this.enhancer_=void 0,this.name_=n,S(Set)||l(22),this.enhancer_=function(e,i){return t(e,i,n)},li(function(){i.atom_=te(i.name_),e&&i.replace(e)})}var t=e.prototype;return t.dehanceValue_=function(e){return void 0!==this.dehancer?this.dehancer(e):e},t.clear=function(){var e=this;ln(function(){ht(function(){for(var t,n=K(e.data_.values());!(t=n()).done;){var i=t.value;e.delete(i)}})})},t.forEach=function(e,t){for(var n,i=K(this);!(n=i()).done;){var s=n.value;e.call(t,s,s,this)}},t.add=function(e){var t=this;if(this.atom_,dn(this)){var n=gn(this,{type:Mn,object:this,newValue:e});if(!n)return this;e=n.newValue}if(!this.has(e)){ln(function(){t.data_.add(t.enhancer_(e,void 0)),t.atom_.reportChanged()});var i=pn(this),s=i?{observableKind:"set",debugObjectName:this.name_,type:Mn,object:this,newValue:e}:null;i&&bn(this,s)}return this},t.delete=function(e){var t=this;if(dn(this)&&!gn(this,{type:Cn,object:this,oldValue:e}))return!1;if(this.has(e)){var n=pn(this),i=n?{observableKind:"set",debugObjectName:this.name_,type:Cn,object:this,oldValue:e}:null;return ln(function(){t.atom_.reportChanged(),t.data_.delete(e)}),n&&bn(this,i),!0}return!1},t.has=function(e){return this.atom_.reportObserved(),this.data_.has(this.dehanceValue_(e))},t.entries=function(){var e=this.values();return $n({next:function(){var t=e.next(),n=t.value,i=t.done;return i?{value:void 0,done:i}:{value:[n,n],done:i}}})},t.keys=function(){return this.values()},t.values=function(){this.atom_.reportObserved();var e=this,t=this.data_.values();return $n({next:function(){var n=t.next(),i=n.value,s=n.done;return s?{value:void 0,done:s}:{value:e.dehanceValue_(i),done:s}}})},t.intersection=function(e){return I(e)&&!Gn(e)?e.intersection(this):new Set(this).intersection(e)},t.union=function(e){return I(e)&&!Gn(e)?e.union(this):new Set(this).union(e)},t.difference=function(e){return new Set(this).difference(e)},t.symmetricDifference=function(e){return I(e)&&!Gn(e)?e.symmetricDifference(this):new Set(this).symmetricDifference(e)},t.isSubsetOf=function(e){return new Set(this).isSubsetOf(e)},t.isSupersetOf=function(e){return new Set(this).isSupersetOf(e)},t.isDisjointFrom=function(e){return I(e)&&!Gn(e)?e.isDisjointFrom(this):new Set(this).isDisjointFrom(e)},t.replace=function(e){var t=this;return Gn(e)&&(e=new Set(e)),ln(function(){Array.isArray(e)||I(e)?(t.clear(),e.forEach(function(e){return t.add(e)})):null!=e&&l("Cannot initialize set from "+e)}),this},t.observe_=function(e,t){return vn(this,e)},t.intercept_=function(e){return fn(this,e)},t.toJSON=function(){return Array.from(this)},t.toString=function(){return"[object ObservableSet]"},t[Symbol.iterator]=function(){return this.values()},$(e,[{key:"size",get:function(){return this.atom_.reportObserved(),this.data_.size}},{key:Symbol.toStringTag,get:function(){return"Set"}}])}(),Gn=V("ObservableSet",Un);function $n(e){return e[Symbol.toStringTag]="SetIterator",vi(e)}var Kn=Object.create(null),zn="remove",Fn=function(){function e(e,t,n,i){void 0===t&&(t=new Map),void 0===i&&(i=Ae),this.target_=void 0,this.values_=void 0,this.name_=void 0,this.defaultAnnotation_=void 0,this.keysAtom_=void 0,this.changeListeners_=void 0,this.interceptors_=void 0,this.proxy_=void 0,this.isPlainObject_=void 0,this.appliedAnnotations_=void 0,this.pendingKeys_=void 0,this.target_=e,this.values_=t,this.name_=n,this.defaultAnnotation_=i,this.keysAtom_=new Q("ObservableObject.keys"),this.isPlainObject_=E(this.target_)}var t=e.prototype;return t.getObservablePropValue_=function(e){return this.values_.get(e).get()},t.setObservablePropValue_=function(e,t){var n=this.values_.get(e);if(n instanceof tt)return n.set(t),!0;if(dn(this)){var i=gn(this,{type:wn,object:this.proxy_||this.target_,name:e,newValue:t});if(!i)return null;t=i.newValue}if((t=n.prepareNewValue_(t))!==yt.UNCHANGED){var s=pn(this),r=s?{type:wn,observableKind:"object",debugObjectName:this.name_,object:this.proxy_||this.target_,oldValue:n.value_,name:e,newValue:t}:null;n.setNewValue_(t),s&&bn(this,r)}return!0},t.get_=function(e){return yt.trackingDerivation&&!L(this.target_,e)&&this.has_(e),this.target_[e]},t.set_=function(e,t,n){return void 0===n&&(n=!1),L(this.target_,e)?this.values_.has(e)?this.setObservablePropValue_(e,t):n?Reflect.set(this.target_,e,t):(this.target_[e]=t,!0):this.extend_(e,{value:t,enumerable:!0,writable:!0,configurable:!0},this.defaultAnnotation_,n)},t.has_=function(e){if(!yt.trackingDerivation)return e in this.target_;this.pendingKeys_||(this.pendingKeys_=new Map);var t=this.pendingKeys_.get(e);return t||(t=new et(e in this.target_,se,"ObservableObject.key?",!1),this.pendingKeys_.set(e,t)),t.get()},t.make_=function(e,t){if(!0===t&&(t=this.defaultAnnotation_),!1!==t){if(!(e in this.target_)){var n;if(null!=(n=this.target_[W])&&n[e])return;l(1,t.annotationType_,this.name_+"."+e.toString())}for(var i=this.target_;i&&i!==p;){var s=f(i,e);if(s){var r=t.make_(this,e,s,i);if(0===r)return;if(1===r)break}i=Object.getPrototypeOf(i)}Yn(this,t,e)}},t.extend_=function(e,t,n,i){if(void 0===i&&(i=!1),!0===n&&(n=this.defaultAnnotation_),!1===n)return this.defineProperty_(e,t,i);var s=n.extend_(this,e,t,i);return s&&Yn(this,n,e),s},t.defineProperty_=function(e,t,n){void 0===n&&(n=!1),this.keysAtom_;try{St();var i=this.delete_(e);if(!i)return i;if(dn(this)){var s=gn(this,{object:this.proxy_||this.target_,name:e,type:Mn,newValue:t.value});if(!s)return null;var r=s.newValue;t.value!==r&&(t=z({},t,{value:r}))}if(n){if(!Reflect.defineProperty(this.target_,e,t))return!1}else g(this.target_,e,t);this.notifyPropertyAddition_(e,t.value)}finally{At()}return!0},t.defineObservableProperty_=function(e,t,n,i){void 0===i&&(i=!1),this.keysAtom_;try{St();var s=this.delete_(e);if(!s)return s;if(dn(this)){var r=gn(this,{object:this.proxy_||this.target_,name:e,type:Mn,newValue:t});if(!r)return null;t=r.newValue}var a=Wn(e),o={configurable:!yt.safeDescriptors||this.isPlainObject_,enumerable:!0,get:a.get,set:a.set};if(i){if(!Reflect.defineProperty(this.target_,e,o))return!1}else g(this.target_,e,o);var u=new et(t,n,"ObservableObject.key",!1);this.values_.set(e,u),this.notifyPropertyAddition_(e,u.value_)}finally{At()}return!0},t.defineComputedProperty_=function(e,t,n){void 0===n&&(n=!1),this.keysAtom_;try{St();var i=this.delete_(e);if(!i)return i;if(dn(this))if(!gn(this,{object:this.proxy_||this.target_,name:e,type:Mn,newValue:void 0}))return null;t.name||(t.name="ObservableObject.key"),t.context=this.proxy_||this.target_;var s=Wn(e),r={configurable:!yt.safeDescriptors||this.isPlainObject_,enumerable:!1,get:s.get,set:s.set};if(n){if(!Reflect.defineProperty(this.target_,e,r))return!1}else g(this.target_,e,r);this.values_.set(e,new tt(t)),this.notifyPropertyAddition_(e,void 0)}finally{At()}return!0},t.delete_=function(e,t){if(void 0===t&&(t=!1),this.keysAtom_,!L(this.target_,e))return!0;if(dn(this)&&!gn(this,{object:this.proxy_||this.target_,name:e,type:zn}))return null;try{var n;St();var i,s=pn(this),r=this.values_.get(e),a=void 0;if(!r&&s)a=null==(i=f(this.target_,e))?void 0:i.value;if(t){if(!Reflect.deleteProperty(this.target_,e))return!1}else delete this.target_[e];if(r&&(this.values_.delete(e),r instanceof et&&(a=r.value_),Et(r)),this.keysAtom_.reportChanged(),null==(n=this.pendingKeys_)||null==(n=n.get(e))||n.set(e in this.target_),s){var o={type:zn,observableKind:"object",object:this.proxy_||this.target_,debugObjectName:this.name_,oldValue:a,name:e};0,s&&bn(this,o)}}finally{At()}return!0},t.observe_=function(e,t){return vn(this,e)},t.intercept_=function(e){return fn(this,e)},t.notifyPropertyAddition_=function(e,t){var n,i=pn(this);if(i){var s=i?{type:Mn,observableKind:"object",debugObjectName:this.name_,object:this.proxy_||this.target_,name:e,newValue:t}:null;i&&bn(this,s)}null==(n=this.pendingKeys_)||null==(n=n.get(e))||n.set(!0),this.keysAtom_.reportChanged()},t.ownKeys_=function(){return this.keysAtom_.reportObserved(),C(this.target_)},t.keys_=function(){return this.keysAtom_.reportObserved(),Object.keys(this.target_)},e}();function qn(e,t){var n;if(L(e,Z))return e;var i=null!=(n=null==t?void 0:t.name)?n:"ObservableObject",s=new Fn(e,new Map,String(i),function(e){var t;return e?null!=(t=e.defaultDecorator)?t:xe(e):void 0}(t));return P(e,Z,s),e}var Hn=V("ObservableObjectAdministration",Fn);function Wn(e){return Kn[e]||(Kn[e]={get:function(){return this[Z].getObservablePropValue_(e)},set:function(t){return this[Z].setObservablePropValue_(e,t)}})}function Xn(e){return!!x(e)&&Hn(e[Z])}function Yn(e,t,n){var i;null==(i=e.target_[W])||delete i[n]}var Jn,Zn,Qn=si(0),ei=function(){var e=!1,t={};return Object.defineProperty(t,"0",{set:function(){e=!0}}),Object.create(t)[0]=1,!1===e}(),ti=0,ni=function(){};Jn=ni,Zn=Array.prototype,Object.setPrototypeOf?Object.setPrototypeOf(Jn.prototype,Zn):void 0!==Jn.prototype.__proto__?Jn.prototype.__proto__=Zn:Jn.prototype=Zn;var ii=function(e){function t(t,n,i,s){var r;return void 0===i&&(i="ObservableArray"),void 0===s&&(s=!1),r=e.call(this)||this,li(function(){var e=new Sn(i,n,s,!0);e.proxy_=r,T(r,Z,e),t&&t.length&&r.spliceWithArray(0,0,t),ei&&Object.defineProperty(r,"0",Qn)}),r}F(t,e);var n=t.prototype;return n.concat=function(){this[Z].atom_.reportObserved();for(var e=arguments.length,t=new Array(e),n=0;nti){for(var t=ti;t=0&&n++}e=gi(e),t=gi(t);var o="[object Array]"===a;if(!o){if("object"!=typeof e||"object"!=typeof t)return!1;var u=e.constructor,l=t.constructor;if(u!==l&&!(S(u)&&u instanceof u&&S(l)&&l instanceof l)&&"constructor"in e&&"constructor"in t)return!1}if(0===n)return!1;n<0&&(n=-1),s=s||[];for(var c=(i=i||[]).length;c--;)if(i[c]===e)return s[c]===t;if(i.push(e),s.push(t),o){if((c=e.length)!==t.length)return!1;for(;c--;)if(!fi(e[c],t[c],n-1,i,s))return!1}else{var h=Object.keys(e),d=h.length;if(Object.keys(t).length!==d)return!1;for(var f=0;fString(e).padStart(2,"0"));return`${this._h}:${e}:${t}`}get_as_string_hhmm(){const[e,t]=[this._h,this._m].map(e=>String(e).padStart(2,"0"));return`${e}:${t}`}add_minutes(e){const t=new Date(0,0,1,this._h,this._m,this._s);return t.setMinutes(t.getMinutes()+e),mi.create_from_js_date(t)}get_seconds_until_next_target(e){const[t,n]=[e,this].map(e=>e._seconds_since_midnight);return ne._seconds_since_midnight);return ithis.detect_light_background(),e.on_button_detect_background_dark=()=>this.detect_dark_background(),e.on_button_apply_background_light=()=>this.apply_light_background(),e.on_button_apply_background_dark=()=>this.apply_dark_background()}detect_light_background(){const e=ji.is_slideshow;this._settings.light_background_is_slideshow=e,e?this._settings.light_background_slideshow_folder=ji.slideshow_folder.replace("directory://","file://"):this._settings.light_background_file=ji.picture_file}detect_dark_background(){const e=ji.is_slideshow;this._settings.dark_background_is_slideshow=e,e?this._settings.dark_background_slideshow_folder=ji.slideshow_folder.replace("directory://","file://"):this._settings.dark_background_file=ji.picture_file}apply_light_background(){const e=this._settings.light_background_is_slideshow;ji.is_slideshow=e,e?ji.slideshow_folder=decodeURIComponent(this._settings.light_background_slideshow_folder.replace("file://","directory://")):ji.picture_file=this._settings.light_background_file}apply_dark_background(){const e=this._settings.dark_background_is_slideshow;ji.is_slideshow=e,e?ji.slideshow_folder=decodeURIComponent(this._settings.dark_background_slideshow_folder.replace("file://","directory://")):ji.picture_file=this._settings.dark_background_file}}const{Gio:Ti,GLib:Vi}=imports.gi;async function Di(e,t,n){try{await async function(e,t=10){const n=`timeout --kill-after=${Ci} ${t}s sh -c ${Vi.shell_quote(e)}`,[i,s]=Vi.shell_parse_argv(n),r=new Ti.Subprocess({argv:s,flags:Ti.SubprocessFlags.STDERR_PIPE}),a=Date.now();r.init(null);const[o,u]=await new Promise((e,t)=>{r.communicate_utf8_async(null,null,(n,i)=>{try{const[t,s,r]=n.communicate_utf8_finish(i);e([s,r])}catch(s){t(s)}})}),l=(Date.now()-a)/1e3,c=r.get_exit_status();switch(c){case 0:break;case Ii:throw new Ti.IOErrorEnum({code:Ti.IOErrorEnum.TIMED_OUT,message:`may have been timed out by SIGTERM (GNU 'timeout' exit status ${Ii})`});case Mi:throw new Ti.IOErrorEnum({code:Ti.IOErrorEnum.TIMED_OUT,message:`probably killed by an external SIGKILL (GNU 'timeout' exit status ${Mi})`});case 1:if(t>0&&l>=t+Ci)throw new Ti.IOErrorEnum({code:Ti.IOErrorEnum.TIMED_OUT,message:"probably timed out by SIGKILL"});default:throw new Ti.IOErrorEnum({code:Ti.IOErrorEnum.FAILED,message:u?u.trim():"exit status: "+c})}}(n,t)}catch(i){const t=""!==e?e:n;let s=`${_("the command")} '${t}' ${_("has failed")}`;i instanceof Vi.ShellError?s+=` ${_("due to a wrong format")}.\n\n${_("Detail")}${_(":")}\n`+i.message:i instanceof Ti.IOErrorEnum?i.code===Ti.IOErrorEnum.TIMED_OUT?s+=` ${_("due to timeout")}.\n\n${_("Detail")}${_(":")}\n`+i.message:i.code===Ti.IOErrorEnum.FAILED&&(s+=` ${_("due to an error")}.\n\n${_("Detail")}${_(":")}\n`+i.message):s+=`${_(":")} ${i}`,u.warn(s)}}const Ii=124,Mi=137,Ci=10;class Ni{_settings;constructor(e,t){this._settings=t,e.on_button_launch_commands_light=()=>this.launch_light_commands(),e.on_button_launch_commands_dark=()=>this.launch_dark_commands()}launch_dark_commands(){this._launch_commands(this._settings.dark_commands_list)}launch_light_commands(){this._launch_commands(this._settings.light_commands_list)}_launch_commands(e){for(const t of e)t.active&&Di(t.name,t.expiry,t.command)}}class Li{_expiration_time=0;set expiration_time(e){const t=wi().get_seconds_until_next_target(e);this._expiration_time=ki()+t}get_if_has_expired(){return ki()>this._expiration_time}reset(){this._expiration_time=0}}const{GLib:Ri}=imports.gi;class Bi{_event_id=void 0;_timer_absolute=new Li;get_if_should_be_expired(){return this._timer_absolute.get_if_has_expired()}set_the_event(e,t){this.unset_the_event();const n=wi().get_seconds_until_next_target(e);this._event_id=Ri.timeout_add_seconds(Ri.PRIORITY_DEFAULT,n,()=>(t(),Ri.SOURCE_REMOVE)),this._timer_absolute.expiration_time=e}get is_set(){return void 0!==this._event_id}unset_the_event(){this._event_id&&(Ri.source_remove(this._event_id),this._event_id=void 0,this._timer_absolute.reset())}dispose(){this.unset_the_event()}}const Ui=imports.ui.main;let Gi=0;class $i{_name;_callback;constructor(e){this._name=s.uuid+Gi++,this._callback=e}set keybinding(e){Ui.keybindingManager.addHotKey(this._name,e,this._callback)}dispose(){Ui.keybindingManager.removeHotKey(this._name)}}const{Gio:Ki}=imports.gi;class zi{_callback_on_change;constructor(e){this._callback_on_change=e}enable(){this._subscribe_to_changes(this._callback_on_change.bind(this))}disable(){this._unsubscribe_to_changes()}dispose(){this.disable()}_signal_id=void 0;_subscribe_to_changes(e){this._signal_id&&this._unsubscribe_to_changes(),this._signal_id=Ki.DBus.system.signal_subscribe("org.freedesktop.timedate1","org.freedesktop.DBus.Properties","PropertiesChanged","/org/freedesktop/timedate1",null,Ki.DBusSignalFlags.NONE,(t,n,i,s,r,a)=>{const o=a.deep_unpack()[1];if(o.Timezone){const t=o.Timezone.deep_unpack();e(t)}})}_unsubscribe_to_changes(){this._signal_id&&(Ki.DBus.system.signal_unsubscribe(this._signal_id),this._signal_id=void 0)}}const{Gio:Fi}=imports.gi;class qi{_database;constructor(e){const t=`${e}/database.json`,n=Fi.File.new_for_path(t),[i,s]=n.load_contents(null);if(!i)throw new Error(`failed to load file/contents of '${t}'`);this._database=JSON.parse((new TextDecoder).decode(s))}find(e){if(!e)throw new Error("timezone is required");if(!(e in this._database))throw new Error(`unknown timezone: '${e}'`);return{latitude:this._database[e][0],longitude:this._database[e][1]}}}const{GLib:Hi}=imports.gi;class Wi{_timezone_change_listener=new zi(e=>this._timezone=e);_timezone=Hi.TimeZone.new_local().get_identifier();get timezone(){return this._timezone}_timezone_location_finder=new qi(`${s.path}/Timezone_location_finder`);get auto_location(){return this._timezone_location_finder.find(this.timezone)}manual_location;is_location_auto;get location(){return this.is_location_auto?this.auto_location:this.manual_location}constructor(e){Object.assign(this,e),yn(this,{_timezone_change_listener:!1,_timezone_location_finder:!1,manual_location:Ge.deep}),this._timezone_change_listener.enable()}dispose(){this._timezone_change_listener.dispose()}}async function Xi(e){return new Promise(t=>setTimeout(t,e))}const{Gio:Yi}=imports.gi;class Ji{try_now_or_postpone_until_unlocked(e){Ji._get_state_async(t=>{t?this._subscribe_to_changes(t=>{t||(this._unsubscribe_to_changes(),e())}):e()})}cancel(){this._unsubscribe_to_changes()}dispose(){this.cancel()}_signal_id=void 0;_subscribe_to_changes(e){this._signal_id&&this._unsubscribe_to_changes(),this._signal_id=Yi.DBus.session.signal_subscribe("org.cinnamon.ScreenSaver","org.cinnamon.ScreenSaver","ActiveChanged","/org/cinnamon/ScreenSaver",null,Yi.DBusSignalFlags.NONE,(t,n,i,s,r,a)=>{const o=a.deep_unpack()[0];e(o)})}_unsubscribe_to_changes(){this._signal_id&&(Yi.DBus.session.signal_unsubscribe(this._signal_id),this._signal_id=void 0)}static _get_state_async(e){Yi.DBus.session.call("org.cinnamon.ScreenSaver","/org/cinnamon/ScreenSaver","org.cinnamon.ScreenSaver","GetActive",null,null,Yi.DBusCallFlags.NONE,-1,null,(t,n)=>{const i=t.call_finish(n).deep_unpack()[0];e(i)})}}const{Gio:Zi}=imports.gi;class Qi{_callback_when_sleep_entries;_callback_when_wakeup_unlocked;constructor(e,t){this._callback_when_sleep_entries=e,this._callback_when_wakeup_unlocked=t}_screen_lock_checker=new Ji;enable(){this._subscribe_to_changes(e=>{e?this._callback_when_sleep_entries():this._screen_lock_checker.try_now_or_postpone_until_unlocked(()=>this._callback_when_wakeup_unlocked())})}disable(){this._unsubscribe_to_changes(),this._screen_lock_checker.cancel()}dispose(){this._unsubscribe_to_changes(),this._screen_lock_checker.dispose()}_signal_id=void 0;_subscribe_to_changes(e){this._signal_id&&this._unsubscribe_to_changes(),this._signal_id=Zi.DBus.system.signal_subscribe("org.freedesktop.login1","org.freedesktop.login1.Manager","PrepareForSleep","/org/freedesktop/login1",null,Zi.DBusSignalFlags.NONE,(t,n,i,s,r,a)=>{const o=a.deep_unpack()[0];e(o)})}_unsubscribe_to_changes(){this._signal_id&&(Zi.DBus.system.signal_unsubscribe(this._signal_id),this._signal_id=void 0)}}const{Gio:es}=imports.gi,ts=es.Settings.new("org.x.apps.portal");class ns{_callback_on_change;_signal_id=void 0;constructor(e){this._callback_on_change=e}enable(){this.disable(),this._signal_id=ts.connect("changed::color-scheme",()=>{this._callback_on_change(ns.value)})}disable(){void 0!==this._signal_id&&(ts.disconnect(this._signal_id),this._signal_id=void 0)}dispose(){this.disable()}static get value(){return ts.get_string("color-scheme")}static set value(e){ts.set_string("color-scheme",e)}}const{Gio:is}=imports.gi,ss={desktop:is.Settings.new("org.cinnamon.desktop.interface"),cinnamon:is.Settings.new("org.cinnamon.theme")};class rs{static get mouse(){return ss.desktop.get_string("cursor-theme")}static set mouse(e){ss.desktop.set_string("cursor-theme",e)}static get apps(){return ss.desktop.get_string("gtk-theme")}static set apps(e){ss.desktop.set_string("gtk-theme",e)}static get icons(){return ss.desktop.get_string("icon-theme")}static set icons(e){ss.desktop.set_string("icon-theme",e)}static get desktop(){return ss.cinnamon.get_string("name")}static set desktop(e){ss.cinnamon.set_string("name",e)}}class as{_settings;constructor(e,t){this._settings=t,e.on_button_detect_themes_light=()=>this.detect_light_themes(),e.on_button_detect_themes_dark=()=>this.detect_dark_themes(),e.on_button_apply_themes_light=()=>this.apply_light_themes(),e.on_button_apply_themes_dark=()=>this.apply_dark_themes()}detect_light_themes(){this._settings.setValue("light_themes_mouse",rs.mouse),this._settings.setValue("light_themes_apps",rs.apps),this._settings.setValue("light_themes_icons",rs.icons),this._settings.setValue("light_themes_desktop",rs.desktop),this._settings.light_themes_have_been_detected=!0}detect_dark_themes(){this._settings.setValue("dark_themes_mouse",rs.mouse),this._settings.setValue("dark_themes_apps",rs.apps),this._settings.setValue("dark_themes_icons",rs.icons),this._settings.setValue("dark_themes_desktop",rs.desktop),this._settings.dark_themes_have_been_detected=!0}apply_light_themes(){rs.mouse=this._settings.getValue("light_themes_mouse"),rs.apps=this._settings.getValue("light_themes_apps"),rs.icons=this._settings.getValue("light_themes_icons"),rs.desktop=this._settings.getValue("light_themes_desktop"),ns.value="prefer-light"}apply_dark_themes(){rs.mouse=this._settings.getValue("dark_themes_mouse"),rs.apps=this._settings.getValue("dark_themes_apps"),rs.icons=this._settings.getValue("dark_themes_icons"),rs.desktop=this._settings.getValue("dark_themes_desktop"),ns.value="prefer-dark"}}const{Gio:os,GLib:us}=imports.gi,_s="auto-dark-light-time-change-listener";class ls{_callback_when_changes;constructor(e){this._callback_when_changes=e;const t=`${s.path}/Time_change_listener`,n=`${t}/${_s}`;us.file_test(n,us.FileTest.EXISTS)||ls._compile(t),this._run(n)}static _compile(e){if(!us.find_program_in_path("make")||!us.find_program_in_path("g++"))throw new Error(_("Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-based system with 'sudo apt install make g++', then restart Cinnamon (Ctrl+Alt+Esc)."));const t=new os.Subprocess({argv:["make","-C",e],flags:os.SubprocessFlags.STDERR_PIPE});t.init(null);try{const[e,n,i]=t.communicate_utf8(null,null);if(!t.get_successful())throw new Error(i||_("Unknown compilation error"))}catch(n){throw new Error(`${_("Failed compilation of")} '${_s}'.\n\n`+n.message)}finally{us.spawn_command_line_async(`make -C ${e} clean`)}}_input;_input_error;_output;_subprocess;_should_run=!0;_run(e){this._subprocess=new os.Subprocess({argv:[e],flags:os.SubprocessFlags.STDOUT_PIPE|os.SubprocessFlags.STDIN_PIPE|os.SubprocessFlags.STDERR_PIPE}),this._subprocess.init(null),this._output=this._subprocess.get_stdin_pipe(),this._input=new os.DataInputStream({base_stream:this._subprocess.get_stdout_pipe()}),this._input_error=new os.DataInputStream({base_stream:this._subprocess.get_stderr_pipe()}),this._listen_input(),this._listen_error()}async _listen_input(){do{await new Promise(e=>this._input.read_line_async(us.PRIORITY_DEFAULT,null,e)),this._callback_when_changes()}while(this._should_run)}async _listen_error(){do{const[e,t]=await new Promise(e=>this._input_error.read_line_async(us.PRIORITY_DEFAULT,null,(t,n)=>{try{e(t.read_line_finish(n))}catch(i){u.warn(i),e([null,0])}}));null!==e&&t>0&&u.warn(`${_("the subprocess")} \`${_s}\` ${_("has written on its error output")}${_(":")} ${e}`)}while(this._should_run)}enable(){this._output.write("enable\n",null)}disable(){this._output.write("disable\n",null)}dispose(){this._callback_when_changes=()=>{},this._should_run=!1,this._output.write("exit\n",null),this._subprocess.wait(null)}}const{PI:cs,sin:hs,cos:ds,asin:fs,acos:gs,round:ps}=Math,vs=2*cs,bs=cs/180,ms=9e-4,ys=2440587.5,ks=2451545;function ws(e){return 86400*(e-ys)}function Os(e,t,n){return ms+(e+t)/vs+n}function Ss(e,t,n){return ks+e+.0053*hs(t)-.0069*hs(2*n)}const As=hs(23.4397*bs),xs=102.9372*bs+cs;function Es(e,t){const[n,i]=function(e,t,n){const i=bs*-n,s=bs*t,r=ps(e/86400-10957.5-ms-i/vs),a=Os(0,i,r),o=bs*(.98560028*a+357.5291),u=o+bs*(1.9148*hs(o)+.02*hs(2*o)+3e-4*hs(3*o))+xs,l=fs(As*hs(u)),c=Ss(a,o,u),h=Ss(Os(gs((hs(-.833*bs)-hs(s)*hs(l))/(ds(s)*ds(l))),i,r),o,u);return[ws(2*c-h),ws(h)]}(e.to_unix(),t.latitude,t.longitude);return{sunrise:Oi(n),sunset:Oi(i)}}const{DateTime:js}=imports.gi.GLib;class Ps{_date=js.new_now_local();update(){this._date=js.new_now_local()}location;get _location_twilights(){return Es(this._date,this.location)}auto_sunrise_offset;auto_sunset_offset;get auto_sunrise(){return this._location_twilights.sunrise.add_minutes(this.auto_sunrise_offset)}get auto_sunset(){return this._location_twilights.sunset.add_minutes(this.auto_sunset_offset)}manual_sunrise;manual_sunset;is_sunrise_auto;is_sunset_auto;get _sunrise(){return this.is_sunrise_auto?this.auto_sunrise:this.manual_sunrise}get _sunset(){return this.is_sunset_auto?this.auto_sunset:this.manual_sunset}get twilights(){return{sunrise:this._sunrise,sunset:this._sunset}}constructor(e){Object.assign(this,e),yn(this)}}const{GLib:Ts}=imports.gi,Vs=2e3;const{AppletSettings:Ds}=imports.ui.settings;const{IconApplet:Is}=imports.ui.applet; +//! @preserve +function main(n,i,a,o){!function(n){Object.assign(s,n);const i=t.get_home_dir()+"/.local/share/locale";e.bindtextdomain(s.uuid,i),r=_(s.name)}(n);const l=new Is(i,a,o),c=function(e,t){const n=new Ds({},e,t);return["is_appearance_dark","appearance_keybinding","is_appearance_auto","auto_sunrise_offset","auto_sunset_offset","manual_sunrise","manual_sunset","is_sunrise_auto","is_sunset_auto","manual_latitude","manual_longitude","is_location_auto","enable_background","light_background_is_slideshow","light_background_file","light_background_slideshow_folder","dark_background_is_slideshow","dark_background_file","dark_background_slideshow_folder","light_commands_is_enabled","light_commands_list","dark_commands_is_enabled","dark_commands_list","scheduler_timer_absolute_time","light_themes_have_been_detected","dark_themes_have_been_detected"].forEach(e=>n.bindWithObject(n,e,e)),n}(n.uuid,o);try{!function(e,t){const n=new Wi({manual_location:{latitude:t.manual_latitude,longitude:t.manual_longitude},is_location_auto:t.is_location_auto});t.bind("manual_latitude",null,e=>{n.manual_location.latitude=e}),t.bind("manual_longitude",null,e=>{n.manual_location.longitude=e}),t.bind("is_location_auto",null,e=>{n.is_location_auto=e}),qt(()=>{t.setValue("system_timezone",n.timezone)}),qt(()=>{t.setValue("auto_latitude",n.auto_location.latitude),t.setValue("auto_longitude",n.auto_location.longitude)});const i=new Ps({location:n.location,auto_sunrise_offset:t.auto_sunrise_offset,auto_sunset_offset:t.auto_sunset_offset,manual_sunrise:new mi(t.manual_sunrise),manual_sunset:new mi(t.manual_sunset),is_sunrise_auto:t.is_sunrise_auto,is_sunset_auto:t.is_sunset_auto});qt(()=>{i.location=n.location}),t.bind("auto_sunrise_offset",null,e=>{i.auto_sunrise_offset=e}),t.bind("auto_sunset_offset",null,e=>{i.auto_sunset_offset=e}),t.bind("manual_sunrise",null,e=>{i.manual_sunrise=new mi(e)}),t.bind("manual_sunset",null,e=>{i.manual_sunset=new mi(e)}),t.bind("is_sunrise_auto",null,e=>{i.is_sunrise_auto=e}),t.bind("is_sunset_auto",null,e=>{i.is_sunset_auto=e}),Xt(()=>i.auto_sunrise,async()=>{await Xi(Vs),t.setValue("auto_sunrise",i.auto_sunrise.get_as_string_hhmm())},{fireImmediately:!0}),Xt(()=>i.auto_sunset,async()=>{await Xi(Vs),t.setValue("auto_sunset",i.auto_sunset.get_as_string_hhmm())},{fireImmediately:!0});const s=new Ai({twilights:i.twilights,manual_is_dark:"prefer-dark"===ns.value,is_auto:t.is_appearance_auto});qt(()=>{s.twilights=i.twilights}),e.on_applet_clicked=()=>{s.toggle_is_dark()},e.on_applet_middle_clicked=()=>{s.toggle_is_auto()},t.bind("is_appearance_dark",null,e=>{s.manual_is_dark=e}),t.bind("is_appearance_auto",null,e=>{s.is_auto=e}),Xt(()=>s.manual_is_dark,async()=>{await Xi(Vs),t.is_appearance_dark=s.manual_is_dark},{fireImmediately:!0}),Xt(()=>s.is_auto,()=>{t.is_appearance_auto=s.is_auto}),Xt(()=>s.is_unsynced,async()=>{await Xi(Vs),t.setValue("is_appearance_unsynced",s.is_unsynced)},{fireImmediately:!0}),Xt(()=>s.next_twilight,async()=>{await Xi(Vs),t.setValue("next_update",s.next_twilight.get_as_string_hhmm())},{fireImmediately:!0}),qt(()=>{e.set_applet_icon_symbolic_name(s.is_auto?s.is_unsynced?"auto-inverted-symbolic":"auto-symbolic":s.manual_is_dark?"dark-symbolic":"light-symbolic")});const r=new $i(()=>{s.toggle_is_dark()});r.keybinding=t.appearance_keybinding,t.bind("appearance_keybinding",null,e=>{r.keybinding=e});const a=new as(e,t);"prefer-dark"===ns.value?t.dark_themes_have_been_detected&&a.detect_dark_themes():t.light_themes_have_been_detected&&a.detect_light_themes();const o=yn({value:ns.value}),u=new ns(e=>{o.value=e});let l=!1;qt(()=>{s.manual_is_dark="prefer-dark"===o.value,l=!0});const c=new Pi(e,t),h=new Ni(e,t);Xt(()=>s.manual_is_dark,()=>{!0!==l?s.manual_is_dark?(u.disable(),a.apply_dark_themes(),u.enable(),t.enable_background&&c.apply_dark_background(),t.dark_commands_is_enabled&&h.launch_dark_commands()):(u.disable(),a.apply_light_themes(),u.enable(),t.enable_background&&c.apply_light_background(),t.light_commands_is_enabled&&h.launch_light_commands()):l=!1},{fireImmediately:!0}),qt(()=>{s.is_auto&&(s.manual_is_dark=s.is_dark)});const d=new ls(()=>zt(()=>{i.update(),s.update_time(),g.is_set&&g.get_if_should_be_expired()&&s.sync_is_dark()})),f=new Qi(()=>{d.disable()},()=>zt(()=>{i.update(),s.update_time(),g.is_set&&g.get_if_should_be_expired()&&s.sync_is_dark(),d.enable()})),g=new Bi,p=()=>{g.set_the_event(s.next_twilight,()=>{i.update(),s.update_time(),s.sync_is_dark()})};Xt(()=>s.is_auto,()=>{s.is_auto?(s.update_time(),s.sync_is_dark(),p(),d.enable(),f.enable()):(g.unset_the_event(),d.disable(),f.disable())}),Xt(()=>s.next_twilight,()=>{s.is_auto&&p()},{fireImmediately:!0}),e.set_applet_tooltip(`${_("Click")}${_(":")} ${_("toggle dark/light appearance")}\n${_("Middle-click")}${_(":")} ${_("toggle automatic switch")}`,!0),e.on_button_open_os_timezone_settings=()=>Ts.spawn_command_line_async("cinnamon-settings calendar"),e.on_button_open_os_themes_settings=()=>Ts.spawn_command_line_async("cinnamon-settings themes"),e.on_button_open_os_background_settings=()=>Ts.spawn_command_line_async("cinnamon-settings background"),e.on_applet_removed_from_panel=()=>{r.dispose(),n.dispose(),g.dispose(),f.dispose(),u.dispose(),d.dispose(),t.finalize()},u.enable(),d.enable(),f.enable()}(l,c)}catch(h){l.set_applet_icon_symbolic_name("on-error-symbolic"),h instanceof Error?u.error(h.message):u.error(String(h)),c.finalize()}return l} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js.sha256sum b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js.sha256sum new file mode 100644 index 00000000000..58f0429636c --- /dev/null +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js.sha256sum @@ -0,0 +1 @@ +122d3313587ab5ab3543c309c5eca6a3dace69cb27e3d6dd96e031982978d4b7 applet.js diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/globals.d.ts b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/globals.d.ts deleted file mode 100644 index fb2e87fcb86..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/globals.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare var imports: any; diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/jsconfig.json b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/jsconfig.json deleted file mode 100644 index f40b843bfd3..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/jsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "checkJs": true, - "target": "ES2024", - }, - "include": [ - "**/*.js", - "**/*.d.ts" - ] -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/CLASSES HIERARCHY.drawio.svg b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/CLASSES HIERARCHY.drawio.svg deleted file mode 100644 index 1ae325dba3c..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/CLASSES HIERARCHY.drawio.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
Dbus
light, dark
Background_handler
Color_scheme_change_listener
Event_scheduler
Screen_lock_checker
Sleep_wakeup_listener
SunCalc
light, dark
Themes_handler
Time_of_day
Timer_absolute
Timezone_change_listener
Twilights_calculator
ThisApplet
IconApplet
Time_change_listener
Timezone_coordinates_finder
Commands_launcher
light, dark
Timezone
Screen_lock
Sleep
<Class_name>
class:
<Namespace_name>
<Class_name>
namespace:
<Class_name>
static class:
Legends
inheritance:
<members>
composition:
("uses")
association:
\ No newline at end of file diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/background_handler.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/background_handler.js deleted file mode 100644 index e5d37559c9e..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/background_handler.js +++ /dev/null @@ -1,56 +0,0 @@ -const {XletSettingsBase} = imports.ui.settings; // Only for JSDoc -const Gio = imports.gi.Gio; - -const IO = { - BACKGROUND : new Gio.Settings({schema: "org.cinnamon.desktop.background"}), - SLIDESHOW : new Gio.Settings({schema: "org.cinnamon.desktop.background.slideshow"}), - KEYS: { - IS_SLIDESHOW: 'slideshow-enabled', - BACKGROUND_FILE: 'picture-uri', - SLIDESHOW_FOLDER: 'image-source' - } -}; - -/** A `Cinnamon desktop` background handler that detects and applies the background settings. */ -module.exports = class Background_handler { - /** - * @param {XletSettingsBase} settings - The settings of the desk/applet. - * @param {object} keys - The keys of the settings' memorized variables. - * @param {string} keys.is_slideshow - The key for the slideshow state. - * @param {string} keys.background_file - The key for the background file. - * @param {string} keys.slideshow_folder - The key for the slideshow folder. - */ - constructor(settings, keys) { - settings.bindWithObject(this, keys.is_slideshow, "is_slideshow"); - settings.bindWithObject(this, keys.background_file, "background_file"); - settings.bindWithObject(this, keys.slideshow_folder, "slideshow_folder"); - } - - /** Detects and saves the current background settings applied to Cinnamon desktop. */ - detect() { - this.is_slideshow = IO.SLIDESHOW.get_boolean(IO.KEYS.IS_SLIDESHOW); - if (!this.is_slideshow) // Irrelevant to get both - this.background_file = IO.BACKGROUND.get_string(IO.KEYS.BACKGROUND_FILE); - else - // The widget filechooser set as 'folderchooser' gives the URI prefixed with `file://` instead of `directory://`. - // https://github.com/linuxmint/cinnamon/issues/12374 - // This "replace" is done so the widget display the folder correctly (it wants 'file://'): - this.slideshow_folder = IO.SLIDESHOW.get_string(IO.KEYS.SLIDESHOW_FOLDER).replace('directory://', "file://"); - // Replace the above line by the below one once solved. - // this.slideshow_folder = IO.SLIDESHOW.get_string( IO.KEYS.SLIDESHOW_FOLDER); - } - - /** Applies the saved background settings to Cinnamon desktop. */ - apply() { - IO.SLIDESHOW.set_boolean(IO.KEYS.IS_SLIDESHOW, this.is_slideshow); - if (!this.is_slideshow) // Important to not set both - IO.BACKGROUND.set_string(IO.KEYS.BACKGROUND_FILE, this.background_file); - else - // The widget filechooser set as 'folderchooser' gives the URI prefixed with `file://` instead of `directory://`. - // https://github.com/linuxmint/cinnamon/issues/12374 - // This "replace" is done so the saved value from the widget is applied correctly to Cinnamon settings: - IO.SLIDESHOW. set_string(IO.KEYS.SLIDESHOW_FOLDER, decodeURIComponent(this.slideshow_folder.replace('file://', "directory://"))); - // Replace the above line by the below one once solved. - // IO.SLIDESHOW. set_string(IO.KEYS.SLIDESHOW_FOLDER, decodeURIComponent(this.slideshow_folder)); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/color_scheme_change_listener.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/color_scheme_change_listener.js deleted file mode 100644 index 2a2e661af31..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/color_scheme_change_listener.js +++ /dev/null @@ -1,31 +0,0 @@ -const Gio = imports.gi.Gio; - -/** A listenener for changes in the color scheme which calls a provided callback */ -module.exports = class Color_scheme_change_listener { - #interface = Gio.Settings.new('org.x.apps.portal'); - #callback; - #signal_id; - - /** @param {() => void} callback_when_color_scheme_changes - The function to be executed when the color scheme changes. */ - constructor(callback_when_color_scheme_changes) { - this.#callback = callback_when_color_scheme_changes; - } - - enable() { - this.disable(); // Ensures only one signal is connected - this.#signal_id = - this.#interface.connect('changed::color-scheme', this.#callback); - } - - disable() { - if (this.#signal_id !== undefined) { - this.#interface.disconnect(this.#signal_id); - this.#signal_id = undefined; - } - } - - /** Declares the object as finished to release any ressource acquired. */ - finalize() { - this.disable(); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/README.md b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/README.md deleted file mode 100644 index 13dd7a9fb78..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Example usage of `launch_command.js` - -```js -const launch_command = require('lib/commands_launcher/launch_command.js'); - -async function main() { - console.error("start"); - try { - await launch_command('./test'); - } catch (error) { - if (error instanceof GLib.ShellError) - console.error("command format: " + error.message); - else - if (error instanceof Gio.IOErrorEnum) { - if (error.code === Gio.IOErrorEnum.TIMED_OUT) - console.error("command aborted due to time out"); - else - if (error.code === Gio.IOErrorEnum.FAILED) - console.error("command failed: " + error.message); - } else - console.error(error); // full object so we can see the stack trace - } -} - -main(); - -new GLib.MainLoop(null, false).run(); -``` diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/commands_launcher.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/commands_launcher.js deleted file mode 100644 index 4287fb626f1..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/commands_launcher.js +++ /dev/null @@ -1,59 +0,0 @@ -const launch_command = require('lib/commands_launcher/launch_command.js'); -const _ = require('lib/translator.js'); - -const {XletSettingsBase} = imports.ui.settings; -const {Gio, GLib} = imports.gi; - -/** A launcher for the commands of the settings list. */ -module.exports = class Commands_launcher { - #callback_for_errors; - - /** - * @param {XletSettingsBase} settings - The settings of the desk/applet. - * @param {object} key_of_list - The keys of the settings' commands list. - * @param {(message: string) => void} callback_for_errors - The function to call with a message for when an error occurs. - */ - constructor(settings, key_of_list, callback_for_errors) { - settings.bindWithObject(this, key_of_list, "list"); - this.#callback_for_errors = callback_for_errors; - } - - /** @type {Array<{name: string, active: boolean, expiry: number, command: string}>} */ - list; - - async launch_commands() { - for (const item of this.list) { - const { name, active, expiry, command } = item; - if (!active) - continue; - - try { await launch_command(command, expiry); } - catch (error) { - const name_for_error = name !== '' ? name : command; - let msg = `${_("the command")} '${name_for_error}' ${_("failed")}`; - if (error instanceof GLib.ShellError) - msg += ` ${_("due to a wrong format")}.\n` - + "\n" - + `${_("Detail")}${_(":")}\n` - + error.message; - else - if (error instanceof Gio.IOErrorEnum) { - if (error.code === Gio.IOErrorEnum.TIMED_OUT) - msg += ` ${_("due to time expiration")}.\n` - + "\n" - + `${_("Detail")}${_(":")}\n` - + error.message; - else - if (error.code === Gio.IOErrorEnum.FAILED) - msg += ` ${_("due to an error")}.\n` - + "\n" - + `${_("Detail")}${_(":")}\n` - + error.message; - } else - msg += `${_(":")} ${error}` // last resort: full `error` object so we may see the stack trace - - this.#callback_for_errors(msg); - } - } - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/launch_command.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/launch_command.js deleted file mode 100644 index aecc6a4d6e7..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/commands_launcher/launch_command.js +++ /dev/null @@ -1,61 +0,0 @@ -const {Gio, GLib} = imports.gi; - -const TIMEOUT_EXIT_STATUS_SIGTERM = 124; -const TIMEOUT_EXIT_STATUS_SIGKILL = 137; -const SIGKILL_TIMEOUT = 10; // [s] the time to wait after 'timeout' sends SIGTERM so it sends SIGKILL - -Gio._promisify(Gio.Subprocess.prototype, 'communicate_utf8_async'); - -/** - * Executes a command with a timeout and transmits any error on failure. - * @async - * @param {string} command - The shell command to execute. - * @param {number} [timeout=10] - The delay in seconds before cancelling the command with a SIGTERM, then a few seconds later with a SIGKILL. `0` means infinity/never. - * @returns {Promise} - * @throws {GLib.ShellError} - If the command format is invalid. - * @throws {Gio.IOErrorEnum.TIMED_OUT} - If the command is cancelled due to a timeout. - * @throws {Gio.IOErrorEnum.FAILED} - If the command fails with a non-zero exit code. The error message is the `stderr` output if any, otherwise the exit status. - */ -module.exports = async function launch_command(command, timeout = 10) { - const wrapped_command = - `timeout --kill-after=${SIGKILL_TIMEOUT} ${timeout}s sh -c ${GLib.shell_quote(command)}`; - const [_ok, argvp] = GLib.shell_parse_argv(wrapped_command); // can throw GLib.ShellError - - const process = new Gio.Subprocess({ - argv: argvp, - flags: Gio.SubprocessFlags.STDERR_PIPE - }); - - const start_time = Date.now(); // [ms] - process.init(null); - const [_stdout, stderr] = await process.communicate_utf8_async(null, null); - const elapsed_time = (Date.now() - start_time) / 1000; // [s] - - const exit_status = process.get_exit_status(); - switch (exit_status) { - case 0: - break; - case TIMEOUT_EXIT_STATUS_SIGTERM: - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.TIMED_OUT, - message: `may have been timed out by SIGTERM (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGTERM})` - }); - case TIMEOUT_EXIT_STATUS_SIGKILL: - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.TIMED_OUT, - message: `probably killed by an external SIGKILL (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGKILL})` - }); - case 1: // workaround for 'timeout' sending SIGKILL not reported with the intended 137 exit status - if (timeout > 0 && elapsed_time >= timeout + SIGKILL_TIMEOUT) - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.TIMED_OUT, - message: `probably timed out by SIGKILL` - }); - // no break, needs to stay directly above the default case - default: - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.FAILED, - message: stderr ? stderr.trim() : "exit status: " + exit_status - }); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/dbus.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/dbus.js deleted file mode 100644 index 20ce821e34d..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/dbus.js +++ /dev/null @@ -1,150 +0,0 @@ -const {Gio, GLib} = imports.gi; - -module.exports = class Dbus { // namespace-like - /** An interface to read and subscribe to changes in the system screensaver lock state. */ - static Screen_lock = class { - #signal_id; - - /** - * Listens to the screensaver lock state changes. - * @param {(is_locked: boolean) => void} callback - The callback function to be executed when the screen saver lock state changes. - */ - subscribe_to_changes(callback) { - if (this.#signal_id) - return; - this.#signal_id = Gio.DBus.session.signal_subscribe( - 'org.cinnamon.ScreenSaver', // sender - 'org.cinnamon.ScreenSaver', // interface_name - 'ActiveChanged', // member - '/org/cinnamon/ScreenSaver', // object_path - null, // arg0 - Gio.DBusSignalFlags.NONE, // flags - (_1, _2, _3, _4, _5, parameters) => { // callback - const is_locked = parameters.deep_unpack()[0]; - callback(is_locked); - } - ); - } - - unsubscribe_to_changes() { - if (!this.#signal_id) - return; - Gio.DBus.session.signal_unsubscribe(this.#signal_id); - this.#signal_id = undefined; - } - - /** - * Gets the current screensaver lock state asynchronously. - * @param {object} callback - The callback object to handle the result. - * @property {boolean} callback.is_locked - The lock state. - */ - static get_state_async(callback) { - Gio.DBus.session.call( - 'org.cinnamon.ScreenSaver', // bus_name - '/org/cinnamon/ScreenSaver', // object_path - 'org.cinnamon.ScreenSaver', // interface_name - 'GetActive', // method_name - null, // parameters - null, // reply_type - Gio.DBusCallFlags.NONE, // flags - -1, // timeout_msec - null, // cancellable - (connection, result) => { // callback - const reply = connection.call_finish(result); - const is_locked = reply.deep_unpack()[0]; - callback(is_locked); - } - ); - } - } - - /** An interface subscribe to changes in the system sleep/wakeup state. */ - static Sleep = class { - #signal_id; - - /** - * Listens to the system sleep/wakeup state changes. - * @param {(is_sleeping: boolean) => void} callback - The callback function to be executed when the system sleep state changes. - */ - subscribe_to_changes(callback) { - if (this.#signal_id) - return; - this.#signal_id = Gio.DBus.system.signal_subscribe( - 'org.freedesktop.login1', // sender - 'org.freedesktop.login1.Manager', // interface_name - 'PrepareForSleep', // member - '/org/freedesktop/login1', // object_path - null, // arg0 - Gio.DBusSignalFlags.NONE, // flags - (_1, _2, _3, _4, _5, parameters) => { // callback - const is_sleeping = parameters.deep_unpack()[0]; - callback(is_sleeping); - } - ); - } - - unsubscribe_to_changes() { - if (!this.#signal_id) - return; - Gio.DBus.system.signal_unsubscribe(this.#signal_id); - this.#signal_id = undefined; - } - } - - /** An interface to read and subscribe to changes in the system timezone. */ - static Timezone = class { - #signal_id; - - /** - * Listens to the system timezone changes. - * @param {(new_timezone: string) => void} callback - The callback function to be executed when the timezone changes. - */ - subscribe_to_changes(callback) { - if (this.#signal_id) - return; - this.#signal_id = Gio.DBus.system.signal_subscribe( - 'org.freedesktop.timedate1', // sender - 'org.freedesktop.DBus.Properties', // interface_name - 'PropertiesChanged', // member - '/org/freedesktop/timedate1', // object_path - null, // arg0 - Gio.DBusSignalFlags.NONE, // flags - (_1, _2, _3, _4, _5, parameters) => { // callback - const changed_properties = parameters.deep_unpack()[1]; - if (changed_properties['Timezone']) { - const new_timezone = changed_properties['Timezone'].deep_unpack(); - callback(new_timezone); - } - } - ); - } - - unsubscribe_to_changes() { - if (!this.#signal_id) - return; - Gio.DBus.system.signal_unsubscribe(this.#signal_id); - this.#signal_id = undefined; - } - - /** @returns {string} The current system timezone. */ - static get_current() { - const reply = Gio.DBus.system.call_sync( - 'org.freedesktop.timedate1', // bus_name - '/org/freedesktop/timedate1', // object_path - 'org.freedesktop.DBus.Properties', // interface_name - 'Get', // method_name - new GLib.Variant( // parameters - '(ss)', - ['org.freedesktop.timedate1', 'Timezone'] - ), - GLib.VariantType.new('(v)'), // reply_type - Gio.DBusCallFlags.NONE, // flags - -1, // timeout_msec - null // cancellable - ); - const variant = reply.deep_unpack()[0]; - const timezone = variant.deep_unpack(); - return timezone; - } - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/event_scheduler.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/event_scheduler.js deleted file mode 100644 index 1616a604ddb..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/event_scheduler.js +++ /dev/null @@ -1,42 +0,0 @@ -const Mainloop = imports.mainloop; - -const Time_of_day = require('lib/time_of_day.js'); - -/** A single-event scheduler which call a function at a specified due time of day. */ -module.exports = class Event_scheduler { - #event_id; - - /** - * Schedules the event to execute a callback function at the specified due time of day. - * If the event is already scheduled, it will be replaced. - * @param {Time_of_day} due_time - The time at which the callback function should be executed. - * @param {() => void} on_event_callback - The callback function to be executed when the event occurs. - */ - set_the_event(due_time, on_event_callback) { - this.unset_the_event(); - const due_delay = due_time.get_seconds_from_now(); // [s] - this.#event_id = Mainloop.timeout_add_seconds(due_delay, () => { - on_event_callback(); - return false; // to not repeat - }); - - // // Debug - // imports.ui.main.notify( - // 'Scheduler', - // `Event scheduled at ${due_time.as_string()}, in ${due_delay} seconds.` - // ); - } - - /** Unsets the scheduled event if it exists. */ - unset_the_event() { - if (this.#event_id !== undefined) { - Mainloop.source_remove(this.#event_id); - this.#event_id = undefined; - } - } - - /** Declares the object as finished to release any ressource acquired. */ - finalize() { - this.unset_the_event(); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/sleep_wakeup_listener/screen_lock_checker.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/sleep_wakeup_listener/screen_lock_checker.js deleted file mode 100644 index 2ac1486cb26..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/sleep_wakeup_listener/screen_lock_checker.js +++ /dev/null @@ -1,34 +0,0 @@ -const Dbus = require('lib/dbus.js'); - -/** A gatekeeper for the screen locked state. */ -module.exports = class Screen_lock_checker { - #dbus_screen_lock = new Dbus.Screen_lock(); - - /** - * Tries now or postpones until the screen is unlocked to execute a procedure. - * @param {() => void} callback_when_unlocked - The function to be executed when the screen is unlocked. - */ - try_now_or_postpone_until_unlocked(callback_when_unlocked) { - Dbus.Screen_lock.get_state_async((is_locked) => { - if (!is_locked) - callback_when_unlocked(); - else - this.#dbus_screen_lock.subscribe_to_changes((is_locked) => { - if (!is_locked) { - this.#dbus_screen_lock.unsubscribe_to_changes(); - callback_when_unlocked(); - } - }); - }); - } - - /** Cancels the `try_now_or_postpone_until_unlocked` procedure. */ - cancel() { - this.#dbus_screen_lock.unsubscribe_to_changes(); - } - - /** Declares the object as finished to release any ressource acquired. */ - finalize() { - this.cancel(); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/sleep_wakeup_listener/sleep_wakeup_listener.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/sleep_wakeup_listener/sleep_wakeup_listener.js deleted file mode 100644 index 5e17eb8ef2b..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/sleep_wakeup_listener/sleep_wakeup_listener.js +++ /dev/null @@ -1,41 +0,0 @@ -const Dbus = require('lib/dbus.js'); -const Screen_lock_checker = require('lib/sleep_wakeup_listener/screen_lock_checker.js'); - -/** A gatekeeper for the sleep combined with the screen locked on wakeup. */ -module.exports = class Sleep_wakeup_listener { - #dbus_sleep = new Dbus.Sleep(); - #screen_lock_checker = new Screen_lock_checker(); - #callback_when_sleep_entries; - #callback_when_wakeup_unlocked; - - /** - * @param {() => void} callback_when_sleep_entries - The function to be executed when the system goes to sleep. Will be called again even without unlock. - * @param {() => void} callback_when_wakeup_unlocked - The function to be executed when the system wakes up and the screen is unlocked. - */ - constructor(callback_when_sleep_entries, callback_when_wakeup_unlocked) { - this.#callback_when_sleep_entries = callback_when_sleep_entries; - this.#callback_when_wakeup_unlocked = callback_when_wakeup_unlocked; - } - - enable() { - this.#dbus_sleep.subscribe_to_changes((is_sleeping) => { - if (is_sleeping) - this.#callback_when_sleep_entries(); - else - this.#screen_lock_checker.try_now_or_postpone_until_unlocked( - this.#callback_when_wakeup_unlocked.bind(this) - ); - }); - } - - disable() { - this.#dbus_sleep.unsubscribe_to_changes(); - this.#screen_lock_checker.cancel(); - } - - /** Declares the object as finished to release any ressource acquired. */ - finalize() { - this.#dbus_sleep.unsubscribe_to_changes(); - this.#screen_lock_checker.finalize(); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/themes_handler.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/themes_handler.js deleted file mode 100644 index 9b2f9993a2f..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/themes_handler.js +++ /dev/null @@ -1,67 +0,0 @@ -const {XletSettingsBase} = imports.ui.settings; -const Gio = imports.gi.Gio; - -const IO = { - DESKTOP: Gio.Settings.new('org.cinnamon.desktop.interface'), - CINNAMON: Gio.Settings.new('org.cinnamon.theme'), - X_APPS: Gio.Settings.new('org.x.apps.portal'), - KEYS: { - MOUSE_POINTER: 'cursor-theme', - APPLICATIONS: 'gtk-theme', - ICONS: 'icon-theme', - DESKTOP: 'name', - COLOR_SCHEME: 'color-scheme' - } -}; - -/** A `Cinnamon desktop` themes handler that detects and applies the themes. */ -module.exports = class Themes_handler { - #color_scheme; - - /** - * @param {XletSettingsBase} settings - The settings of the desk/applet. - * @param {boolean} is_dark - Wether the color scheme is light (false) or dark (true). - * @param {object} keys - The keys of the settings' memorized variables. - * @param {string} keys.mouse_pointer - The key for the mouse pointer theme. - * @param {string} keys.applications - The key for the applications theme. - * @param {string} keys.icons - The key for the icons theme. - * @param {string} keys.desktop - The key for the desktop theme. - * @param {string} keys.has_detected - The key for the "has detected" indicator. - */ - constructor(settings, is_dark, keys) { - settings.bindWithObject(this, keys.mouse_pointer, "mouse_pointer"); - settings.bindWithObject(this, keys.applications, "applications"); - settings.bindWithObject(this, keys.icons, "icons"); - settings.bindWithObject(this, keys.desktop, "desktop"); - settings.bindWithObject(this, keys.has_detected, "_has_detected"); - this.#color_scheme = is_dark ? 'prefer-dark' : 'prefer-light'; - } - - /** Detects and save the current themes applied to Cinnamon desktop. */ - detect() { - this.mouse_pointer = IO.DESKTOP .get_string(IO.KEYS.MOUSE_POINTER); - this.applications = IO.DESKTOP .get_string(IO.KEYS.APPLICATIONS); - this.icons = IO.DESKTOP .get_string(IO.KEYS.ICONS); - this.desktop = IO.CINNAMON.get_string(IO.KEYS.DESKTOP); - this._has_detected = true; - } - - /** Applies the saved themes to Cinnamon desktop. */ - apply() { - if (!this.has_detected) - return; - IO.DESKTOP .set_string(IO.KEYS.MOUSE_POINTER, this.mouse_pointer); - IO.DESKTOP .set_string(IO.KEYS.APPLICATIONS, this.applications); - IO.DESKTOP .set_string(IO.KEYS.ICONS, this.icons); - IO.CINNAMON.set_string(IO.KEYS.DESKTOP, this.desktop); - IO.X_APPS .set_string(IO.KEYS.COLOR_SCHEME, this.#color_scheme); - } - - get has_detected() { - return this._has_detected; - } - - static get_system_color_scheme() { - return IO.X_APPS.get_string(IO.KEYS.COLOR_SCHEME); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/main.cpp b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/main.cpp deleted file mode 100644 index d8a24815f4f..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/main.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "time_change_listener.hpp" - -#include -#include -#include -#include -#include - -int main(int argc, char* argv[]) { - { - std::vector args{argv, argv + argc}; - - if (std::find(args.begin(), args.end(), "--help") != args.end()) { - std::cout - << "Usage: " << args[0] << '\n' - << "Listens for system time changes and prints 'changed' to `stdout` each time it occurs.\n" - << '\n' - << "Commands via `stdin`:\n" - << " 'enable': Enable listening for the system time changes.\n" - << " 'disable': Disable listening for the system time changes.\n" - << " 'exit': Exit the program.\n" - << '\n' - << "Options:\n" - << " --help: Display this help message.\n" - << std::endl; - return 0; - } - } - - try { - Time_change_listener listener([]() { - std::cout << "changed" << std::endl; - }); - - std::string input; - while (std::getline(std::cin, input)) { - if (input == "enable") - listener.enable(); - else - if (input == "disable") - listener.disable(); - else - if (input == "exit") - break; - } - } catch (const std::exception& e) { - std::cerr << e.what() << std::endl; - return 1; - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.js deleted file mode 100644 index 5536cc09e3a..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_change_listener/time_change_listener.js +++ /dev/null @@ -1,117 +0,0 @@ -const _ = require('lib/translator.js'); - -const {Gio, GLib} = imports.gi; - -const EXECUTABLE_NAME = "auto-dark-light-time-change-listener"; - -/** A passive listener for system time changes. It interfaces the C++ program whose API is in `time_change_listener.hpp`. */ -module.exports = class Time_change_listener { - #callback_when_changes; - #callback_for_errors; - #subprocess; - #input; - #input_error; - #output; - #end_listen = false; - - /** - * @param {string} path - The absolute path where the C++ files are located. - * @param {() => void} callback_when_changes - The function to be called when the system time changes. - * @param {(message: string) => void} callback_for_errors - The function to call with a message for when an error occurs. - * @throws {Error} If the `make` and `gcc` commands are not found in the system or if the compilation of the C++ program fails. - */ - constructor(path, callback_when_changes, callback_for_errors) { - this.#callback_when_changes = callback_when_changes; - this.#callback_for_errors = callback_for_errors; - - if (!(GLib.find_program_in_path('make') && GLib.find_program_in_path('g++'))) - throw new Error(_("Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-based system with `sudo apt install make g++`, then reload the applet in restarting Cinnamon.")); - - const compilation = new Gio.Subprocess({ - argv: ['make', '-C', path], - flags: Gio.SubprocessFlags.STDERR_PIPE - }); - compilation.init(null); - try { - const [_ok, _stdout, stderr] = compilation.communicate_utf8(null, null); - if (!compilation.get_successful()) - throw new Error(stderr); - } catch (error) { - throw new Error( - `${_("Compilation of")} \`${EXECUTABLE_NAME}\` ${_("failed")}.\n` - + "\n" - + error.message - ); - } - - const executable_path = `${path}/${EXECUTABLE_NAME}`; - this.#subprocess = new Gio.Subprocess({ - argv: [executable_path], - flags: - Gio.SubprocessFlags.STDOUT_PIPE | - Gio.SubprocessFlags.STDIN_PIPE | - Gio.SubprocessFlags.STDERR_PIPE - }); - this.#subprocess.init(null); - - this.#output = this.#subprocess.get_stdin_pipe(); - this.#input = new Gio.DataInputStream({ - base_stream: this.#subprocess.get_stdout_pipe() - }); - this.#input_error = new Gio.DataInputStream({ - base_stream: this.#subprocess.get_stderr_pipe() - }); - - this.#listen_input(); - this.#listen_error(); - } - - async #listen_input() { // thread-like - do { - await new Promise(resolve => - this.#input.read_line_async(GLib.PRIORITY_DEFAULT, null, resolve) - ); - this.#callback_when_changes(); - } while (!this.#end_listen); - } - - async #listen_error() { // thread-like - do { - let [line, length] = await new Promise(resolve => - this.#input_error.read_line_async( - GLib.PRIORITY_DEFAULT, - null, - (source, result) => { - try { resolve(source.read_line_finish(result)); } - catch (error) { - this.#callback_for_errors(error); - resolve([null, 0]); - } - } - ) - ); - if (line !== null && length > 0) - this.#callback_for_errors( - `${_("the subprocess")} \`${EXECUTABLE_NAME}\` ${_("wrote on its error output")}${_(":")} ${line}` - ); - } while (!this.#end_listen); - } - - /** Enables listening for the system time changes. */ - enable() { - this.#output.write('enable\n', null); - } - - /** Disables listening for the system time changes. */ - disable() { - this.#output.write('disable\n', null); - } - - /** Declares the object as finished to release any ressource acquired. */ - finalize() { - this.#callback_when_changes = () => {}; // Be sure to not call it again - this.#end_listen = true; - this.#output.write('exit\n', null); - this.#subprocess.wait(null); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_of_day.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_of_day.js deleted file mode 100644 index c58b850188e..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/time_of_day.js +++ /dev/null @@ -1,60 +0,0 @@ -const {DateTime} = imports.gi.GLib; - -/** A time handler in hour, minute and second and 24-hour format. */ -module.exports = class Time_of_day { - #hour; - #minute; - #second; - - /** - * @param {DateTime} date - The object to take the hour, minute and second from. - * @note `GLib.DateTime` type is chosen over `Date` to take into account timezone changes during runtime. - */ - constructor(date) { - this.#hour = date.get_hour(); - this.#minute = date.get_minute(); - this.#second = date.get_second(); - } - - /** @returns {Time_of_day} The current local time of day. */ - static now() { return new Time_of_day(DateTime.new_now_local()); } - - /** @returns {string} The time of day as a string in the format "(H)H:MM:SS". */ - as_string() { - const minute = String(this.#minute).padStart(2, '0'), - second = String(this.#second).padStart(2, '0'); - return `${this.#hour}:${minute}:${second}`; - } - - /** - * Gets the delay from now until the next occurence of `this`. - * @returns {number} The delay in seconds from now. - */ - get_seconds_from_now() { - const [now, time] = [Time_of_day.now(), this].map(time => - time.#get_seconds_since_midnight() - ); - const ONE_DAY = 24 * 3600; - return now < time ? time - now - : time - now + ONE_DAY; - } - - /** - * Tests if `this` is between two other `Time_of_day`. - * @param {Time_of_day} start - The start time. - * @param {Time_of_day} end - The end time. - * @returns {boolean} Wether the time is between the start and end times. - */ - is_between(start, end) { - let time; - [time, start, end] = [this, start, end].map(time => - time.#get_seconds_since_midnight() - ); - return start < end ? start <= time && time < end - : start <= time || time < end; - } - - #get_seconds_since_midnight() { - return this.#hour * 3600 + this.#minute * 60 + this.#second; - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timer_absolute.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timer_absolute.js deleted file mode 100644 index 71c90e15843..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timer_absolute.js +++ /dev/null @@ -1,16 +0,0 @@ -const Time_of_day = require('lib/time_of_day.js'); - -/** A basic query-based absolute timer in time of day. */ -module.exports = class Timer_absolute { - #expiration_time = 0; - - /** @param {Time_of_day} value - The next time of day at which the timer has to expire. */ - set expiration_time(value) { - const due_delay = value.get_seconds_from_now(); // [s] - this.#expiration_time = new Date().getTime() + due_delay * 1000; // [ms] - } - - get_if_has_expired() { - return new Date().getTime() > this.#expiration_time; - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezone_change_listener.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezone_change_listener.js deleted file mode 100644 index 5551bbecb1b..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezone_change_listener.js +++ /dev/null @@ -1,28 +0,0 @@ -const Dbus = require('lib/dbus.js'); - -/** A listener for the system timezone changes. - * - * The user has to call `finalize` when it is not needed anymore. - */ -module.exports = class Timezone_change_listener { - #timezone_dbus = new Dbus.Timezone(); - #callback; - - /** @param {() => void} callback_when_changes - The function to be executed when the system timezone changes. */ - constructor(callback_when_changes) { - this.#callback = callback_when_changes; - } - - enable() { - this.#timezone_dbus.subscribe_to_changes(this.#callback.bind(this)); - } - - disable() { - this.#timezone_dbus.unsubscribe_to_changes(); - } - - /** Declares the object as finished to release any ressource acquired. */ - finalize() { - this.disable(); - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/generate_database.ipynb b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/generate_database.ipynb deleted file mode 100644 index a0b8eb9e902..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/generate_database.ipynb +++ /dev/null @@ -1,1553 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Find appropriate coordinates for every timezone" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Get timezones" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
regionsubregionplace
timezone
Africa/AbidjanAfricaNoneAbidjan
Africa/AccraAfricaNoneAccra
Africa/Addis_AbabaAfricaNoneAddis Ababa
Africa/AlgiersAfricaNoneAlgiers
Africa/AsmaraAfricaNoneAsmara
............
Pacific/TahitiPacificNoneTahiti
Pacific/TarawaPacificNoneTarawa
Pacific/TongatapuPacificNoneTongatapu
Pacific/WakePacificNoneWake
Pacific/WallisPacificNoneWallis
\n", - "

417 rows × 3 columns

\n", - "
" - ], - "text/plain": [ - " region subregion place\n", - "timezone \n", - "Africa/Abidjan Africa None Abidjan\n", - "Africa/Accra Africa None Accra\n", - "Africa/Addis_Ababa Africa None Addis Ababa\n", - "Africa/Algiers Africa None Algiers\n", - "Africa/Asmara Africa None Asmara\n", - "... ... ... ...\n", - "Pacific/Tahiti Pacific None Tahiti\n", - "Pacific/Tarawa Pacific None Tarawa\n", - "Pacific/Tongatapu Pacific None Tongatapu\n", - "Pacific/Wake Pacific None Wake\n", - "Pacific/Wallis Pacific None Wallis\n", - "\n", - "[417 rows x 3 columns]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pytz\n", - "\n", - "def generate_timezones():\n", - " for timezone in pytz.common_timezones:\n", - " split = timezone.replace(\"_\", \" \").split(\"/\")\n", - " match len(split):\n", - " case 1: continue\n", - " case 2: region, subregion, place = split[0], None, split[1]\n", - " case 3: region, subregion, place = split[0], split[1], split[2]\n", - " case _: raise ValueError(f\"Unexpected timezone format: {timezone}\")\n", - " if region == \"US\" or region == \"Canada\":\n", - " continue\n", - " yield timezone, region, subregion, place\n", - "\n", - "df_timezones = pd.DataFrame(\n", - " list(generate_timezones()),\n", - " columns=['timezone', 'region', 'subregion', 'place']\n", - ").set_index('timezone')\n", - "\n", - "df_timezones" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Get a city-coordinates database from `libtimezonemap`" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
latitudelongitudetimezone
city
les Escaldes42.507291.53414Europe/Andorra
Andorra la Vella42.507791.52109Europe/Andorra
Umm al Qaywayn25.5647355.55517Asia/Dubai
Ras al-Khaimah25.7895355.94320Asia/Dubai
Khawr Fakkan25.3313256.34199Asia/Dubai
............
Bulawayo-20.1500028.58333Africa/Harare
Bindura-17.3019231.33056Africa/Harare
Beitbridge-22.2166730.00000Africa/Harare
Epworth-17.8900031.14750Africa/Harare
Chitungwiza-18.0127431.07555Africa/Harare
\n", - "

23461 rows × 3 columns

\n", - "
" - ], - "text/plain": [ - " latitude longitude timezone\n", - "city \n", - "les Escaldes 42.50729 1.53414 Europe/Andorra\n", - "Andorra la Vella 42.50779 1.52109 Europe/Andorra\n", - "Umm al Qaywayn 25.56473 55.55517 Asia/Dubai\n", - "Ras al-Khaimah 25.78953 55.94320 Asia/Dubai\n", - "Khawr Fakkan 25.33132 56.34199 Asia/Dubai\n", - "... ... ... ...\n", - "Bulawayo -20.15000 28.58333 Africa/Harare\n", - "Bindura -17.30192 31.33056 Africa/Harare\n", - "Beitbridge -22.21667 30.00000 Africa/Harare\n", - "Epworth -17.89000 31.14750 Africa/Harare\n", - "Chitungwiza -18.01274 31.07555 Africa/Harare\n", - "\n", - "[23461 rows x 3 columns]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = pd.read_csv(\n", - " '/usr/share/libtimezonemap/ui/cities15000.txt',\n", - " delimiter='\\t',\n", - " header=None,\n", - " usecols=[2, 4, 5, 17],\n", - " names=['city', 'latitude', 'longitude', 'timezone'],\n", - " quotechar='_' # allow all other weird characters\n", - ").set_index('city')\n", - "\n", - "df.index = df.index.map(lambda x: x.replace(\"'\", \" \"))\n", - "\n", - "df_cities = df\n", - "\n", - "df_cities" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Find timezones coordinates in the database" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Solve some by finding unique timezones in the database" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
latitudelongitude
timezone
America/Antigua17.11717-61.84573
America/Anguilla18.21704-63.05783
America/Argentina/Ushuaia-54.80000-68.30000
Pacific/Pago_Pago-14.27806-170.70250
Australia/Broken_Hill-31.96173141.45998
.........
America/North_Dakota/New_Salem46.82666-100.88958
Europe/Vatican41.9023612.45332
Pacific/Efate-17.73381168.32188
Pacific/Wallis-13.28163-176.17453
Pacific/Apia-13.83333-171.76666
\n", - "

68 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " latitude longitude\n", - "timezone \n", - "America/Antigua 17.11717 -61.84573\n", - "America/Anguilla 18.21704 -63.05783\n", - "America/Argentina/Ushuaia -54.80000 -68.30000\n", - "Pacific/Pago_Pago -14.27806 -170.70250\n", - "Australia/Broken_Hill -31.96173 141.45998\n", - "... ... ...\n", - "America/North_Dakota/New_Salem 46.82666 -100.88958\n", - "Europe/Vatican 41.90236 12.45332\n", - "Pacific/Efate -17.73381 168.32188\n", - "Pacific/Wallis -13.28163 -176.17453\n", - "Pacific/Apia -13.83333 -171.76666\n", - "\n", - "[68 rows x 2 columns]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_results = df_cities.drop_duplicates(subset=['timezone'], keep=False).set_index('timezone')\n", - "\n", - "df_timezones = df_timezones[~df_timezones.index.isin(df_results.index)] # remove found timezones\n", - "\n", - "df_results" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Africa/El_Aaiun not matched to any city\n", - "Africa/Ndjamena not matched to any city\n", - "((Hint) Africa/Tripoli: found city Tripoli but its timezone was Europe/Athens)\n", - "((Hint) Africa/Tripoli: found city Tripoli but its timezone was Asia/Beirut)\n", - "America/Adak not matched to any city\n", - "America/Argentina/Catamarca not matched to any city\n", - "America/Argentina/Jujuy not matched to any city\n", - "America/Argentina/Tucuman not matched to any city\n", - "America/Aruba not matched to any city\n", - "America/Atikokan not matched to any city\n", - "America/Bahia not matched to any city\n", - "America/Bahia_Banderas not matched to any city\n", - "((Hint) America/Belem: found city Belem but its timezone was America/Fortaleza)\n", - "America/Belize not matched to any city\n", - "America/Blanc-Sablon not matched to any city\n", - "America/Cambridge_Bay not matched to any city\n", - "((Hint) America/Cayenne: found city Cayenne but its timezone was Europe/Paris)\n", - "((Hint) America/Ciudad_Juarez: found city Ciudad Juarez but its timezone was America/Ojinaga)\n", - "America/Ciudad_Juarez not matched to any city\n", - "America/Costa_Rica not matched to any city\n", - "America/Creston not matched to any city\n", - "America/Danmarkshavn not matched to any city\n", - "America/Dawson not matched to any city\n", - "America/El_Salvador not matched to any city\n", - "America/Fort_Nelson not matched to any city\n", - "America/Goose_Bay not matched to any city\n", - "America/Guadeloupe not matched to any city\n", - "America/Guatemala not matched to any city\n", - "America/Guyana not matched to any city\n", - "America/Indiana/Knox not matched to any city\n", - "America/Indiana/Marengo not matched to any city\n", - "((Hint) America/Indiana/Petersburg: found city Petersburg but its timezone was America/New_York)\n", - "America/Indiana/Petersburg not matched to any city\n", - "America/Indiana/Tell_City not matched to any city\n", - "America/Indiana/Vevay not matched to any city\n", - "((Hint) America/Indiana/Vincennes: found city Vincennes but its timezone was Europe/Paris)\n", - "America/Indiana/Winamac not matched to any city\n", - "America/Inuvik not matched to any city\n", - "America/Iqaluit not matched to any city\n", - "((Hint) America/Jamaica: found city Jamaica but its timezone was America/New_York)\n", - "America/Jamaica not matched to any city\n", - "America/Kentucky/Monticello not matched to any city\n", - "((Hint) America/La_Paz: found city La Paz but its timezone was America/Argentina/Cordoba)\n", - "((Hint) America/Los_Angeles: found city Los Angeles but its timezone was America/Santiago)\n", - "America/Martinique not matched to any city\n", - "((Hint) America/Matamoros: found city Matamoros but its timezone was America/Monterrey)\n", - "America/Matamoros not matched to any city\n", - "((Hint) America/Merida: found city Merida but its timezone was Europe/Madrid)\n", - "America/Metlakatla not matched to any city\n", - "America/Montserrat not matched to any city\n", - "America/New_York not matched to any city\n", - "America/Nome not matched to any city\n", - "America/Noronha not matched to any city\n", - "America/North_Dakota/Beulah not matched to any city\n", - "America/North_Dakota/Center not matched to any city\n", - "((Hint) America/Nuuk: found city Nuuk but its timezone was America/Godthab)\n", - "America/Nuuk not matched to any city\n", - "America/Port_of_Spain not matched to any city\n", - "((Hint) America/Puerto_Rico: found city Puerto Rico but its timezone was America/Argentina/Cordoba)\n", - "America/Puerto_Rico not matched to any city\n", - "((Hint) America/Punta_Arenas: found city Punta Arenas but its timezone was America/Santiago)\n", - "America/Punta_Arenas not matched to any city\n", - "America/Rankin_Inlet not matched to any city\n", - "America/Resolute not matched to any city\n", - "((Hint) America/Santiago: found city Santiago but its timezone was America/Sao_Paulo)\n", - "((Hint) America/Santo_Domingo: found city Santo Domingo but its timezone was America/Havana)\n", - "America/Scoresbysund not matched to any city\n", - "America/Sitka not matched to any city\n", - "America/St_Johns not matched to any city\n", - "America/St_Thomas not matched to any city\n", - "America/St_Vincent not matched to any city\n", - "America/Swift_Current not matched to any city\n", - "America/Thule not matched to any city\n", - "America/Yakutat not matched to any city\n", - "Antarctica/Casey not matched to any city\n", - "((Hint) Antarctica/Davis: found city Davis but its timezone was America/Los_Angeles)\n", - "Antarctica/Davis not matched to any city\n", - "Antarctica/DumontDUrville not matched to any city\n", - "Antarctica/Macquarie not matched to any city\n", - "Antarctica/Mawson not matched to any city\n", - "Antarctica/McMurdo not matched to any city\n", - "((Hint) Antarctica/Palmer: found city Palmer but its timezone was America/New_York)\n", - "Antarctica/Palmer not matched to any city\n", - "Antarctica/Rothera not matched to any city\n", - "Antarctica/Syowa not matched to any city\n", - "Antarctica/Troll not matched to any city\n", - "Antarctica/Vostok not matched to any city\n", - "Asia/Anadyr not matched to any city\n", - "Asia/Aqtau not matched to any city\n", - "((Hint) Asia/Atyrau: found city Atyrau but its timezone was Asia/Oral)\n", - "Asia/Atyrau not matched to any city\n", - "Asia/Bahrain not matched to any city\n", - "((Hint) Asia/Barnaul: found city Barnaul but its timezone was Asia/Omsk)\n", - "Asia/Barnaul not matched to any city\n", - "((Hint) Asia/Chita: found city Chita but its timezone was Asia/Yakutsk)\n", - "Asia/Chita not matched to any city\n", - "((Hint) Asia/Colombo: found city Colombo but its timezone was America/Sao_Paulo)\n", - "((Hint) Asia/Famagusta: found city Famagusta but its timezone was Asia/Nicosia)\n", - "Asia/Famagusta not matched to any city\n", - "Asia/Ho_Chi_Minh not matched to any city\n", - "((Hint) Asia/Hovd: found city Hovd but its timezone was Asia/Ulaanbaatar)\n", - "Asia/Hovd not matched to any city\n", - "Asia/Kamchatka not matched to any city\n", - "Asia/Khandyga not matched to any city\n", - "Asia/Kuwait not matched to any city\n", - "Asia/Qatar not matched to any city\n", - "Asia/Qostanay not matched to any city\n", - "Asia/Qyzylorda not matched to any city\n", - "Asia/Sakhalin not matched to any city\n", - "Asia/Samarkand not matched to any city\n", - "Asia/Srednekolymsk not matched to any city\n", - "((Hint) Asia/Tomsk: found city Tomsk but its timezone was Asia/Novosibirsk)\n", - "Asia/Tomsk not matched to any city\n", - "Asia/Urumqi not matched to any city\n", - "Asia/Ust-Nera not matched to any city\n", - "((Hint) Asia/Yangon: found city Yangon but its timezone was Asia/Rangoon)\n", - "Asia/Yangon not matched to any city\n", - "Atlantic/Canary not matched to any city\n", - "Atlantic/Cape_Verde not matched to any city\n", - "Atlantic/Madeira not matched to any city\n", - "Australia/Eucla not matched to any city\n", - "Australia/Lindeman not matched to any city\n", - "Australia/Lord_Howe not matched to any city\n", - "Europe/Andorra not matched to any city\n", - "Europe/Astrakhan not matched to any city\n", - "Europe/Busingen not matched to any city\n", - "((Hint) Europe/Kirov: found city Kirov but its timezone was Europe/Volgograd)\n", - "((Hint) Europe/Kirov: found city Kirov but its timezone was Europe/Moscow)\n", - "Europe/Kirov not matched to any city\n", - "Europe/Kyiv not matched to any city\n", - "((Hint) Europe/London: found city London but its timezone was America/Toronto)\n", - "((Hint) Europe/Madrid: found city Madrid but its timezone was America/Bogota)\n", - "Europe/Malta not matched to any city\n", - "((Hint) Europe/Saratov: found city Saratov but its timezone was Europe/Volgograd)\n", - "Europe/Saratov not matched to any city\n", - "Europe/Tirane not matched to any city\n", - "((Hint) Europe/Ulyanovsk: found city Ulyanovsk but its timezone was Europe/Moscow)\n", - "Europe/Ulyanovsk not matched to any city\n", - "Indian/Chagos not matched to any city\n", - "Indian/Comoro not matched to any city\n", - "Indian/Mauritius not matched to any city\n", - "Indian/Mayotte not matched to any city\n", - "Indian/Reunion not matched to any city\n", - "((Hint) Pacific/Chatham: found city Chatham but its timezone was Europe/London)\n", - "Pacific/Chatham not matched to any city\n", - "Pacific/Chuuk not matched to any city\n", - "Pacific/Easter not matched to any city\n", - "Pacific/Fakaofo not matched to any city\n", - "Pacific/Fiji not matched to any city\n", - "Pacific/Galapagos not matched to any city\n", - "Pacific/Gambier not matched to any city\n", - "Pacific/Guam not matched to any city\n", - "Pacific/Kanton not matched to any city\n", - "Pacific/Kiritimati not matched to any city\n", - "Pacific/Kosrae not matched to any city\n", - "Pacific/Kwajalein not matched to any city\n", - "Pacific/Marquesas not matched to any city\n", - "Pacific/Midway not matched to any city\n", - "Pacific/Nauru not matched to any city\n", - "Pacific/Tahiti not matched to any city\n", - "Pacific/Wake not matched to any city\n" - ] - } - ], - "source": [ - "for timezone_row in df_timezones.itertuples():\n", - " timezone = timezone_row.Index\n", - " found = False\n", - " for city in df_cities.itertuples():\n", - " city_name = city.Index\n", - " if timezone_row.place == city_name:\n", - " if timezone == city.timezone:\n", - " found = True\n", - " df_timezones = df_timezones.drop(timezone)\n", - " df_results.loc[timezone] = [city.latitude, city.longitude]\n", - " break\n", - " print(f\"((Hint) {timezone}: found city {city_name} but its timezone was {city.timezone})\")\n", - "\n", - " if not found:\n", - " print(f\"{timezone} not matched to any city\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Remaining timezones to match" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
regionsubregionplace
timezone
Africa/El_AaiunAfricaNoneEl Aaiun
Africa/NdjamenaAfricaNoneNdjamena
America/AdakAmericaNoneAdak
America/Argentina/CatamarcaAmericaArgentinaCatamarca
America/Argentina/JujuyAmericaArgentinaJujuy
............
Pacific/MarquesasPacificNoneMarquesas
Pacific/MidwayPacificNoneMidway
Pacific/NauruPacificNoneNauru
Pacific/TahitiPacificNoneTahiti
Pacific/WakePacificNoneWake
\n", - "

127 rows × 3 columns

\n", - "
" - ], - "text/plain": [ - " region subregion place\n", - "timezone \n", - "Africa/El_Aaiun Africa None El Aaiun\n", - "Africa/Ndjamena Africa None Ndjamena\n", - "America/Adak America None Adak\n", - "America/Argentina/Catamarca America Argentina Catamarca\n", - "America/Argentina/Jujuy America Argentina Jujuy\n", - "... ... ... ...\n", - "Pacific/Marquesas Pacific None Marquesas\n", - "Pacific/Midway Pacific None Midway\n", - "Pacific/Nauru Pacific None Nauru\n", - "Pacific/Tahiti Pacific None Tahiti\n", - "Pacific/Wake Pacific None Wake\n", - "\n", - "[127 rows x 3 columns]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_timezones" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Matched timezones" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
latitudelongitude
timezone
America/Antigua17.11717-61.84573
America/Anguilla18.21704-63.05783
America/Argentina/Ushuaia-54.80000-68.30000
Pacific/Pago_Pago-14.27806-170.70250
Australia/Broken_Hill-31.96173141.45998
.........
Pacific/Auckland-36.86667174.76667
Pacific/Honolulu21.30694-157.85833
Pacific/Majuro7.08971171.38027
Pacific/Noumea-22.27631166.45720
Pacific/Port_Moresby-9.44314147.17972
\n", - "

293 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " latitude longitude\n", - "timezone \n", - "America/Antigua 17.11717 -61.84573\n", - "America/Anguilla 18.21704 -63.05783\n", - "America/Argentina/Ushuaia -54.80000 -68.30000\n", - "Pacific/Pago_Pago -14.27806 -170.70250\n", - "Australia/Broken_Hill -31.96173 141.45998\n", - "... ... ...\n", - "Pacific/Auckland -36.86667 174.76667\n", - "Pacific/Honolulu 21.30694 -157.85833\n", - "Pacific/Majuro 7.08971 171.38027\n", - "Pacific/Noumea -22.27631 166.45720\n", - "Pacific/Port_Moresby -9.44314 147.17972\n", - "\n", - "[293 rows x 2 columns]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Search remaining timezones online" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Africa/El_Aaiun matched to Laâyoune العيون, Pachalik de Laâyoune باشوية العيون, Province de Laâyoune إقليم العيون, Maroc ⵍⵎⵖⵔⵉⴱ المغرب\n", - "Africa/Ndjamena matched to N'Djaména انجمينا, Tchad تشاد\n", - "America/Adak matched to Adak, Aleutians West Census Area, Alaska, 99546, United States\n", - "America/Argentina/Catamarca matched to Catamarca, Argentina\n", - "America/Argentina/Jujuy matched to Jujuy, Argentina\n", - "America/Argentina/Tucuman matched to Tucumán, Argentina\n", - "America/Aruba matched to Aruba, Nederland\n", - "America/Atikokan matched to Atikokan, Rainy River District, Northwestern Ontario, Ontario, Canada\n", - "America/Bahia matched to Bahia, Região Nordeste, Brasil\n", - "America/Bahia_Banderas matched to Bahía Banderas, Bahías de Jaltenco, Alborada Jaltenco, Jaltenco, 55783, México\n", - "America/Belize matched to Belize\n", - "America/Blanc-Sablon matched to Blanc-Sablon, Le Golfe-du-Saint-Laurent, Côte-Nord, Québec, Canada\n", - "America/Cambridge_Bay matched to Iqaluktuuttiaq (Cambridge Bay), ᕿᑎᕐᒥᐅᑦ Kitikmeot Region, ᓄᓇᕗᑦ Nunavut, X0B 0C0, Canada\n", - "America/Ciudad_Juarez matched to Ciudad Juárez, Juárez, Chihuahua, 32001, México\n", - "America/Costa_Rica matched to Costa Rica\n", - "America/Creston matched to Creston, Union County, Iowa, 50801, United States\n", - "America/Danmarkshavn matched to Danmarkshavn, Kalaallit Nunaat\n", - "America/Dawson matched to Dawson County, Texas, United States\n", - "America/El_Salvador matched to El Salvador\n", - "America/Fort_Nelson matched to Fort Nelson, Northern Rockies Regional Municipality, British Columbia, V0C 1R0, Canada\n", - "America/Goose_Bay matched to Goose Bay, Happy Valley-Goose Bay, Labrador, Newfoundland and Labrador, Canada\n", - "America/Guadeloupe matched to Guadeloupe, France\n", - "America/Guatemala matched to Guatemala\n", - "America/Guyana matched to Guyana\n", - "America/Indiana/Knox matched to Knox County, Indiana, United States\n", - "America/Indiana/Marengo matched to Marengo, Crawford County, Indiana, United States\n", - "America/Indiana/Petersburg matched to Petersburg, Pike County, Indiana, United States\n", - "America/Indiana/Tell_City matched to Tell City, Perry County, Indiana, United States\n", - "America/Indiana/Vevay matched to Vevay, Switzerland County, Indiana, United States\n", - "America/Indiana/Winamac matched to Winamac, Pulaski County, Indiana, United States\n", - "America/Inuvik matched to Inuvik, Gwich'in Settlement Area, Northwest Territories, Canada\n", - "America/Iqaluit matched to Iqaluit ᐃᖃᓗᐃᑦ, ᐃᖃᓗᐃᑦ, ᕿᑭᖅᑖᓗᒃ Qikiqtaaluk Region, ᓄᓇᕗᑦ Nunavut, Canada\n", - "America/Jamaica matched to Jamaica\n", - "America/Kentucky/Monticello matched to Monticello, Wayne County, Kentucky, 42633, United States\n", - "America/Martinique matched to Martinique, France\n", - "America/Matamoros matched to Matamoros, Tamaulipas, 87300, México\n", - "America/Metlakatla matched to Metlakatla, Unorganized Borough, Alaska, 99926, United States\n", - "America/Montserrat matched to Montserrat\n", - "America/New_York matched to City of New York, New York, United States\n", - "America/Nome matched to Nome, Unorganized Borough, Alaska, United States\n", - "America/Noronha matched to Olímpio Noronha, Região Geográfica Imediata de São Lourenço, Região Geográfica Intermediária de Pouso Alegre, Minas Gerais, Região Sudeste, Brasil\n", - "America/North_Dakota/Beulah matched to Beulah, Mercer County, North Dakota, United States\n", - "America/North_Dakota/Center matched to Center, Oliver County, North Dakota, United States\n", - "America/Nuuk matched to Nuuk, Sermersooq, 3900, Kalaallit Nunaat\n", - "America/Port_of_Spain matched to Port of Spain, Trinidad and Tobago\n", - "America/Puerto_Rico matched to Puerto Rico, United States\n", - "America/Punta_Arenas matched to Punta Arenas, Provincia de Magallanes, Región de Magallanes y de la Antártica Chilena, Chile\n", - "America/Rankin_Inlet matched to ᑲᖏᕿᓂᖅ Rankin Inlet, ᑭᕙᓪᓕᖅ Kivalliq Region, ᓄᓇᕗᑦ Nunavut, Canada\n", - "America/Resolute matched to Resolute, ᕿᑭᖅᑖᓗᒃ Qikiqtaaluk Region, ᓄᓇᕗᑦ Nunavut, X0A 0V0, Canada\n", - "America/Scoresbysund matched to Ittoqqortoormiit, Sermersooq, 3980, Kalaallit Nunaat\n", - "America/Sitka matched to Sitka, Alaska, 99835, United States\n", - "America/St_Johns matched to St. John's, Saint John, Antigua, Antigua and Barbuda\n", - "America/St_Thomas matched to Saint Thomas, Charlotte Amalie, Saint Thomas - Saint John District, United States Virgin Islands, United States\n", - "America/St_Vincent matched to St. Vincent, Kittson County, Minnesota, 56755, United States\n", - "America/Swift_Current matched to Swift Current, Division No. 8, Saskatchewan, Canada\n", - "America/Thule matched to Thule, Qacha's Nek District, Lesotho\n", - "America/Yakutat matched to Yakutat, Alaska, United States\n", - "Antarctica/Casey matched to Casey County, Kentucky, United States\n", - "Antarctica/Davis matched to Davis County, Iowa, United States\n", - "No coordinates found for Antarctica/DumontDUrville\n", - "Antarctica/Macquarie matched to Macquarie Island, Huon Valley, Tasmania, Australia\n", - "Antarctica/Mawson matched to Mawson, District of Woden Valley, Australian Capital Territory, 2607, Australia\n", - "Antarctica/McMurdo matched to McMurdo, Area A (Kicking Horse/Kinbasket Lake), Columbia-Shuswap Regional District, British Columbia, V0A 1H7, Canada\n", - "Antarctica/Palmer matched to Palmer, Matanuska-Susitna, Alaska, 99645, United States\n", - "Antarctica/Rothera matched to Rothera Research Station\n", - "Antarctica/Syowa matched to 昭和基地\n", - "Antarctica/Troll matched to Troll, Flyplassveien, Troll\n", - "Antarctica/Vostok matched to Vostok\n", - "Asia/Anadyr matched to Анадырь, городской округ Анадырь, Чукотский автономный округ, Дальневосточный федеральный округ, 689000, Россия\n", - "Asia/Aqtau matched to Ақтау Қ.Ә., Маңғыстау облысы, Қазақстан\n", - "Asia/Atyrau matched to Атырау облысы, Қазақстан\n", - "Asia/Bahrain matched to البحرين\n", - "Asia/Barnaul matched to Барнаул, городской округ Барнаул, Алтайский край, Сибирский федеральный округ, 656000, Россия\n", - "Asia/Chita matched to Чита, городской округ Чита, Забайкальский край, Дальневосточный федеральный округ, 672000, Россия\n", - "Asia/Famagusta matched to Gazimağusa, Gazimağusa Belediyesi, Gazimağusa ilçesi, Kuzey Kıbrıs, Κύπρος - Kıbrıs\n", - "Asia/Ho_Chi_Minh matched to Ho Chi Minh, Muralla Street, Barangay 654, Intramuros, Fifth District, Manila, Capital District, Metro Manila, 1002, Pilipinas\n", - "Asia/Hovd matched to Ховд ᠬᠣᠪᠳᠤ, Монгол улс ᠮᠤᠩᠭᠤᠯ ᠤᠯᠤᠰ\n", - "Asia/Kamchatka matched to Камчатский край, Дальневосточный федеральный округ, Россия\n", - "Asia/Khandyga matched to Хандыга, городское поселение Хандыга, Томпонский улус, Республика Саха (Якутия), Дальневосточный федеральный округ, 678720, Россия\n", - "Asia/Kuwait matched to مدينة الكويت, إدارة النظافة العامة وإشغالات الطرق, العاصمة, 15005, الكويت\n", - "Asia/Qatar matched to قطر\n", - "Asia/Qostanay matched to Қостанай облысы, Қазақстан\n", - "Asia/Qyzylorda matched to Қызылорда облысы, Қазақстан\n", - "Asia/Sakhalin matched to Сахалин, Дальневосточный федеральный округ, Россия\n", - "Asia/Samarkand matched to Samarqand shahri, Samarqand Viloyati, 140000, Oʻzbekiston\n", - "Asia/Srednekolymsk matched to Среднеколымск, городское поселение Среднеколымск, Среднеколымский улус, Республика Саха (Якутия), Дальневосточный федеральный округ, Россия\n", - "Asia/Tomsk matched to Томская область, Сибирский федеральный округ, Россия\n", - "Asia/Urumqi matched to 乌鲁木齐县, 乌鲁木齐市 ئۈرۈمچى, 新疆维吾尔自治区 شىنجاڭ ئۇيغۇر ئاپتونوم رايونی, 830000, 中国\n", - "Asia/Ust-Nera matched to Усть-Нера, городское поселение Усть-Нера, Оймяконский улус, Республика Саха (Якутия), Дальневосточный федеральный округ, 678730, Россия\n", - "Asia/Yangon matched to Yangon, ရန်ကုန်တိုင်းဒေသကြီး, မြန်မာ\n", - "Atlantic/Canary matched to Canary, Madison County, Texas, United States\n", - "Atlantic/Cape_Verde matched to Cabo Verde\n", - "Atlantic/Madeira matched to Madeira, Portugal\n", - "Australia/Eucla matched to Eucla, Shire Of Dundas, Western Australia, Australia\n", - "Australia/Lindeman matched to Lindeman, Uusikaupunki, Vakka-Suomen seutukunta, Varsinais-Suomi, Lounais-Suomen aluehallintovirasto, Manner-Suomi, Suomi / Finland\n", - "Australia/Lord_Howe matched to Lord Howe Island, New South Wales, 2898, Australia\n", - "Europe/Andorra matched to Andorra\n", - "Europe/Astrakhan matched to Астрахань, городской округ Астрахань, Астраханская область, Южный федеральный округ, 414000, Россия\n", - "Europe/Busingen matched to Büsingen am Hochrhein, Verwaltungsgemeinschaft Gottmadingen, Landkreis Konstanz, Baden-Württemberg, 78266, Deutschland\n", - "Europe/Kirov matched to Киров, городской округ Киров, Кировская область, Приволжский федеральный округ, 610000, Россия\n", - "Europe/Kyiv matched to Київ, Україна\n", - "Europe/Malta matched to Malta\n", - "Europe/Saratov matched to Саратов, городской округ Саратов, Саратовская область, Приволжский федеральный округ, 410000, Россия\n", - "Europe/Tirane matched to Tiranë, Bashkia Tiranë, Qarku i Tiranës, Shqipëria Qendrore, 1001-1028, Shqipëria\n", - "Europe/Ulyanovsk matched to Ульяновск, городской округ Ульяновск, Ульяновская область, Приволжский федеральный округ, Россия\n", - "Indian/Chagos matched to Chagos, La Vilieḷḷa, Ḷḷarón, Cangas del Narcea, 33811, España\n", - "Indian/Comoro matched to Comoro, Asmat, Papua Selatan, Western New Guinea, Indonesia\n", - "Indian/Mauritius matched to Mauritius / Maurice\n", - "Indian/Mayotte matched to Mayotte, France\n", - "Indian/Reunion matched to La Réunion, France\n", - "Pacific/Chatham matched to Chatham County, North Carolina, United States\n", - "Pacific/Chuuk matched to Chuuk, Micronesia\n", - "Pacific/Easter matched to Easter, Castro County, Texas, United States\n", - "Pacific/Fakaofo matched to Fakaofo, Tokelau\n", - "Pacific/Fiji matched to Viti\n", - "Pacific/Galapagos matched to Galápagos, Ecuador\n", - "Pacific/Gambier matched to Gambier, College Township, Knox County, Ohio, United States\n", - "Pacific/Guam matched to Guam, United States\n", - "Pacific/Kanton matched to Kanton, Phoenix Islands, Kiribati\n", - "Pacific/Kiritimati matched to Kiritimati, Line Islands, Kiribati\n", - "Pacific/Kosrae matched to Kosrae, Utwe, Kosrae, 96944, Micronesia\n", - "Pacific/Kwajalein matched to Kuwajleen, Rālik, Ṃajeḷ\n", - "Pacific/Marquesas matched to Îles Marquises, Polynésie Française, France\n", - "Pacific/Midway matched to Midway, Madison County, Texas, United States\n", - "Pacific/Nauru matched to Naoero\n", - "Pacific/Tahiti matched to Tahiti, Îles du Vent, Polynésie Française, France\n", - "Pacific/Wake matched to Wake County, North Carolina, United States\n" - ] - } - ], - "source": [ - "from geopy.geocoders import Nominatim\n", - "\n", - "geolocator = Nominatim(user_agent=\"Cinnamon Desktop Applet Auto-night-light, manual single shot\")\n", - "\n", - "for timezone_row in df_timezones.itertuples():\n", - " timezone = timezone_row.Index\n", - " subregion = timezone_row.subregion\n", - " geocode = geolocator.geocode(f\"{timezone_row.place}{f\", {subregion}\" if subregion else \"\"}\")\n", - " if not geocode:\n", - " print(f\"No coordinates found for {timezone}\")\n", - " continue\n", - " print(f\"{timezone} matched to {geocode.address}\")\n", - " df_timezones = df_timezones.drop(timezone)\n", - " df_results.loc[timezone] = [round(geocode.latitude, 5), round(geocode.longitude, 5)]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Remaining timezones to match" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
regionsubregionplace
timezone
Antarctica/DumontDUrvilleAntarcticaNoneDumontDUrville
\n", - "
" - ], - "text/plain": [ - " region subregion place\n", - "timezone \n", - "Antarctica/DumontDUrville Antarctica None DumontDUrville" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_timezones" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Matched timezones" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
latitudelongitude
timezone
America/Antigua17.11717-61.84573
America/Anguilla18.21704-63.05783
America/Argentina/Ushuaia-54.80000-68.30000
Pacific/Pago_Pago-14.27806-170.70250
Australia/Broken_Hill-31.96173141.45998
.........
Pacific/Marquesas-9.77941-139.00678
Pacific/Midway31.02602-95.75050
Pacific/Nauru-0.52523166.93244
Pacific/Tahiti-17.68734-149.44517
Pacific/Wake35.79794-78.61183
\n", - "

419 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " latitude longitude\n", - "timezone \n", - "America/Antigua 17.11717 -61.84573\n", - "America/Anguilla 18.21704 -63.05783\n", - "America/Argentina/Ushuaia -54.80000 -68.30000\n", - "Pacific/Pago_Pago -14.27806 -170.70250\n", - "Australia/Broken_Hill -31.96173 141.45998\n", - "... ... ...\n", - "Pacific/Marquesas -9.77941 -139.00678\n", - "Pacific/Midway 31.02602 -95.75050\n", - "Pacific/Nauru -0.52523 166.93244\n", - "Pacific/Tahiti -17.68734 -149.44517\n", - "Pacific/Wake 35.79794 -78.61183\n", - "\n", - "[419 rows x 2 columns]" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Check and rectify the results manually\n", - "\n", - "Check procedure:\n", - "- check if the `timezone` name makes sense with the address found,\n", - "- if not:\n", - " - search on a web search engine if the full `timezone` gives similar results to the address found by Nomatim,\n", - " - if not: find better or more values for a new search" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "America/Creston matched to Creston, Regional District of Central Kootenay, British Columbia, Canada\n", - "America/Dawson matched to Dawson City, Yukon, Y0B 1G0, Canada\n", - "America/St_Johns matched to Saint Johns Island, Labrador, Newfoundland and Labrador, Canada\n", - "America/St_Vincent matched to Saint Vincent and the Grenadines\n", - "America/Thule matched to Qaanaaq, Avannaata, 3971, Kalaallit Nunaat\n", - "Antarctica/Casey matched to Casey Station, Shirley Island Walking Route, Casey Station\n", - "Antarctica/Davis matched to Davis Station\n", - "Antarctica/DumontDUrville matched to Base Dumont d'Urville\n", - "Antarctica/Mawson matched to Mawson Station, Alternate Route, Mawson Station\n", - "Antarctica/McMurdo matched to McMurdo Station\n", - "Asia/Ho_Chi_Minh matched to Thành phố Hồ Chí Minh, Việt Nam\n", - "Atlantic/Canary matched to Canary Islands, España\n", - "Australia/Lindeman matched to Lindeman Island, Coral Sea, Mackay Regional, Queensland, Australia\n", - "Indian/Chagos matched to Chagos Archipelago, Downtown, British Indian Ocean Territory\n", - "Indian/Comoro matched to Archipel des Comores, Nzwani أنجوان, Comores Komori جزر القمر\n", - "Pacific/Chatham matched to Chatham Island, Chatham Islands, New Zealand / Aotearoa\n", - "Pacific/Easter matched to Isla de Pascua, Provincia de Isla de Pascua, Región de Valparaíso, 2770000, Chile\n", - "Pacific/Galapagos matched to Archipélago de Galápagos, Galápagos, Ecuador\n", - "Pacific/Gambier matched to Îles Gambier, Gambier, Tuamotu-Gambier, Polynésie Française, 98755, France\n", - "Pacific/Midway matched to Midway Atoll, United States\n", - "Pacific/Wake matched to United States Minor Outlying Islands, United States\n" - ] - } - ], - "source": [ - "timezones_to_search_again = {\n", - " 'America/Creston': {'city': \"Creston\", 'country': \"Canada\"},\n", - " 'America/Dawson': {'city': \"Dawson\", 'country': \"Canada\"},\n", - " 'America/St_Johns': \"Saint Johns Island, Canada\",\n", - " 'America/St_Vincent': \"Saint Vincent and the Grenadines\",\n", - " 'America/Thule': {'city': \"Thule\", 'country': \"Greenland\"},\n", - " 'Antarctica/Casey': \"Casey Station\",\n", - " 'Antarctica/Davis': \"Davis Station\",\n", - " 'Antarctica/DumontDUrville': \"Dumont d'Urville Station\",\n", - " 'Antarctica/Mawson': \"Mawson Station\",\n", - " 'Antarctica/McMurdo': \"McMurdo Station\",\n", - " 'Asia/Ho_Chi_Minh': {'city': \"Ho Chi Minh\", 'country': \"Vietnam\"},\n", - " 'Atlantic/Canary': \"Canary Islands, Spain\",\n", - " 'Australia/Lindeman': \"Lindeman Island, Australia\",\n", - " 'Indian/Chagos': \"Chagos Archipelago\",\n", - " 'Indian/Comoro': \"Comoro Islands\",\n", - " 'Pacific/Chatham': \"Chatham, New Zealand\",\n", - " 'Pacific/Easter': \"Easter Island, Chile\",\n", - " 'Pacific/Galapagos': \"Galapagos Islands\",\n", - " 'Pacific/Gambier': \"Gambier Islands\",\n", - " 'Pacific/Midway': \"Midway Atoll\",\n", - " 'Pacific/Wake': \"Minor Outlying Islands\"\n", - "}\n", - "\n", - "for timezone, search in timezones_to_search_again.items():\n", - " geocode = geolocator.geocode(search)\n", - " if not geocode:\n", - " print(f\"No coordinates found for {timezone}\")\n", - " continue\n", - " print(f\"{timezone} matched to {geocode.address}\")\n", - " df_results.loc[timezone] = [round(geocode.latitude, 5), round(geocode.longitude, 5)]" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
latitudelongitude
timezone
America/Antigua17.11717-61.84573
America/Anguilla18.21704-63.05783
America/Argentina/Ushuaia-54.80000-68.30000
Pacific/Pago_Pago-14.27806-170.70250
Australia/Broken_Hill-31.96173141.45998
.........
Pacific/Midway28.24175-177.37543
Pacific/Nauru-0.52523166.93244
Pacific/Tahiti-17.68734-149.44517
Pacific/Wake16.72882-169.53338
Antarctica/DumontDUrville-66.66328140.00110
\n", - "

420 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " latitude longitude\n", - "timezone \n", - "America/Antigua 17.11717 -61.84573\n", - "America/Anguilla 18.21704 -63.05783\n", - "America/Argentina/Ushuaia -54.80000 -68.30000\n", - "Pacific/Pago_Pago -14.27806 -170.70250\n", - "Australia/Broken_Hill -31.96173 141.45998\n", - "... ... ...\n", - "Pacific/Midway 28.24175 -177.37543\n", - "Pacific/Nauru -0.52523 166.93244\n", - "Pacific/Tahiti -17.68734 -149.44517\n", - "Pacific/Wake 16.72882 -169.53338\n", - "Antarctica/DumontDUrville -66.66328 140.00110\n", - "\n", - "[420 rows x 2 columns]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Export results" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "dict_results = df_results[['latitude', 'longitude']].T.to_dict('list')\n", - "\n", - "json_results = json.dumps(dict_results, sort_keys=True)\n", - "\n", - "with open('database.json', 'w') as f:\n", - " f.write(json_results)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/timezone_coordinates_finder.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/timezone_coordinates_finder.js deleted file mode 100644 index 0adbfd9dd64..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/timezones_coordinates/timezone_coordinates_finder.js +++ /dev/null @@ -1,30 +0,0 @@ -const {Gio} = imports.gi; - -/** A finder of timezone's city coordinates using a local database. */ -module.exports = class Timezone_coordinates_finder { - #database - - /** - * @param {string} path - The absolute path where the `timezones_coordinates.json` file is located. - * @throws {Error} - If the file cannot be loaded or JSON-parsed - */ - constructor(path) { - const file_path = `${path}/database.json`, - file = Gio.File.new_for_path(file_path), - [ok, contents] = file.load_contents(null); - - if (!ok) - throw new Error(`failed to load file/contents of '${file_path}'`); - - this.#database = JSON.parse(new TextDecoder().decode(contents)); // can throw - } - - /** - * Gets the latitude and longitude of the timezone's city. - * @param {string} timezone - The timezone to get the coordinates from. - * @returns {[number, number]} The system timezone's city latitude and longitude. - */ - find_coordinates(timezone) { - return this.#database[timezone]; - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/translator.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/translator.js deleted file mode 100644 index 1d86049741a..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/translator.js +++ /dev/null @@ -1,11 +0,0 @@ -const Gettext = imports.gettext; -const GLib = imports.gi.GLib; - -const UUID = 'auto-dark-light@gihaume'; // TODO: SSOT - -Gettext.bindtextdomain(UUID, GLib.get_home_dir() + "/.local/share/locale"); - -/** @param {string} string - The string to translate. */ -module.exports = function _(string) { - return Gettext.dgettext(UUID, string); -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/twilights_calculator/suncalc.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/twilights_calculator/suncalc.js deleted file mode 100644 index b95020594b7..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/twilights_calculator/suncalc.js +++ /dev/null @@ -1,172 +0,0 @@ -/* -LICENSE - -Copyright (c) 2014, Vladimir Agafonkin -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are -permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other materials - provided with the distribution - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* -(c) 2011-2015, Vladimir Agafonkin -SunCalc is a JavaScript library for calculating sun/moon position and light phases. -https://github.com/mourner/suncalc -*/ - -// This version has been reduced to contain only the useful parts for the `auto-dark-light` applet. - -(function () { 'use strict'; - - // shortcuts for easier to read formulas - - var PI = Math.PI, - sin = Math.sin, - cos = Math.cos, - asin = Math.asin, - acos = Math.acos, - rad = PI / 180; - - // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas - - - // date/time constants and conversions - - var dayMs = 1000 * 60 * 60 * 24, - J1970 = 2440588, - J2000 = 2451545; - - function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } - function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); } - function toDays(date) { return toJulian(date) - J2000; } - - - // general calculations for position - - var e = rad * 23.4397; // obliquity of the Earth - - function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); } - - - // general sun calculations - - function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } - - function eclipticLongitude(M) { - - var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center - P = rad * 102.9372; // perihelion of the Earth - - return M + C + P + PI; - } - - - var SunCalc = {}; - - - // sun times configuration (angle, morning name, evening name) - - var times = SunCalc.times = [ - [-0.833, 'sunrise', 'sunset' ], - [ -0.3, 'sunriseEnd', 'sunsetStart' ], - [ -6, 'dawn', 'dusk' ], - [ -12, 'nauticalDawn', 'nauticalDusk'], - [ -18, 'nightEnd', 'night' ], - [ 6, 'goldenHourEnd', 'goldenHour' ] - ]; - - // adds a custom time to the times config - - SunCalc.addTime = function (angle, riseName, setName) { - times.push([angle, riseName, setName]); - }; - - - // calculations for sun times - - var J0 = 0.0009; - - function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } - - function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; } - function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); } - - function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); } - function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; } - - // returns set time for the given sun altitude - function getSetJ(h, lw, phi, dec, n, M, L) { - - var w = hourAngle(h, phi, dec), - a = approxTransit(w, lw, n); - return solarTransitJ(a, M, L); - } - - - // calculates sun times for a given date, latitude/longitude, and, optionally, - // the observer height (in meters) relative to the horizon - - SunCalc.getTimes = function (date, lat, lng, height) { - - height = height || 0; - - var lw = rad * -lng, - phi = rad * lat, - - dh = observerAngle(height), - - d = toDays(date), - n = julianCycle(d, lw), - ds = approxTransit(0, lw, n), - - M = solarMeanAnomaly(ds), - L = eclipticLongitude(M), - dec = declination(L, 0), - - Jnoon = solarTransitJ(ds, M, L), - - i, len, time, h0, Jset, Jrise; - - - var result = { - solarNoon: fromJulian(Jnoon), - nadir: fromJulian(Jnoon - 0.5) - }; - - for (i = 0, len = times.length; i < len; i += 1) { - time = times[i]; - h0 = (time[0] + dh) * rad; - - Jset = getSetJ(h0, lw, phi, dec, n, M, L); - Jrise = Jnoon - (Jset - Jnoon); - - result[time[1]] = fromJulian(Jrise); - result[time[2]] = fromJulian(Jset); - } - - return result; - }; - - // export as Node module / AMD module / browser variable - if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc; - else if (typeof define === 'function' && define.amd) define(SunCalc); - else window.SunCalc = SunCalc; - -}()); diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/twilights_calculator/twilights_calculator.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/twilights_calculator/twilights_calculator.js deleted file mode 100644 index c6b03ea41b0..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/lib/twilights_calculator/twilights_calculator.js +++ /dev/null @@ -1,31 +0,0 @@ -const SunCalc = require('lib/twilights_calculator/suncalc.js'); -const Time_of_day = require('lib/time_of_day.js'); -const _ = require('lib/translator.js'); - -const {DateTime} = imports.gi.GLib; - -/** A twilight times calculator of the ~current day. */ -module.exports = class Twilights_calculator { - /** - * Gets the twilight times of the current day. - * @param {number} latitude The latitude of the location. - * @param {number} longitude The longitude of the location. - * @returns {{sunrise: Time_of_day, sunset: Time_of_day}} The twilight times of the current day. - * @throws {Error} If the calculation fails. - */ - static get_today(latitude, longitude) { - const now = DateTime.new_now_local().to_unix() * 1000, // [ms] - dates = SunCalc.getTimes(now, latitude, longitude); - - if (isNaN(dates.sunrise) || isNaN(dates.sunset)) - throw Error(_("unable to calculate twilight times, check coordinates format or range")); - - const [sunrise, sunset] = [dates.sunrise, dates.sunset].map(date => { - const unix_time = date.getTime() / 1000, // [s] - date_glib = DateTime.new_from_unix_local(unix_time); - return new Time_of_day(date_glib); - }); - - return {sunrise, sunset}; - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/settings-schema.json b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/settings-schema.json index 684f4eb0b83..5912f41d0fe 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/settings-schema.json +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/settings-schema.json @@ -1,290 +1,447 @@ { "layout": { "type": "layout", - "pages": ["settings", "light-mode", "dark-mode"], - "settings": { - "type": "page", - "title": "Settings", - "sections": [ - "settings_state", - "settings_control", - "settings_location" - ] - }, - "light-mode": { - "type": "page", - "title": "Light mode", - "sections": [ - "light-mode_themes", - "light-mode_others", - "light-mode_background", - "light-mode_commands" - ] - }, - "dark-mode": { - "type": "page", - "title": "Dark mode", - "sections": [ - "dark-mode_themes", - "dark-mode_others", - "dark-mode_background", - "dark-mode_commands" - ] - }, - - "settings_state": { - "type": "section", - "title": "State", - "keys": ["settings_state_switch_dark-mode"] - }, - "settings_control": { - "type": "section", - "title": "Control", - "keys": ["settings_control_switch_auto-mode"] - }, - "settings_location": { - "dependency": "settings_control_switch_auto-mode=true", - "type": "section", - "title": "Location", - "keys": [ - "settings_location_switch_sync-from-timezone", - "settings_location_button_open-os-settings", - "settings_location_entry_latitude", - "settings_location_entry_longitude", - "settings_location_button_show-twilight-times" - ] - }, - "light-mode_themes": { - "type": "section", - "title": "Themes", - "keys": [ - "light-mode_themes_button_open-os-settings", - "light-mode_themes_button_detect", - "light-mode_themes_entry_mouse-pointer", - "light-mode_themes_entry_applications", - "light-mode_themes_entry_icons", - "light-mode_themes_entry_desktop", - "light-mode_themes_button_apply" - ] - }, - "light-mode_others": { - "type": "section", - "title": "Others", - "keys": [ - "both-modes_background_switch_enable", - "light-mode_commands_switch_enable" - ] - }, - "light-mode_background": { - "dependency": "both-modes_background_switch_enable=true", - "type": "section", - "title": "Desktop background", - "keys": [ - "light-mode_background_button_open-os-settings", - "light-mode_background_button_detect", - "light-mode_background_switch_slideshow", - "light-mode_background_filechooser_file", - "light-mode_background_filechooser_folder", - "light-mode_background_button_apply" - ] - }, - "light-mode_commands": { - "dependency": "light-mode_commands_switch_enable=true", - "type": "section", - "title": "Custom commands", - "keys": [ - "light-mode_commands_list", - "light-mode_commands_button_launch" - ] - }, - "dark-mode_themes": { - "type": "section", - "title": "Themes", - "keys": [ - "dark-mode_themes_button_open-os-settings", - "dark-mode_themes_button_detect", - "dark-mode_themes_entry_mouse-pointer", - "dark-mode_themes_entry_applications", - "dark-mode_themes_entry_icons", - "dark-mode_themes_entry_desktop", - "dark-mode_themes_button_apply" - ] - }, - "dark-mode_others": { - "type": "section", - "title": "Others", - "keys": [ - "both-modes_background_switch_enable", - "dark-mode_commands_switch_enable" - ] - }, - "dark-mode_background": { - "dependency": "both-modes_background_switch_enable=true", - "type": "section", - "title": "Desktop background", - "keys": [ - "dark-mode_background_button_open-os-settings", - "dark-mode_background_button_detect", - "dark-mode_background_switch_slideshow", - "dark-mode_background_filechooser_file", - "dark-mode_background_filechooser_folder", - "dark-mode_background_button_apply" - ] - }, - "dark-mode_commands": { - "dependency": "dark-mode_commands_switch_enable=true", - "type": "section", - "title": "Custom commands", - "keys": [ - "dark-mode_commands_list", - "dark-mode_commands_button_launch" - ] - } - }, - - "settings_control_switch_auto-mode": { + "pages": ["general_page", "light_page", "dark_page"], + "general_page": { + "type": "page", + "title": "General", + "sections": [ + "appearance_section", + "light_schedule_section", + "dark_schedule_section", + "location_section" + ] + }, + "appearance_section": { + "type": "section", + "title": "Appearance", + "keys": [ + "is_appearance_dark", + "appearance_keybinding", + "is_appearance_auto", + "is_appearance_unsynced", + "next_update" + ] + }, + "light_schedule_section": { + "dependency": "is_appearance_auto=true", + "type": "section", + "title": "Sunrise", + "keys": [ + "is_sunrise_auto", + "manual_sunrise", + "auto_sunrise_offset", + "auto_sunrise" + ] + }, + "dark_schedule_section": { + "dependency": "is_appearance_auto=true", + "type": "section", + "title": "Sunset", + "keys": [ + "is_sunset_auto", + "manual_sunset", + "auto_sunset_offset", + "auto_sunset" + ] + }, + "location_section": { + "dependency": "is_appearance_auto=true", + "type": "section", + "title": "Location", + "keys": [ + "is_location_auto", + "open_os_location_settings", + "system_timezone", + "auto_latitude", + "auto_longitude", + "manual_latitude", + "manual_longitude" + ] + }, + "light_page": { + "type": "page", + "title": "Light", + "sections": [ + "light_themes_section", + "light_background_section", + "light_commands_section" + ] + }, + "light_themes_section": { + "type": "section", + "title": "Themes", + "keys": [ + "light_themes_open_os_settings_button", + "light_themes_detect_button", + "light_themes_mouse", + "light_themes_apps", + "light_themes_icons", + "light_themes_desktop", + "light_themes_apply_button", + "enable_background" + ] + }, + "light_background_section": { + "dependency": "enable_background=true", + "type": "section", + "title": "Desktop background", + "keys": [ + "light_background_open_os_settings_button", + "light_background_detect_button", + "light_background_is_slideshow", + "light_background_file", + "light_background_slideshow_folder", + "light_background_apply_button" + ] + }, + "light_commands_section": { + "type": "section", + "title": "Custom commands", + "keys": [ + "light_commands_is_enabled", + "light_commands_list", + "light_commands_launch_button" + ] + }, + "dark_page": { + "type": "page", + "title": "Dark", + "sections": [ + "dark_themes_section", + "dark_background_section", + "dark_commands_section" + ] + }, + "dark_themes_section": { + "type": "section", + "title": "Themes", + "keys": [ + "dark_themes_open_os_settings_button", + "dark_themes_detect_button", + "dark_themes_mouse", + "dark_themes_apps", + "dark_themes_icons", + "dark_themes_desktop", + "dark_themes_apply_button", + "enable_background" + ] + }, + "dark_background_section": { + "dependency": "enable_background=true", + "type": "section", + "title": "Desktop background", + "keys": [ + "dark_background_open_os_settings_button", + "dark_background_detect_button", + "dark_background_is_slideshow", + "dark_background_file", + "dark_background_slideshow_folder", + "dark_background_apply_button" + ] + }, + "dark_commands_section": { + "type": "section", + "title": "Custom commands", + "keys": [ + "dark_commands_is_enabled", + "dark_commands_list", + "dark_commands_launch_button" + ] + } + }, + "is_appearance_dark": { "type": "switch", "default": false, - "description": "Automatically switch modes", - "tooltip": "Automatically switch between light and dark modes based on the location and time of day" + "description": "Light/dark", + "tooltip": "Current appearance" + }, + "appearance_keybinding": { + "type": "keybinding", + "default": "", + "description": "Manual toggle shortcut", + "tooltip": "Keyboard shortcut to manually toggle between light and dark appearances" }, - "settings_state_switch_dark-mode": { + "is_appearance_auto": { "type": "switch", + "default": true, + "description": "Switch automatically", + "tooltip": "Automatically switch between light and dark appearances based on twilight times" + }, + "is_appearance_unsynced": { + "dependency": "is_appearance_auto=true", + "type": "custom", + "file": "./widgets/Switch_read_only.py", + "widget": "Switch", "default": false, - "description": "Light/dark mode", - "tooltip": "Toggle light or dark mode manually" + "description": "Unsynced with time and twilights", + "tooltip": "Whether the current appearance is unsynced regarding the current time and twilight times" + }, + "next_update": { + "dependency": "is_appearance_auto=true", + "type": "custom", + "file": "./widgets/Button_read_only.py", + "widget": "Button", + "default": "00:00", + "description": "Next update", + "tooltip": "Next time (HH:MM) when the automatic appearance switch will be evaluated" }, - "settings_state_is-auto-mode-inverted": { - "type": "generic", - "default": false + + "is_sunrise_auto": { + "type": "switch", + "default": true, + "description": "Sync from location", + "tooltip": "Dynamically sync the schedule from the location" + }, + "manual_sunrise": { + "dependency": "is_sunrise_auto!=true", + "type": "timechooser", + "default": { + "h": 6, + "m": 0, + "s": 0 + }, + "description": "Light appearance start time", + "tooltip": "Time (HH:MM(:SS)) when to switch to light appearance" + }, + "auto_sunrise_offset": { + "dependency": "is_sunrise_auto=true", + "type": "spinbutton", + "min": -120, + "max": 120, + "step": 1, + "units": "minutes", + "default": 0, + "wrap": false, + "description": "Offset", + "tooltip": "Offset in minutes to be added to the time calculated from the location" + }, + "auto_sunrise": { + "dependency": "is_sunrise_auto=true", + "type": "custom", + "file": "./widgets/Button_read_only.py", + "widget": "Button", + "default": "06:00", + "description": "Light appearance start time", + "tooltip": "Time (HH:MM) when to switch to light appearance" + }, + + "is_sunset_auto": { + "type": "switch", + "default": true, + "description": "Sync from location", + "tooltip": "Dynamically sync the schedule from location" + }, + "manual_sunset": { + "dependency": "is_sunset_auto!=true", + "type": "timechooser", + "default": { + "h": 18, + "m": 0, + "s": 0 + }, + "description": "Dark appearance start time", + "tooltip": "Time (HH:MM(:SS)) when to switch to dark appearance" + }, + "auto_sunset_offset": { + "dependency": "is_sunset_auto=true", + "type": "spinbutton", + "min": -120, + "max": 120, + "step": 1, + "units": "minutes", + "default": 0, + "wrap": false, + "description": "Offset", + "tooltip": "Offset in minutes to be added to the time calculated from the location" + }, + "auto_sunset": { + "dependency": "is_sunset_auto=true", + "type": "custom", + "file": "./widgets/Button_read_only.py", + "widget": "Button", + "default": "18:00", + "description": "Dark appearance start time", + "tooltip": "Time (HH:MM) when to switch to dark appearance" }, - "settings_location_switch_sync-from-timezone": { + + "is_location_auto": { "type": "switch", "default": true, - "description": "Sync from the system", + "description": "Sync from system", "tooltip": "Dynamically sync the location coordinates from the region and city defined in the system using a local database" }, - "settings_location_button_open-os-settings": { - "dependency": "settings_location_switch_sync-from-timezone=true", + "open_os_location_settings": { + "dependency": "is_location_auto=true", "type": "button", - "callback": "on_button_open_os_date_time_settings", + "callback": "on_button_open_os_timezone_settings", "description": "Open the system settings", "tooltip": "Open the system's settings window to select the region and city for the time zone" }, - "settings_location_entry_latitude": { - "dependency": "settings_location_switch_sync-from-timezone!=true", - "type": "entry", - "default": "0.0", + "system_timezone": { + "dependency": "is_location_auto=true", + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "", + "description": "System timezone", + "tooltip": "The current timezone (region/city) set in the system" + }, + "auto_latitude": { + "dependency": "is_location_auto=true", + "type": "custom", + "file": "./widgets/Spin_button_read_only.py", + "widget": "Spin_button", + "min": -90, + "max": 90, + "step": 0.001, + "default": 0, + "wrap": true, "description": "Latitude", - "tooltip": "Geographical latitude in decimal degrees" - }, - "settings_location_entry_longitude": { - "dependency": "settings_location_switch_sync-from-timezone!=true", - "type": "entry", - "default": "0.0", + "tooltip": "Geographical latitude in decimal degrees (°N)" + }, + "auto_longitude": { + "dependency": "is_location_auto=true", + "type": "custom", + "file": "./widgets/Spin_button_read_only.py", + "widget": "Spin_button", + "min": -180, + "max": 180, + "step": 0.001, + "default": 0, + "wrap": true, "description": "Longitude", - "tooltip": "Geographical longitude in decimal degrees" - }, - "settings_location_button_show-twilight-times": { - "type": "button", - "callback": "on_button_show_start_times", - "description": "Show switch times in a notification", - "tooltip": "Show today's switch times for light and dark modes based on the current location via a system notification message" + "tooltip": "Geographical longitude in decimal degrees (°E)" + }, + "manual_latitude": { + "dependency": "is_location_auto!=true", + "type": "spinbutton", + "min": -90, + "max": 90, + "step": 0.001, + "default": 0, + "wrap": true, + "description": "Latitude", + "tooltip": "Geographical latitude in decimal degrees (°N)" + }, + "manual_longitude": { + "dependency": "is_location_auto!=true", + "type": "spinbutton", + "min": -180, + "max": 180, + "step": 0.001, + "default": 0, + "wrap": true, + "description": "Longitude", + "tooltip": "Geographical longitude in decimal degrees (°E)" }, - "light-mode_themes_button_open-os-settings": { + + + "light_themes_open_os_settings_button": { "type": "button", "callback": "on_button_open_os_themes_settings", "description": "Open the system settings", "tooltip": "Open the system's settings window to select the themes" }, - "light-mode_themes_button_detect": { + "light_themes_detect_button": { "type": "button", "callback": "on_button_detect_themes_light", "description": "Detect from the system", - "tooltip": "Detect the system's themes currently set and assign them to the light mode" + "tooltip": "Detect the current system's themes settings and save them as presets" }, - "light-mode_themes_entry_mouse-pointer": { - "type": "entry", - "default": "", + "light_themes_mouse": { + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "Bibata-Modern-Classic", "description": "Mouse pointer", "tooltip": "Name of the mouse pointer theme" }, - "light-mode_themes_entry_applications": { - "type": "entry", - "default": "", + "light_themes_apps": { + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "Mint-Y-Aqua", "description": "Applications", "tooltip": "Name of the applications theme (GTK theme)" }, - "light-mode_themes_entry_icons": { - "type": "entry", - "default": "", + "light_themes_icons": { + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "Mint-Y-Sand", "description": "Icons", "tooltip": "Name of the icons theme" }, - "light-mode_themes_entry_desktop": { - "type": "entry", - "default": "", + "light_themes_desktop": { + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "Mint-Y-Aqua", "description": "Desktop", "tooltip": "Name of the desktop theme (Cinnamon theme)" }, - "light-mode_themes_button_apply": { + "light_themes_apply_button": { "type": "button", "callback": "on_button_apply_themes_light", "description": "Test applying to the system", - "tooltip": "Apply the light mode themes to the system manually" + "tooltip": "Apply the themes presets to the system manually" }, - "both-modes_background_switch_enable": { + "enable_background": { "type": "switch", "default": false, - "description": "Set desktop background", - "tooltip": "Enable setting the desktop backgrounds for light and dark modes" - }, - "light-mode_commands_switch_enable": { - "type": "switch", - "default": false, - "description": "Launch custom commands", - "tooltip": "Enable setting commands to be launched when switching to light mode" + "description": "Set desktop backgrounds", + "tooltip": "Enable desktop background settings as being part of the themes presets" }, - "light-mode_background_button_open-os-settings": { + + "light_background_open_os_settings_button": { "type": "button", "callback": "on_button_open_os_background_settings", "description": "Open the system settings", "tooltip": "Open the system's settings window to set the background settings" }, - "light-mode_background_button_detect": { + "light_background_detect_button": { "type": "button", "callback": "on_button_detect_background_light", "description": "Detect from the system", - "tooltip": "Detect the system's background settings currently set and assign them to the light mode" + "tooltip": "Detect the system's background settings currently set and save them as presets" }, - "light-mode_background_switch_slideshow": { + "light_background_is_slideshow": { "type": "switch", "default": false, "description": "Slideshow", "tooltip": "Set the desktop background to be a slideshow" }, - "light-mode_background_filechooser_file": { - "dependency": "light-mode_background_switch_slideshow!=true", + "light_background_file": { + "dependency": "light_background_is_slideshow!=true", "type": "filechooser", "default": "", "description": "Image file", "tooltip": "Image file to be set as the desktop background" }, - "light-mode_background_filechooser_folder": { - "dependency": "light-mode_background_switch_slideshow=true", + "light_background_slideshow_folder": { + "dependency": "light_background_is_slideshow=true", "type": "filechooser", "select-dir": true, "default": "", "description": "Images folder", "tooltip": "Folder containing images to be set for the desktop background slideshow" }, - "light-mode_background_button_apply": { + "light_background_apply_button": { "type": "button", "callback": "on_button_apply_background_light", "description": "Test applying to the system", - "tooltip": "Apply the light mode background settings to the system manually" + "tooltip": "Apply the desktop background presets to the system manually" }, - "light-mode_commands_list": { + + "light_commands_is_enabled": { + "type": "switch", + "default": false, + "description": "Launch custom commands", + "tooltip": "Enable setting commands to be launched when switching to this appearance" + }, + "light_commands_list": { + "dependency": "light_commands_is_enabled=true", "type" : "list", "columns" : [ {"id": "name", "title": "Name", "type": "string", "default": "unnamed"}, @@ -293,102 +450,115 @@ {"id": "command", "title": "Command", "type": "string"} ], "default" : [], - "tooltip" : "List of commands to be executed when switching to this mode\n\nNotes:\n- the name's purpose is for error messages\n- the expiry time terminates the command's process early\n- an expiry of 0 second means never\n- a process refusing to terminate 10 seconds after the expiry is killed\n- the path is in the user's home directory (~/)\n- the error messages are displayed in a notification and reports stderr" + "tooltip" : "List of commands to be executed when switching to this appearance\n\nNotes:\n- the name's purpose is for error messages\n- the expiry time terminates the command's process early\n- an expiry of 0 second means never\n- a process refusing to terminate 10 seconds after the expiry is killed\n- the path is in the user's home directory (~/)\n- the error messages are displayed in a notification and reports stderr" }, - "light-mode_commands_button_launch": { + "light_commands_launch_button": { + "dependency": "light_commands_is_enabled=true", "type": "button", "callback": "on_button_launch_commands_light", "description": "Test commands launch", - "tooltip": "Test launching the commands set for the light mode" + "tooltip": "Launch the commands manually" }, - "dark-mode_themes_button_open-os-settings": { + + + "dark_themes_open_os_settings_button": { "type": "button", "callback": "on_button_open_os_themes_settings", "description": "Open the system settings", "tooltip": "Open the system's settings window to select the themes" }, - "dark-mode_themes_button_detect": { + "dark_themes_detect_button": { "type": "button", "callback": "on_button_detect_themes_dark", "description": "Detect from the system", - "tooltip": "Detect the system's themes currently set and assign them to the dark mode" + "tooltip": "Detect the current system's themes settings and save them as presets" }, - "dark-mode_themes_entry_mouse-pointer": { - "type": "entry", - "default": "", + "dark_themes_mouse": { + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "Bibata-Modern-Classic", "description": "Mouse pointer", "tooltip": "Name of the mouse pointer theme" }, - "dark-mode_themes_entry_applications": { - "type": "entry", - "default": "", + "dark_themes_apps": { + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "Mint-Y-Dark-Aqua", "description": "Applications", "tooltip": "Name of the applications theme (GTK theme)" }, - "dark-mode_themes_entry_icons": { - "type": "entry", - "default": "", + "dark_themes_icons": { + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "Mint-Y-Sand", "description": "Icons", "tooltip": "Name of the icons theme" }, - "dark-mode_themes_entry_desktop": { - "type": "entry", - "default": "", + "dark_themes_desktop": { + "type": "custom", + "file": "./widgets/Entry_read_only.py", + "widget": "Entry", + "default": "Mint-Y-Dark-Aqua", "description": "Desktop", "tooltip": "Name of the desktop theme (Cinnamon theme)" }, - "dark-mode_themes_button_apply": { + "dark_themes_apply_button": { "type": "button", "callback": "on_button_apply_themes_dark", "description": "Test applying to the system", - "tooltip": "Apply the dark mode themes to the system manually" + "tooltip": "Apply the themes presets to the system manually" }, - "dark-mode_commands_switch_enable": { - "type": "switch", - "default": false, - "description": "Launch custom commands", - "tooltip": "Enable setting commands to be launched when switching to dark mode" - }, - "dark-mode_background_button_open-os-settings": { + "dark_background_open_os_settings_button": { "type": "button", "callback": "on_button_open_os_background_settings", "description": "Open the system settings", "tooltip": "Open the system's settings window to set the background settings" }, - "dark-mode_background_button_detect": { + "dark_background_detect_button": { "type": "button", "callback": "on_button_detect_background_dark", "description": "Detect from the system", - "tooltip": "Detect the system's background settings currently set and assign them to the dark mode" + "tooltip": "Detect the system's background settings currently set and save them as presets" }, - "dark-mode_background_switch_slideshow": { + "dark_background_is_slideshow": { "type": "switch", "default": false, "description": "Slideshow", "tooltip": "Set the desktop background to be a slideshow" }, - "dark-mode_background_filechooser_file": { - "dependency": "dark-mode_background_switch_slideshow!=true", + "dark_background_file": { + "dependency": "dark_background_is_slideshow!=true", "type": "filechooser", "default": "", "description": "Image file", "tooltip": "Image file to be set as the desktop background" }, - "dark-mode_background_filechooser_folder": { - "dependency": "dark-mode_background_switch_slideshow=true", + "dark_background_slideshow_folder": { + "dependency": "dark_background_is_slideshow=true", "type": "filechooser", "select-dir": true, "default": "", "description": "Images folder", "tooltip": "Folder containing images to be set for the desktop background slideshow" }, - "dark-mode_background_button_apply": { + "dark_background_apply_button": { "type": "button", "callback": "on_button_apply_background_dark", "description": "Test applying to the system", - "tooltip": "Apply the dark mode background settings to the system manually" + "tooltip": "Apply the desktop background presets to the system manually" + }, + + "dark_commands_is_enabled": { + "type": "switch", + "default": false, + "description": "Launch custom commands", + "tooltip": "Enable setting commands to be launched when switching to this appearance" }, - "dark-mode_commands_list": { + "dark_commands_list": { + "dependency": "dark_commands_is_enabled=true", "type" : "list", "columns" : [ {"id": "name", "title": "Name", "type": "string", "default": "unnamed"}, @@ -397,25 +567,28 @@ {"id": "command", "title": "Command", "type": "string"} ], "default" : [], - "tooltip" : "List of commands to be executed when switching to this mode\n\nNotes:\n- the name's purpose is for error messages\n- the expiry time kills the command's process\n- an expiry of 0 seconds means never\n- any child process won't be able to expire\n- the path is in the ~ directory\n- the error messages reports stderr when the return status is not 0 and will appear in a notification" + "tooltip" : "List of commands to be executed when switching to this appearance\n\nNotes:\n- the name's purpose is for error messages\n- the expiry time terminates the command's process early\n- an expiry of 0 second means never\n- a process refusing to terminate 10 seconds after the expiry is killed\n- the path is in the user's home directory (~/)\n- the error messages are displayed in a notification and reports stderr" }, - "dark-mode_commands_button_launch": { + "dark_commands_launch_button": { + "dependency": "dark_commands_is_enabled=true", "type": "button", "callback": "on_button_launch_commands_dark", "description": "Test commands launch", - "tooltip": "Test launching the commands set for the dark mode" + "tooltip": "Launch the commands manually" }, - "has-detected-themes-light": { + + "scheduler_timer_absolute_time": { "type": "generic", - "default": false + "default": 0 }, - "has-detected-themes-dark": { + + "light_themes_have_been_detected": { "type": "generic", "default": false }, - "timer-absolute-set-timeout": { + "dark_themes_have_been_detected": { "type": "generic", - "default": 0 + "default": false } } diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Button_read_only.py b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Button_read_only.py new file mode 100644 index 00000000000..a87e928bb0a --- /dev/null +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Button_read_only.py @@ -0,0 +1,30 @@ +from typing import Any + +from gettext import gettext as _ # For linter +from gi.repository import Gio, Gtk + +from JsonSettingsWidgets import SettingsWidget, JSONSettingsHandler + +class Button(SettingsWidget): + def __init__( + self, + info: dict[str, Any], + key: str, + settings: JSONSettingsHandler, + dep_key=None + ): + super().__init__(dep_key=dep_key) + + button = Gtk.Button.new() + + button.set_sensitive(False) + + description = _(info['description']) + label = Gtk.Label(label=description, halign=Gtk.Align.START) + + self.pack_start(label, False, False, 0) + self.pack_end(button, False, False, 0) + + settings.bind(key, button, 'label', Gio.SettingsBindFlags.DEFAULT) + + self.set_tooltip_text(_(info['tooltip']) if 'tooltip' in info else '') diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Entry_read_only.py b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Entry_read_only.py new file mode 100644 index 00000000000..d9cdceb8d50 --- /dev/null +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Entry_read_only.py @@ -0,0 +1,31 @@ +from typing import Any + +from gettext import gettext as _ # For linter +from gi.repository import Gio, Gtk + +from JsonSettingsWidgets import SettingsWidget, JSONSettingsHandler + +class Entry(SettingsWidget): + def __init__( + self, + info: dict[str, Any], + key: str, + settings: JSONSettingsHandler, + dep_key=None + ): + super().__init__(dep_key=dep_key) + + entry = Gtk.Entry() + entry.set_sensitive(False) + # entry.set_can_focus(False) + # entry.set_editable(False) + + description = _(info['description']) + label = Gtk.Label(label=description, halign=Gtk.Align.START) + + self.pack_start(label, False, False, 0) + self.pack_end(entry, False, False, 0) + + settings.bind(key, entry, 'text', Gio.SettingsBindFlags.DEFAULT) + + self.set_tooltip_text(_(info['tooltip']) if 'tooltip' in info else "") diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Spin_button_read_only.py b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Spin_button_read_only.py new file mode 100644 index 00000000000..3a0b28ab7ba --- /dev/null +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Spin_button_read_only.py @@ -0,0 +1,34 @@ +from typing import Any + +from gettext import gettext as _ # For linter +from gi.repository import Gio, Gtk + +from JsonSettingsWidgets import SettingsWidget, JSONSettingsHandler + +class Spin_button(SettingsWidget): + def __init__( + self, + info: dict[str, Any], + key: str, + settings: JSONSettingsHandler, + dep_key=None + ): + super().__init__(dep_key=dep_key) + + spinbutton = Gtk.SpinButton.new_with_range( + info['min'], info['max'], info['step'] + ) + spinbutton.set_sensitive(False) + + description = _(info['description']) + units = info.get('units') + if units is not None: + description += f" ({_(units)})" + label = Gtk.Label(label=description, halign=Gtk.Align.START) + + self.pack_start(label, False, False, 0) + self.pack_end(spinbutton, False, False, 0) + + settings.bind(key, spinbutton, 'value', Gio.SettingsBindFlags.DEFAULT) + + self.set_tooltip_text(_(info['tooltip']) if 'tooltip' in info else '') diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Switch_read_only.py b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Switch_read_only.py new file mode 100644 index 00000000000..dab104fcf88 --- /dev/null +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/widgets/Switch_read_only.py @@ -0,0 +1,29 @@ +from typing import Any + +from gettext import gettext as _ # For linter +from gi.repository import Gio, Gtk + +from JsonSettingsWidgets import SettingsWidget, JSONSettingsHandler + +class Switch(SettingsWidget): + def __init__( + self, + info: dict[str, Any], + key: str, + settings: JSONSettingsHandler, + dep_key=None + ): + super().__init__(dep_key=dep_key) + + toggle = Gtk.Switch() + toggle.set_sensitive(False) + + description = _(info['description']) + label = Gtk.Label(label=description, halign=Gtk.Align.START) + + self.pack_start(label, False, False, 0) + self.pack_end(toggle, False, False, 0) + + settings.bind(key, toggle, 'active', Gio.SettingsBindFlags.DEFAULT) + + self.set_tooltip_text(_(info['tooltip']) if 'tooltip' in info else "") diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/metadata.json b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/metadata.json index 1f5457383e0..ce6dc5404ba 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/metadata.json +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/metadata.json @@ -1,8 +1,8 @@ { "uuid": "auto-dark-light@gihaume", "name": "Automatic dark/light themes", - "description": "Automatically switch between dark and light themes at twilight times.", - "version": "1.2.6", + "description": "Automatically switch between dark and light appearances at twilight times.", + "version": "2.0.0", "max-instances": "1", "multiversion": true } diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/.gitignore b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/.gitignore new file mode 100644 index 00000000000..cd1f2c94391 --- /dev/null +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/.gitignore @@ -0,0 +1 @@ +*.mo diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/auto-dark-light@gihaume.pot b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/auto-dark-light@gihaume.pot index 9c516f438db..021f2567067 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/auto-dark-light@gihaume.pot +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/auto-dark-light@gihaume.pot @@ -5,10 +5,10 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: auto-dark-light@gihaume 1.2.5\n" +"Project-Id-Version: auto-dark-light@gihaume 2.0.0\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -17,97 +17,79 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 +msgid ":" msgstr "" -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" +#. 5.8/applet.js:1 +msgid "the command" msgstr "" -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" +#. 5.8/applet.js:1 +msgid "has failed" msgstr "" -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 -msgid ":" -msgstr "" - -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" +#. 5.8/applet.js:1 +msgid "due to a wrong format" msgstr "" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" +#. 5.8/applet.js:1 +msgid "Detail" msgstr "" -#. 5.8/applet.js:412 -msgid "Error" +#. 5.8/applet.js:1 +msgid "due to timeout" msgstr "" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" +#. 5.8/applet.js:1 +msgid "due to an error" msgstr "" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +msgid "Unknown compilation error" msgstr "" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" +#. 5.8/applet.js:1 +msgid "Failed compilation of" msgstr "" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +msgid "has written on its error output" msgstr "" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" +#. 5.8/applet.js:3 +msgid "toggle dark/light appearance" msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" +#. 5.8/applet.js:3 +msgid "Middle-click" msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" +#. 5.8/applet.js:3 +msgid "toggle automatic switch" msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "" - -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" +#. 2.2/applet.js:19 +msgid "Critical error" msgstr "" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +msgid "this applet only supports" msgstr "" #. metadata.json->name @@ -115,290 +97,367 @@ msgid "Automatic dark/light themes" msgstr "" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +msgid "" +"Automatically switch between dark and light appearances at twilight times." +msgstr "" + +#. 5.8->settings-schema.json->general_page->title +msgid "General" msgstr "" -#. 5.8->settings-schema.json->settings->title -msgid "Settings" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title -msgid "Themes" +#. 5.8->settings-schema.json->light_page->title +msgid "Light" msgstr "" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title +msgid "Themes" msgstr "" -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" +#. 5.8->settings-schema.json->dark_page->title +msgid "Dark" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_dark->description +msgid "Light/dark" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +msgid "" +"Automatically switch between light and dark appearances based on twilight " +"times" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_location_auto->description +msgid "Sync from system" +msgstr "" + +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" msgstr "" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" msgstr "" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description -msgid "Latitude" +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" msgstr "" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" msgstr "" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description -msgid "Longitude" +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description +msgid "Latitude" msgstr "" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +msgid "Geographical latitude in decimal degrees (°N)" msgstr "" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description +msgid "Longitude" msgstr "" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +msgid "Geographical longitude in decimal degrees (°E)" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +msgid "Detect the current system's themes settings and save them as presets" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" -msgstr "" - -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" -msgstr "" - -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +msgid "Apply the themes presets to the system manually" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" +#. 5.8->settings-schema.json->enable_background->description +msgid "Set desktop backgrounds" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" msgstr "" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +msgid "Apply the desktop background presets to the system manually" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -409,52 +468,12 @@ msgid "" "- the error messages are displayed in a notification and reports stderr" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +msgid "Launch the commands manually" msgstr "" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/ca.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/ca.po index 021848c69b8..6f1dbe43cae 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/ca.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/ca.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: 2025-09-28 16:17+0200\n" "Last-Translator: Odyssey \n" "Language-Team: \n" @@ -19,102 +19,91 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.6\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Clic: alterna el mode fosc/clar" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Clic del mig: alterna el mode de canvi automàtic" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "Hores de canvi de mode automàtic d'avui" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Mode clar" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "l'ordre" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Mode fosc" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "ha fallat" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Error" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "degut a un format invàlid" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Error crític" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "Detall" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "degut a l'esgotament del temps" + +#. 5.8/applet.js:1 +msgid "due to an error" +msgstr "per culpa d'un error" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +#, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "Falten les dependències `make` i/o `g++`. Instal·leu-les, per exemple, en " "sistemes basats en Debian, amb `sudo apt install make g++` i recarregueu la " "miniaplicació reiniciant Cinnamon." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "Compilació de" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "ha fallat" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "Compilació de" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "el subprocés" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "ha escrit a la seva sortida d'error" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -"no s'han pogut calcular les hores de crepuscle, reviseu el format o el rang " -"de les coordenades" - -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "l'ordre" -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "degut a un format invàlid" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "Clic: alterna el mode fosc/clar" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" -msgstr "Detall" +#. 5.8/applet.js:3 +msgid "Middle-click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "degut a l'esgotament del temps" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle automatic switch" +msgstr "Clic del mig: alterna el mode de canvi automàtic" -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" -msgstr "per culpa d'un error" +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Error crític" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +#, fuzzy +msgid "this applet only supports" msgstr "aquesta miniaplicació només és suportada per" #. metadata.json->name @@ -122,73 +111,166 @@ msgid "Automatic dark/light themes" msgstr "Temes fosc/clar automàtics" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "" "Canvia de manera automàtica entre els temes fosc i clar en hores de " "crepuscle." -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Opcions" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "Estat" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Control" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" + +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Ubicació" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "Mode clar" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Temes" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Altres" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Fons d'escriptori" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Ordres personalitzades" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Canvia de mode automàticament" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "Mode fosc" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "Mode clar/fosc" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "" "Canvia de modes entre clar i fosc basat en la ubicació i l'hora del dia" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Mode clar/fosc" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Alterna el mode clar o fosc manualment" +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "Sincronitza des del sistema" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -196,21 +278,18 @@ msgstr "" "Sincronitza de manera dinàmica les coordenades d'ubicació de la regió i " "ciutat definides al sistema utilitzant una base de dades local" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Obre la configuració del sistema" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" @@ -218,211 +297,211 @@ msgstr "" "Obre la finestra de la configuració del sistema per seleccionar regió i " "ciutat per la zona horària" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Latitud" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "Latitud geogràfica en graus decimals" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Longitud" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +#, fuzzy +msgid "Geographical longitude in decimal degrees (°E)" msgstr "Longitud geogràfica en graus decimals" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" -msgstr "Mostra els horaris de canvi en una notificació" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"Mostra els horaris de canvi d'avui entre els modes clar i fosc basats en la " -"ubicació actual mitjançant un missatge de notificació del sistema" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "" "Obre la finestra de configuració del sistema per a seleccionar els temes" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "Detecta des del sistema" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" -msgstr "Detecta els temes actius del sistema i els assigna al mode clar" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" +msgstr "Detecta els temes actius del sistema i els assigna al mode fosc" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Cursor del ratolí" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Nom del tema del cursor del ratolí" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Aplicacions" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Nom del tema d'aplicacions (tema GTK)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "Icones" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "Nom del tema d'icones" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Escriptori" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Nom del tema de l'escriptori (tema Cinnamon)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "Prova d'aplicar al sistema" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "Aplica els temes clars al sistema manualment" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "Establir fons d'escriptori" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" -msgstr "Activar l'establiment dels fons d'escriptori per als modes clar i fosc" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Llançar ordres personalitzades" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" -msgstr "Activar el llançament d'ordres en canviar al mode clar" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" +msgstr "" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "" "Obre la finestra de configuració del sistema per establir les opcions del " "fons d'escriptori" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" "Detecta els paràmetres establerts sobre el fons d'escriptori i els assigna " -"al mode clar" +"al mode fosc" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Presentació" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "Estableix el fons de l'escriptori com una presentació" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "Fitxer d'imatge" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "Fitxer d'imatge a establir com a fons de l'escriptori" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Carpeta d'imatges" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "" "Carpeta contenidora de les imatges a utilitzar per a la presentació dels " "fons d'escriptori" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" msgstr "" -"Aplica la configuració dels fons d'escriptori clars al sistema manualment" +"Aplica la configuració dels fons d'escriptori foscos al sistema manualment" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Llançar ordres personalitzades" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "Activar l'execució d'ordres en canviar al mode fosc" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Nom" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Actiu" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Esgotament (s)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Ordre" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip +#, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -442,65 +521,13 @@ msgstr "" "- La ruta és al directori de l'usuari (~/)\n" "- Els missatges d'error reporten a stderr i apareixeran en una notificació" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "Inicia la prova d'ordres" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "Prova a executar les ordres assignades pel mode clar" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "Detecta els temes actius del sistema i els assigna al mode fosc" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Aplica els temes foscos al sistema manualment" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "Activar l'execució d'ordres en canviar al mode fosc" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Detecta els paràmetres establerts sobre el fons d'escriptori i els assigna " -"al mode fosc" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "" -"Aplica la configuració dels fons d'escriptori foscos al sistema manualment" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Llista d'ordres que seran executades en canviar a aquest mode\n" -"\n" -"Notes:\n" -"- La finalitat del nom és facilitar la identificació de missatges d'error\n" -"- El temps d'esgotament interromp el procés d'execució de l'ordre\n" -"- Un temps d'esgotament de 0 segons significa mai\n" -"- Qualsevol procés fill no serà aturat\n" -"- La ruta és al directori ~\n" -"- Els missatges d'error reporten stderr quan l'estat del retorn no és 0 i " -"apareixeran en una notificació" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" -msgstr "Prova a executar les ordres assignades pel mode fosc" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +#, fuzzy +msgid "Launch the commands manually" +msgstr "Llançar ordres personalitzades" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/es.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/es.po index 8a9c98b0c21..938a63ed24a 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/es.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/es.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: 2025-05-18 11:23-0400\n" "Last-Translator: \n" "Language-Team: \n" @@ -18,102 +18,91 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.4.4\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Clic: alternar modo oscuro/claro" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Botón central: cambiar el modo de conmutación automática" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "Tiempos de cambio de modo automático de hoy" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Modo claro" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "el comando" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Modo oscuro" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "ha fallado" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Error" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "debido a un formato incorrecto" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Error crítico" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "Detalle" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "por expiración del plazo" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +msgid "due to an error" +msgstr "debido a un error" + +#. 5.8/applet.js:1 +#, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "Faltan las dependencias `make` y/o `g++`. Instálelas, por ejemplo, en un " "sistema basado en Debian con `sudo apt install make g++`, y vuelva a cargar " "el applet al reiniciar Cinnamon." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "Compilación de" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "ha fallado" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "Compilación de" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "el subproceso" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "escribió en su salida de error" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -"no puede calcular las horas crepusculares, compruebe el formato o el rango " -"de las coordenadas" -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "el comando" - -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "debido a un formato incorrecto" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "Clic: alternar modo oscuro/claro" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" -msgstr "Detalle" +#. 5.8/applet.js:3 +msgid "Middle-click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "por expiración del plazo" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle automatic switch" +msgstr "Botón central: cambiar el modo de conmutación automática" -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" -msgstr "debido a un error" +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Error crítico" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +#, fuzzy +msgid "this applet only supports" msgstr "este applet sólo es compatible con" #. metadata.json->name @@ -121,74 +110,167 @@ msgid "Automatic dark/light themes" msgstr "Temas oscuros/claro automáticos" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "" "Cambia automáticamente entre los temas oscuro y claro en las horas " "crepusculares." -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Configuraciones" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "Estado" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Control" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" + +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Ubicación" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "Modo claro" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Temas" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Otros" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Fondo de escritorio" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Comandos personalizados" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Cambio automático de modos" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "Modo oscuro" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "Modo claro/oscuro" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "" "Cambia automáticamente entre los modos claro y oscuro en función de la " "ubicación y la hora del día" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Modo claro/oscuro" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Alternar manualmente entre modo claro y modo oscuro" +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "Sincronización desde el sistema" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -196,21 +278,18 @@ msgstr "" "Sincronizar dinámicamente las coordenadas de localización de la región y la " "ciudad definidas en el sistema mediante una base de datos local" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Abrir la configuración del sistema" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" @@ -218,216 +297,216 @@ msgstr "" "Abra la ventana de configuración del sistema para seleccionar la región y la " "ciudad de la zona horaria" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Latitud" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "Latitud geográfica en grados decimales" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Longitud" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +#, fuzzy +msgid "Geographical longitude in decimal degrees (°E)" msgstr "Longitud geográfica en grados decimales" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" -msgstr "Mostrar la hora de cambio en una notificación" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"Mostrar las horas de conmutación de hoy para los modos claro y oscuro en " -"función de la ubicación actual a través de un mensaje de notificación del " -"sistema" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "" "Abra la ventana de configuración del sistema para seleccionar los temas" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "Detectar desde el sistema" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" msgstr "" -"Detecta los temas del sistema actualmente configurados y los asigna al modo " -"claro" +"Detectar los temas del sistema actualmente configurados y asignarlos al modo " +"oscuro" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Puntero del ratón" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Nombre del tema del puntero del ratón" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Aplicaciones" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Nombre del tema de la aplicación (tema GTK)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "Iconos" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "Nombre del tema de los iconos" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Escritorio" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Nombre del tema de escritorio (tema Cinnamon)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "Prueba de aplicación al sistema" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "Aplicar manualmente los temas del modo claro al sistema" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "Establecer fondo de escritorio" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" msgstr "" -"Habilitar la configuración de los fondos de escritorio para los modos claro " -"y oscuro" -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Lanzar comandos personalizados" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" -msgstr "Permitir el lanzamiento de comandos de ajuste al cambiar al modo claro" - -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "" "Abra la ventana de configuración del sistema para establecer la " "configuración del fondo" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" -"Detecta los ajustes de fondo del sistema actualmente configurados y los " -"asigna al modo de claro" +"Detectar los ajustes de fondo del sistema actualmente configurados y " +"asignarlos al modo oscuro" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Presentación" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "" "Configurar el fondo de escritorio para que sea una presentación de imágenes" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "Archivo de imagen" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "Archivo de imagen que se establecerá como fondo de escritorio" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Carpeta de imágenes" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "" "Carpeta que contiene las imágenes que se van a utilizar en la presentación " "de fondo de escritorio" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" -msgstr "Aplicar manualmente los ajustes de fondo del modo claro al sistema" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" +msgstr "" +"Aplicar manualmente la configuración de fondo del modo oscuro al sistema" + +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Lanzar comandos personalizados" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "" +"Permitir el lanzamiento de comandos de configuración al cambiar al modo " +"oscuro" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Nombre" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Activo" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Expiración" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Comando" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip +#, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -448,69 +527,13 @@ msgstr "" "- La ruta está en el directorio personal del usuario (~/)\n" "- Los mensajes de error se muestran en una notificación e informes de stderr" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "Lanzar comandos de prueba" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "Lanzamiento de prueba de los comandos establecidos para el modo claro" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "" -"Detectar los temas del sistema actualmente configurados y asignarlos al modo " -"oscuro" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Aplicar manualmente los temas del modo oscuro al sistema" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "" -"Permitir el lanzamiento de comandos de configuración al cambiar al modo " -"oscuro" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Detectar los ajustes de fondo del sistema actualmente configurados y " -"asignarlos al modo oscuro" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "" -"Aplicar manualmente la configuración de fondo del modo oscuro al sistema" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Lista de comandos que se ejecutarán al cambiar a este modo\n" -"\n" -"Notas:\n" -"- el propósito del nombre es para mensajes de error\n" -"- el tiempo de expiración mata el proceso del comando\n" -"- una expiración de 0 segundos significa nunca\n" -"- ningún proceso secundario podrá expirar\n" -"- la ruta está en el directorio ~\n" -"- los mensajes de error informan stderr cuando el estado de retorno no es 0 " -"y aparecerán en una notificación" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" -msgstr "Lanzamiento de prueba de los comandos establecidos para el modo oscuro" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +#, fuzzy +msgid "Launch the commands manually" +msgstr "Lanzar comandos personalizados" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/fi.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/fi.po index 390ef0196bd..986c58e330b 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/fi.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/fi.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: auto-dark-light@gihaume 1.2.1\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: \n" "Last-Translator: Kimmo Kujansuu \n" "Language-Team: \n" @@ -18,104 +18,91 @@ msgstr "" "X-Generator: Poedit 2.3\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Paina: tumma/vaalea tila vaihtuu" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Keskipainnallus: automaattinen vaihtotila" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "Tämän päivän autom. tilan vaihtoajat" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Vaalea tila" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "komento" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Tumma tila" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "epäonnistui" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Virhe" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "väärän formaatin takia" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Kriittinen virhe" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "ajan erääntymisen takia" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to an error" +msgstr "väärän formaatin takia" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 #, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "Puuttuvat riippuvuudet \"make\" ja \"gcc\". Asenna komennolla \"sudo apt " "install build-essential\", lataa sovelma sitten uudelleen (tai " "käyttöjärjestelmä uudelleen)." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "Koonti aiheesta" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "epäonnistui" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "Koonti aiheesta" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "taustaprosessi" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "kirjoitti virhetulokseen" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -"ei pysty laskemaan auringon laskun jälkeistä aikaa tai tarkistamaan maa " -"koordinaatteja" - -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "komento" -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "väärän formaatin takia" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "Paina: tumma/vaalea tila vaihtuu" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" +#. 5.8/applet.js:3 +msgid "Middle-click" msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "ajan erääntymisen takia" - -#. 5.8/lib/commands_launcher/commands_launcher.js:48 +#. 5.8/applet.js:3 #, fuzzy -msgid "due to an error" -msgstr "väärän formaatin takia" +msgid "toggle automatic switch" +msgstr "Keskipainnallus: automaattinen vaihtotila" + +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Kriittinen virhe" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +msgid "this applet only supports" msgstr "" #. metadata.json->name @@ -123,72 +110,165 @@ msgid "Automatic dark/light themes" msgstr "Autom. tumma/vaalea teema" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "Vaihtaa autom. tummien ja vaaleiden teemojen välillä hämärän tultua." -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Asetukset" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "Tila" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Hallinta" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" + +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Sijainti" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "Vaalea tila" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Teemat" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Muut" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Pöydän taustakuva" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Mukautetut komennot" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Autom. tilan vaihto" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "Tumma tila" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "Tila vaalea/tumma" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "" "Vaihtaa autom. vaalean ja tumman välillä sijainnin ja vuorokauden kellonajan " "mukaan" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Tila vaalea/tumma" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Vaihda vaalea tai tumma tila manuaalisesti" +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "Synkronoi tietokoneesta" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -196,228 +276,223 @@ msgstr "" "Synkronoi sijainnin koordinaatit tietokoneeseen annetun maan ja kaupungin " "mukaan" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Avaa tietokoneen asetukset" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" msgstr "Avaa asetusikkuna ja valitse aikavyöhyke ja kaupunki" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Leveysaste" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "Maantieteellinen leveysaste desimaaleina" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Pituusaste" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" -msgstr "Maantieteellinen pituusaste desimaaleina" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip #, fuzzy -msgid "Show switch times in a notification" -msgstr "Tarkista tämän päivän vaihtoajat ilmoituksesta" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"Näytä ilmoitusviestinä tämän päivän vaihtoajat vaalealle ja tummalle tilalle " -"nykyisen sijainnin perusteella" +msgid "Geographical longitude in decimal degrees (°E)" +msgstr "Maantieteellinen pituusaste desimaaleina" -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "Valitse teemat avaamalla asetusikkuna" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "Havaitse tietokoneesta" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" -msgstr "Tunnista tällä hetkellä asetetut teemat ja määritä ne vaaleaan tilaan" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" +msgstr "Tunnista tällä hetkellä asetetut teemat ja määritä ne tummaan tilaan" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Hiiren osoitin" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Hiiren osoittimen teeman nimi" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Sovellukset" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Sovellusten teeman nimi (GTK-teema)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "Kuvakkeet" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "Kuvakkeiden teeman nimi" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Pöytä" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Pödän teeman nimi (Cinnamon teema)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description #, fuzzy msgid "Test applying to the system" msgstr "Hyväksy nämä asetukset" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "Käytä vaaleita teemoja manuaalisesti" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "Aseta pöydän taustakuva" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" -msgstr "Aseta pöydän taustakuva vaaleille ja tummille tiloille" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Mukautetut komennot" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" -msgstr "Salli komentojen käynnistäminen kun vaihdat vaaleaan tilaan" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" +msgstr "" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "Avaa asetusikkuna taustakuville" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" -"Tunnista tällä hetkellä asetetut taustakuvat ja määritä ne vaaleaan tilaan" +"Tunnista tällä hetkellä asetetut taustakuvat ja määritä ne tummaan tilaan" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Diaesitys" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "Aseta diaesitys pöydän taustakuvaksi" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "Kuvatiedosto" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "Kuvatiedosto, joka asetetaan pöydän taustakuvaksi" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Kuvat kansio" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "" "Kansio, joka sisältää kuvat diaesitykseen ja näytetään pöydän taustakuvina" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" -msgstr "Käytä vaalean tilan taustakuvien asetuksia manuaalisesti" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" +msgstr "Käytä tumman tilan taustakuvien asetuksia manuaalisesti" + +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Mukautetut komennot" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "Salli komentojen käynnistäminen kun vaihdat tummaan tilaan" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Nimi" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Aktiivinen" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Erääntyy (s)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Komento" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip #, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -438,66 +513,14 @@ msgstr "" "- Virheilmoitukset raportoi stderr, kun paluutila ei ole 0 ja ne näkyvät " "ilmoituksena" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description #, fuzzy msgid "Test commands launch" msgstr "Mukautetut komennot" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip #, fuzzy -msgid "Test launching the commands set for the light mode" -msgstr "Käynnistää vaalealle tilalle asetetut komennot" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "Tunnista tällä hetkellä asetetut teemat ja määritä ne tummaan tilaan" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Käytä tummia teemoja manuaalisesti" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "Salli komentojen käynnistäminen kun vaihdat tummaan tilaan" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Tunnista tällä hetkellä asetetut taustakuvat ja määritä ne tummaan tilaan" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "Käytä tumman tilan taustakuvien asetuksia manuaalisesti" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Luettelo komennoista, jotka suoritetaan, kun vaihdat tähän tilaan\n" -"\n" -"Huomaa:\n" -"- nimen on virheilmoituksia varten\n" -"- erääntymisaika tappaa komennon prosessin\n" -"- 0 sekunnin erääntyminen tarkoittaa ei koskaan\n" -"- mikään aliprosessi ei voi erääntyä\n" -"- polku on ~-hakemistoon\n" -"- Virheilmoitukset raportoi stderr, kun paluutila ei ole 0 ja ne näkyvät " -"ilmoituksena" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -#, fuzzy -msgid "Test launching the commands set for the dark mode" -msgstr "Käynnistää tummalle tilalle asetetut komennot" +msgid "Launch the commands manually" +msgstr "Mukautetut komennot" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/fr.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/fr.po index 547dee5d06d..63e314d2ff3 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/fr.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/fr.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: auto-dark-light@gihaume 1.0.0\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" -"PO-Revision-Date: 2025-05-18 11:33+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" +"PO-Revision-Date: 2025-11-02 20:10+0100\n" "Last-Translator: gihaume \n" "Language-Team: \n" "Language: fr\n" @@ -18,177 +18,251 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.4.2\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Clique : basculer le mode sombre/clair" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Clique du milieu : basculer la commutation de mode automatique" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "Heures des commutations de mode automatiques d'aujourd'hui" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr " :" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Mode clair" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "la commande" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Mode sombre" +#. 5.8/applet.js:1 +msgid "has failed" +msgstr "a échoué" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Erreur" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "en raison d'un mauvais format" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Erreur critique" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "Détail" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +msgid "due to timeout" +msgstr "en raison de l'expiration du délai" + +#. 5.8/applet.js:1 +msgid "due to an error" +msgstr "en raison d'une erreur" + +#. 5.8/applet.js:1 msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "Dépendances `make` et/ou `g++` manquantes. Installez-les, p. ex. sur un " "système basé sur Debian avec `sudo apt install make g++`, puis rechargez " -"l'applet en redémarrant Cinnamon." +"l'applet en redémarrant Cinnamon (Ctrl+Alt+Esc)." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" -msgstr "La compilation de" +#. 5.8/applet.js:1 +msgid "Unknown compilation error" +msgstr "Erreur de compilation inconnue" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "a échoué" +#. 5.8/applet.js:1 +msgid "Failed compilation of" +msgstr "Échec de la compilation de" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "le sous-processus" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +msgid "has written on its error output" msgstr "a écrit sur sa sortie d'erreur" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" -msgstr "" -"impossible de calculer les heures de crépuscule, vérifiez le format ou la " -"plage des coordonnées" +#. 5.8/applet.js:3 +msgid "Click" +msgstr "Clique" -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "la commande" - -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "en raison d'un mauvais formattage" +#. 5.8/applet.js:3 +msgid "toggle dark/light appearance" +msgstr "basculer l'apparence sombre/claire" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" -msgstr "Détail" +#. 5.8/applet.js:3 +msgid "Middle-click" +msgstr "Clique central" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "en raison de l'expiration du délai" +#. 5.8/applet.js:3 +msgid "toggle automatic switch" +msgstr "basculer le mode automatique" -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" -msgstr "en raison d'une erreur" +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Erreur critique" #. 2.2/applet.js:20 -msgid "this applet is only supported by" -msgstr "cet applet est seulement supporté par" +msgid "this applet only supports" +msgstr "cet applet supporte seulement" #. metadata.json->name msgid "Automatic dark/light themes" msgstr "Thèmes sombres/clairs automatiques" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "" -"Basculer automatiquement entre les thèmes sombres et clairs aux heures de " -"crépuscule." +"Alterner automatiquement entre les apparences sombre et claire aux heures " +"des crépuscules." + +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "Général" -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Paramètres" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "Apparence" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "État" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "Lever du soleil" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Contrôle" +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "Coucher du soleil" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Emplacement" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +msgid "Light" +msgstr "Clair" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Thèmes" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Autres" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Arrière-plan du bureau" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Commandes personnalisées" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Basculer automatiquement entre les modes" +#. 5.8->settings-schema.json->dark_page->title +msgid "Dark" +msgstr "Sombre" + +#. 5.8->settings-schema.json->is_appearance_dark->description +msgid "Light/dark" +msgstr "Clair/sombre" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "Apparence actuelle" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "Raccourci de basculement manuel" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" +"Raccourci clavier pour alterner manuellement entre les apparences claire et " +"sombre" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "Basculer automatiquement" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +msgid "" +"Automatically switch between light and dark appearances based on twilight " +"times" +msgstr "" +"Alterner automatiquement entre les apparences claire et sombre en fonction " +"de l'emplacement et de l'heure de la journée" + +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "Désynchronisé avec l'heure et les crépuscules" + +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" +"Si l'apparence actuelle est désynchronisée par rapport à l'heure actuelle et " +"aux heures des crépuscules" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "Prochaine mise à jour" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->next_update->tooltip msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" msgstr "" -"Basculer automatiquement entre les modes clair et sombre en fonction de " -"l'emplacement et de l'heure de la journée" +"Prochaine heure (HH:MM) à laquelle le basculement automatique d'apparence " +"sera évalué" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "Synchroniser à l'emplacement" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "Synchroniser dynamiquement l'horaire à partir de l'emplacement" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "Heure de début de l'apparence claire" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "Heure (HH:MM(:SS)) à laquelle basculer à l'apparence claire" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "minutes" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "Décalage" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" +"Décalage en minute à ajouter à l'heure calculée à partir de l'emplacement" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "Heure (HH:MM) à laquelle basculer à l'apparence claire" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "Synchroniser dynamiquement l'horaire à partir de l'emplacement" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Mode clair/sombre" +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "Heure de début de l'apparence sombre" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Basculer entre mode clair ou sombre manuellement" +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "Heure (HH:MM(:SS)) à laquelle basculer à l'apparence sombre" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "Heure (HH:MM) à laquelle basculer à l'apparence sombre" + +#. 5.8->settings-schema.json->is_location_auto->description +msgid "Sync from system" msgstr "Synchroniser depuis le système" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -196,21 +270,18 @@ msgstr "" "Synchroniser dynamiquement les coordonnées de l'emplacement depuis la région " "et la ville définies dans le système en utilisant une base de données locale" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Ouvrir les paramètres du système" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" @@ -218,215 +289,208 @@ msgstr "" "Ouvrir la fenêtre des paramètres du système pour sélectionner la région et " "la ville pour le fuseau horaire" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "Fuseau horaire du système" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "Le fuseau horaire (région/ville) actuel du système" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Latitude" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" -msgstr "Latitude géographique en degrés décimaux" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +msgid "Geographical latitude in decimal degrees (°N)" +msgstr "Latitude géographique en degrés décimaux (°N)" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Longitude" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" -msgstr "Longitude géographique en degrés décimaux" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +msgid "Geographical longitude in decimal degrees (°E)" +msgstr "Longitude géographique en degrés décimaux (°E)" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" -msgstr "Montrer les heures de commutation dans une notification" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"Afficher les heures de commutation d'aujourd'hui pour les modes clair et " -"sombre en fonction de l'emplacement actuel via un message de notification du " -"système" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "" "Ouvrir la fenêtre des paramètres du système pour sélectionner les thèmes" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "Détecter depuis le système" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +msgid "Detect the current system's themes settings and save them as presets" msgstr "" -"Détecter les thèmes actuellement définis dans le système et les attribuer au " -"mode clair" +"Détecter les paramètres de thèmes actuels du système et les sauver comme pré-" +"réglages" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Pointeur de la souris" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Nom du thème du pointeur de la souris" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Applications" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Nom du thème des applications (thème GTK)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "Icônes" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "Nom du thème des icônes" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Bureau" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Nom du thème du bureau (thème Cinnamon)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "Tester d'appliquer au système" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" -msgstr "Appliquer manuellement les thèmes du mode clair au système" - -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" -msgstr "Définir l'arrière-plan du bureau" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +msgid "Apply the themes presets to the system manually" +msgstr "Appliquer manuellement les pré-réglages de thèmes au système" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" -msgstr "Définir les arrière-plans du bureau pour les modes clair et sombre" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Lancer des commandes personnalisées" +#. 5.8->settings-schema.json->enable_background->description +msgid "Set desktop backgrounds" +msgstr "Définir les arrière-plans du bureau" -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" msgstr "" -"Permettre de choisir des commandes à lancer lors du passage au mode clair" +"Activer les paramètres d'arrière-plan du bureau comme faisant partie des pré-" +"réglages de thèmes" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "" "Ouvrir la fenêtre des paramètres du système pour régler les paramètres " "d'arrière-plan du bureau" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" -"Détecter les paramètres d'arrière-plan du bureau actuellement définis dans " -"le système et les attribuer au mode clair" +"Détecter les paramètres d'arrière-plan actuels du système et les sauver " +"comme pré-réglages" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Diaporama" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "Définir l'arrière-plan du bureau comme diaporama" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "Fichier d'image" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "Fichier d'image à utiliser comme arrière-plan du bureau" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Dossier d'images" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "" "Dossier contenant des images à utiliser pour le diaporama d'arrière-plan du " "bureau" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +msgid "Apply the desktop background presets to the system manually" +msgstr "" +"Appliquer manuellement les pré-réglages d'arrière-plan du bureau au système" + +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Lancer des commandes personnalisées" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +msgid "" +"Enable setting commands to be launched when switching to this appearance" msgstr "" -"Appliquer manuellement les paramètres d'arrière-plan du mode clair au système" +"Permettre de choisir des commandes à lancer lors du basculement à cette " +"apparence" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Nom" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Activée" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Expiration (s)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Commande" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -436,7 +500,7 @@ msgid "" "- the path is in the user's home directory (~/)\n" "- the error messages are displayed in a notification and reports stderr" msgstr "" -"Liste des commandes à exécuter lors du passage vers ce mode\n" +"Liste des commandes à exécuter lors du basculement à cette apparence\n" "\n" "Notes :\n" "- le nom est utilisé pour les messages d'erreur\n" @@ -447,69 +511,12 @@ msgstr "" "- les messages d'erreur sont affichés dans une notification et rapportent " "stderr" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "Tester le lancement des commandes" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "Tester de lancer les commandes choisies pour le mode clair" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "" -"Détecter les thèmes actuellement définis dans le système et les attribuer au " -"mode sombre" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Appliquer manuellement les thèmes du mode sombre au système" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "" -"Permettre de choisir des commandes à lancer lors du passage au mode sombre" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Détecter les paramètres d'arrière-plan actuellement définis dans le système " -"et les attribuer au mode sombre" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "" -"Appliquer manuellement les paramètres d'arrière-plan du mode sombre au " -"système" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Liste des commandes à exécuter lors du passage vers ce mode\n" -"\n" -"Notes :\n" -"- le nom est utilisé pour les messages d'erreur\n" -"- le délai d'expiration tue le processus de la commande\n" -"- un délai d'expiration de 0 seconde signifie jamais\n" -"- le délai ne fait pas expirer les processus enfants\n" -"- le chemin d'accès est dans le répertoire ~\n" -"- les messages d'erreur rapportent stderr lorsque l'état de retour n'est pas " -"0 et apparaîtront dans une notification" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" -msgstr "Tester de lancer les commandes choisies pour le mode sombre" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +msgid "Launch the commands manually" +msgstr "Lancer les commandes manuellement" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/hu.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/hu.po index e98afb1713e..008841b2acc 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/hu.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/hu.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: auto-dark-light@gihaume 1.1.0\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -18,102 +18,91 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.6\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Kattintás: sötét/világos üzemmód váltása" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Középső kattintás: automatikus kapcsolási mód váltása" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "A mai automatikus üzemmódváltás ideje" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Világos mód" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "a parancs" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Sötét mód" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "sikertelen" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Hiba" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "rossz formátum miatt" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Kritikus hiba" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "Részlet" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "idő lejárta miatt" + +#. 5.8/applet.js:1 +msgid "due to an error" +msgstr "egy hiba miatt" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +#, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "Hiányzó `make` és/vagy `g++` függőségek. Telepítsd őket például Debian-alapú " "rendszerre a `sudo apt install make g++` paranccsal, majd indítsd újra az " "appletet a Cinnamon újraindításakor." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "A következő összeállítása:" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "sikertelen" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "A következő összeállítása:" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "az alfolyamat" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "írta a hibakimenetére" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -"nem tudja kiszámítani a szürkület idejét, ellenőrizze a koordináták " -"formátumát vagy tartományát" - -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "a parancs" -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "rossz formátum miatt" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "Kattintás: sötét/világos üzemmód váltása" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" -msgstr "Részlet" +#. 5.8/applet.js:3 +msgid "Middle-click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "idő lejárta miatt" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle automatic switch" +msgstr "Középső kattintás: automatikus kapcsolási mód váltása" -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" -msgstr "egy hiba miatt" +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Kritikus hiba" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +#, fuzzy +msgid "this applet only supports" msgstr "ezt a kisalkalmazást csak a következő támogatja:" #. metadata.json->name @@ -121,72 +110,165 @@ msgid "Automatic dark/light themes" msgstr "Automatic dark/light themes" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "Automatikus váltás a sötét és világos témák között szürkületkor." -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Beállítások" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "Állapot" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Vezérlés" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" + +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Hely" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "Világos mód" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Témák" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Mások" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Asztal háttere" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Egyéni parancsok" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Automatikus üzemmódváltás" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "Sötét mód" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "Világos/sötét üzemmód" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "" "Automatikus váltás a világos és sötét üzemmódok között a helyszín és a " "napszak alapján" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Világos/sötét üzemmód" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Világos vagy sötét üzemmód manuális váltása" +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "Szinkronizálás a rendszerből" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -194,21 +276,18 @@ msgstr "" "Dinamikusan szinkronizálja a helykoordinátákat a rendszerben meghatározott " "régióból és városból egy helyi adatbázis segítségével" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Nyissa meg a rendszerbeállításokat" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" @@ -216,211 +295,209 @@ msgstr "" "Nyissa meg a rendszer beállítási ablakát az időzóna régiójának és városának " "kiválasztásához" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Magasság" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "Földrajzi szélesség tizedes fokban" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Hosszúság" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +#, fuzzy +msgid "Geographical longitude in decimal degrees (°E)" msgstr "Földrajzi hosszúság tizedes fokban" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" -msgstr "Kapcsolási idők megjelenítése értesítésben" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"A világos és sötét üzemmódok mai kapcsolási idejének megjelenítése az " -"aktuális hely alapján egy rendszerértesítési üzenetben" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "Nyissa meg a rendszer beállítások ablakát a témák kiválasztásához" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "A rendszerből történő észlelés" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" msgstr "" -"A rendszer jelenleg beállított témáinak felismerése és hozzárendelése a " -"világos módhoz" +"Felismeri a rendszer jelenleg beállított témáit, és hozzárendeli őket a " +"sötét módhoz" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Egérmutató" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Az egérmutató témájának neve" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Alkalmazások" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Az alkalmazások témájának neve (GTK téma)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "Ikonok" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "Az ikonok témájának neve" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Asztal" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Az asztali téma neve (Cinnamon téma)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "A rendszerre vonatkozó teszt" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "A világítási mód témáinak manuális alkalmazása a rendszerre" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "Asztali háttér beállítása" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" msgstr "" -"Engedélyezze az asztal hátterének beállítását világos és sötét módokhoz" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Egyéni parancsok indítása" -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" -msgstr "" -"Engedélyezze a beállítási parancsok elindítását, amikor világos üzemmódra " -"vált" - -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "" "Nyissa meg a rendszer beállítási ablakát a háttérbeállítások beállításához" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" -"A rendszer jelenleg beállított háttérbeállításainak felismerése és " -"hozzárendelése a világos módhoz" +"Felismeri a rendszer jelenleg beállított háttérbeállításait, és hozzárendeli " +"azokat a sötét módhoz" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Diavetítés" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "Az asztali háttér beállítása diavetítésre" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "Képfájl" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "Az asztali háttérként beállítandó képfájl" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Képek mappa" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "Az asztali háttér diavetítéshez beállítandó képeket tartalmazó mappa" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" -msgstr "A fénymód háttérbeállításainak manuális alkalmazása a rendszerre" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" +msgstr "Alkalmazza a sötét mód háttérbeállításait a rendszerre manuálisan" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Egyéni parancsok indítása" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "" +"Engedélyezze a beállítási parancsok elindítását, amikor sötét módba vált" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Név" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Aktív" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Lejárat(ok)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Parancs" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip +#, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -442,67 +519,13 @@ msgstr "" "- a hibaüzenetek egy értesítésben jelennek meg, és a standard könyvtárból " "(stderr) jelentést küldenek" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "Tesztparancsok indítása" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "A világos módhoz beállított parancsok elindításának tesztelése" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "" -"Felismeri a rendszer jelenleg beállított témáit, és hozzárendeli őket a " -"sötét módhoz" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Alkalmazza a sötét üzemmód témáit a rendszerre manuálisan" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "" -"Engedélyezze a beállítási parancsok elindítását, amikor sötét módba vált" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Felismeri a rendszer jelenleg beállított háttérbeállításait, és hozzárendeli " -"azokat a sötét módhoz" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "Alkalmazza a sötét mód háttérbeállításait a rendszerre manuálisan" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Az ebbe a módba váltáskor végrehajtandó parancsok listája\n" -"\n" -"Megjegyzések:\n" -"- a név célja a hibaüzenetek\n" -"- a lejárati idő leállítja a parancs folyamatát\n" -"- 0 másodperc lejárta azt jelenti, hogy soha\n" -"- az alárendelt folyamatok nem járhatnak le\n" -"- az elérési út a ~ könyvtárban van\n" -"- a hibaüzenetek az stderr-t jelentik, ha a visszatérési állapot nem 0, és " -"értesítésben jelenik meg" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" -msgstr "A sötét módhoz beállított parancsok elindításának tesztelése" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +#, fuzzy +msgid "Launch the commands manually" +msgstr "Egyéni parancsok indítása" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/it.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/it.po index a5c3c9ed448..509d7711be4 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/it.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/it.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: auto-dark-light@gihaume 1.2.1\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: \n" "Last-Translator: Dragone2 \n" "Language-Team: \n" @@ -18,102 +18,91 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.4.2\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Clic: attiva/disattiva la modalità scura/chiara" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Clic centrale: attiva/disattiva la modalità di commutazione automatica" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "Orari di cambio modalità automatica di oggi" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Modalità chiara" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "il comando" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Modalità scura" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "fallita" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Errore" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "a causa di un formato errato" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Errore critico" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "Dettagli" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "a causa della scadenza del tempo" + +#. 5.8/applet.js:1 +msgid "due to an error" +msgstr "a causa di un errore" + +#. 5.8/applet.js:1 +#, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "Dipendenze mancanti `make` e/o `g++`. Installarle, ad esempio su un sistema " "basato su Debian, con `sudo apt install make g++`, quindi ricaricare " "l'applet riavviando Cinnamon." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "Compilazione di" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "fallita" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "Compilazione di" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "il sottoprocesso" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "ha scritto sul suo output di errore" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -"impossibile calcolare gli orari del crepuscolo, controllare il formato o " -"l'intervallo delle coordinate" -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "il comando" - -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "a causa di un formato errato" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "Clic: attiva/disattiva la modalità scura/chiara" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" -msgstr "Dettagli" +#. 5.8/applet.js:3 +msgid "Middle-click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "a causa della scadenza del tempo" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle automatic switch" +msgstr "Clic centrale: attiva/disattiva la modalità di commutazione automatica" -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" -msgstr "a causa di un errore" +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Errore critico" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +#, fuzzy +msgid "this applet only supports" msgstr "questa applet è solo supportata da" #. metadata.json->name @@ -121,74 +110,167 @@ msgid "Automatic dark/light themes" msgstr "Temi scuri/chiari automatici" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "" "Passa automaticamente dal tema scuro a quello chiaro e viceversa al " "crepuscolo." -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Impostazioni" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "Stato" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Controllo" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" + +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Posizione" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "Modalità chiara" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Temi" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Altri" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Sfondo del desktop" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Comandi personalizzati" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Cambia automaticamente modalità" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "Modalità scura" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "Modalità chiara/scura" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "" "Passa automaticamente dalla modalità chiara a quella scura in base alla " "posizione e all'ora del giorno" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Modalità chiara/scura" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Attiva/disattiva manualmente la modalità chiara o scura" +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "Sincronizza dal sistema" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -196,21 +278,18 @@ msgstr "" "Sincronizza dinamicamente le coordinate della posizione dalla regione e " "dalla città definite nel sistema utilizzando un database locale" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Aprire le impostazioni di sistema" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" @@ -218,217 +297,214 @@ msgstr "" "Apre la finestra delle impostazioni del sistema per selezionare la regione e " "la città per il fuso orario" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Latitudine" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "Latitudine geografica in gradi decimali" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Longitudine" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +#, fuzzy +msgid "Geographical longitude in decimal degrees (°E)" msgstr "Longitudine geografica in gradi decimali" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" -msgstr "Mostra gli orari di cambio in una notifica" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"Mostra gli orari di commutazione odierni per le modalità luce e buio in base " -"alla posizione corrente tramite un messaggio di notifica di sistema" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "Apre la finestra delle impostazioni del sistema per selezionare i temi" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "Rileva dal sistema" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" msgstr "" "Rileva i temi del sistema attualmente impostati e li assegna alla modalità " -"chiara" +"scura" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Puntatore del mouse" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Nome del tema del puntatore del mouse" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Applicazioni" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Nome del tema dell'applicazione (tema GTK)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "Icone" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "Nome del tema delle icone" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Scrivania" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Nome del tema del desktop (tema Cinnamon)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "Testa applicando al sistema" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "Applica manualmente i temi della modalità chiara al sistema" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "Imposta sfondo desktop" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" -msgstr "" -"Abilita l'impostazione degli sfondi del desktop per le modalità chiara e " -"scura" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Avvia comandi personalizzati" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" msgstr "" -"Abilita i comandi di impostazione da avviare quando si passa alla modalità " -"chiara" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "" "Apre la finestra delle impostazioni del sistema per impostare le " "impostazioni dello sfondo" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" "Rileva le impostazioni di sfondo del sistema attualmente impostate e le " -"assegna alla modalità chiara" +"assegna alla modalità scura" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Presentazione" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "Imposta lo sfondo del desktop come presentazione" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "File immagine" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "File immagine da impostare come sfondo del desktop" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Cartella immagini" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "" "Cartella contenente le immagini da impostare per la presentazione sullo " "sfondo del desktop" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" msgstr "" -"Applica manualmente le impostazioni dello sfondo in modalità chiara al " -"sistema" +"Applica manualmente le impostazioni dello sfondo in modalità scura al sistema" + +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Avvia comandi personalizzati" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "" +"Abilita i comandi di impostazione da avviare quando si passa alla modalità " +"scura" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Nome" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Attiva" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Scadenza (s)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Comando" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip +#, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -450,69 +526,13 @@ msgstr "" "- i messaggi di errore vengono visualizzati in una notifica e riportano " "stderr" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "Avvia i comandi di prova" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "Prova ad avviare i comandi impostati per la modalità chiara" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "" -"Rileva i temi del sistema attualmente impostati e li assegna alla modalità " -"scura" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Applica manualmente i temi della modalità scura al sistema" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "" -"Abilita i comandi di impostazione da avviare quando si passa alla modalità " -"scura" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Rileva le impostazioni di sfondo del sistema attualmente impostate e le " -"assegna alla modalità scura" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "" -"Applica manualmente le impostazioni dello sfondo in modalità scura al sistema" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Elenco dei comandi da eseguire quando si passa a questa modalità\n" -"\n" -"Nota:\n" -"- lo scopo del nome è per i messaggi di errore\n" -"- il tempo di scadenza uccide il processo del comando\n" -"- una scadenza di 0 secondi significa mai\n" -"- nessun processo figlio potrà scadere\n" -"- il percorso è nella directory ~\n" -"- i messaggi di errore segnalano stderr quando lo stato di ritorno non è 0 e " -"appariranno in una notifica" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" -msgstr "Prova ad avviare i comandi impostati per la modalità scura" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +#, fuzzy +msgid "Launch the commands manually" +msgstr "Avvia comandi personalizzati" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/nl.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/nl.po index a872286f56e..7ebb6655a13 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/nl.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/nl.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: auto-dark-light@gihaume 1.1.0\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: 2025-06-13 18:21+0200\n" "Last-Translator: qadzek\n" "Language-Team: \n" @@ -17,102 +17,91 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.4.2\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Klik: schakelen tussen donkere/lichte modus" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Middelklik: in- en uitschakelen van automatische omschakelingsmodus" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "Automatische omschakeltijden van vandaag" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Lichte modus" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "het commando" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Donkere modus" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "mislukt" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Fout" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "vanwege een verkeerd formaat" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Kritieke fout" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "Detail" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "vanwege tijdsoverschrijding" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +msgid "due to an error" +msgstr "vanwege een fout" + +#. 5.8/applet.js:1 +#, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "Ontbrekende afhankelijkheden `make` en/of `gcc`. Installeer ze, bv. op een " "Debian-gebaseerd systeem met `sudo apt install make g++`, en herlaad " "vervolgens de applet door Cinnamon opnieuw op te starten." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "Compilatie van" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "mislukt" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "Compilatie van" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "het subprocess" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "schreef naar zijn foutuitvoer" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -"kan de schemeringstijden niet berekenen, controleer het coördinatenformaat " -"of het bereik" -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "het commando" - -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "vanwege een verkeerd formaat" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "Klik: schakelen tussen donkere/lichte modus" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" -msgstr "Detail" +#. 5.8/applet.js:3 +msgid "Middle-click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "vanwege tijdsoverschrijding" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle automatic switch" +msgstr "Middelklik: in- en uitschakelen van automatische omschakelingsmodus" -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" -msgstr "vanwege een fout" +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Kritieke fout" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +#, fuzzy +msgid "this applet only supports" msgstr "deze applet wordt alleen ondersteund door" #. metadata.json->name @@ -120,73 +109,166 @@ msgid "Automatic dark/light themes" msgstr "Automatische donkere/lichte thema's" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "" "Schakel automatisch tussen donkere en lichte thema's op schemeringstijden." -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Instellingen" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" + +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "Staat" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Besturing" +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Locatie" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "Lichte modus" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Thema's" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Overige" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Bureaubladachtergrond" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Aangepaste commando's" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Automatisch schakelen tussen modi" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "Donkere modus" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "Lichte/donkere modus" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "" "Automatisch schakelen tussen lichte en donkere modi op basis van de locatie " "en het tijdstip van de dag" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Lichte/donkere modus" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Handmatig schakelen tussen lichte of donkere modus" +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "Synchroniseer met het systeem" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -194,21 +276,18 @@ msgstr "" "Dynamisch synchroniseren van de locatiecoördinaten op basis van de regio en " "stad gedefinieerd in het systeem met een lokale database" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Open de systeeminstellingen" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" @@ -216,217 +295,216 @@ msgstr "" "Open het instellingenvenster van het systeem om de regio en stad voor de " "tijdzone te selecteren" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Breedtegraad" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "Geografische breedte in decimale graden" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Lengtegraad" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +#, fuzzy +msgid "Geographical longitude in decimal degrees (°E)" msgstr "Geografische lengte in decimale graden" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" -msgstr "Toont schakeltijden in een melding" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"Toon de omschakeltijden voor lichte en donkere modi op basis van de huidige " -"locatie via een systeemwaarschuwingsbericht" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "" "Open het instellingenvenster van het systeem om de thema's in te stellen" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "Detecteer vanuit het systeem" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" msgstr "" "Detecteer de momenteel ingestelde thema's van het systeem en wijs ze toe aan " -"de lichte modus" +"de donkere modus" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Muisaanwijzer" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Naam van het muisaanwijzer-thema" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Toepassingen" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Naam van het toepassings-thema (GTK-thema)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "Pictogrammen" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "Naam van het pictogrammen-thema" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Bureaublad" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Naam van het bureaublad-thema (Cinnamon-thema)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "Test toepassen op het systeem" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "Pas de lichte modus thema's handmatig toe op het systeem" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "Stel bureaubladachtergrond in" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" -msgstr "" -"Schakel instellen in van bureaubladachtergrond voor lichte en donkere modi" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Start aangepaste commando's" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" msgstr "" -"Inschakelen van commando's om uit te voeren bij het overschakelen naar de " -"lichte modus" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "" "Open het instellingenvenster van het systeem om de achtergrondinstellingen " "in te stellen" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" "Detecteer de momenteel ingestelde achtergrondinstellingen van het systeem en " -"wijs ze toe aan de lichte modus" +"wijs ze toe aan de donkere modus" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Diavoorstelling" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "Stel de bureaubladachtergrond in als een diavoorstelling" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "Afbeeldingsbestand" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "Afbeeldingsbestand om in te stellen als bureaubladachtergrond" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Afbeeldingenmap" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "" "Map met afbeeldingen om in te stellen voor de bureaubladachtergrond " "diavoorstelling" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" msgstr "" -"Pas de achtergrondinstellingen van de lichte modus handmatig toe op het " +"Pas de achtergrondinstellingen van de donkere modus handmatig toe op het " "systeem" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Start aangepaste commando's" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "" +"Inschakelen van commando's om uit te voeren bij het overschakelen naar de " +"donkere modus" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Naam" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Actief" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Verlooptijd (s)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Commando" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip +#, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -448,71 +526,13 @@ msgstr "" " - het pad bevindt zich in de home-directory van de gebruiker (~/)\n" " - de foutmeldingen worden weergegeven in een melding en rapporteren stderr" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "Testcommando’s starten" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "Test het starten van de commando’s voor de lichte modus" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "" -"Detecteer de momenteel ingestelde thema's van het systeem en wijs ze toe aan " -"de donkere modus" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Pas de donkere modus thema's handmatig toe op het systeem" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "" -"Inschakelen van commando's om uit te voeren bij het overschakelen naar de " -"donkere modus" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Detecteer de momenteel ingestelde achtergrondinstellingen van het systeem en " -"wijs ze toe aan de donkere modus" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "" -"Pas de achtergrondinstellingen van de donkere modus handmatig toe op het " -"systeem" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Lijst met commando's die moeten worden uitgevoerd bij het overschakelen naar " -"deze modus\n" -" \n" -" Opmerkingen:\n" -" - de naam wordt gebruikt voor foutmeldingen\n" -" - de verlooptijd beëindigt het proces van het commando\n" -" - een verlooptijd van 0 seconden betekent nooit\n" -" - elk subprocess kan niet verlopen\n" -" - het pad bevindt zich in de ~ map\n" -" - de foutmeldingen rapporteren stderr wanneer de terugkeerstatus niet 0 is " -"en verschijnen in een melding" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" -msgstr "Test het starten van de commando’s voor de donkere modus" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +#, fuzzy +msgid "Launch the commands manually" +msgstr "Start aangepaste commando's" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/tr.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/tr.po index 6b3c8f8efa7..6f37a40527d 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/tr.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/tr.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: auto-dark-light@gihaume 1.2.1\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: 2025-04-20 19:00+0300\n" "Last-Translator: @cevheri\n" "Language-Team: \n" @@ -17,104 +17,91 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Tıkla: karanlık/aydınlık modu değiştir" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Orta-tıkla: otomatik değiştirme modunu aç/kapat" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "Bugünün otomatik mod geçiş zamanları" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Aydınlık modu" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "komut" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Karanlık modu" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "başarısız oldu" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Hata" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "yanlış format nedeniyle" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Kritik hata" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "zaman aşımı nedeniyle" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to an error" +msgstr "yanlış format nedeniyle" + +#. 5.8/applet.js:1 #, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "`make` ve `gcc` bağımlılıkları eksik. Örnek olarak: Debian tabanlı bir " "sistemde `sudo apt install build-essential` komutuyla yükleyin, ardından " "appleti yeniden yükleyin (Cinnamon'ı yeniden başlatmak gibi)." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "Derlenmesi" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "başarısız oldu" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "Derlenmesi" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "alt süreç" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "hata çıktısına yazdı" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -"Alacakaranlık(gün doğumu/batımı) zamanlarını hesaplanamadı, koordinat " -"formatını veya aralığı kontrol edin" -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "komut" - -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "yanlış format nedeniyle" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "Tıkla: karanlık/aydınlık modu değiştir" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" +#. 5.8/applet.js:3 +msgid "Middle-click" msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "zaman aşımı nedeniyle" - -#. 5.8/lib/commands_launcher/commands_launcher.js:48 +#. 5.8/applet.js:3 #, fuzzy -msgid "due to an error" -msgstr "yanlış format nedeniyle" +msgid "toggle automatic switch" +msgstr "Orta-tıkla: otomatik değiştirme modunu aç/kapat" + +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Kritik hata" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +msgid "this applet only supports" msgstr "" #. metadata.json->name @@ -122,74 +109,167 @@ msgid "Automatic dark/light themes" msgstr "Otomatik karanlık/aydınlık temalar" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "" "Alacakaranlık(gün doğumu/batımı) zamanlarında karanlık ve aydınlık temalar " "arasında otomatik geçiş yapın." -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Ayarlar" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "Durum" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Kontrol" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" + +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Konum" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "Aydınlık modu" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Temalar" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Diğerleri" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Masaüstü arka planı" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Özel komutlar" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Modları otomatik olarak değiştirin" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "Karanlık modu" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "Aydınlık/karanlık mod" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "" "Konum ve günün saatine göre aydınlık ve karanlık modlar arasında otomatik " "geçiş yapın" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Aydınlık/karanlık mod" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Aydınlık veya karanlık modu manuel olarak değiştirin" +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "Sistemden senkronize edin" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -197,21 +277,18 @@ msgstr "" "Yerel bir veritabanı kullanarak sistemde tanımlanan bölge ve şehirden konum " "koordinatlarını dinamik olarak senkronize eder" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Sistem ayarlarını açın" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" @@ -219,207 +296,207 @@ msgstr "" "Saat dilimi için bölge ve şehir seçmek üzere sistemin ayarlar penceresini " "açın" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Enlem" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "Ondalık derece cinsinden coğrafi enlem" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Boylam" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" -msgstr "Ondalık derece cinsinden coğrafi boylam" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip #, fuzzy -msgid "Show switch times in a notification" -msgstr "Bugünün geçiş zamanlarını bir bildirimde kontrol edin" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"Bugünün geçiş zamanlarını şu anki konum bilgileriyle birlikte bir sistem " -"bildirim mesajı aracılığıyla görüntüleyin" +msgid "Geographical longitude in decimal degrees (°E)" +msgstr "Ondalık derece cinsinden coğrafi boylam" -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "Temaları seçmek için sistemin ayarlar penceresini açın" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "Sistemden algıla" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" -msgstr "Sistemde şu anda ayarlı olan temaları algılar ve aydınlık moda atar" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" +msgstr "" +"Sistemde şu anda yapılandırılmış olan temaları algılar ve karanlık moda atar" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Fare imleci" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Fare imleci temasının adı" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Uygulamalar" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Uygulamaların temasının adı (GTK teması)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "İkonlar" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "İkonların temasının adı" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Masaüstü" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Masaüstü temasının adı (Cinnamon teması)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description #, fuzzy msgid "Test applying to the system" msgstr "Sisteme uygula" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "Aydınlık mod temalarını sisteme manuel olarak uygulayın" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "Masaüstü arka planını ayarlayın" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" msgstr "" -"Aydınlık ve karanlık modlar için masaüstü arka planlarını etkinleştirin" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Özel komutları başlatın" -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" -msgstr "Aydınlık mod geçişinde çalıştırılacak komutları etkinleştirin" - -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "Arka plan ayarlarını yapmak için sistemin ayarlar penceresini açın" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" -msgstr "Sistemde etkin olan arka plan ayarlarını algılar ve aydınlık moda atar" - -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +"Detect the system's background settings currently set and save them as " +"presets" +msgstr "" +"Sistemde şu anda yapılandırılmış olan arka plan ayarlarını algılar ve " +"karanlık moda atar" + +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Slayt gösterimi" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "Masaüstü arka planını slayt gösterimi yapmak için ayarlayın" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "Resim dosyası" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "Masaüstü arka planı için ayarlanacak görüntü dosyası" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Resimler klasörü" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "Masaüstü arka planı slayt gösterimi resimlerinin bulunduğu klasör" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" -msgstr "Aydınlık mod arka plan ayarlarını sisteme manuel olarak uygulayın" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" +msgstr "Karanlık mod arka plan ayarlarını sisteme manuel olarak uygulayın" + +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Özel komutları başlatın" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "Karanlık mod geçişinde çalıştırılacak komutları etkinleştirin" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Adı" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Aktif" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Zaman aşımı (s)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Komut" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip #, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -440,68 +517,14 @@ msgstr "" "- hata mesajları, dönüş durumu 0 olmadığında stderr'i raporlar ve bir " "bildirimde görüntülenir" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description #, fuzzy msgid "Test commands launch" msgstr "Özel komutlar" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip #, fuzzy -msgid "Test launching the commands set for the light mode" -msgstr "Aydınlık mod için ayarlanan komutları başlatın" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "" -"Sistemde şu anda yapılandırılmış olan temaları algılar ve karanlık moda atar" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Karanlık mod temalarını sisteme manuel olarak uygulayın" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "Karanlık mod geçişinde çalıştırılacak komutları etkinleştirin" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Sistemde şu anda yapılandırılmış olan arka plan ayarlarını algılar ve " -"karanlık moda atar" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "Karanlık mod arka plan ayarlarını sisteme manuel olarak uygulayın" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Bu modda çalıştırılacak komutların listesi\n" -"\n" -"Notlar:\n" -"- ismin amacı hata mesajları içindir\n" -"- zaman aşımı komutun işlemini sonlandırır\n" -"- 0 saniye anlamı asla sonlanmaz demektir\n" -"- her alt süreç zaman aşımına uğramaz\n" -"- yol ~ dizininde bulunur\n" -"- hata mesajları, dönüş durumu 0 olmadığında stderr'i raporlar ve bir " -"bildirimde görüntülenir" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -#, fuzzy -msgid "Test launching the commands set for the dark mode" -msgstr "Karanlık mod için ayarlanan komutları başlatın" +msgid "Launch the commands manually" +msgstr "Özel komutları başlatın" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/vi.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/vi.po index 039075d3a70..3b0877321ea 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/vi.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/vi.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: auto-dark-light@gihaume 1.2.5\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: \n" "Last-Translator: loccun \n" "Language-Team: \n" @@ -18,102 +18,91 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.4.2\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "Nhấp chuột: chuyển chế độ tối/sáng" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "Nhấp chuột giữa: bật/tắt chế độ chuyển đổi tự động" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "Thời gian chuyển đổi chế độ tự động ngày nay" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "Chế độ sáng" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "lệnh" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "Chế độ tối" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "thất bại" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "Lỗi" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "do định dạng sai" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "Lỗi nghiêm trọng" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "Chi tiết" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "do hết thời gian" + +#. 5.8/applet.js:1 +msgid "due to an error" +msgstr "do lỗi" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +#, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "Thiếu các phụ thuộc `make` và/hoặc `g++`. Hãy cài đặt chúng, ví dụ trên hệ " "thống dựa trên Debian bằng lệnh `sudo apt install make g++`, sau đó tải lại " "applet bằng cách khởi động lại Cinnamon." -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "Biên soạn của" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "thất bại" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "Biên soạn của" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "quá trình phụ" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "đã viết trên đầu ra lỗi của nó" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" +#. 5.8/applet.js:3 +msgid "Click" msgstr "" -"không thể tính toán thời gian hoàng hôn, hãy kiểm tra định dạng hoặc phạm vi " -"tọa độ" - -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "lệnh" -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "do định dạng sai" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "Nhấp chuột: chuyển chế độ tối/sáng" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" -msgstr "Chi tiết" +#. 5.8/applet.js:3 +msgid "Middle-click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "do hết thời gian" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle automatic switch" +msgstr "Nhấp chuột giữa: bật/tắt chế độ chuyển đổi tự động" -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" -msgstr "do lỗi" +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "Lỗi nghiêm trọng" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +#, fuzzy +msgid "this applet only supports" msgstr "applet này chỉ được hỗ trợ bởi" #. metadata.json->name @@ -121,72 +110,165 @@ msgid "Automatic dark/light themes" msgstr "Chủ đề tối/sáng tự động" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "Tự động chuyển đổi giữa chủ đề tối và sáng vào lúc chạng vạng." -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "Cài đặt" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "Trạng thái" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "Điều khiển" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" + +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "Vị trí" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "Chế độ sáng" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "Chủ đề" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "Khác" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "Hình nền máy tính" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "Lệnh tùy chỉnh" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "Tự động chuyển đổi chế độ" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "Chế độ tối" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "Chế độ sáng/tối" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "" "Tự động chuyển đổi giữa chế độ sáng và tối dựa trên vị trí và thời gian " "trong ngày" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "Chế độ sáng/tối" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "Chuyển đổi chế độ sáng hoặc tối theo cách thủ công" +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "Đồng bộ từ hệ thống" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" @@ -194,227 +276,225 @@ msgstr "" "Đồng bộ hóa động tọa độ vị trí từ khu vực và thành phố được xác định trong " "hệ thống bằng cơ sở dữ liệu cục bộ" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "Mở cài đặt hệ thống" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" msgstr "Mở cửa sổ cài đặt hệ thống để chọn khu vực và thành phố cho múi giờ" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "Vĩ độ" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "Vĩ độ địa lý tính bằng độ thập phân" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "Kinh độ" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +#, fuzzy +msgid "Geographical longitude in decimal degrees (°E)" msgstr "Kinh độ địa lý tính theo độ thập phân" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" -msgstr "Hiển thị thời gian chuyển đổi trong thông báo" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "" -"Hiển thị thời gian chuyển đổi chế độ sáng và tối trong ngày dựa trên vị trí " -"hiện tại thông qua tin nhắn thông báo hệ thống" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "Mở cửa sổ cài đặt hệ thống để chọn các chủ đề" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "Phát hiện từ hệ thống" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" msgstr "" -"Phát hiện các chủ đề hiện tại của hệ thống và gán chúng vào chế độ sáng" +"Phát hiện các chủ đề hiện đang được thiết lập của hệ thống và gán chúng vào " +"chế độ tối" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "Con trỏ chuột" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "Tên của chủ đề con trỏ chuột" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "Ứng dụng" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "Tên chủ đề ứng dụng (chủ đề GTK)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "Biểu tượng" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "Tên của chủ đề biểu tượng" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "Máy tính" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "Tên chủ đề máy tính (chủ đề Cinnamon)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "Kiểm tra áp dụng cho hệ thống" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "Áp dụng chủ đề chế độ sáng cho hệ thống theo cách thủ công" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "Đặt hình nền máy tính " -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" -msgstr "Cho phép thiết lập chế độ sáng và tối cho hình nền máy tính" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "Khởi chạy lệnh tùy chỉnh" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" -msgstr "Cho phép khởi chạy lệnh cài đặt khi chuyển sang chế độ sáng" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" +msgstr "" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "Mở cửa sổ cài đặt hệ thống để thiết lập cài đặt nền" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" +"Detect the system's background settings currently set and save them as " +"presets" msgstr "" -"Phát hiện các thiết lập nền của hệ thống hiện đang được thiết lập và gán " -"chúng vào chế độ sáng" +"Phát hiện các cài đặt nền của hệ thống hiện đang được thiết lập và gán chúng " +"vào chế độ tối" -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "Trình chiếu" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "Đặt hình nền máy tính để bàn thành trình chiếu" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "Tập tin hình ảnh" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "Tệp hình ảnh sẽ được đặt làm hình nền máy tính" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "Thư mục hình ảnh" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "" "Thư mục chứa hình ảnh sẽ được thiết lập làm trình chiếu hình nền máy tính" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" -msgstr "Áp dụng cài đặt nền chế độ sáng cho hệ thống theo cách thủ công" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" +msgstr "Áp dụng cài đặt nền chế độ tối cho hệ thống theo cách thủ công" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "Khởi chạy lệnh tùy chỉnh" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "Cho phép các lệnh cài đặt được khởi chạy khi chuyển sang chế độ tối" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "Tên" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "Đang hoạt động" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "Hết hạn (s)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "Lệnh" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip +#, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -434,66 +514,13 @@ msgstr "" "- Đường dẫn nằm trong thư mục Nhà của người dùng (~/)\n" "- Thông báo lỗi được hiển thị trong thông báo và báo cáo stderr" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "Lệnh kiểm tra khởi chạy" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "Kiểm tra việc khởi chạy các lệnh được thiết lập cho chế độ sáng" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "" -"Phát hiện các chủ đề hiện đang được thiết lập của hệ thống và gán chúng vào " -"chế độ tối" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "Áp dụng chủ đề chế độ tối cho hệ thống theo cách thủ công" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "Cho phép các lệnh cài đặt được khởi chạy khi chuyển sang chế độ tối" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "" -"Phát hiện các cài đặt nền của hệ thống hiện đang được thiết lập và gán chúng " -"vào chế độ tối" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "Áp dụng cài đặt nền chế độ tối cho hệ thống theo cách thủ công" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"Danh sách các lệnh sẽ được thực thi khi chuyển sang chế độ này\n" -"\n" -"Lưu ý:\n" -"- Mục đích của tên là để hiển thị thông báo lỗi\n" -"- Thời gian hết hạn sẽ kết thúc tiến trình của lệnh\n" -"- Thời gian hết hạn 0 giây nghĩa là không bao giờ\n" -"- Bất kỳ tiến trình con nào cũng sẽ không thể hết hạn\n" -"- Đường dẫn nằm trong thư mục ~\n" -"- Thông báo lỗi sẽ báo cáo stderr khi trạng thái trả về không phải là 0 và " -"sẽ xuất hiện trong thông báo" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" -msgstr "Kiểm tra việc khởi chạy các lệnh được thiết lập cho chế độ tối" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +#, fuzzy +msgid "Launch the commands manually" +msgstr "Khởi chạy lệnh tùy chỉnh" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/zh_CN.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/zh_CN.po index 80eebc50056..b69be068d4d 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/zh_CN.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/zh_CN.po @@ -6,9 +6,9 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/\n" +"Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: 2025-05-18 11:23-0400\n" "Last-Translator: \n" "Language-Team: \n" @@ -16,101 +16,93 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"issues\n" "X-Generator: Poedit 3.4.4\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "点击:切换深色/浅色模式" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "鼠标中键点击:切换自动切换模式" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "今天的自动模式切换时间" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "浅色模式" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "命令" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "深色模式" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "失败" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "错误" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "由于格式错误" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "严重错误" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "详细信息" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "由于时间到期" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 +msgid "due to an error" +msgstr "由于错误" + +#. 5.8/applet.js:1 +#, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "缺少依赖项 `make` 和/或 `g++`。 安装它们,例如在基于 Debian 的系统上使用 " "`sudo apt install make g++`,然后在重新启动 Cinnamon 后重新加载小程序。" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "编译" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "失败" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "编译" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "子进程" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "在其错误输出中写入" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" -msgstr "无法计算暮光时间,请检查坐标格式或范围" - -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "命令" +#. 5.8/applet.js:3 +msgid "Click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "由于格式错误" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "点击:切换深色/浅色模式" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" -msgstr "详细信息" +#. 5.8/applet.js:3 +msgid "Middle-click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "由于时间到期" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle automatic switch" +msgstr "鼠标中键点击:切换自动切换模式" -#. 5.8/lib/commands_launcher/commands_launcher.js:48 -msgid "due to an error" -msgstr "由于错误" +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "严重错误" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +#, fuzzy +msgid "this applet only supports" msgstr "此小程序仅受以下版本支持" #. metadata.json->name @@ -118,292 +110,382 @@ msgid "Automatic dark/light themes" msgstr "自动深色/浅色主题" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "在暮光时分自动切换深色和浅色主题。" -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "设置" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" + +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "状态" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "控制" +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "位置" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "浅色模式" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "主题" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "其他" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "桌面背景" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "自定义命令" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "自动切换模式" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "深色模式" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "浅色/深色模式" + +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "根据位置和一天中的时间自动在浅色和深色模式之间切换" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "浅色/深色模式" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "手动切换浅色或深色模式" +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "从系统同步" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" msgstr "使用本地数据库从系统中定义的区域和城市动态同步位置坐标" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "打开系统设置" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" msgstr "打开系统设置窗口以选择时区的区域和城市" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "纬度" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "以十进制度数表示的地理纬度" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "经度" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip +#, fuzzy +msgid "Geographical longitude in decimal degrees (°E)" msgstr "以十进制度数表示的地理经度" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description -msgid "Show switch times in a notification" -msgstr "在通知中显示切换时间" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "通过系统通知消息显示今天基于当前位置的浅色和深色模式的切换时间" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "打开系统设置窗口以选择主题" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "从系统检测" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" -msgstr "检测当前设置的系统主题并将它们分配给浅色模式" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" +msgstr "检测当前设置的系统主题并将它们分配给深色模式" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "鼠标指针" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "鼠标指针主题的名称" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "应用程序" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "应用程序主题的名称 (GTK 主题)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "图标" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "图标主题的名称" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "桌面" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "桌面主题的名称 (Cinnamon 主题)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description msgid "Test applying to the system" msgstr "测试应用于系统" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "手动将浅色模式主题应用于系统" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "设置桌面背景" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "" -"Enable setting the desktop backgrounds for light and dark modes" -msgstr "启用为浅色和深色模式设置桌面背景" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "启动自定义命令" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" -msgstr "启用设置在切换到浅色模式时要启动的命令" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" +msgstr "" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "打开系统设置窗口以设置背景设置" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" -msgstr "检测当前设置的系统背景设置并将它们分配给浅色模式" - -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +"Detect the system's background settings currently set and save them as " +"presets" +msgstr "检测当前设置的系统背景设置并将它们分配给深色模式" + +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "幻灯片" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "将桌面背景设置为幻灯片" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "图像文件" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "要设置为桌面背景的图像文件" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "图片文件夹" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip -msgid "" -"Folder containing images to be set for the desktop background slideshow" +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip +msgid "Folder containing images to be set for the desktop background slideshow" msgstr "包含要设置为桌面背景幻灯片的图像的文件夹" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" -msgstr "手动将浅色模式背景设置应用于系统" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" +msgstr "手动将深色模式背景设置应用于系统" + +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "启动自定义命令" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "启用设置在切换到深色模式时要启动的命令" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "名称" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "活动" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "过期时间 (秒)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "命令" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip +#, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -423,61 +505,13 @@ msgstr "" "- 路径在用户的主目录 (~/) 中\n" "- 错误消息显示在通知中并报告 stderr" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description msgid "Test commands launch" msgstr "测试命令启动" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the light mode" -msgstr "测试启动为浅色模式设置的命令" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "检测当前设置的系统主题并将它们分配给深色模式" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "手动将深色模式主题应用于系统" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "启用设置在切换到深色模式时要启动的命令" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "检测当前设置的系统背景设置并将它们分配给深色模式" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "手动将深色模式背景设置应用于系统" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"切换到此模式时要执行的命令列表\n" -"\n" -"注意:\n" -"- 姓名的目的是为了错误消息\n" -"- 过期时间会终止命令的进程\n" -"- 0 秒的过期时间表示永不过期\n" -"- 任何子进程都无法过期\n" -"- 路径在 ~ 目录中\n" -"- 当返回状态不为 0 时,错误消息会报告 stderr,并将显示在通知中" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -msgid "Test launching the commands set for the dark mode" -msgstr "测试启动为深色模式设置的命令" +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip +#, fuzzy +msgid "Launch the commands manually" +msgstr "启动自定义命令" diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/zh_TW.po b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/zh_TW.po index f1e8920fe82..64e769969c6 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/zh_TW.po +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/po/zh_TW.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: auto-dark-light@gihaume 1.2.1\n" "Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-applets/" "issues\n" -"POT-Creation-Date: 2025-05-18 11:37+0200\n" +"POT-Creation-Date: 2025-11-02 20:25+0100\n" "PO-Revision-Date: 2025-04-24 00:59+0800\n" "Last-Translator: Peter Dave Hello \n" "Language-Team: \n" @@ -17,101 +17,90 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#. 5.8/applet.js:33 -msgid "Click: toggle dark/light mode" -msgstr "點選:切換深色/淺色模式" - -#. 5.8/applet.js:34 -msgid "Middle-click: toggle automatic switch mode" -msgstr "中鍵點選:切換自動切換模式" - -#. 5.8/applet.js:367 -msgid "Today's automatic mode switch times" -msgstr "今天的自動模式切換時間" - -#. 5.8/applet.js:367 5.8/applet.js:368 5.8/applet.js:369 5.8/applet.js:412 -#. 5.8/applet.js:418 5.8/lib/time_change_listener/time_change_listener.js:95 -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -#. 5.8/lib/commands_launcher/commands_launcher.js:53 2.2/applet.js:19 +#. 5.8/applet.js:1 5.8/applet.js:3 2.2/applet.js:19 msgid ":" msgstr ":" -#. 5.8->settings-schema.json->light-mode->title -#. 5.8/applet.js:368 -msgid "Light mode" -msgstr "淺色模式" +#. 5.8/applet.js:1 +msgid "the command" +msgstr "命令" -#. 5.8->settings-schema.json->dark-mode->title -#. 5.8/applet.js:369 -msgid "Dark mode" -msgstr "深色模式" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has failed" +msgstr "失敗" -#. 5.8/applet.js:412 -msgid "Error" -msgstr "錯誤" +#. 5.8/applet.js:1 +msgid "due to a wrong format" +msgstr "因格式錯誤" -#. 5.8/applet.js:418 2.2/applet.js:19 -msgid "Critical error" -msgstr "嚴重錯誤" +#. 5.8/applet.js:1 +msgid "Detail" +msgstr "" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to timeout" +msgstr "因逾時" + +#. 5.8/applet.js:1 +#, fuzzy +msgid "due to an error" +msgstr "因格式錯誤" -#. 5.8/lib/time_change_listener/time_change_listener.js:28 +#. 5.8/applet.js:1 #, fuzzy msgid "" -"Missing dependencies `make` and/or `g++`. Install them, in e.g. on Debian-" -"based system with `sudo apt install make g++`, then reload the applet in " -"restarting Cinnamon." +"Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-" +"based system with 'sudo apt install make g++', then restart Cinnamon " +"(Ctrl+Alt+Esc)." msgstr "" "缺少相依套件 `make` 與 `gcc`。請在 Debian 系統上執行 `sudo apt install build-" "essential` 進行安裝,然後重新載入小程式(例如重新啟動 Cinnamon)。" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -msgid "Compilation of" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Unknown compilation error" msgstr "編譯" -#. 5.8/lib/time_change_listener/time_change_listener.js:41 -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "failed" -msgstr "失敗" +#. 5.8/applet.js:1 +#, fuzzy +msgid "Failed compilation of" +msgstr "編譯" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 +#. 5.8/applet.js:1 msgid "the subprocess" msgstr "子程序" -#. 5.8/lib/time_change_listener/time_change_listener.js:95 -msgid "wrote on its error output" +#. 5.8/applet.js:1 +#, fuzzy +msgid "has written on its error output" msgstr "寫入其錯誤輸出" -#. 5.8/lib/twilights_calculator/twilights_calculator.js:21 -msgid "unable to calculate twilight times, check coordinates format or range" -msgstr "無法計算曙暮光時間,請檢查座標格式或範圍" - -#. 5.8/lib/commands_launcher/commands_launcher.js:33 -msgid "the command" -msgstr "命令" +#. 5.8/applet.js:3 +msgid "Click" +msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:35 -msgid "due to a wrong format" -msgstr "因格式錯誤" +#. 5.8/applet.js:3 +#, fuzzy +msgid "toggle dark/light appearance" +msgstr "點選:切換深色/淺色模式" -#. 5.8/lib/commands_launcher/commands_launcher.js:37 -#. 5.8/lib/commands_launcher/commands_launcher.js:44 -#. 5.8/lib/commands_launcher/commands_launcher.js:50 -msgid "Detail" +#. 5.8/applet.js:3 +msgid "Middle-click" msgstr "" -#. 5.8/lib/commands_launcher/commands_launcher.js:42 -msgid "due to time expiration" -msgstr "因逾時" - -#. 5.8/lib/commands_launcher/commands_launcher.js:48 +#. 5.8/applet.js:3 #, fuzzy -msgid "due to an error" -msgstr "因格式錯誤" +msgid "toggle automatic switch" +msgstr "中鍵點選:切換自動切換模式" + +#. 2.2/applet.js:19 +msgid "Critical error" +msgstr "嚴重錯誤" #. 2.2/applet.js:20 -msgid "this applet is only supported by" +msgid "this applet only supports" msgstr "" #. metadata.json->name @@ -119,293 +108,383 @@ msgid "Automatic dark/light themes" msgstr "自動深色/淺色主題" #. metadata.json->description -msgid "Automatically switch between dark and light themes at twilight times." +#, fuzzy +msgid "" +"Automatically switch between dark and light appearances at twilight times." msgstr "在曙暮光時分自動切換深色與淺色主題。" -#. 5.8->settings-schema.json->settings->title -msgid "Settings" -msgstr "設定" +#. 5.8->settings-schema.json->general_page->title +msgid "General" +msgstr "" -#. 5.8->settings-schema.json->settings_state->title -msgid "State" -msgstr "狀態" +#. 5.8->settings-schema.json->appearance_section->title +msgid "Appearance" +msgstr "" -#. 5.8->settings-schema.json->settings_control->title -msgid "Control" -msgstr "控制" +#. 5.8->settings-schema.json->light_schedule_section->title +msgid "Sunrise" +msgstr "" + +#. 5.8->settings-schema.json->dark_schedule_section->title +msgid "Sunset" +msgstr "" -#. 5.8->settings-schema.json->settings_location->title +#. 5.8->settings-schema.json->location_section->title msgid "Location" msgstr "位置" -#. 5.8->settings-schema.json->light-mode_themes->title -#. 5.8->settings-schema.json->dark-mode_themes->title +#. 5.8->settings-schema.json->light_page->title +#, fuzzy +msgid "Light" +msgstr "淺色模式" + +#. 5.8->settings-schema.json->light_themes_section->title +#. 5.8->settings-schema.json->dark_themes_section->title msgid "Themes" msgstr "主題" -#. 5.8->settings-schema.json->light-mode_others->title -#. 5.8->settings-schema.json->dark-mode_others->title -msgid "Others" -msgstr "其他" - -#. 5.8->settings-schema.json->light-mode_background->title -#. 5.8->settings-schema.json->dark-mode_background->title +#. 5.8->settings-schema.json->light_background_section->title +#. 5.8->settings-schema.json->dark_background_section->title msgid "Desktop background" msgstr "桌面背景" -#. 5.8->settings-schema.json->light-mode_commands->title -#. 5.8->settings-schema.json->dark-mode_commands->title +#. 5.8->settings-schema.json->light_commands_section->title +#. 5.8->settings-schema.json->dark_commands_section->title msgid "Custom commands" msgstr "自訂命令" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->description -msgid "Automatically switch modes" -msgstr "自動切換模式" +#. 5.8->settings-schema.json->dark_page->title +#, fuzzy +msgid "Dark" +msgstr "深色模式" + +#. 5.8->settings-schema.json->is_appearance_dark->description +#, fuzzy +msgid "Light/dark" +msgstr "淺色/深色模式" -#. 5.8->settings-schema.json->settings_control_switch_auto-mode->tooltip +#. 5.8->settings-schema.json->is_appearance_dark->tooltip +msgid "Current appearance" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->description +msgid "Manual toggle shortcut" +msgstr "" + +#. 5.8->settings-schema.json->appearance_keybinding->tooltip +msgid "Keyboard shortcut to manually toggle between light and dark appearances" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->description +msgid "Switch automatically" +msgstr "" + +#. 5.8->settings-schema.json->is_appearance_auto->tooltip +#, fuzzy msgid "" -"Automatically switch between light and dark modes based on the location and " -"time of day" +"Automatically switch between light and dark appearances based on twilight " +"times" msgstr "根據位置與時間,自動切換淺色與深色模式" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->description -msgid "Light/dark mode" -msgstr "淺色/深色模式" +#. 5.8->settings-schema.json->is_appearance_unsynced->description +msgid "Unsynced with time and twilights" +msgstr "" -#. 5.8->settings-schema.json->settings_state_switch_dark-mode->tooltip -msgid "Toggle light or dark mode manually" -msgstr "手動切換淺色或深色模式" +#. 5.8->settings-schema.json->is_appearance_unsynced->tooltip +msgid "" +"Whether the current appearance is unsynced regarding the current time and " +"twilight times" +msgstr "" + +#. 5.8->settings-schema.json->next_update->description +msgid "Next update" +msgstr "" + +#. 5.8->settings-schema.json->next_update->tooltip +msgid "" +"Next time (HH:MM) when the automatic appearance switch will be evaluated" +msgstr "" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->description -msgid "Sync from the system" +#. 5.8->settings-schema.json->is_sunrise_auto->description +#. 5.8->settings-schema.json->is_sunset_auto->description +msgid "Sync from location" +msgstr "" + +#. 5.8->settings-schema.json->is_sunrise_auto->tooltip +msgid "Dynamically sync the schedule from the location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->description +#. 5.8->settings-schema.json->auto_sunrise->description +msgid "Light appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunrise->tooltip +msgid "Time (HH:MM(:SS)) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->units +#. 5.8->settings-schema.json->auto_sunset_offset->units +msgid "minutes" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->description +#. 5.8->settings-schema.json->auto_sunset_offset->description +msgid "Offset" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise_offset->tooltip +#. 5.8->settings-schema.json->auto_sunset_offset->tooltip +msgid "Offset in minutes to be added to the time calculated from the location" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunrise->tooltip +msgid "Time (HH:MM) when to switch to light appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_sunset_auto->tooltip +msgid "Dynamically sync the schedule from location" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->description +#. 5.8->settings-schema.json->auto_sunset->description +msgid "Dark appearance start time" +msgstr "" + +#. 5.8->settings-schema.json->manual_sunset->tooltip +msgid "Time (HH:MM(:SS)) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->auto_sunset->tooltip +msgid "Time (HH:MM) when to switch to dark appearance" +msgstr "" + +#. 5.8->settings-schema.json->is_location_auto->description +#, fuzzy +msgid "Sync from system" msgstr "與系統同步" -#. 5.8->settings-schema.json->settings_location_switch_sync-from- -#. timezone->tooltip +#. 5.8->settings-schema.json->is_location_auto->tooltip msgid "" "Dynamically sync the location coordinates from the region and city defined " "in the system using a local database" msgstr "使用本機資料庫,從系統定義的地區與城市動態同步位置座標" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->description -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->description +#. 5.8->settings-schema.json->open_os_location_settings->description +#. 5.8->settings- +#. schema.json->light_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->description +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->description +#. 5.8->settings- +#. schema.json->dark_background_open_os_settings_button->description msgid "Open the system settings" msgstr "開啟系統設定" -#. 5.8->settings-schema.json->settings_location_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->open_os_location_settings->tooltip msgid "" "Open the system's settings window to select the region and city for the time " "zone" msgstr "開啟系統設定視窗以選擇時區的地區與城市" -#. 5.8->settings-schema.json->settings_location_entry_latitude->description +#. 5.8->settings-schema.json->system_timezone->description +msgid "System timezone" +msgstr "" + +#. 5.8->settings-schema.json->system_timezone->tooltip +msgid "The current timezone (region/city) set in the system" +msgstr "" + +#. 5.8->settings-schema.json->auto_latitude->description +#. 5.8->settings-schema.json->manual_latitude->description msgid "Latitude" msgstr "緯度" -#. 5.8->settings-schema.json->settings_location_entry_latitude->tooltip -msgid "Geographical latitude in decimal degrees" +#. 5.8->settings-schema.json->auto_latitude->tooltip +#. 5.8->settings-schema.json->manual_latitude->tooltip +#, fuzzy +msgid "Geographical latitude in decimal degrees (°N)" msgstr "以十進位度數表示的地理緯度" -#. 5.8->settings-schema.json->settings_location_entry_longitude->description +#. 5.8->settings-schema.json->auto_longitude->description +#. 5.8->settings-schema.json->manual_longitude->description msgid "Longitude" msgstr "經度" -#. 5.8->settings-schema.json->settings_location_entry_longitude->tooltip -msgid "Geographical longitude in decimal degrees" -msgstr "以十進位度數表示的地理經度" - -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->description +#. 5.8->settings-schema.json->auto_longitude->tooltip +#. 5.8->settings-schema.json->manual_longitude->tooltip #, fuzzy -msgid "Show switch times in a notification" -msgstr "在通知中檢視今天的切換時間" +msgid "Geographical longitude in decimal degrees (°E)" +msgstr "以十進位度數表示的地理經度" -#. 5.8->settings-schema.json->settings_location_button_show-twilight- -#. times->tooltip -msgid "" -"Show today's switch times for light and dark modes based on the current " -"location via a system notification message" -msgstr "透過系統通知顯示根據目前位置的今日淺色/深色模式切換時間" - -#. 5.8->settings-schema.json->light-mode_themes_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_button_open-os- -#. settings->tooltip +#. 5.8->settings-schema.json->light_themes_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_themes_open_os_settings_button->tooltip msgid "Open the system's settings window to select the themes" msgstr "開啟系統設定視窗以選擇主題" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->description -#. 5.8->settings-schema.json->light-mode_background_button_detect->description -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->description -#. 5.8->settings-schema.json->dark-mode_background_button_detect->description +#. 5.8->settings-schema.json->light_themes_detect_button->description +#. 5.8->settings-schema.json->light_background_detect_button->description +#. 5.8->settings-schema.json->dark_themes_detect_button->description +#. 5.8->settings-schema.json->dark_background_detect_button->description msgid "Detect from the system" msgstr "從系統偵測" -#. 5.8->settings-schema.json->light-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the light mode" -msgstr "偵測目前系統設定的主題並套用至淺色模式" +#. 5.8->settings-schema.json->light_themes_detect_button->tooltip +#. 5.8->settings-schema.json->dark_themes_detect_button->tooltip +#, fuzzy +msgid "Detect the current system's themes settings and save them as presets" +msgstr "偵測目前系統設定的主題並套用至深色模式" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse- -#. pointer->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse- -#. pointer->description +#. 5.8->settings-schema.json->light_themes_mouse->description +#. 5.8->settings-schema.json->dark_themes_mouse->description msgid "Mouse pointer" msgstr "滑鼠指標" -#. 5.8->settings-schema.json->light-mode_themes_entry_mouse-pointer->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_mouse-pointer->tooltip +#. 5.8->settings-schema.json->light_themes_mouse->tooltip +#. 5.8->settings-schema.json->dark_themes_mouse->tooltip msgid "Name of the mouse pointer theme" msgstr "滑鼠指標主題名稱" -#. 5.8->settings-schema.json->light- -#. mode_themes_entry_applications->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->description +#. 5.8->settings-schema.json->light_themes_apps->description +#. 5.8->settings-schema.json->dark_themes_apps->description msgid "Applications" msgstr "應用程式" -#. 5.8->settings-schema.json->light-mode_themes_entry_applications->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_applications->tooltip +#. 5.8->settings-schema.json->light_themes_apps->tooltip +#. 5.8->settings-schema.json->dark_themes_apps->tooltip msgid "Name of the applications theme (GTK theme)" msgstr "應用程式主題名稱(GTK 主題)" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->description +#. 5.8->settings-schema.json->light_themes_icons->description +#. 5.8->settings-schema.json->dark_themes_icons->description msgid "Icons" msgstr "圖示" -#. 5.8->settings-schema.json->light-mode_themes_entry_icons->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_icons->tooltip +#. 5.8->settings-schema.json->light_themes_icons->tooltip +#. 5.8->settings-schema.json->dark_themes_icons->tooltip msgid "Name of the icons theme" msgstr "圖示主題名稱" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->description -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->description +#. 5.8->settings-schema.json->light_themes_desktop->description +#. 5.8->settings-schema.json->dark_themes_desktop->description msgid "Desktop" msgstr "桌面" -#. 5.8->settings-schema.json->light-mode_themes_entry_desktop->tooltip -#. 5.8->settings-schema.json->dark-mode_themes_entry_desktop->tooltip +#. 5.8->settings-schema.json->light_themes_desktop->tooltip +#. 5.8->settings-schema.json->dark_themes_desktop->tooltip msgid "Name of the desktop theme (Cinnamon theme)" msgstr "桌面主題名稱(Cinnamon 主題)" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->description -#. 5.8->settings-schema.json->light-mode_background_button_apply->description -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->description -#. 5.8->settings-schema.json->dark-mode_background_button_apply->description +#. 5.8->settings-schema.json->light_themes_apply_button->description +#. 5.8->settings-schema.json->light_background_apply_button->description +#. 5.8->settings-schema.json->dark_themes_apply_button->description +#. 5.8->settings-schema.json->dark_background_apply_button->description #, fuzzy msgid "Test applying to the system" msgstr "套用至系統" -#. 5.8->settings-schema.json->light-mode_themes_button_apply->tooltip -msgid "Apply the light mode themes to the system manually" +#. 5.8->settings-schema.json->light_themes_apply_button->tooltip +#. 5.8->settings-schema.json->dark_themes_apply_button->tooltip +#, fuzzy +msgid "Apply the themes presets to the system manually" msgstr "手動套用淺色模式主題至系統" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->description -msgid "Set desktop background" +#. 5.8->settings-schema.json->enable_background->description +#, fuzzy +msgid "Set desktop backgrounds" msgstr "設定桌面背景" -#. 5.8->settings-schema.json->both-modes_background_switch_enable->tooltip -msgid "Enable setting the desktop backgrounds for light and dark modes" -msgstr "啟用設定淺色與深色模式的桌面背景" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->description -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->description -msgid "Launch custom commands" -msgstr "執行自訂命令" - -#. 5.8->settings-schema.json->light-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to light mode" -msgstr "啟用切換至淺色模式時執行命令的功能" +#. 5.8->settings-schema.json->enable_background->tooltip +msgid "Enable desktop background settings as being part of the themes presets" +msgstr "" -#. 5.8->settings-schema.json->light-mode_background_button_open-os- -#. settings->tooltip -#. 5.8->settings-schema.json->dark-mode_background_button_open-os- -#. settings->tooltip +#. 5.8->settings- +#. schema.json->light_background_open_os_settings_button->tooltip +#. 5.8->settings-schema.json->dark_background_open_os_settings_button->tooltip msgid "Open the system's settings window to set the background settings" msgstr "開啟系統設定視窗以設定背景選項" -#. 5.8->settings-schema.json->light-mode_background_button_detect->tooltip +#. 5.8->settings-schema.json->light_background_detect_button->tooltip +#. 5.8->settings-schema.json->dark_background_detect_button->tooltip +#, fuzzy msgid "" -"Detect the system's background settings currently set and assign them to the " -"light mode" -msgstr "偵測目前系統設定的背景並套用至淺色模式" - -#. 5.8->settings-schema.json->light- -#. mode_background_switch_slideshow->description -#. 5.8->settings-schema.json->dark- -#. mode_background_switch_slideshow->description +"Detect the system's background settings currently set and save them as " +"presets" +msgstr "偵測目前系統設定的背景並套用至深色模式" + +#. 5.8->settings-schema.json->light_background_is_slideshow->description +#. 5.8->settings-schema.json->dark_background_is_slideshow->description msgid "Slideshow" msgstr "投影片播放" -#. 5.8->settings-schema.json->light-mode_background_switch_slideshow->tooltip -#. 5.8->settings-schema.json->dark-mode_background_switch_slideshow->tooltip +#. 5.8->settings-schema.json->light_background_is_slideshow->tooltip +#. 5.8->settings-schema.json->dark_background_is_slideshow->tooltip msgid "Set the desktop background to be a slideshow" msgstr "將桌面背景設為投影片播放" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_file->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_file->description +#. 5.8->settings-schema.json->light_background_file->description +#. 5.8->settings-schema.json->dark_background_file->description msgid "Image file" msgstr "圖片檔案" -#. 5.8->settings-schema.json->light-mode_background_filechooser_file->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_file->tooltip +#. 5.8->settings-schema.json->light_background_file->tooltip +#. 5.8->settings-schema.json->dark_background_file->tooltip msgid "Image file to be set as the desktop background" msgstr "要設為桌面背景的圖片檔案" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->description -#. 5.8->settings-schema.json->dark- -#. mode_background_filechooser_folder->description +#. 5.8->settings-schema.json->light_background_slideshow_folder->description +#. 5.8->settings-schema.json->dark_background_slideshow_folder->description msgid "Images folder" msgstr "圖片資料夾" -#. 5.8->settings-schema.json->light- -#. mode_background_filechooser_folder->tooltip -#. 5.8->settings-schema.json->dark-mode_background_filechooser_folder->tooltip +#. 5.8->settings-schema.json->light_background_slideshow_folder->tooltip +#. 5.8->settings-schema.json->dark_background_slideshow_folder->tooltip msgid "Folder containing images to be set for the desktop background slideshow" msgstr "包含要用於桌面背景投影片播放的圖片資料夾" -#. 5.8->settings-schema.json->light-mode_background_button_apply->tooltip -msgid "Apply the light mode background settings to the system manually" -msgstr "手動套用淺色模式背景設定至系統" +#. 5.8->settings-schema.json->light_background_apply_button->tooltip +#. 5.8->settings-schema.json->dark_background_apply_button->tooltip +#, fuzzy +msgid "Apply the desktop background presets to the system manually" +msgstr "手動套用深色模式背景設定至系統" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_is_enabled->description +#. 5.8->settings-schema.json->dark_commands_is_enabled->description +msgid "Launch custom commands" +msgstr "執行自訂命令" + +#. 5.8->settings-schema.json->light_commands_is_enabled->tooltip +#. 5.8->settings-schema.json->dark_commands_is_enabled->tooltip +#, fuzzy +msgid "" +"Enable setting commands to be launched when switching to this appearance" +msgstr "啟用切換至深色模式時執行命令的功能" + +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Name" msgstr "名稱" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Active" msgstr "啟用" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Expiry (s)" msgstr "逾時(秒)" -#. 5.8->settings-schema.json->light-mode_commands_list->columns->title -#. 5.8->settings-schema.json->dark-mode_commands_list->columns->title +#. 5.8->settings-schema.json->light_commands_list->columns->title +#. 5.8->settings-schema.json->dark_commands_list->columns->title msgid "Command" msgstr "命令" -#. 5.8->settings-schema.json->light-mode_commands_list->tooltip +#. 5.8->settings-schema.json->light_commands_list->tooltip +#. 5.8->settings-schema.json->dark_commands_list->tooltip #, fuzzy msgid "" -"List of commands to be executed when switching to this mode\n" +"List of commands to be executed when switching to this appearance\n" "\n" "Notes:\n" "- the name's purpose is for error messages\n" @@ -425,64 +504,14 @@ msgstr "" "- 路徑位於 ~ 目錄\n" "- 當回傳狀態非 0 時,錯誤訊息會顯示標準錯誤輸出並出現在通知中" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->description -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->description +#. 5.8->settings-schema.json->light_commands_launch_button->description +#. 5.8->settings-schema.json->dark_commands_launch_button->description #, fuzzy msgid "Test commands launch" msgstr "自訂命令" -#. 5.8->settings-schema.json->light-mode_commands_button_launch->tooltip +#. 5.8->settings-schema.json->light_commands_launch_button->tooltip +#. 5.8->settings-schema.json->dark_commands_launch_button->tooltip #, fuzzy -msgid "Test launching the commands set for the light mode" -msgstr "執行淺色模式所設定的命令" - -#. 5.8->settings-schema.json->dark-mode_themes_button_detect->tooltip -msgid "" -"Detect the system's themes currently set and assign them to the dark mode" -msgstr "偵測目前系統設定的主題並套用至深色模式" - -#. 5.8->settings-schema.json->dark-mode_themes_button_apply->tooltip -msgid "Apply the dark mode themes to the system manually" -msgstr "手動套用深色模式主題至系統" - -#. 5.8->settings-schema.json->dark-mode_commands_switch_enable->tooltip -msgid "Enable setting commands to be launched when switching to dark mode" -msgstr "啟用切換至深色模式時執行命令的功能" - -#. 5.8->settings-schema.json->dark-mode_background_button_detect->tooltip -msgid "" -"Detect the system's background settings currently set and assign them to the " -"dark mode" -msgstr "偵測目前系統設定的背景並套用至深色模式" - -#. 5.8->settings-schema.json->dark-mode_background_button_apply->tooltip -msgid "Apply the dark mode background settings to the system manually" -msgstr "手動套用深色模式背景設定至系統" - -#. 5.8->settings-schema.json->dark-mode_commands_list->tooltip -msgid "" -"List of commands to be executed when switching to this mode\n" -"\n" -"Notes:\n" -"- the name's purpose is for error messages\n" -"- the expiry time kills the command's process\n" -"- an expiry of 0 seconds means never\n" -"- any child process won't be able to expire\n" -"- the path is in the ~ directory\n" -"- the error messages reports stderr when the return status is not 0 and will " -"appear in a notification" -msgstr "" -"切換至此模式時要執行的命令清單\n" -"\n" -"註:\n" -"- 名稱用於錯誤訊息\n" -"- 逾時時間會終止命令程序\n" -"- 0 秒代表永不逾時\n" -"- 子程序無法被逾時終止\n" -"- 路徑位於 ~ 目錄\n" -"- 當回傳狀態非 0 時,錯誤訊息會顯示標準錯誤輸出並出現在通知中" - -#. 5.8->settings-schema.json->dark-mode_commands_button_launch->tooltip -#, fuzzy -msgid "Test launching the commands set for the dark mode" -msgstr "執行深色模式所設定的命令" +msgid "Launch the commands manually" +msgstr "執行自訂命令" diff --git a/auto-dark-light@gihaume/info.json b/auto-dark-light@gihaume/info.json index 4b0a95e8259..4289c58e9b8 100644 --- a/auto-dark-light@gihaume/info.json +++ b/auto-dark-light@gihaume/info.json @@ -1,4 +1,4 @@ { - "author": "guillaume-mueller", - "license": "GPLv3" + "author": "guillaume-mueller", + "license": "GPLv3" } diff --git a/auto-dark-light@gihaume/package.json b/auto-dark-light@gihaume/package.json new file mode 100644 index 00000000000..a99541cb2f7 --- /dev/null +++ b/auto-dark-light@gihaume/package.json @@ -0,0 +1,24 @@ +{ + "scripts": { + "dev": "vite build --watch", + "build": "vite build --mode=final", + "test": "vitest" + }, + "dependencies": { + "mobx": "6.15.0" + }, + "devDependencies": { + "@ci-types/cjs": "6.0.2-5", + "@types/luxon": "^3.7.1", + "luxon": "3.7.2", + "terser": "5.44.0", + "typescript": "5.9.3", + "vite": "7.1.12", + "vitest": "^4.0.6" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild" + ] + } +} diff --git a/auto-dark-light@gihaume/pnpm-lock.yaml b/auto-dark-light@gihaume/pnpm-lock.yaml new file mode 100644 index 00000000000..6c76a106815 --- /dev/null +++ b/auto-dark-light@gihaume/pnpm-lock.yaml @@ -0,0 +1,1017 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + mobx: + specifier: 6.15.0 + version: 6.15.0 + devDependencies: + '@ci-types/cjs': + specifier: 6.0.2-5 + version: 6.0.2-5 + '@types/luxon': + specifier: ^3.7.1 + version: 3.7.1 + luxon: + specifier: 3.7.2 + version: 3.7.2 + terser: + specifier: 5.44.0 + version: 5.44.0 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: 7.1.12 + version: 7.1.12(@types/node@24.9.2)(terser@5.44.0) + vitest: + specifier: ^4.0.6 + version: 4.0.6(@types/node@24.9.2)(terser@5.44.0) + +packages: + + '@ci-types/cjs@6.0.2-5': + resolution: {integrity: sha512-evU4UuSP6EVzkBZpNQI8cb2lkrbj/FH8g1ZUryzckoGxfeRfrM6BxFkfZTGNvJUSflMiHNsYI+UD/i16eXZTJg==} + + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} + cpu: [x64] + os: [win32] + + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/luxon@3.7.1': + resolution: {integrity: sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==} + + '@types/node@24.9.2': + resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==} + + '@vitest/expect@4.0.6': + resolution: {integrity: sha512-5j8UUlBVhOjhj4lR2Nt9sEV8b4WtbcYh8vnfhTNA2Kn5+smtevzjNq+xlBuVhnFGXiyPPNzGrOVvmyHWkS5QGg==} + + '@vitest/mocker@4.0.6': + resolution: {integrity: sha512-3COEIew5HqdzBFEYN9+u0dT3i/NCwppLnO1HkjGfAP1Vs3vti1Hxm/MvcbC4DAn3Szo1M7M3otiAaT83jvqIjA==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.0.6': + resolution: {integrity: sha512-4vptgNkLIA1W1Nn5X4x8rLJBzPiJwnPc+awKtfBE5hNMVsoAl/JCCPPzNrbf+L4NKgklsis5Yp2gYa+XAS442g==} + + '@vitest/runner@4.0.6': + resolution: {integrity: sha512-trPk5qpd7Jj+AiLZbV/e+KiiaGXZ8ECsRxtnPnCrJr9OW2mLB72Cb824IXgxVz/mVU3Aj4VebY+tDTPn++j1Og==} + + '@vitest/snapshot@4.0.6': + resolution: {integrity: sha512-PaYLt7n2YzuvxhulDDu6c9EosiRuIE+FI2ECKs6yvHyhoga+2TBWI8dwBjs+IeuQaMtZTfioa9tj3uZb7nev1g==} + + '@vitest/spy@4.0.6': + resolution: {integrity: sha512-g9jTUYPV1LtRPRCQfhbMintW7BTQz1n6WXYQYRQ25qkyffA4bjVXjkROokZnv7t07OqfaFKw1lPzqKGk1hmNuQ==} + + '@vitest/utils@4.0.6': + resolution: {integrity: sha512-bG43VS3iYKrMIZXBo+y8Pti0O7uNju3KvNn6DrQWhQQKcLavMB+0NZfO1/QBAEbq0MaQ3QjNsnnXlGQvsh0Z6A==} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + chai@6.2.0: + resolution: {integrity: sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==} + engines: {node: '>=18'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + luxon@3.7.2: + resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} + engines: {node: '>=12'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + mobx@6.15.0: + resolution: {integrity: sha512-UczzB+0nnwGotYSgllfARAqWCJ5e/skuV2K/l+Zyck/H6pJIhLXuBnz+6vn2i211o7DtbE78HQtsYEKICHGI+g==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + terser@5.44.0: + resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} + engines: {node: '>=10'} + hasBin: true + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + vite@7.1.12: + resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.0.6: + resolution: {integrity: sha512-gR7INfiVRwnEOkCk47faros/9McCZMp5LM+OMNWGLaDBSvJxIzwjgNFufkuePBNaesGRnLmNfW+ddbUJRZn0nQ==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.6 + '@vitest/browser-preview': 4.0.6 + '@vitest/browser-webdriverio': 4.0.6 + '@vitest/ui': 4.0.6 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + +snapshots: + + '@ci-types/cjs@6.0.2-5': {} + + '@esbuild/aix-ppc64@0.25.11': + optional: true + + '@esbuild/android-arm64@0.25.11': + optional: true + + '@esbuild/android-arm@0.25.11': + optional: true + + '@esbuild/android-x64@0.25.11': + optional: true + + '@esbuild/darwin-arm64@0.25.11': + optional: true + + '@esbuild/darwin-x64@0.25.11': + optional: true + + '@esbuild/freebsd-arm64@0.25.11': + optional: true + + '@esbuild/freebsd-x64@0.25.11': + optional: true + + '@esbuild/linux-arm64@0.25.11': + optional: true + + '@esbuild/linux-arm@0.25.11': + optional: true + + '@esbuild/linux-ia32@0.25.11': + optional: true + + '@esbuild/linux-loong64@0.25.11': + optional: true + + '@esbuild/linux-mips64el@0.25.11': + optional: true + + '@esbuild/linux-ppc64@0.25.11': + optional: true + + '@esbuild/linux-riscv64@0.25.11': + optional: true + + '@esbuild/linux-s390x@0.25.11': + optional: true + + '@esbuild/linux-x64@0.25.11': + optional: true + + '@esbuild/netbsd-arm64@0.25.11': + optional: true + + '@esbuild/netbsd-x64@0.25.11': + optional: true + + '@esbuild/openbsd-arm64@0.25.11': + optional: true + + '@esbuild/openbsd-x64@0.25.11': + optional: true + + '@esbuild/openharmony-arm64@0.25.11': + optional: true + + '@esbuild/sunos-x64@0.25.11': + optional: true + + '@esbuild/win32-arm64@0.25.11': + optional: true + + '@esbuild/win32-ia32@0.25.11': + optional: true + + '@esbuild/win32-x64@0.25.11': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@rollup/rollup-android-arm-eabi@4.52.5': + optional: true + + '@rollup/rollup-android-arm64@4.52.5': + optional: true + + '@rollup/rollup-darwin-arm64@4.52.5': + optional: true + + '@rollup/rollup-darwin-x64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-arm64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-x64-musl@4.52.5': + optional: true + + '@rollup/rollup-openharmony-arm64@4.52.5': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.52.5': + optional: true + + '@standard-schema/spec@1.0.0': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/luxon@3.7.1': {} + + '@types/node@24.9.2': + dependencies: + undici-types: 7.16.0 + optional: true + + '@vitest/expect@4.0.6': + dependencies: + '@standard-schema/spec': 1.0.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.6 + '@vitest/utils': 4.0.6 + chai: 6.2.0 + tinyrainbow: 3.0.3 + + '@vitest/mocker@4.0.6(vite@7.1.12(@types/node@24.9.2)(terser@5.44.0))': + dependencies: + '@vitest/spy': 4.0.6 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.1.12(@types/node@24.9.2)(terser@5.44.0) + + '@vitest/pretty-format@4.0.6': + dependencies: + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.6': + dependencies: + '@vitest/utils': 4.0.6 + pathe: 2.0.3 + + '@vitest/snapshot@4.0.6': + dependencies: + '@vitest/pretty-format': 4.0.6 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.0.6': {} + + '@vitest/utils@4.0.6': + dependencies: + '@vitest/pretty-format': 4.0.6 + tinyrainbow: 3.0.3 + + acorn@8.15.0: {} + + assertion-error@2.0.1: {} + + buffer-from@1.1.2: {} + + chai@6.2.0: {} + + commander@2.20.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + es-module-lexer@1.7.0: {} + + esbuild@0.25.11: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + expect-type@1.2.2: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fsevents@2.3.3: + optional: true + + luxon@3.7.2: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + mobx@6.15.0: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + rollup@4.52.5: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 + fsevents: 2.3.3 + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + terser@5.44.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyrainbow@3.0.3: {} + + typescript@5.9.3: {} + + undici-types@7.16.0: + optional: true + + vite@7.1.12(@types/node@24.9.2)(terser@5.44.0): + dependencies: + esbuild: 0.25.11 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.52.5 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.9.2 + fsevents: 2.3.3 + terser: 5.44.0 + + vitest@4.0.6(@types/node@24.9.2)(terser@5.44.0): + dependencies: + '@vitest/expect': 4.0.6 + '@vitest/mocker': 4.0.6(vite@7.1.12(@types/node@24.9.2)(terser@5.44.0)) + '@vitest/pretty-format': 4.0.6 + '@vitest/runner': 4.0.6 + '@vitest/snapshot': 4.0.6 + '@vitest/spy': 4.0.6 + '@vitest/utils': 4.0.6 + debug: 4.4.3 + es-module-lexer: 1.7.0 + expect-type: 1.2.2 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.1.12(@types/node@24.9.2)(terser@5.44.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.9.2 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 diff --git a/auto-dark-light@gihaume/pnpm-workspace.yaml b/auto-dark-light@gihaume/pnpm-workspace.yaml new file mode 100644 index 00000000000..483f12ea4b1 --- /dev/null +++ b/auto-dark-light@gihaume/pnpm-workspace.yaml @@ -0,0 +1 @@ +useNodeVersion: 24.11.0 diff --git a/auto-dark-light@gihaume/requirements.txt b/auto-dark-light@gihaume/requirements.txt new file mode 100644 index 00000000000..9f80d67d559 --- /dev/null +++ b/auto-dark-light@gihaume/requirements.txt @@ -0,0 +1 @@ +pygobject-stubs --config-settings=config=Gtk3,Gdk3,Soup2 diff --git a/auto-dark-light@gihaume/screenshot.png b/auto-dark-light@gihaume/screenshot.png index ada2f7144fc5e10c7744ba8dbfca82d55c5c80fc..ee6223a2de74e4862ac6cb5b8050d043299ea7c6 100644 GIT binary patch literal 261107 zcmeFZbySq?_dYu6tC;W_h@yZ&NGqwNihv^$f^;g~(vpKB79cW|Gzv&}=U~y@jna(* zLrtCi;QPLxIOm_U)>-R&e!uk_mNGo^#2x$I``XvO?s=u8AbaE>{XrB8bp(C;mNE); z7~WEO@81W%=AM7`L7{f}m`h11p{1nGJ+ikoF}E^Cp)Lh^28rMPa{cT#eHH2U*Do1v zo#ngFR=(+Ln0fOk$1|<>s#L*pxOlV_c5LiY$;q=sjSP{JtMhZ;IrcwgI=A#R_=8`_ zCN8n)TSJ2g(!=0=n=VJQ{j0a&_Ls(F#Wzh(b^3~ck>1Xn0zi@O6N$32)t6~_PAFR@46tx-R9Pkvltua?%t{+ZEzJXzY2c~m+}C@IC~ zRt;Gv64@tKs|lw)RZgC&*z49)F%n6*>WS*;QeD}1_39rr2SX~CR+pC6N66xx3(Hgi zs`j~WJVL(0tn7OzCwmJ;L4M*ZlY`;Nfk(GB9Z)Eqi^#uSkCP;wkvVik%S%(u9@>5M z+?B1(wQM+a+EH4=QOefZ+StYsC1r2?z|q*~oQt`m**RIXypsA8YC06^914Bw#{I_w z3&XBD_f^Mhe=Rq8FYM=dX_dF%CgqiTZ}dX;5OL+(ov4$IY>;tnlW9OrwQ zxu8`$FD2V(Q5Oa5#MG3G;XlU$Pnqxj`;UKq&qj=YVb4%qeA zk?Z20|M~Q3!K-zqQ${dkmd_}5@kXMMrxzpp5Yf3vac)Xkfp zn{`_?{sH*?I0Sa};a5=u> ziJ@`TLxX^mmM`@<#(DFTqWub$t^e&B>NAUb4E}Wui`}pLBa5BJHYe3Mznyur6mCaW zQLc%g=Z*T;JcWFEPC)tVh{IJ~Y)eZ^b3K{q3yX_p{#p}rb7?PM?w7uGtFE~@U>?lO zd%L#uz5TLRQqNNinvd|D(`6zZ>mW6N^z#zcwS1?ylszca_dJ7fPgDld45ht+65B8L z(J)$Vx%OnJ7Z}wm3N*2tq^JMTpFbL0Sy_q2Vg>9caG}A$DyDP2>Aj(DXl|CyL*EV^Z-WI6Wv@&M4CwXfkJ&(7jqs+6eQ1XH(`dSkd zI3o0sac$RS;z{@{FK*Z3qGPwJI;|@g2S-|uD5}hP@x%A;=g=Juq3KRzUtcw*4Rfw+ zfBF2`$kvt@y|TI*{Nlw6WfhfDbITja3PIS!#6)JKT@IsV9=aBDo=&AWNqFpBRE1@Y z2KQz-bG|<3q%OZ!O_FW?RpMnsr1=%6)YOgcN%GEv6r0}17%x4}#J8TgrZFYiQ~&7l zb3b_OqgQV!`t%bNC#o&UWkqD-v#MZxkQT*bw>OrHg%YDpBQ$m%cf5PeEs4dCsWE!NanG*P2Ifzre&ayVs{)KO~ z{-eCMBNx*Z!Qi<*Y)?KU%f(WRk~%KxyAROAAk){tc??Do+CRX3M@Yv(D+jkt5x@E&)n}^~H&?v5dsT1g&!Cn5kC%`0DEG zo|``i*hFbRuP)2%%6oIA1I4zK=PT3`wxh#MDC?Caf@uCzAmh#;uYHp1jB~4Au@C8r3?rmBxro)V4w@KUh zpzQ2ydLgS62%0n1PabpYYz8{7K>0tR*H`Gz;DUDL(Y>r{d1pN4pQX$^v zyKanBTN2gIl{OOzSyJbXK`d4y&S<#y+1L%3fv?R(;I}4_ai^2QzgZ5kB1g z^%ad)Yg|j)9^dQ$BE?gt7cG5C3>P^`3^76X6x~4izD-0Bv=YPEG zdZ)CsRLwdrj9VMAc6y-&6LAXB4;GzuXaf`9gou3f)f?;U>tVGwrKD)->C;+bF5*cW zes{!+SO=%82us~BkGiOpk-<$DKBN5l^~-IgKKZpTg@=d7qB|`q@ijL^`>4-8-E?#? zV~CHB&t&e~w}1LRdzRw9VdF+2(Qs~(7t+~PVngbUIGpv@XWDfG#n($#R+^k-#4k0f(u^fznl%bX;q?HjY)Eetxldlxv+4 zzp)XH!{N5qW;0z^B|4+8#r>oLSkP4gfPhfU;}D*qlh3FhmqwEi*#L9>;@${-{#=Qd zxQ;#5btXx+N{af=xERwOl_-U<@;`F=aRC!QE+#RIM}nKsIJzadh0&~|q(3Ld5pm#1 zP^glLIZY<-`p*1c0$Cj3Nw#!!bOc;izVJod6>*vi8F9BQVxC=_?JS!Ndw@-3m5-bm zw8il{XTVr2m5e*1J6;`UL!u>1?D&8sRYPs9EVkg$58*qCit2Y7?5z9qq+v~mO-qm* zV^4BxC4zx)@GL1Bo0@W7zO0mQic5cf%APycaL(?xE64fQSW)N~^xUegy`q-UtgTqNB4@(0Rd3x8%_cu)l6t#ghvQ zTr@N^=&kdFnt&+3rbI&ldi+#WHYXR?U996m-xbf*=3=d)1-ftFzOi4ve7&Wm1-V^% zx?B+T>(^D}m4U6eMTeQT^O+jC%G$*?p`XreZEn^X@uj*frx(E7v#_zL&yi;Ug2cK` zvCF+XLr0fP%c*A38Y>AcPwC0j<~&!eA3!gNWnS!GeKF~zmh4I1Dm${z2i7`ket*Uu zDr&Rk5zjk!?sQBwYd2WMA@0IuSa2*`NUBXVa;E#%NtfJ+_+sqIxBvr` zqt4*6+2?0=Zr`6=VQJy%_$Yq{JlkE~%C*-kD=W;Cyp{x5EsZTLdgC<#?e)QI`071| zp^=dsXjn^bKYVBBMk>n>?@MsQm*w3)Q()Pv001c{1edX37%2X}sR`$UW0CXfsBm=v z>&<{DX}-Qd!~Nb|S|8)uU>OI2OAposI2xoaW`y;bgW=YfPdScyZfJSw<$SlSq>!n? z+`pO$Sd4u=Q1;{byqs8-$l|IZM7uk;Z@2Nc-tB!a^@8I*<%UmIH)(?+i*=l8IxQbd zG)t8`?=lx6IjCx4@)1l)CDVP-;Ic*wCt8wRqLGawKc6f+6(9p=<^VvxZ=(r!+$L@4 zg2QKz5qEE~CrZ)CceTBjVnz#(dL)GLkWyuq)6>FK`nONMyZj*9UnaO|N(|hfe^2(P zf$NeVZ&g=j@yG|e@tV3XUsR5>`gg9j;xxv#EXO_dhPMT+=Q7nYwa^XA*WG`9LWlKd z^<)y{2a9WGGK=+8+}z5vifvRAtpET;8c>^Q|M2W()@>tkDs%lH6G*RHcHf`;j*I7c za+L2D@8k!>>m5K0#r!X?7e{0QXDW!#1hB>eW|Z>osiq>c`Qm_+bgXuvMS!t;wKrKU zTl?0nXJyXKOi7XN-lYhSJWkgrq0A=7X@(6QK6FTBd8AT~3l@XAZ6!X7vR^e1%9g9B)`lE-PaY^{VHXrs&CSil zGPALF}T}jgsi%3aios`khMe(aeR;qZ?S0q;LFT@{`~vfa1Mk& zH^QO|0`HFnX3ws>uJ=!KoF#8S=m}<%0~JnawigA*m15a^10jM;z4Wpdz;9I|}S zPc~&UdJrXS8^nD2u#EJrg2DkpMHyc1_U)Vsm+iIEJ6~RmatIfH*w~)!Oy2T=gu^1B zf4ID(HUnK2eHS{Jc+D6=EMR$}r&HMR&0X#i`!{9!D`O;ltX9%wHQ=UMI z;2-W$kt&gcLb0OKuSemNou#6VOC<%+@f1 z9bNB!T98z3c0_G%ZD|#akB`d@XJ6>eDCiGmo*gR1nf9kPH7OLPa^S5;h|7dch(@Vx zuJnQ{1;58lUOaWVil7IsDHuFajsNLPD#j8;D(bJ65UyUodesg|6Bj=-biJ!&pMt80 z)nw4&VRbWh19U?RzvaT*xRxt(f`yaaqcJxa!Qb8l!B7J>6O_=XLi$j?;XP z+icQldq>9*W@Dp7%g&G712{>ASFdCXT$Uxoe^!&qw&!*g+LK=wDXP*^ub&a-@qE?a z5f)c@e=#^ZI>U#GX10OTz3$Ved#z%tAu@rC$$oUaVUKN{=R$CYo#mUz7ty9I#9_^` zCB5yu8p=XOi4KFPb5owU(_AO5*4)-Yf4-0^u0kw-s+Dp_A5*EsAgcGiuI`P+U{NMy z5!~+X?f}g#)@BHk0NqL*Bqu+@APCNn?X9oR?0A8vdDOGuHDd9z7mLGoRfphC{G3r$ zjox)>es?dDI~@dD2qa1}ZDH<#K_CkZlJkuCSo~i!LEVSi2TrVb=r}MWWq=}q1{=mE4%#whDN2&=LJ%1O+BLrBR10Hx zDfS2EuN*`_XTsJwt3U6=PbyNSph>qK$*shm0ri}pT?b(?IA=y711YPctOil&q{;f% zkgOAKv))}Sfw~xe0^VAY2$V|VGM&ChYO4gHqKg9YN4Bx*-o1Nai@+;1-leOmYMvNV z_Rv%Sc57>EOKrjDyCmzu*M5Y~JWmo{N-hRHQ**{P$7*?$$+S?&|D_oxx}l)~5Eey! ztm$@h6qOp$=Mf9r9gZOh;UOhALdEu6BP4Y$0+39AMcgkTK6@q=w)kEuJGfn=!o%HN zRM&m+dU}DP^jUGY`|Rwsp|P>=XFKE66%^h~l3_Kt?)SUzs_ z^Sh;7Y0thRXCD_jk#kK`v?qz3WDo{67aC6v(eaoq4Jn33M_cvxc6J6!D#5^*#H0*`CvI!l4EC`x3&0IJSL|s0k=NgXh)E&xW z=cS=*jm~Cfw}YnPZR*SnQAr3gJIJTGPuh>VPA|^&{W^$N2KcR(t!G&1+*DVmU)C@( zlJ(V~67nd3HqsHsA^7b^l@ib0yLSsb_+0YvJn8NE-c*%j1&iUbLWD|bYRWhmjns2$luijlSH>6&8PeJpcp^N3}6gM_e zAx31jN86UYNO5)QNuNF#5K(*R#7LrqOR z*PWj1wPjq&JPX89anl-~QJoVES*Y_uA3GbHtkdFvs*O$7>o;%IjEsz488cn|)3(2A zKIBYCb zpy&M^?I%y4P6am)$xlk5g7@5rx}dIt>xk!ur_84r_esJ1eGxvS| z-0XX`B^N^=lJ?Bb&Z?1OG-I~8wF)$fhwSsg{GD3GT{xMUZv!^Fr`974$Y!=|eqSSu z0Jh-qFJgYCVr+B6GoJ^uDp)`t@iVre?KNdlz8Y^IM9V16o{hF4u8;8-yFZ8Qm zPXL$I*4BoT7@Rck$>{B>@+?*2D@j%+)~pOCCXz@*8nzrUYdOibs;j~`*v zh7X-*@>|J@*_G>eG7A))BAQJqH^=TaN2~^kiHmnb3Qd}pr1VfRc_ad7q4~5oasl-= zQQu25%NvCOX7t73edGG?DWfq4gpK81;KIzNn&>Piozyp~(q`=&95#PG5a0aHEFZD* zj7TJQ0ow)u^?je0To_mP3np^w9F9L-1(zTjIG39I(Htfj*d=wy-nz?Oeodx?^HNlS zTA_t3uzY(xAg}p#oI=?7Uo;UU?eH=`pZfR+@u)iB*uLrH%VdjWh05NcSw)h~cdE65 z<#EOI?+&|Vxf^E6mBnZ1IHcB|I<|4!ytX9hKW6y|%<|ivSvKID*>h>l_N!bUmBEA> z!1ha;N=k2^`uMP*uU+d8OX6Dqv0_WZ`E3*cM_5tpS5 zzz;ioX-AS|sHTmx^BYzL4~z_$3sIylYkv7Eiczz?=R$3+Zb`jRc(&ReXFgV z|Ll7RB45{!FE0@4-J&anVm4kQ-$Oa1wwZ zX_7tF6Sy^6;I{T2s_J2I@o$5|QaVutw>2dS1+07Xz1iwoT9J8qc_)~dvY~>e0qo~9 z9=)cl!u8aMc}FdNlL{lv8gQF0(xK)RHi>bt&ntA8UKVsyfDDX6vVFrU?{xxoCbQJ%I31;f6gECAh|+s@1+zlw zfOyLI8}_H@;!|m=|2%fAg^dlST_Yel`2|EVqsym4fj0B(C#Mk3~8XL6_6{xjxGii$KqRo`B~ zU77e>3y`)oiQ%T~w}13DKVKy^yWD`42Ms*$31Ou2Y@w)^<&Ue#t`ODdawu-tN1+w3 z*<39bJVr!HeBrydaMp!1NVbFG5&fsyg;I*FtGj*r@IJKQ=q>}>-*pdtPkgDKm#fLE z#z{9fx0#|rn_S{q28J)v5Yw(_f-h|Rv$AV@dbmpCxs+%r+;FEyJDo|`?w~T*f8cB9Wxb&z_KW9uiEN7W1Lxyf4G?doZcl-zOSKt z-Z+A!r8(*NJh76`Yds~zA-ATXsj1=|8j_GPH<(ORj>zw-ohCk><}WP(&uJGIVell0 zkoRg$c>(L&8N#kOJNC^_fF7>M_yQGW*(wgf_3Yu*=({1aowAAk{DN9sJLON5&Yhj| zY)Yq9#XmP>{~gliff(ly5V)nMCvPMq2S(8Ok_y z^`mfA^Qw8azrMK2_$S;~_zYg*U~TYgPTL>( z_a!u0XJJcM@lb#WI{f@KgQ-yC+Y;I5)_z8P`D%Q#UN;H+sJv&IIGx95bT#-wjM#-QKQvB{B_tIXs%0|%9!TV>ln){!RMk7z z@BBA+`ro7jlBfS4g(Uwv{L__xz4`yAbmjj=OGS}VRNse%1;2*+`g?kM zu}voYM|Pu9u0UB(CgGm5vvXdt?RB5uJw{4asQ4m8uHn7?6ubwj`s2H16JrxSB^w(a zPzj|J;sgOvHZ(V@LKb$GAqIS}*>4??x7IC4#dB&#>5;Xr#I&Od=nFYS#}^VF&gS#! z93*tWu+i@gzon)Y#>{^8s(($%VFs~NwfOAXl@)u)?y?FBf{|82{p8xUYn?lHK%oj# z&QXLT7A9u+Cukc8%QMzn*a@nfyXF$kRZDM4q&$Tv5+2^sv z1Wul!BoqnCC>}{1D&np)(r#yGp(DR-UrFxZ3MRN-flS_I@8B@qNC7-4i_i&k&C~Qd z!}dBl`Yd|eatbrB2c^_VF%X(+6$+;azoh;>T;2o9Zz=9>LSgM@vM_=cv^(6?Rx7^% z3|$T_BLN~jPKX~wr1*DHw2_z`!enO=Q$yZ07b+mzsbtDaJa>CmvS zkHh5~W~)<~Q0?iH)6-u9*^7aEx_Wlb+!o;F5A9%7a}mJQ;uqaRMS#r&>I#iLc03qZ zZK(8msaP%8(5KSZ9co;Ms-Ri5_a!K|&c?bgWp?H6+C`2O-N5jjI;@pvl&a@pXA;ou z=XGZO9K!uy8k`)Usz%1Z+rpwP{t2U-*@x$cOBG}c+xLcDxG=zR;X@|!H&QEs@jnJE_SHm!u_z!bade&s>Lr~79Birpa*D~LYrYX9yJ!gC;*P@hlk~#JlRDLJnBQk zjTsQF^!^%WGdqVo4N%@;5DRR#VwT#ycagYHTRaKl{?eUiT!Ls+2dMfgL#Rz*o^XUcEfXr?{dF2ipsk!>31 zdE>x=7v=~uLOS=y5qg2PuGB!z3m*cQXQ9HZl|LoSAoln+Kz}c?R7!_ zGr~P9lN8WWSq>D;LWdoLJP|PvR8xUE7QX}&AbjlK}r9s18T z#>U38)lW7b2Fl9T&b(kcIbSsRd^Swm2Kz!*NAyo5e1NK*g>~9yUdUC=3FO}qV+F`eOV5Op?b%1gr zuy}3Za<*1+9rD7%DJIPx0%mQ6Nz^FdkGqFmMw4R2vqJ(ERbnLLvVc6dAZ;Ik3~U*y zQ`%#8jp4k(`T4<&7$VxbFXtZAl0M$>+1Jq9tDdZwJliTsgYb<7wxd;i^P0z}0|SOL zVHDwx?hTFUuSVSFtwEX8mX{5poP9^i)b8CQ(VjSw`25K5Z*M^X{eWMA>*`6H%bbKU zKgEfenUswY!gU;3tHL1-W}jZd;~jVkUQkQMT(!Gd?y}tebnoa)S868+x>})zw)XiD zFRZk8$66ooMF=>~7~mHNwdJGS=9?n&kuo-%eKM-hWP2@{JKqwm{P^*^Dw1;*vpI!) zRh+!3qEo;D<>AWb)C?JIZGRr2cMPZ^*xY-yYzcf1e!f>*++8o#8zl*dVHU~)12~Ez zX{GVtVqb247Xi2hb?CX*5hkznGRIf<6J!DeT$aSR^@u9IbDPVUz^=FFeLx6-uQ{`9 zHe80+xr*2hp!a5{-Xqu$O40xbc6fg^QhZ69=vJ*{MoUtN`P57j zI!jkzeB9RiXJNfV5i+3Wq0c_>x^w-eaY2EBfscRKYv_t8;@$fHs z)?kxnH}r6sQ=wQ-Mnqtw;Of0V#$o)JAAf;WKQ9ZT_VH;Kuuv+d3N}ee+_5;@fr3=M z$3L!tdrqqx*VEIR8|;;X%5o1Py=dgceGX8Qg*c}G1V#MN@Gw^(aQqFet?EGg^@Ol@ zHgJCdCbA)<*6|zdB6pyxyLEauCIf2-eWr_Xr?VB{ei5MGG+{e(Y(Vstx z&FbC~se5Q7Hkp3F;32P!27}8fmc5Xf!ph}fpEWD31zhl+!;q|zI^L)O*!@IsV47hqby)4e>5SzHer<65 zoWJ@auVP$F^_?7~HS~dw13Tbf`Dte6$^~)b$&)8#b7^|?qRu*{#_#U3A|YmOpwMqJ z_cKYE-=wJvO4SLuncfIT@O|YI(qeCp{nXTX9;ZcEO=Nuo2Z1Cicm5W(8I8lmjkr#8 z_YV$oUb%vf^Ab@6p>AlU=N?@m^QuO93vD?<~~uenSs|4!H_*NqcL46?paDA z0=lxUGAB-;n&%)mbgxV{IuSPyz)a2pV`K?@XC7%>TYNhPScZqKFrA|g9u(`nEw>>qX> zybPdgW|UH;Jy;~Iz0_zL>#6{GM}o|7(tOq#&~Z?@f)yp2_oki)6~%_XT&9*U-7Mr&^u|MVJRbT&v$|A2JCj}+t-CQkaPKkVg{|hOe`)Y zf$H;;kaHj(AD`oznSCjqp3f-fIZdm+?qskcSrJFfd+PUB(KQ{Ex*$OFV`dj}R)onZ zcfqYM4eO6NK(TnHbUHQ+bfnneK=U7;mmR-fuK?vc(5IY;uiCw5&svvC;Qad+jGchn z?r@m`WI9Mg!zpOWAjlzUDzB)R9l9DGO6b0owSOLwT&nAPO0x#vOID2Q0f>+VmC5kn z;NUXH*~Ft4Wq?beGv*78p^Vx$HbYe7E!0O8MFTkx5?W%Lm(?S${yLBD@S%Cri->p- zgt#`7tMiurCX%Q;ay38Ogmnd^ARoQ?mXDvGyLEA}SP`hk z4q!DWCMT2Np)-{mBfPoMZy2)Mo*f7V)t{lO74WnokIw03SFGfTiP5L&wK?1g?a<(=c(qM9~(i7c=V{X;Nzc#fR^?k zw2Ny#_(& zv^FaMMWaC^2tb(H#?Pxfr1CB<4hNsdA}y=#;SHi=$pCt%aAqjK+ZLF$KjZ;k5_x50 z{mkg`U2U5yAuJsQqP-J@$guVi4mVHC1!n(4f(xuiePswyj-B$omLnCda$L#QgFVJm z8B0qxbL|OHUL+^u%xGN3P&TW*v_>y!W0Wnp9uW?k5jUxToiuXgVP%yObzbO7&u-xm zrqEDR^W^I{3=iv)2pgRnqm*;#unb9FUP+2@R6WJ=*zb_>>GpAG-~HI~@^WL*E4kZy zP@t>rD&J7WCZ6UuIk~ms`Q+KNFIpu(&!9WH)oCsjX24h|F&lB`*p0I`c2w@#wX4vX z3|wsJ<|O4Q-%{m<#IR#$&INrkuYpihAs`2|G8Ei~%);NnVlQ)Q)X#GPio z5M~G+VH)etk3@0MB2p=N!a!#~-Q=)S%>*3MmmK3pwM^ae ztf9QL4qo2@X=G_AQF0OH@jC6P08C&)Q*$%BU7V2h0F=T^!nJB<+Q&f>$b(jf+6*&0 zc;Oe+EFo@9plcR<_>}={2wPlS{Dw&qYL=DmluP(cV9Et;88wXd`b0`lmWIn4t#RYE ziXp@wT`j;Lkg?1z8_!`FH6A@`)8BZU1=UxTIWJDN3^jE8ICIxsmGXvBko%CG|3`cxYWiZ2MSKN8h+sCjz-Vk+-{ir_cp9t7fKpxni_umM&?X(BPgRV|BH*hTWM!G&w$*Vedx z9okItb;crlB+%H(O5MyD$%_{gZf2Ki@-smU(F4Wm3LYN{AP1Z(RC=3^sL7siJdyM< z_P&XU8VHrx*uu3Tr8G~HP|q2A7Q;Xh%VkCO)^u#G&KfUuLNMFAZ(kkgohm9K>j0~O zX2LiuCc^doO{WUlhbl7oyeh3p+NKYS zu;*fR8lyJn<-588O4hK=y~MPM3_(}&>nShQX4(hhd-dxS(bx3G(%SZN+-zu`OgeL=?_r5^e-gSAyZHa`BGIPoX5w2X7eCxc5XL+uImuLA?s%bkx78980Q zaoq!?gM1sD>7A)CXt|{IGq{#8pvVKJzExy?{q* zxy^ZmPAC!Ep`GFnj*X3l1liqaX;HA~&58-*<(07X0_qPc3K|o+P<+-dQj8I??w4>A z!0f|=rc=P8t5OXk-XnrhQgQ$tmG;Woni42bg=|MYz$OR|335CZd(4UKQHE5!_o2Fu znzl~0I!-Pv=}mb7QV<9WFo$})ak&Be%5E~*%WbJN89vPN_dhg{YnTj(za2^eA<-Up zPoF+bFEA5H4_G6r84Bf!U0J%%pb+r^!pRL-JDux`S9F;F8m42w>L`O&7nmCmZj^x7 zT;D1VveLP_pbz{I8QMnjV#1tj@?x;|L&{4)|JdMr4Kr7@`PFaXlaeMC7sh}5xHshm zJxI*8I{e$QKlz;tyoHPxj$42T7I4k^?Ulx@I|>Rs8zoTVL3aRA;s{Wnar^}hQ&@F(^_SY5#YX( z!68q=k~q%xrgx$~aDMaGaUCvjs~7)Cv>(6|VDp%axchorx4JA8s#(H#+ryJ|%Z0Ej z{KcOmw3IvUp||uaDop`;0#bp9G6l`na%65 z#@|Gofq-E_4;IUYpCZdCo0&Zd=t}y&aUG;NkX-4~@tQPtcS{2cf;5Q-b^#(Uo>xp5 z9S$@C6zYN~9Ky$!yHXR3_kJ(5^vgQ+=;!zIz%>B2Pj}zQN(yT)NG%3-$3l!!+_RM# z0ZZoCu@$!Gh)^HrO#)4?c|fFw~u)rjHJq4#r{&9A_1=i3g6?qysqq){sNMtS^bRq~|R$QRev%?fG&+ zG>`M(L5}!yDf@Yhv&@aNtSw*-7LQhR4zl2ZaQEcTY~ot&5h!jN?&|t_NAs(%s`Syl z4^WyW&m*=-p91THzWMH&-qSig{$u>twcgSerBw|Q=w!45nN3|6AEo2m z-x}q_6_rNmRz%PB=TB>G&@fgQu8(3c!s>^94LPXrJ4|IT*XPzUhEg+#WZW~2vfehu zk=FaorgJ>DUNfVOjgt=LJ%PzxjcE1Y(+eJV@OTwd@B{rpYP-IgGjAF!0{BjiLO!ZZ(D;Etid9 z*@-R{MKrc4hG3C}BiFDJrdvD(0efA?PCPp<5dk8ktacf5bMvZ|P~IuRC`F-)w0P)u zuQn|8f;Og7lVckkTIJ=j9_#sRNrts=EK5xWr{79Zk3cW1`tz94<<5&bZ;u#}nNS9e zDy%@%FAvjTHpkZ%2Zg^pKhiwYp0ENp<^jQ0t3#`Jxa+E(B5c>>v+8T}r!REJCT3+x z(CMzlWN73*3@FMf8SCxGP)MDX?!`p%hWca!XLiFxy<$>Y8pob}R#A$cbHS&Dtjqv7 zMA@3J=UTlcQ}Eds<5ACAW9aQvx<2WSP05d%rZ`E-N;iDdyDNtFW3Si}%iN?J8V1Tr zM-qUX6O*0r#(;4^LEv>jBFl9KWw45qI(+s4KL4>^gItBRS=#$DbMEmivkT7M9JV+X^%Mc?f%o`v zD0u>yzB=z+gHy0wNZYcqk*8b?c2cY72O6uaVH&xMO_nQbjbJXO-xFTh7BykEul$-kx>tJ1@VEBd$abxi6EpnoK21@6|lon#8q0 zXFl4FN?e-^2}XQNQ!EMV_uCW-A4)s%RQ&u9?XmJ|tD0(E9^g&ha+P5|{Oe5-_1ta( zcSRc^IKNd`RQTwDYKzExg~y_0auRa8t%>73TFW$;66XZ2m%}GWxY55zjyjmD6DOSk7nZJ_UKZKM32 z+x}KKlJm9Y3I}Y4o8h-0S;onS*}hvC6l&xyWGU7A(z3EzT&h-wiL;8r6W@JknwH9! zVfH&6_1j8yLx-Gi!%X$Pfi3&#*M!b6@nd5@{qnOYiWh4>$$Rk zP}mXt+jC^SCj=N9Zs>!xXJbeiXYIcJ*qV_IyggdwsRB^|(&=ewaC(;~VVp`B-hhADklADleVF3Z#iq;rq^U2rcvWiuUTA5~M?gSjTE zXUDR0b2o!xYPC%&Z~_FxEwS!z2F#`_kU0cLQ96P3gS`>bRb)IR96AxrrC&9)7h!P> zg40q{>k-Sb!I9o96pxl1J|iRmEUChLPiFq(Usy2;@sR66Zmq+pCq_<6>WkZ;+pll^ zTcGC_l|5^xArm+vu5CMfk%c8GLfBUCqe4s=jyU%<_ zO1|mW!sgt`xpYhn^VXCwZwqXc8Cs|nv+OD0p4twFec1&Cj+xnqMwBzEMivJOH~h|^ zUbpR`87f8-23)2*{%Vq1`Gqfiy@Q?!0kFz~(Qm}+n9Gm@>**W{{+(YsM?H*X^+^q8;B46m-n zQ7*kWYu_d^f7WaBJsK(FH$#xZ&kz&Js#)Y z{adOc{T;&e9oX^eusxe>T=({T>13ETANcGO2Ys!|7mKbfl^EvNGA0BwtLu}fc7Xum zWa4Fm>iB&RP^j0R&e(FHu|Od0-?v;oH#f&zUo=QPlu@gx+0P2o9?oykRfq2>hv;Ar zo~i#~79~Tov*_i#V(0vDmah9JxJAut+QwjJC_x-OjEeuJEl#nm3J5d6dwicFd)^1d zzXMRhMhktFz1qtkqipIosy0Y4&9>~Ll(x0$VWK2T$*KZL8Z?q&Abl8+$qn zEsHb2Y+=J(^V%%G{jgK7DMaX}u(Y`S5rx5bYY-h?InH|b#Bbq3pT9p78Es`kFut^9}LRN@A38<-9qJE)C^$}e z*HYe{K^6+@UZrrV_e>>)>)lRP(Cq};E+i!6AT_GF25y~GdI>yF-KxVb?+@*5ZEtBg z!;-UFj(el}HsKo}fJlitVFX|PB5m^R^&}eGlQ{@qVx@Efx}L)x0XhBa2w`}Nbdu7g zMER(OuAVHnV@lu==;sFx7fguac^uToIeQ`eD^3u$PS zZ`f&P^%T+^;9T`z{ke1C_kY(L+5X22MClT5w%MP*y+ogffIt@;`rzKyT?l)K@@__J zJ|yjQ3uP7S0qh3yiVDsHAbRw7DWT7wOM6`g3m`SdVCU0nldt8Nf9uWvQfpzS2Rr}$ zpJt=}zja&JBmQhVMtjg##}gk4uEQaC1+dn+Q3{!6?{5dIl>;(}A^XN7%Uhf9EiYH} zw>#9a%mD5X*WF&SJeQtbPa%!spY8}!zh-#8ls+1!DDTU9yV zf*|Y{Y>XK8Xz4+ux+uHEdi`G$TzxY6?tU}#gT6P{N8Gb(7U}ff#lTi6A)CN6!a|@f ze|LSyh_4?iw4ZDMNGsfX34{u|Emz0aY8Hh@G$Q4ANuTKPVZ8c0FL&;0c^(>M3h7s8 zlH7F7;tM7(<|9YkjUmxzK_g&`mX;Rst&_iFlGzh_dis@C4B0YZ9cK9~W222obP7q$rU<3eNu zJ1kdjOagNdQ@K9C51XEvAn6%L(v;?bRu>$BB)0io3Q2t5TpjzlwmixUM1CCzE9^Vv zi;X@%do_R7629KXVIqjBxi08pM}q7IV3CTI22NM<7M%lE32cejbjHQZ=nqHJPH*9Yc1U{6g(Z6Gio3Zjc$ur+?oTt@1} zQuKQ%mzEb2YoCbg#kfYuuybWF;%<(u#Z^uZ+%}fF6DvTWjx3?)hx@OXAiIcR|9_W?VV_9(CZYMy*U-g{gkAwW!qr#5R zyxNW-j;B!(DpVbs+0@mF>dlj5B56Eld;*MNw_O8!vIo!P5NSRtE!zm)gBW~LHv7^+YhZ}@(t~bEY;menRH-tpm(s{)7_M2-{Da2MvbU2;f z<4;F+Fq3q~t^H=<*t7Pfrr&WDe5qaGb}T^&y8qRwoV)4*S`pQBA{p zUQSLP^xr|5d@?N(wj57L@DS8JZ9WwM8BdJ4aVwon4PKFgqp18^L^&*u8Hx&DS2tiL=P<}F}0YrMcdXw z*J-HFXnf!t^Wv3+guTG^+ygzi7A;qo2SP$vEReX78pf)_%`BACJ5fRN=dBYxb}VfA z?(!Gy)!m`J*7?n6l)>7*QH}s;MoCU_3SN*KqotqY#nwkWg2^Oi)}~HuPH>Ehg$Gy`8?tt2Jygf3ri8e~&l;w7jE<$UWOZhI>w$dR zo>}M@*g~_ZFfyCF@T*o3pNS2{01U;TlUJ{~%_LUWXOAXqo(vbuAz10#+icvRn&inQnc0$!ZAbsyk^VNn0b3xAt_# zDWNa8MK!oB0o-mAQ(ks}``YIhp8hW0$Rba;39EDNC1Hz;i{+;Qy9_icmwZ$wh~)r) z3K_~aZ(g$T=*r@=?G1}(vv>hDhO$^mFn4xLRsKk?+6N$|GTpEmpigd%znbooswx#L zu9Udz{t>Iw>E+@~j=dkSbS~48QheDTfQ}i7l&o97kx!_E0HZj=q$y>d^aBGDB_{yC zR(o>S)+TAx5roC^F!{M`*Sc`PrvU5n= z%aD83WBY zgz&*lT;?B_(a4)BE|bJaA9yBTs~b?81{^ZEXi|+7&VLyxkDbLhf*~d(-vUoA=&}bZ zC#`uB1Qx+ox2Z4F+k}d(x@n>+aZyo^f#dpEiOdQf6EDmIem7g`v2J}m+TsYj{NU6$ zw^)Z^%)foMlW_&J>}F#)y2Zn4a_A%U6bn`ymo|E*&RdIzEDsCP(xzuy zwk9I#@rB1>EYZxbs9|BS|1SmI!dnvzh8(Jw1zUCVZ?`qj1WJfAiiLL{lo0I&?jVhkX$#L&Chh#cOsoDf7F^N-FkbI+sRE# z^Dk$Z1aa4LKDs;H>o zprF<4GY%~-f9>6to&4^_)dGW$FLWk{6x`W!I%flyht zyE%LH^}QGj&YHQl)tVjsJC-Js>!3M=(* zpZ_CI=JY~u|LGD?vbfM~QcDMpVnmt|6$czH0w7gVQo5d`tfcgIr!~J%;LL|Hoe~E%15!%INi~N^jHt9JO!XrryJlY1+gt z#k?}{E_lWTJxOu!vt)V#nf5b$dxEmJa=MD=<<+KUXAAUHNQ6)HFe^~N5ETX$xz@Vk zfNz*RLx(yPj%NMIs-uV}`NQV&M<&5^Up@7-!vSS?XwnM$0!sMeMJzkIs20wjN=JEI z=3lTH5?zl?61nca>4CaV@fzL{r}T|{Cx72Ae8Wqi0Em;a{DRAN(XZ$BoxZU|K4)cu z+N@=folm(FTBc0~m)s~@_wn5Ny{9OCQ6pmQ5flIN;I*<+{j^%W+tO$V5+c@tP+KFn z6>7E3@$^TQRf$dIJYJ+GzA~iHUpQ4;i?pQ$!xsw=MJL|)lFY0= zDmmMNqjQbNrT7Mq{ahzg`*WyN>eQ#--RmevWt%l=FE=q)?UZ6{&PC@#Bo=~( z8ZWMV7G63%*FmdPQPT;Fjc{W{&Q=>Mu~KP& zXOOVE@b|v8A^UclSc&Ug=P~EeEUBJiUwPp}B&k3X3aEZ_uUDz`WTUcj$KT7sLie?J zzex5_0}Vkt$c_ue;y`#v@ZBF1>*JLxSdcIuavm3B&FNYU%xZT3e7AL|yTqz^I+{Bv zqo#XhY)5=zqFF$X8k$bk+%&sdvAHA`$YN=r;lnF56jeuBmeJ925jM2R>eSv^k#Ttn zA0MB=WN$1FP*E0Xv<7VY{MCBz(i_EQX0l+B<&m!@B$_E*n&^rU&m`**92~qn8CX(< z8{Dp*JrEw5f&W`HX(&{13fMB_{F6kQ3u!L8Ox_FcCJ6w*O#bGj`3i~PBi{2j_Ht_a zq5mKlG>{q}Kl7B4Y$GHi-Qt26J>z}yqBx$7M7MkRB>6M(tO+6+RD=-Xv^s*bUXOg zJ$I)S6D1N-%U0{@KEVOI&3h?k*w~enVtHR*Ss8zRH8V#F#Q}85ni%@_|NQrZ%ZLZp z@m#GHX{>xW-z_Is<6edCH#!G_tjM5m>6;WUb&mI;n`d{9T+5lAQyb~J)PCQ%?IN<` zU_bEhOS)!r-Iw)UwhIrQ^J>QvFP~$n!)w*GoYjnmnVuokmq;~O58nS}6&1tbMw7g$ z+5%pa`re$;@ghdrT!{n)l1KwR%rtfTc8eCs+KQnM5hUU6MiNxiKd$JXOvI~`tfibc-`^%(U`RLy zkm4QEcuxIj*ei%m7_2U~h-8?z@(8Y>bi4Cjy?=Iu;g8!jl_cqG)-dL?>~@*5$ouk8 z&nmrV?Y!!;stzc6!V;fke(c*2*o%F~cdmUmSzNrXFR*<3&9`6A?0o$1f22E4fXx4T z?Y{lbk0dRB@_;ks&|?QWPWAr}e&UnA-ymck834!Yg(Lg_oe#0@@3;B(W{MmBFI~a^ zPrkY850ANqFJ&rs$Rd;)C7!$QeTUBc34!ggzCygTx~0m039gf`dHTbx^>mzfF0zq7 z2pkJ{+4kZgX~mL1^wUf>ueDjoAJ<<0(^?fVjg4pj;R4{D|DWu60D1g&F{RGR%F1DF zZNVsJVxK)bdj@~)!71}h@q)Cp34%{Ug34WwQr3SpYr3NE-CI1NmCc7@cx@cmJPnaf zNiB!R&W=M_OUt*aD*O0unGG8S4*#^q#Z$cyg zCi*sJWIdjiN*@090h^yclUr)s+RB~v`>c$P&uDhX>D@Av=F$51`8vZn!%wD}gM%6U zSdP2eNmj**2dgU3IPdn!cJR@epF-!ymu1hM;k7sYMh!?j_;Zp^iyy=n9N*q=x($MDntS2ZQHg&~wWzs#}C%yKYE1oJX#uoxyr$hNNhhCibDll01ax;J7PNw6mRZW+D zNbI<5MM#|j<;2oQM~zl1dcid|866$puFZ6c8?swt+{?W?MF3%+7xRAj@Zm^q&-T`< z_s?=c#hGrrAV2)~^ywo5QO^oz_VSOZc+%<=S_^~rC;Ln~@-{5=Px-d((XgM_(CTQ1 z{0(_s(Z^X3QaTjtepImIhDGsQ(Rd+M-+8t}7^${3(9r6I5o3kx%~Ol7ncYJ6TjmNd z&zHJ|uxyW%91XW}rQUHFvprTs)o;(S3MBtZ-UO#|zI1ALj5iq?*steWz@=gTai0mB zSr#t$MY`|-tCG{vDz*Yndib?|V%F35*F)9fE|SCT_V(WnNib0;X#Z*>2|yi5iNfp` z=Wqv*$XHTl0m^FB<8p@*Moj*+Q%b0xIMX{2mG8QeXEb1+=m`{MO> z0%1%dHJQwwxxcObs5FoD^EKqNOM+j-ySmE4zVl0Y=Ww*N$<#=+nyXTrcq&bT>K-7MFPyTx&aWT#Ikcm0EK1bF~To3UjD`U_YvUbLt65hzn zmjzmH)vd5c`LIbT_0wICf+Cvyg#=?p70Epdm{P(zu7e)dSoi{i!i^q)XuGS`dG4VFvYNd z@%{7i&i?pBSSZ3qj{ zurcllxSv0EXM4d*B-C}bg%=#l@^r$ff)HM-Mb77iGVYYOzwZ#A4zEkYnqt&jo^mlb zb9RHr&Lj3UY9)((nHZ{0OHzpFA}Ky_QO@p#+GrH{W-Tc~J&$Nrv+Y(bQH3B-?1Mld z2CV(bG6d?aQnQ%4vn>q49;MYZYt7wi(HFsLtX(!m+q%r^#44VJ>o12zW-jXZtlOWw zQlF4FbgRNgIo;fP3rB#_&=|AH&K@ouKEb|JdFSrBNSCojKQ2d34rlYgMQ^RxDASaX zzZnxRkrd@OJmMcM74z{46x}E){}R21TQcE?;jC zwc1j(-B-Lw)~=eO9i(I5Dny!Npt$tD*(KqR>DE6BC(5BO@FUl}Dq?~B>CehSy^nwA zv1pqPwXI#Cn!95=p{AGH%dJb%$OzZd2MW7l)2u-Y`}NslFvfa8W2pgI)`GD@O2X+k zkO)1^EDBHp&{j%P35!=&M@I(@x-rq^uSXnLW?IlS40M@)ec#~SUqv>h>zLmH3gmTL zmT0-&6Bp@Cik?Y8zlNxnGHwplzYChGYA>f@E7bz04q^e{PNFy5S+oeL&eNlbqa{>H zvw}=hOW~E7`^Po1PfOR^e@Qqtmh%UThib;L>_1u;o~EXFc+eR?|WYi2@zgWTUa z%s6EOpj83`f!C0J<>eihp8ehLI`U|aHlRBy3_zK>1|x$0zdn1>WeKx z19EqqD5JNXZ8eTT@N6|p6|m43!#o6-cE74e1+{dfp)p39V81^4_@XgU?_$M$)8 zH<2oIJu*`(`-Z&m>WtKJjp8V2$E${N_3s}S)|6BWW>2bxTbycn+Qd<3R3^VEDrKP5 z;9Dq0c)gV)^9S8S^U$AZLL(}(`TKDz@Q}qmpsQmF3hp89647Io z33q45n_gT!=gWe5U|oGZ@ZWi_y|I*5<&1KlBHyVHPN`sWc1gA%Y)=&1#sfd<&D;2v z(GvLqD7^YZML~F^v!F$@{nqq{ims+FG}7}12BnStNhpAz?QXL~cH?nau_ezTBS%A% zU+}>A`~(_OYFn8?1ZPhVyXq}Ruo$Y?YQE!VOLlT>${MV1*+y==`9wCxRS`vV*H~US z)Bh5rJM*N?C}dTdf`*Ie*V1#;BnR4xdo`2uBTXwUoL}k##esU^zF^#*FXo|oM%X)N{-{)VynK#^fQvy<5t>BcVs==k56QqIL2(78+!YMz zf*3RnOfb^2mrMIE)Z)FQ69OvqN6qf2TJ{zl2RY34hk+$ckIlZc;g1^0R9&&DNM@bj zsK;Q7N=PhJ)`5uW;qcpcbi3oB7M~U83ND|rj!sdnQ)(g4oJG54?hDhfCGeHgh6B&H zIxpF!P1T+Quu1_qTDiP1)$*~#$$AyYLIx-XcG*(^V2UjCFdbeE%$rd8u&`r8&BnwBv+!q0 zl%iUQpgrwE&+0V|-1?(g)mrcJcAKh($(}nOO`d{}BhXUlN6ZU5w?phSxS(>g@LV_| z<~02lJv0KLEPUSKPHD~1YdhSN3GmRkV05Fw=T~Wc8%^;3^NXZ zIQmXrWSjJ7&L2-;mt>J<#R&Q{+nB0Bh_zhq0D_G(^~h9(gzkV55~7b={p&0ivvaFx zK1EC3KF@1ur&qf=`F{Sn-uYL5`RljedwzUuDxu)B>!m$YsQS*c4?R8&eU6WfwXs)F z`0euUeHuZW`>)TIkm_HQHa@C zhX#xbjvf$q=?(T&xp+|!<4%_`Q1$$(uyyh97tIfgN2I(>F-!ot^C(bB&Yr~4uDBq4 z>=4~BglH*}8zEV>$8umuBd6$1b_JN`NPhE%1%ERL3U9jXCOXfu=MWT7N9#rz9|Vv44@8Uw%5$-6*v=WT zD<|Hmq*Z1pwd)SLg%k#cQcg*<=f86u;Mq5s(dT5Uh6T_Y={O^4+q~xqy{ByDiLLjR z8MhG7#Urr|X;MVi1ZG2>AtO1(wXbj#)-5e>pS*^^rz>Ox;{Mzf@nL>Kfn7u-gzmeR z2QySbGPS>fR8A__ST>wl@q2tjm9qP%PtXxq))G2+@M-PjFF$=sef;UTk z-K)FZ!?6(oLwdBu97qOX{+bWzS99w(EKDsosZqvCvzPwaBQ09YwVd<=)cuU}SzTVs zdL8e_A6CkKC@cIWqk#<}gpMvn(`&z!Y42MY)a2%#hQR2}5Z)ZE6Tn}m!+_7pDOHXP zxzE4W*?^N6_wtYtWQ*eKx6?tqYq*tHlG@xlwzDf%Ayv3qe`t^fz5G%0(i9@4&z@pNfFlvPhk*MrUIA7E54aRv#;sEs&ovG3ZQh5CHUNGose=g-e# z!<~MGMu76wtB1ZP1rS}zm6*(1dp7aKPtTrr+gX)s7+UD=6#4EVU5Q<^Am+mkN1POj z4$VD0d2Mzxci!Ik*yG41$>kxu_!}r%r)e;|d`)}k>B-UI2Kmmm4C7QH)=Mm{Amrq4 z_kve?5!%OrAt50~b>WG*xyktp{UH#Cp@TCF`so*N3tFHI6;~6|!!GI#FSxOM>UQM& zDj3Tqv$hyi$}*G<4LG5}p3!Q~+d1wd;WDqNpaA|V;#*G^XK^%T!@P2uL`TE2cW{wlG`sI%T%C3F*>lAbh_>-$D5=}$R zH0AqiR|>v-$sU3&SpyWBdV6{z=jS&NA1utf7qL`APVL;ijs&pAAm?@gBB79Y@ep6= zowA{gS&dT_8z!yua`*1ttI9qWZS71=&Z*7}e9_`ck6kUX{MizEN0*?TuVgbRgzYV* z=azQ{<&0+LAjdv0)}rZp^RhCFEGW!lj6sUm*hvgiqwLF45bd5 z*GHvo+&(h?LbSKfpKlm)H#vF5nd?hy!wRZ9D^OQvIgGo3MJDOcaY~5{;pf>NH_S$9 z68Su`;NwN~9}@O*1_z34arfK{VIZ{~1rbY_zMRI9O?@I&o&ZH?1~DhtGmT5^zDPDn z?wz1orps3oyHsS9dzs^>avu5CK@&V6eVc$y+qTBLOb$99yl6+`Pv&NIY)>sXJgM|k z$MBb|(-&`(Quc-lgtLY}9Fe5#-d~_JF|pZSX0GyB#1JR~s=)VQ^mP{PiS)d2=w&F0 zIR~sP8CQ5;8vb}nrrR|~9S!mLnvHFslGisVD6sMVUI?vb7Z;btG<`p0{u_%HhpCwK zG+3B1^}VDVb5RLTOHwr^tRZa`H#o?(I3UqopP*vKsFo@iH2uYsI}Y(8KJ zx;FflEwGw8JdyB<$=b%=zPT~px0=t*3bzZT_HiK*5i_Wl1dF>q)XcnoRR`mmNuNGl zDSLCXMOi^C79;le_3pQ^GxKxLHIp$V*_ zM-K$i;?8q%)j|)-`fmH~-MiJL=29PE7fUg_ChX(Yy{xVt2PLd{sOe(x_dW*9pJSq8 z7^6M1$gd#T;qZ1LR9J;aQ;!Hn%#A04Bv94bssRrUa(~`GE1Icz@X%#(XaMT5fyB%R zD^d@}TqNwI5}@M*xh|QUPJv&S=9m>h;pdVrFl%AL<)~f0ya`SVY%9|ZN-*x@V2g`N zcSb_RCQ))`Y;4VCW`x=fKbB|y<0`sm${|C-+4fG((%-|UHKKos|JgaeU^x;mS&u`$N&n~gSkK!!aYEK$>jm>SJIo2=SUp-5sfR=$5zynY3n*Dt3o zLb?G%;@nkHKSF&hNrRU-gJl@+%EDl-uuX4VXsC?09lBXWCLDXCnH*>w9Mwil_qXP$ z;M{2p)N_j-ZFh)6{5v2bN#y4!*q-Iyu8LaO<`7@BkFIru=m8d(fwzC%wgbYyk=b+9 ziR=zbAc#TmJL*o4kE*tIXnH!=>E7k)Da_6%m^82wcp5kMIdsI~1tf*RsHTr;kxg*W zf(0Ef-t1Cef56uC9MdLKJn6W|tjkxfcu;)nbke(#lw_GZhOwCRRW&t<>l*f$r=IR~ znIhI4P3=}REl}m2L_|a&KHF!RHp!r$710Q_Y+~Zzxz{zeCM1Vk4{==_&GGSr8VC3% zSLK3ulB?!)?NZLk)h^jsXQ`i1Vejq>TpI3l*tzp_u&^DpaUzKy1SFA7U_NI0zEln! z^+pIgH~z?d(eK0cOfwSO6h#K1NBI2xdqq6Cp<8l<5cR{|oUTRB=0F|`0%R^;Oky$+ z(Q{g!kg7_mgAPieqt!5IaKgPVNQ$51)Qh+7x!|>bj$T>`5(G@HH$#I3EDm#XEA&Aj z2?i5;#s=O#iF6vxYMBWv5oKp)wh{w*#<2O=v4{q|mv-pJw4}ajch#FW)$GPPE`f&8 z3~{yUBp)9IMe`9EsHQ}myY_XgV5%ueW7pmL_eoG3#zeTV>*ChC2S`9nITQ0JgXic0 zU!gb+|Av0S@tCQNzZa^y!qYUj{+^f?Hv>(Ul6UFxmi4K=w)M}1YoxB;;0O|1Zy+Ol zSYPtz?+Khys)AGG<6<7q`V#+i^%F7|FDm`^TQ0mi%q;=L%dUKV?E{~}a~fRslYpNd zVGuv{SokloIDJgsJh-Zv-g_)M)>ys4i)qCe@}Wa8g$d>{%!j5-+ETPEMQS z5!t>Lcv?fRP0k5eb|hg!mk3j;;OF8=+ru33^r&pWP~Lzp+tm7|agKMk{mVMzD04}w zj+ThViM@!Ha97xCRv&fTpXuszVcfhK6onl45Gg4sPW?ffAyB#Q@BB`Y%UShu$@Y&Y zG~*rW6x+TIu;{NWYH;Sf=2W}Lq-~%4^dQNtb4_t8H6(2cK!S_S8Ih8DGD;` zieCt@aj9r)C()J%j_ldH7qNk)Gp0H%=prMG2eK3`^tT%_2nGt*)Dt2{l?{F~LffPhT0b{;HkXD$;@)t`UXj(K8_ zCyJf^R_-0~aj#4j5Mzj^ z2#d);ZD$sP468gQWJP#d=i~?$A0z+2B4t+KcTDd@zpg7&Q z@wj+(vD&7A!L7me8TPHf{?o<=27V#pf;k3%I2jvP@Slr+HxU+E#nc@>pclR{CGj4~ z+B5jFLY-BXI20E-`+#?o3hyxZzjYerBhC^`01AM^?KwHci>A-)bWrG#>LAZHP{&(s zr*nDy&FnjqezdveV1Bk#d2Q23mqy7v+KMav&q_SIByome4ug9s>}uVAEftgJpF=UH z^d-$cJRdige{xLv^*#TKWm+9bd?I{gaWcqmIwKPFN526!DWtg%K;! z{z??E(5&w6)nE*7a8bMM z=mt57rSj;}ZT*SPh56pTkt)ZyW&! zsMN?)`b>(|0i2mGj!CuQVjPuE5hAuRi(f{&%a4UjjAR9*;`daLwEDhVYoVm5ZwsJl zwa(RCO1nSKZ`VcdBylj-wxZ8vOg)(~m2FU1XK=-MA9qy3%ZCnZx5%odI31G@RkXLy zhB79}k&<~#AxomVLH!6yvu^uBnDVukN7x$+~ zS%lHR9pbnCVt`x|^9C}Yqh3ONvt{en%S3h2s;hgZrDRoZXvk2?7S4lS8+R0+2jswh z_^>us=n|ew*s(ZSub37vrKa@sURUv|ZgO(>v)_wNlW;=>Y0rH>vN)&1$$8d-f<2j2 z>kEtj#dY)bvdaAKt0nkf1hCZiW<4~dJ?aT?dTORHFpy~pSc zw>s(?jVs<~t{&MH^GGYg_e7cLi}`V${*(No_y!NNr(K3=>a=^#4RV6&QZpr?=)8$b zE8#GQL6f0v$m7S4x6DC)iB;Or$V9?6rq|ZMAon6`1HXfq>C&>Yazmy~AA8YEvj|K$ zDyDth3%LMOL4FDV%jZCI_fMr~5#ZP$slwa;h30&L0=d0t9LpbPZmG$Hrub2BWOXr5 zOc)=P2B^TpP;JGq_m^J=ACt$1t|Ahud?17xDr3N>pGpkqfy%nwMo{R%~o z4=5rVK?=WrWo<`%6^V&DVxz|=d+$}D*>EA}wn9GvoBS>7LqtY?Ie)h0xWyYjjZp30 z)lNpCqX(i($@kMuC!7dFABgT-O}S4`>1!+{pR(QIF_lWlwr5U8YGJ%Sx_1%s%o-H3c=s7oQ@-?GZ~Bw$f;SZvvJ{vqL-4!KCI>>S zKCi3z@fjICw<9KAsqoeb795xJVy5|xmAGeO-XaZ2#lTFn*7zWX{5Oy@h|a_2blG^| z((@pm-q4bm+V=WV*?mW1j;D5d*>^i2aQKT~OE5@#yAl%Ed(&yh+U$BMf8YE>PxHPu z=jjI@Q1v#&JqfI_xW8@xbD(}tSV&q^LR-TXuQzg*iVwK1 zLWMIDekT&aLbmxeW+S-OVR@e$<9P+<(wt@(q?Hm?Irr?`nPOBETy-t&I}+|-G~k*yNqsx16OK4FjBz_k6zH}UMi)^$JV$veoTLp7RcYGVaZc97ELi!~ zS^niOjsQOju`pkHpTBd{_djKx{!W~qIXU_5G3|Y?^)9QHq>)NsAaGZo-;Kv>^Y@>E z(bZ-~-xOYUFpM68H+)O?s(?J2uBzw*@i|Siq4;6+IH)`9P?nUg zUVTP{qBSyfl`dX%AXe1Smg_8#f=KK>2-e}me?suD8rM*m^UmMSFE(CX*7TvTz28cFuO|vi9~Nmy&pXXDHKehB!V-@ zaO&D${k37q8OFYhswsG=KB>$9LG~hEEyDWELXIvo&$r}nRd(|cF|@WXFsdy&SonMW zn4=1pl)zipaUP*#Oq3G=RYwJWx%^9qjL@i+s@oKk($(7?&2H?077}l-9FJLhzH^PB zAZ@xh9RwlUOd_L3QXr@bzsLW%2JJ+!5;-H6NWl{3R{S5o*M-;vVEZ}QW^Uc(-;0+g z6J-NpV`Hg69a}Jz6#wAC4=5#n30b1``qtrT9M<${g6<=9%cO~BF`9q66h8{(IgX~Z zYO=lqb;iSefqF3At|I{*3gr%!0_V@4cLF+S2L^-99C|^fqzcDLl|MhOVlUCv_r)bT zaF>+M{owGqzAwXr*s;JjhLMss{dFpmz*?Zab7zPjIdU$wcyY%HR3>hy=YeYF(er*S zs9_Z!8@$+EZAW#mX)Td)>>R&*wP0P#MJYO@QOi^(4qAQ}kKxhkg+}?jP_cutk2dVf zsI632=h1OZvt1t~wqiKDUHR+e5`xP> zA>=THCj|%O3AuZT#cr?&1h$V!V#(MYOqS% zy?1W{SQEf))d+4&&t)K#xfU+0w_duW!}-TLyQ91r2E%8$xvkcigUB4%_U7DUzb)OabcOj8@ATv0vA6d3?(!o=5abhN8LhwVPTX2|`|1 z)BwCZF;Ilipv8`$q+G_90HNkk)_eQ#Mr#ubYzjb=`Ez^AuB3L`g7o0a2)!av~?ra z?^i${ipajW0}8BuSo@^s{`sWe-uvlZ=m|e!5cJMmbw(K1EOz<+_HCWQ)x{8}FMnD; z{BtM;I7~cR-U2yV`8V^5VUJECzhd3Lp1`&D`Ltywr$p>{wG1AfdStT3VPA-) zIUXp@Yia5vwSDx64<34mmX&2?{-t!=-+X(z*1qV>p1cBQwqwV%V8H>TA42Mf*}i>u zun|vC@7UPcgLIpaHvj9Th|9jj#1ziX_ErsP!9&lQcWdDudq`-_K}i~r&ZFfWjX(eU zy=&_I@}-J7=kHZ)WH@r@UvK!&Z$4E?{eN-`{2%VtPisV64_WwE|3q3ZnxFdmVix z%Fr#h+1C5yG{hKL?8lG(yI(jl(5D=sdzw$Q<=3rWguCl+hYr1jj=7S{vIfWwiV~~y zzUdjZKPd5oU&3t^!!GG%vCt?t3BAtHW9xXz*^_Ta0l*`)MCn7&w_{r>`aDF23B*Ago zpva&mm-kG2eXc5^4;4%%2%gsvK<4UeR=BCkRaOp=_t$aI`4I})2OXUR8Znj#%aEI+ z9eE+8DleB8j%G|PcR~Fk9vD0Xcjascik&JKVN85yleRuO3o#Iq(Al|j=OPrhe)xOa zkefRG7sG(2a{_Y?V zzV$@|;kSe2XMcM=4LB8gTG0~>SZHgQNY?|4;wo@O!DYb502AJQ5ZK;%2L0$7QdqH= zO!eo=GSC96-kwgalb}VgRN}rod-iO@f1EXHd+;ckKB?@DBG5H52UG~n7@y?IXw@E@ zUB7WUkOji=8rXMxy5GsmGn{-H0rplrN-eA{biHFpGK}0UOTQvTw%+CMEey#}llJUU z2H|PdnelG5vuAG$yNfFyQwXnzbZ7N}p)9_Yzjry3Ac<9LxXVZZ@@-7gupOa{Cy<^p ziZ8Pjhw6ZqA&|Wvvm8KY#Fw>5-N+e^0)*^Cm=}0o(pi#`0Sd1*J(}Z*d|C1H1Q27p zxlRW*_JrRV_$TXO>j0wyak!cbLLI9GUNC^VeRbUy_F%_!jtx~q(K&^*QptvZiGh$% z9y(!}Xa|_IrtjGkP*xpi;Y%9INQu~4Sk&>@%E*hy0%9Iq8h2N`cCFs9K`m>!Y1(Ne zdzo4I<^_jt*H|zS;0uHf=X89&gHOt(Jd_25Dkos&-2lwpFD%TWWhpM9kAZHuK+>y_ zMH*ch)m$Cz4pp(G5f&nezR%v>ePLy(!Ao#^JrF^Xp+7&I0Tufcv|ZS_EJMzPR|h(~ z!7fKZz`O5Rxz`axfegW8ds*cwDWsr5#ne$(1`*KEJvwK7WS6`Ar?uOhjqv z8K}dJl8!i*2OlaOUKuc{-P;^D_V;;C_8b3sAliG;7)aJDxkN4rw4~h!I?tn|PRp}E zKWh(x!N@ipE1b%Qxj>}t?Ka~wU?f%c15Jo{#rr|Jkl zq1g}(P#}aPN1cWYBn(@YP3LYk@^yQ^&otQur8=S}Zx|qmqLV1xgR01f#s_#1el^o1 zwh*)dRI+A6Z0If9w!wbpL$Ii$)7^?xlf}tQG>2I){*np}bt(_G%fkFE4(tWY;yOXk zGo*PRdjbJOoQ9&~3E3d14-MXj4}NIDD#O2q1Jod^yty)zwD6Q+3+Wq&WKF|xlNqB; zQ55CgSyW4kz}a=Gy+T6ZVyKAgZTb579G_XUHh6J=aQ{jd7lWQ0q++5G69%X1wqcJ7 zXu!KvI$ys36^5<`Qv^3t`QEGi(*)38iU>H0D@>>Qk-kYjvdr=kgL$njRzbT z%sVi?`v#6<$+KsR(XB%;)wXo~Hm&l>)bQjl27JL_ot>bkSNra}#_vdEdwZR4_+8K~ zR2rIS$1t3}aVGBo-Nx-F_N~y!UyC}*NJgf0+#m2&@K(d!$7Y*pP^g}vrc(WagV`k{ zB;bFZh}aOl--(fiYM8j(8bd%bTFfQgIict^{&Znld6W@t0y8HU|YnWl}GDKipb&1)_xhM}-$7682o`H7v@s;V4wn9fw8ylM@Y+TSpA{w8cw-uXuw?S-i@HEicwiE6Mo*2mg z5J`(7O>2mw+860Y6ZRPF4z4#P@WXW>0{Y{yOi_jRb~0iG8=E4;H*YSD9zi1@FXSh5M0v1B5ja{QMe)tLq-@eBGGdXV-==0FhJ0 z#ifuz&@u`8oy0>x(a)EczjIyaQ`_#y6*#y2-HpCDd9g&+nW*97z?Ny(u1hn)!_CTO zi(>7daDtvAiB30lQ;dvPOm~G`gh-F`=ugE0FIZNF=J@opV`g@jSok zxZ@41$ApCZJF2V-C$d2bu+j-c!U39&EFf`m@^1U(eVx&{Mcke1ZJ9x2?d)1{$8aPb zmkXW_1!UM1DfQ@@zFHgS-r2VfD!L~DNuvkZ>`qTlub1A5h7JdU0>}mU{=nVL5m$5^ z5H&$g!yWYP8yzJA(o97wvjv9r-590kVelfNik{rXQ2=zQ`6OZME?$pt^Bjp)jY~71 ztD~e>z5-aZ!Z!zB#3)2WW4luGiJth<>;XW7LO>atKpmYKilrt08YFNW04B>2@{$HL z=bP=|Ezt<=*_b?AV^YBX`s*DF@3)LQcj{hUF#Gu88Af29p{m@{ z4+snP3jx4~lOPeasN+^vRwSw~qSs=PLqAZ}yMr!eF9D#y5d%Re%W3w}CGccPl0*t~ z(A3#PL<&@=8n9Q0izJv1yQqWS#~s%(2p-F(r?>BG>*ypdFLAEzoHMS*Y3isptq!mqLP3Wbjcl9zk92ld;6}#I z#T5WR3#ks52J?YV6&%3`s_3i9-CcU|zGfqpEgd)qpsv^%nS zyx3(h`SZH%FSJkJq?~#oRXlnesWhx316Vk3~Ca z?OMLhMVdvBBv&*592HBcd%-c>3Wx?c&;wZ3HV8w>@~q|wjr7Zuq*HN8ILCX3HF+%1 zi(Zgzj*X6ncNy(@yt1)hyLy~(UusMXH3z+a_0e))|4JztnS}m2nj+X&%&-M~%zXyu z2C`7O2yt1$3pBEo?s;h0`FsW<_k+mS8)UiVnh;Q{;hL#B3CF2O?&A5Xws~64!t!9G z0wIQBS8ro-@kL(1@94HJ?m&}cUGldhWA@hCks&;hI5cNYuE3si=%=(RFJJL^(PRnl z5(LE<50o!^cK2%Sr#U+>!CTj>d~MW}?o%-M#qbA$SBoCu3Df{|?%nlE>1|Rg+@7A^ zYSFG*e}%e8UD8W;EA?5VJ0j_pXa?*6esmck&A*_k+o-hAI!PUh9~I6lu^ zyX5QAu8i=7H^-1hls|`BU_mE$NfM>iJmBRO#fBKKo1e4K$lv{!UTERH-h(bnSfpkHzjOe?o~uvAnWK zU9@S?ONkUmhfM&<+yx2)-`A&q+u?c02!DqL^r86PaZWnM3W%xN9RWoLNhF)7s5Z$k zo*X&qwZE{a2>6+l^ii+C#KR{~p22aV1VHl6o$vO5g9}zAuq~)U9>+rZ z4V#XZ^LA4f3el0qF;P(;8IMlpOkg}5iSm`8or18`sV?Xwuv5_g($-siw|($kRfg#(0QZ%131YttU+>x+j-#1~2*Sl79juVGX72y4m=S7~xmvg@ukTNEFUbCQ!A z-rTej&N-@WJ*JI8-iK9k5q^FbNw6U?gN6D?W-YwXu`MLCh=|Ann7^~`^iK!qJcQFN z+U*SuLIZOgju4Wz*(MLS6{qU!d|>ozf!vtfSp4esYd-st>nL_-DNpX!`+iALelRN^jyl1TxG8DTb~z_`-# zVcg8AX!tNQdcbe1s_K!7W}+R40B8E@j|pV3X-tj=Nweb;ihZ@V{>XRw4Vwc+_u~*U zo5|bybT#qs7~rxN1G0xDqQ~a~Y2I~FPf>+aFG@cm23vT2rOCK+#8;hYpiA&ZNq*o| zNDU&am*k^gV$h%&l%OpTtJ}4(N$k0l8b1AT|2`>aNvaETRaDr@7{6!%Iu5uNcB_n? zHq~-!+M7H$IJ@KHj~)>hFzvN#wUFKKziiLfg>jIL2gx`{%*?d;bz4WdhQQdH236>W z4?-oyL4BFfP>w6dRHBqPAe^bzo}JwE?3^=lrZ@=xIQ99rVn-VLJ$Yh%UOP3P4U)zc zo;V6dT2lw11xCSf;lp$ad_0l+jBvAC;-R`$iE@}y^9l_rmC%+|GSa|==?ux8!06<& z?D#{rUOV@(+~;*El(h{uIZTYsB@axlB;J9(;($W(7uDv-) zN?|aDA@mo8#-t1dXp2hp>?xbx8!**@uCor#X;n?lwxjJBu@GUQ8QE6yiS3cI?ufe- z$-&i~{ifpB1q!@t2&Wkjb4Yt$Zmzo2-A6t?Ia~@CPMgVD@i8PfNYHd0Bj2|m-T3)u znOY8v$*}rXI@K^9h2p;OmJAl0*IFnAQV88({_7zU%TgauRoeT?FU{?w)8@d2NUke= zec$Kuyr?V~Q#gR|Gc5$(XSU2)-nen&F7@@RUysJW+qxlZLYs??Ew|SZt=l8g>|EJw z9Mtc=-;#T$yKY29Az{qfQLcO7fJ$n7@}k0!LpIFjfcsXD`hf!e#_PYJou{?GY+k46 z0FJ^<5FezKAZG&`ZhGl@mkgmsk9ph|Kdy#XdsAz{p$`rcD zh;dxSEnz8513Vu2$pej-<%UV^oingh7&*+Jr9u;O&F>XyudI{?sFL_J{FKLjbUOZi zoe6seaz}-X)S{2~SOPLO!vGaYG>%w~pL{?2!$TYZYAAsjDRUXdvJ4IwvX?^Y?Cl|h z0h5qwDtou1V;=FWlig3nshA3AM3#c0+&<)p@V!4aP`yPYWhkhj6EQ$V%}0k@L&T!P zbuJ79n|u~mUsf;v8&}*z91~GGv#_!fRy8FGPrHJE)UN_T7YR=ptW8@`PBPg?Y4`T0 zv@9>s$S{CKe=9hahYlS*!V)2FQL=L$Vahb4V}AY?6*HRu&~NJ;_tj z(6D6(mk7AS!-vBMGg^}n)>VX8py$sbjT(HqbbTad4hXp(B{aNRuM!Yya_UDcx?#0j z083thAYuzIv7SfdMgE-aG?I27Ce?){;(8hKsbm{dC z3{-<}kYQX$08vmFc(bm5&^~v+D?uZ}i1hCeBGxGSBkkAHAU7)Rf0>7;A6mZrH$Ksk zYF;BFhC#sm0bx8uv9x==Hw!L4j00K%QMVFrOq;LhhD~P;nW7=*N3`rQLZ(2*`-BB) zj;;S}k)v%WAb`HHt~0zw7cYU!GdVF40Nymxi|dQi$5EXS>l?yKZJ}!TQdRc%vEnkI zK~ZE>=SDmZkqkDyy6ZXO#H_;VPIrUs2UYuGgQ?TfQBQ>rC&Ks8`B_)%^ z0@pRVip9nxXpumZSA;;LK>|%30VO@l4&&6Vfj11u4wC$qjPW=@hsX%Xu4CenK;&*j z{@0C<;|1v=P7CV`rW6Ko7}&7qFxOS}?p@N&#s3q6eCHIDBi)kKcP0`z1CSXosg!q% zK*_)>ZfeVYo-$Qr(y*7nB4mE9Be&!N1yCA{k$bq@9>8H{(}RQ}_a0TCl94MM%KB@Zl~aoZayo7`v$#6q>-bFSJ%dkPEj)bq z6~EED^#VCd805%unrUMn72)MohH~HzK!v^-d})FAl-)Pl#X#6x(vjP3vT~_v76Bos zwrWC!D*8`s;Lr16_m!Z_)pP+03bWi65JVIWdTH(ht?71Dd$aYIo!!S*XLVwr0zr75 z`F5Vg1}jLsq6jWHY?~(vo?tzO3qT8haA(8m+;C;(zl*?~YeitA>dOCcD1nTqeKuP6 zue+mo3{R!@I+W?4fZwJ>>A7j>L}w!FAuMvT^~epz4tWcjgqWBPxJC_v-7bktV%Hc0 z<{Y}iQZcDSy|;hkaj;HEgO^k3~Jr8H40?jPbdbdQdyhVCf`sTWzm`3IVvGK{| z6gUHk`sQpbIwMpuuddFS6OQ&0`(5{ z&7aEoPzh_Q8nsD)im(KI?({&g?uh94bbPe{Cb@@a~JQNW|BQM40Jj=Z_f zSA{eD#f!%-dbbh5;(WxN^eBKy87;btGgKSa)7?_Y3%=zf0K!}Z()&cd-<9P4X(0UF z9njvOeMzP}8t%=TH_j9!=Id_g$~i6Z6lj}_ur?wx%P*gt-`^e>7@#jL`_{9Z_iAjk zrOdA|-(W#wBZa4|tPF(!Yq#B-rlzb{I|q&&Ig%8i5FxHVH;w%#i>aiO?VIU_9n`M= zZ`8eYSXFBmJ-Y40!a@OyP!v!k1PK)jDWw~gmhO(D9uX;NX%qz|rAt6XKtQ^rQMwx> z_irrDIp2wU@AKS0@7>S$9Tjo2_FC^d-#Nz|W6a!t^m=ad6FuI=r{E}ab%aEJdSu9A z8H^G1;HL|Ozw`B#%84S{y-o`%tbe3CFXIbgC#Utd9Q>I6!c-elZ@(bLx5e7ro zcE$V0N~ATY#+s+6rM=pamL?Mm?}yxap7ed|2cN$ECVBK;*yk6QuIyp+n(r3L7q}vJ z*ypSU&#|$_sb4RK35Q(!Ii6s3E&ImRkJvd4!!uH<7d(4Tq8!86FK5^sM;hkMixqnw z2~fXnXBU!?V-UoWX9aRet@weA`3d4tRn-zv^7H4+3*=*wmXZQdN(!(;4f1S^XWg;3VIxFM zP+mHsE%4q}(ah|%$B|0L3j*Vwj&>)H965p~IHZt1d~vnuX|?O$SHt_{GG@^eWNF}j z33)aISLh7}S8+g#k=`Qjyqzizjuh|kBTvgF%x1n#y|!qOtrG>Uc#qMA>5Tkb1j1wj zBt}=zfUA^u*@jXJ*BqhokL`&+n|T8lh4CtDPCi$l8^o%&U0hs<(*^&G-D>=3?)c}a zg|@LU8KAK_scO^xUfHwFI?WlZWhWS!GOjIRg`FmN?C$<&=HnDSFN){4e<6&Iwg0j{ z#P5k$=$8lawVxhs3fAlRz%2>*QJAZPSD4_nK7431I8l708WugrW9x5qRtQ#xVGd|k zR@Q3U{8E4h-9OeCi4<1+!wBinN&+0Tu0dIQIC3a4{Q6x58d=86#80ZyAfEp}UOUsF z6+|V^PDr_ARr#dRYxghsp`9Lw%mmrfJFgSYD4LXTe3zDRL$Ap>RK}WbVA8rYU#UIb zd3kh9QepvfL?Oh+EuH?ZmTw@vECAjvF`P{s21Gy?e9JW@309p!>+8fkg&4HrWzxo+ z9jrdkp(UwD{9i~yOw0pagUfSy;PDB9ZQ9?YMUEi2f$%M8fGIl|U9T`@@J6`(Y@yC# zmr0gyxM~DMF@xBuv0xE2S#X5(?R2!d9L%Nlp!eHhN2V7Oe$zAY~=PZtaD$0A4BU&h{eM2Lt* zCMMoRp5pbeXxF0Qt}*$*yx%p`$>TpyLF*Ni#L9ac80K0B8VitM$kSGB)96`scYPF+kO7-3TpE3T{*ujF5} zMGKyznfAz$L=-^~A_`UVo>yIkqxbC(t3s^-KY>f2kB4!tIm)d6fldbvg3%IkpG}^} zl9KuF#@GQ)=^6)l%rafiMx?NdydA1O@$@bhx#to$Q7w)PU9o5RV#;ckJ~+4_ExEk3 zcJs!}o#|@iD}n`C-$_nWvtLi_WWqZWUHMJ4R=?bOpmUj?C>|4*NICuD#*G^TX^kt# zksEatPtBAtZX*iw!1DbRw7j=7T1`?2%Bh6JE1*s{(X8{Pd-UljLNyL!!P+S0$hf#= z6oZVdGd!UcGW8ut+1aJgq=^A42@ds3LKj;ZmYb{)f9UL8Cu}%ERaD>5Fu1aKMC$V8 zAKYn)^c2OyH6VK?fIeV9{^^E7rqP`gbN0BmDz|S#-LjckHBSPO74EivCZ1|915^c>cUX5ST%sy>Hj9i1+W`W903( zEM#~NrIzh{p!a=NA@!|4V-eTD6g^X?NOO509raps}87mtz zI`|dQfMa52t~YdC^!1=AGatK%oVBKwYoPD|IRfL$m-}yU4X`>|kAyTgdLN-ZT`!); zFG)jOeQ%(apO;tD@Jj8B7BoV)#5-PFPld_czWrRYGEW+;ZJU%CIP)o@(-(mnnhs`e zG!4W($7l=;N%T$lU~kWcnu8FGd~yh6T1fpvIdB)@DZhX?L* zRhHXh{PMro$EkgL>%>P#s!zPHo<-+@5O8}>L&(Y%bhWkfdyI%M>fKM#-mfvk zRSNgEya5RFgSpou8)agpgE=*BdWVQPLw2X*(}h}hY=wt~CB5zE^RT?E>TdEzoDoc1 z8F?K^N!2tww3v!O^Z|t)OlocrVmfuII)vMD$c53NFAPQlF!aZBIwORwp`SkbWW5st zZA^N4x^$oJSf#WqvHD2bivLL))@&49X7@ajK-Z3tO*ims!VaqExWcXsy(T6h5HIv+ znb$JwAU@kN3bTDR$QW82%Qu|(Wj@5&Ka>~{gEd;KmTRagPxg&*)r0B!6hH zYnG{N^|9yVepq@AGp*s-gRQD_!%dQqE@+vzH#8hMtmwGpLU}DFKFz{K4#PiF zGspB6;gK5)HZzFf>6zI!1x!=S^Y@aA^Rsy9cEDpZ+U1UYOSz`0v&Rh~;>;X`0~d#@RwGxiZ>Q+qnNxdYwiWq*(hE3tO)E)ACx;cQ(&(BX~SL08m1?X90 zFoYflmsv?(SY_$#2p=uI4v2Zg_8)G_(8etVL{tm4JiGNIU6vAyep9kEg1d}QhR_A- z9Yoh&GFs)$L{~BS=$fO_gi>pefwH%9&MuUO5erA@#m)b17veYLMi3zxIp%6rwqIXF zQvOE-K<-!5+h?G^eC=AH_n<6m{;m*VMIv7c)3Bu(qlpa{z!y zA`$}d@v<>GcBV#{wf{i=uQ#`Z59b%&Eqo>o-5(Ql>nHj7#o*c|i7^;^DJe}KkV`rF zRJDo;FSrA=|K{tCD}m8~W;K*MC=OAk-;7)?_Q0IPJ$rttvjsLUEyc%^3Hj8ZY{lH< zF*S{&o!?@&nzmw>W2crZvxlzk@Q zzgaucHShg8N$p1X0{NhjgoTBePo=DGW#1`d)E6Irf3*Hzw``{cY)P?)b5&>f;Y0ut@OtxPS)qkzl8T?`KThCLSPrbECfhEKV77Ni5#G0 z;zFnMYuuGy2pdW}V9H!31ea!X@AzNm&gzAJT!*%3d7x>q!-T6Xy$~D^2;4Hr7w~2y z_+hL<3nk*CsDX@p*pOW!^l!^unhc*_nwkn8PE1JfqQieZ_t zYQj0D#V|ac>byaf@2P-L$wi*#rfEh71_k0<=mr+YWWg`$h%Az^ElOc7>KcIS=HBHI zLvl26=%9=U8lIb&fZfIPyUK4#nnQ9~CVq6M=--6@?CPpR+)`o*fQ+Lpir7&E1uC2M z{IP%D`hIE^6&2))CXR-j!61+9L|&r= z10>EmFy=^(M)Dm!Iq3s`iz;`niYliyGpC0zrMrfqxUakWrZ+U-*iu)4c}VVeE#x!K zO`FMI99=xb@!&P_E}yqm4)}<#rrv*MPDFW!zd>;viD>|zxHA$X)9Q{OX#TctlXgQ~ zAW&L^rXr1R_%MqH&29JQ+rcC2V%(uGOgGz9I$}tgl|F*pRB8V0QU=4?fGrvE6 zjQFfu9%NqLV7z3NhwfUmukT(YD%3(7adpath4lJ1d9y1@c<2$f|9O0X4%3Lzi((l04Ll=LfCEyLx{3|y+)VXZq3Vwi=RZ$$fIDoY@DS8c|}!``v7uc zFU(xO;gRC;R7F)^g+ZM#YvzHqPjt>$ zo+S1ivWB5XL%pdf^Dliwzp~BqUVqgOmd{QV5-KVTLMZ)L3kv*A=fh8bRuV!eYS*k^ z*Se`C$?@gOA4+;CLs*9EWmP2rO2F?CQ)m~q!52A#f&gF4eh3`+IWNHD13mUXU;Sc$ zs{NktVii(Ix=&BoC|?S=$FP2UJ!i1{(SLqpgrG>Ug*)9N1Rww?76dNh#PXkLNILN0 z#fyVkN@7ISrEEKbmK2cak^!?l#3&FmDmv1~6LM$vKm6l;owi*Ur8u|x`;WC4OXLXv z_0#e)k#UxDm2D;@2HAW64ZM()s?aV$yW(h0TLO4Dgv%Z*rG48B7(r|!^-KKwKqDDl zj*W?_K|)1I;Dlz@|2L8&r@j;a3YbT!wXgrh1z5c{Cl;rF$Nbf=W|RJNWyDwe*Z$|{ z6JLzjcJyCAfcP42-T&v`^ui{B_}^`kg*n8;>*Fbk%3FuRLP^?3{<$OjK5DZIc@GZ8 z{VAmA+#8#=A}>^sLP;7a5Fu_mUQV^98=jQXUc5c~*1=?B@mH$7rvftayGIxUetcF@ zE9f-2)$o8SPMXbs-&eUHM$;AkK-0Oex9@!G#6uHCe_@BSG7uoNJ~gE;uD)T_2#(nL zIw_$TM~k%)%g^2rS)x^pH}510VaBGaawDU}#4hohMzKcRg=3NN zQT&`L_~egEX!kNJPLt{jcS`CvJC^XwGRRxRKNnwEOBGXk@G7q4Q)Q(p`m-h%s4>Up zw)DOd@PYA)ust6r0w*5EU6(HYZ@u1LzBOlFkmzGREs}MHzb$5LV}NA)riK#BVhQ=J z$qHw*;^LntrC;fNRWQl@Ud&tFbuc>UlWYl(*)zR$jHR|+Yppfx7#@|CM64w#eJ48{ za+{pnDWx1Ljd&*(Eyxn!`f>GVI~f$-Jqw~S;NJI>0#%p)TH}{8`i6JE9E?5k{6vgl z#!!xIh0KOH>l?j3^L^$Y=mmuRm(Fl=vfjSdOkM90&a60gXL50nmCgSETPE_mmHam< z?MudgP6fH-d~VO5@U5BF?2DC{4?S51T=N}wGnkC#$tU|=`zmZF$&PG(J*WCp=C>-% z`-l7x!Z&d@sV$uU<0^?ub>f5%?jNsg<{Pb-q&vnBXW7}B#X20;E#3FQD#31!#c(Ry z-qJBTqEKAOJ4TE5lc{qt^-2z&AuFHS5{A~q zcIY(vksZI9{CvK)aYeL;a#W(+FaJ6DRfjOk0kyx6stZIGK=TpJcEHgxC>RizQXQ7B z12c(vKmK?v`0yEqM??cn0%5W^Jr&*&nVc+vc6y{>vjupZo8rkX@C}fpC7sdz+`82jm zZ@==#t-^mhd4ZssIlY0LJj|M(n$<|Eck4>t*Vn=SnsAXnvCn?8Zb-WG!T zqcJ*yG{tdwD0p&it}!~Cr2)urWJwZaSMI1`(&+|(2i+MM2oCn0pGiDYKmH>?yCd%m zCQ6EDWjKz1x(N0{HSW=yu{^~DkOCyo;WQf?YfMbsf998*x36ECDrQRMT%WPAwMB z+$r+#HoyH~P!5ISDex^pxgac2{h1fV&~`F3`L?sGI%IK-oJA-);FzQX2NL>s^~R=I zN=zqDN&$6bR#^(fw1pr(OTk3~(Dn_?lCF(bjfP(CG(1+Vt&711*#jQuCwq@~l8JSX zx4e7i<_1hZkjT&RAabB?YN0dGY8g9Un8wl7Zw{$LeNhmis z%tNq+oAuUygufuUYv`Eh9ui1tw%!)ki~Ko<6oI`%zT!~$=sdwVK&lm{P zNa^!^(LwJm4}=$kD%YSRa5=y^8~_lP2W9i6Roaa`pDOAW-LcJ>`{Ht(Fhd|LpI`+e z7EC(pu!N}tQ1k?@+GblF)iO$@_R4LJcaW6NdziQ2>Q>*wRwwiBLARM_f5w1%-kA-H z7jtQFas@JN)$kl<*1GNMrZK<$Pd+N~WT;oSJ2u`ep@F`zkY%Eq_v+P8(-^g>Ugle( zG|?)#-UOcptX4S920H|Y6IqRd`+~rWAuP%V=kgs|Unw2|pYCE}Lt7#o&&$xQ z!-$b;cq9@Ye6U9(l6K-loRVazMT0igxGPFVwXdP5{O(x-Zp!}gWN7b!11RBp2lEzb zCFJGhQ~HA0df2d9hR}a*K)DOUwpT#@V^#C>g7_98B@BOsTau<;qSc&wO3)%l8SWL0 z(*up*L5W*-EK~9=PcO+7kLWG7c{jL4dSq9iXW9UjBoWX-r2@?Oib3P}@#FY&xMWYG zQ5Vsl;(g9M@zWxYAk4PI>qHZTK7y430^*l1U&hUUva*;@j&7PNEH2g=ZM7yWY;0RTJ#r>Y zcwi{51Q8A7KyG=kLQL_n77;Vs((_{t7?l!xnd?+bdO$2F6wjVHL4~2 z);N(HL&JW}qd%{P^RMI@|JKPAJ?2Y`raYlG3j_0T7(LHTy#qXdcWUk{2(?b|Qe<9U znG=VL=IOT6(_GQ7USU}-(l6VxIX;5HA zCLyAk6)Dt00jPIowq>k8K4V2Z+%EZjVK%2>g&zBS{$*MYftyew zQipQ|?QQ?qW1=(Eu&{5JnwlDq-kA{5R`g@)aW;C+RiX zcHBr2qC}x@=D1vtXKB`|aM6P&CRbXzzWGBIf5N+WYQfAtK|EsKzF~PnX=!P#zwr4< zJG(c#=uh#8YRqq47-Yq9-?-zZWX}uvQ2u#U?{6B`w5Ajy8d)=q$JxXFF-|aK6Xq_N z?LwIhROzO$zg>cmPYsCi2WQaXK`;WJm5@$Cpl61rUNMS)=@fHyO@ljV?v9o$Q9RiZ zA3lsJI|hI|m^jSio`BN;wTCd_d=Kv@Lm>&`v=|V_X#qjiutg3A2Q=M>Ph`c1Jqu{v zD7M0s9g6saz}>@SFS@!42elcn1@5Jxp+}y$dHB7tQM&Qs%HqE4<=G~-KoKB$Qt)K* zVdLh$5zLqV;lod<4p&4m@xwmoYKgfkD!NB{XphB6$8vz(j{!q*Z{MCo;+Zo?kcG~j zyX@T>zFHd6o;*7}T$Zi0^`2hvl}UQ4*s{a=i8RlnCXF+! zzH~bZvB~VW{YHN_{DEt&z~hO{q_)T9nkW9OTS-+zdpYV@qBWV9xNGUgQp|!am)|~tnm#p^>Ax#KpVxcuDo|DU-=sRsT|3B>FMa; z_EMrVP8aQstCl}-Pc$5=gH`vVMl@Sj)k-(i!-rgo+(o*YEEg7kkR%I zX$H6kSIcyr(?3^NpHbK|Qtb4PK)McrlriS*+p1E(Si%U7XzYI4G$xC4eKf0&g*dg4 zkZ>`D`sOdJ| z=8te6g(P$aggo61aYhmCT7nf?u#-WB;M_6xy_JwyFxL*Qpf^BACYmAHS@pfKt}BAm zi1`I-!fp?J%V!dj#Y;!m+zp{a|0Io>L50{@{R(I17Z2NyW$3@7duP%;&B8H%gybYf z=BmGc?9b<)d6(crnDHYX?exNW)(T&a1V@hpIjB3;c?C@R(ve`nnIWsfeGL@t8iMTz z(dMnyn8T6+$ph-hM$BRtrzdUaF(3Bl)HO6VPNI9KRY^-rRSCfWM5kjQW9^idZGS+)18cD#wj_jl~Qu#*n#g)DubbV1>aA|5TsS2&sB6#W)k zH&D^6$4`Lf%m4bfYVioz3I< zY!OMoJEW>;pVTKh%qaT#`m&$u>ZxBUm859=+R~C!xPabhQ-bl-3;oXq zDomnk2}ZpDNEQp9@Q#Hn;W*m665hmldE!QL)&POsgvGs*o8-<}PqNkiP@1sv=3$=A zwW8)*a~2)BxJKl0G;$vZvk+823H1+vBlqhPF(z0#q zR(heNq;ut?TnLRKBHE3a#E}Bh082ouAfsOfgF)yy51#B?@6-p<%j)5-th5$`_Aw%QM~NzBf8B_##ftfZwsH@}RLsNG zwHFS?+f=E0hNHWl{&t17)<65LuVmwWf&a_GkBf>Tz-4bbB8BY>v%OAqmr!5>kHqB? z@juLVbPhq4QAi=%Og?hovg1j_0&jx*B~;_j+!Ey5l≤}H!PaT?RnEhKL4nb-*& zSPy=FVMnlI4~oEGup=c8(wLxaMUTQQAxkrckmDmVC_Bu*0qeelaF79ohR9T$i$I_b z^?r@CrXTY_i24^?DB$26_6uo9j~F%58aQl+Yu$IW-ovi}PEzY`KGT1Zv_g7RrqCGdc9}R5#*v#^ymPla*<3K)Tgt zTL+O6`_Gj|U`vaN?>i-l{Jut*@zk+nmocJ^tZ*jSE9n}DFDp7jW#8h+C$cg! zGVm}_&{V(vhI)iut!M_RW=ve1-h}(wXsALNG_?9oo}1{NzGZuN?|!-I$cM!06>)y~lSuzj&qcKT^v7X9a2$bhDKi*o4O$8- zocBs#eItGcwVfI5vQXYcz+|?m8pTK^2B@_sHq?DxO2~|~9umphbPKC6L7+qku z9OVULD1}|``)!DRV-qT(K7J&DFMG=ya7x?_+W9oiZ<#75u5XvcVgu*4fnak<}*w_Xn3> zKg-gYX|8Syi+Ta3W5-m80`YX>64xVw+}F<}qAA@vn~e5Cj&ueEOZ1hMmG>eV)}ba2 zwnibh3>_{%DZRfTZ&A3!_y^gcJrt1Zc`4aO)~}s?2QHocX#Xd~seOWX?jhsZJ!>OO z(Htb&uMA|%UD35A-DHDZ86FP|(Lh9FoK6VEv1SDEDU@9bSjH&G!xn88RBkZ`1)^&! zR0C%zv$kKKk6X@E6d~qY{`qR&Mo=n3B2nt!LQe-h;iH>ef)!AN?e^n3DF|D zkaC08`Vvx^(J{;6?{5tAm%~01f2-`9lr7~zwz({w(p#!AJIc9i5tu7wQJ%Oj`PZqy z(#hr-C67)yKjr1jZj;ivlmqHaJgnyJcs zG!Vsz)`}C$Hz}h_4z9grcVkCnmM!LIZ~*Rre1_+ z$11DyC>EqoiQT8UfIgM+^-*8HzQ_Wjzwkl4>b=UA7U#RG7vLmzFYcs2y>2dbwSD*2 z?L*gTxJrVoT=c4!HMos$7d1bVk=EMjAvwQq=UeO%w!R~`KmN34+eb5!-u0|crC$$? zFi`s^jvwsgUrmGK0cfbF)MqhboO@6^W2jhkh*-4Sb)W4U3pTXKhS`3i9N$PXV`6*x z$4`$o!g|c*=Lu zKH2ok^N_`5rSK!u%#l4*oZrx004NMb`otW(X*w z#};K}9ov?kxVn2N|4iQ^9QJ&$EZSo|BLA}a4p%9swnT=|dR$fVtf*g_VT{PW-;=xb ze1JEw1@x528DF`s=uTInGvRmQtcXX1T>Z7V0OlXZi4gq0zSOow!aADO_vHfJBVrTb zbzr-5!D!ghSWl1r<-`XRq&~>cOUlan#a@_P7-kE6@oIbOfp*jp*BJJ$e*d@>OE{?> z%|XRmG1R+r=~v#*JtAePBfJYY@K}$i923;1KR3UVckYT-7X|6hd#)dOk1e+FC%uo0 zA9+ou85)y%>Dk*Bm`TJ3J(~MRN0y}h&b@512Y`x>2978qF+<73smOvRhpf^$xMW^--f`_DpS_Q52S`oN zoAhMR%zy`5rebm9fZ2nIpN{Vm5=P@ZP`+lbEa>8G=!KZhoT;1ZNbDcyx3aYbcP2{M zo8XQhr7*Chv7PS6C=+X971DhzHzC;->X6YX3KGTtmIB$PEXIR z_)AI-zLwqp>fUPA<;JD`OOKA8J_Zq=iYgGdE5Gx8r%SjYiT2m|b;tgCm?Tm~I6^GS z9B3*kdDh&mdF=uU;cNCo?(36WFIbH~SFxMW04zHM1)pJU_6@g#m?sj&bXr$nH5#;C zx_0e%XmG2vgPZj3c+&Fude_K88U$wwIPxY}du_Amg|BkWtB^*|`zCdrl^T z`A<*xMHfEpgt^k=EjmzGDRNVLY-8GQm$xQlOPR~x4<;V2fSqB_&qD@t-aj0oC-j^M zqsPym*RCawrHI|&fkB~j3myz>)j3lt#|ZAJw%hcE>6_=yuZETwMWemgxas_^00d9YSE zY+F%4oFFu11eJU=r>ERMi@Xx93m=eX)Q2z?%?r#61S}9l^fXcA0%C>c;0nNxdbA3& zCZ`m|?vBsR)w)sDa@hT%M<-Fz+}xc=q058MrbW4Jdu)3uV5pPv(l&Vsdh_8D?xe`114zO2!6|*AkJ$KO^QGIc-90@u!2A6x361 z@r~6hhYdrHL9~K9A?i@1clYc;0tAKD22I)9=!l_oDlKhJgj#2Rr9S&10&02u*lOk% zdAQBmPP!*|Y@)JR(4r{RTI?(7@vfua9(~(!Xy)XCnE$eSyIlAuH6z_0u25ytr&p|EhNDolW3jvd@BR}%h@vI*I;5Bb!VtRAu z8g{YJBgNye*TX}nbNTD=n zTiDIj{wvU75resUU^+p6>{wpQWL@1}2}w!0OrtfJOX_GcELZY0Toxa)V|i5VbySp@ zVpvGXRTGmvWdW=`P=Tvqwi{owrn*Qs@eVvZr5WFT8115^y>2nfE)$;}a%8z*z}`^o zU~}f-R!4H~8M(8GEtA8;I_g^DUFh-@9a$NdNOa+f%DJexo zMA#un>SPp{XXP|lx_h&acTd-$y?ei6=F(*#&;}~_s9sZY+S(^cQ929H)@&>|yL~^) z2RFD68kBYYyzk=b+5;B+a8pXgjaTM(?;eFq0^RZBKPk)BZQd?&{M0EIDAkhf7b`B) zRBF$(bj%0%Qft8o4@&}Uc5dTWsg3$jJR9+ZlBfknMbC_hTUj04c0lF&&6_tpdw~Db zF*2r@56OU{V5=Ygd{^be4O0_SQ&Y_7kzEKC!^*2zus_DcnaDNL(TmM{6k=+%O1!tPg_EmuYGBjhOf4 z!5H>y2NS=W{Q^|M<5olmvNW({A@;kNn_sZE_ZiPL7qJDIQ-q*TyU2j z;WK0GGX%MxOa019D#D5|4q4FFc9Y{mt!l+Uriyv}12#5>$$c5ovzb9{GSpQN<3dz--tPEP+4pYyhRxx>+Ccu~fx3Lk}+Nl7jr zc*o8xVar1K7bO;Y1-lUAwt6s!2jIU3eQGuQt*=CZV9vt7zGOdktC;>LbmD z*p@~58TK9!%=VqI5|e?qYHkkKYA$3>-Xe4bliiNF7JmFOK9v5g zveFYGDB@8gG$GIoH*=&`>Z4V>cQ3Uj)c<)J_#(A{L&*G8pI1=O=hs41I5NKkyr$i= zXZW=Dx?b3P+}*i zL?`LD%!;RmKe>01or7ayW%01K&ipUuFQuiDh>FQ}^U3^k0%}EOXZCLca;o?JdF_b1 z76(TfdY>saGk!Sq&sv)>An6-P3&%y`=y95yTygy^GBOg|FuG;?48FOpzCJ~-X%F>| zO+rE?=zs2*R|uWo|M0hp6@k5i?t-p`D52IOFX%JD9G~+E*87k%^p>8Mt^WS~X)Vd+`m0lS|5Ibef?icboJMQ0H2gCp2d&q zA7~8J6!JAx2A&Vb)rr*7F>0yh+asM%v6?teLexw%5E@h#3pv?SFWW)-V7ULOiwjkf z=@treEL+ms*x0e8yr?LD$Hk1q@$YKlX2L5+xL5+wTqBLwhOc~3^tK5=2Y6*=&XM%1 z!uX_uf`Zk+oBZjUER$BeOS2iQRZUGU1wT4tViS0yyWrEBU{FF4}6~_>__G@}-ygPbv-9a zi5vak!7a}j#N}V}^Y?-n(9~I;1@-CY>HS~J$}kvu>B*CgAgr&sDJ)EX^5okVj6s1E%7tf0MMt9H@Lf*&6>rz+BxOV;jjYG{yYx9VbUcO-|m zdH-^5Hn=d+SX1*E*+K#yM>Vi8QhFX{d0cn@4A;HUD{22~U0gK&vsn zQTC6)?A0A{p;=k&S6}16#x8RE6Jvk|U|w@e#6MlHuf17Iou!E%T+<32Tv( ze7`)y?cJqt+enTp7MJyP!(C)TM6y<_xOO8k-#Ak#L8TF77)hDlWxYfD_cyEA8@dd1 zhE{*jO`m;9-FSDAWBViI!w%$>mXYPrl(aPW>nKvzvGBoMIk3q?^%Fo}@-^pFS45>liOD^*BR`C4I+S)Q2TH z5{h~3%-QVnraYgp`L_40%3J!iDmn$0hBQ4Eayh(_K(p;mgGXjdNx&jH=d9acVNl?>;q zFP>IMlt@g;wZtI_ae5G_G^)W~lffNJVNjy&L^Hr@vLp@Xs&VHfT5Ib~O=-GZX= zw3d2$XIOKm7x@=Cw-?M=M%O|_JQLxWm?3|%Qc7hsH0vBc|4N95u3?vnX1??n%G_ipaF2f9O6eWB)U{z&5yOm2#a9Y^xOWHpC8$nansDgVn@GCT6+47ZJ4t0#gL(f>gpegwA9oHb>(k693Q!l z!8F;ZNn;9i)xG+dG93ehm&wWAsBM5851EEMAvOx*@qmr{NdMav#Bbc5!;?u;R#qGq zy$JEGvZVKB1IH1&%gf94I`XFCmd(ny%Rx8Zps%Z|>*DTyjEBeOYNZB9pmhxmCPVSz zC(fULgf0n&2$v>n2%jUOjLCcttD~q!&nea51S)2Vf`dl)pXcY3pL-Xr3k~vo$w2143Yg>!d8{c~H>9dk4)R zy|2}?L{-BlC<;D4NZZlhx=GQlwYIlPAhjpo#M5V_*P-$Vh4*58XLp=;MRATb%dW3{>)1a@crdPlm1 zboGBP^~afQ1}F37*%Ka_vlL4c7gDhkXeJI{AJo!HO2ZM`NNd+Fux=i?#bBs2 zeLP<$P zQ;NJF0B_liA20tRHWdtG+V-&%pe99+C?`#$pXb-1d7?zN?eg=W&u3ft> zVV?soMrOYUJJ8OKH&#~lQwMp)lXe5Gpgvc~FG?@h@U5i(-E-nM*Q*w0$lVJ=i6E1` zh>I%;;kEXjo@OTzr^dQLWCYutkii1{?Z?afBD@_`O|IzZ%u$_gGvFfaaE`28h7Z$@ zek%a6UrU;9id9@E`Ja*hk~`<%2NxKEB(V$2qqru=;dpgff_P zTSevEt1h1X6+M|mlJ|8!5*fkc$Lm8XsxD_x?AS4CnOjS>_7X(2hE1pxP!KC9D#~Y! z@+m0VRlR1|}1wb8wM)lLiAdea`#ckkZK4=;G<8>62HF`z(g8^ z{t)8C-bZqiqK3x;@j#7@&yh}@>XLhZmmlVG>Y8HrE5llM>vMg_-4%XxP4MVHlO;A2 z;4pwpc9Bf`Dl}(@<(({LN`7PTH=}2T)D^q8rq2RpL4jt<3{Tg+#<&S(m+^44y6w-a z%rc+~n&_&vRnC9`-sI$t+5Y^uZx7b8VQKn=GO;s^&f z;ZvOac`?t$iQP1fNk)Gy>?12H?f2VfXJ;>Gh~B#OrLwYpDBH=2gd=0k*zk~YcDpY~ zo$b0N>>%cc;(!Jb`s%hP`v4piA zzd2|f7NcHRT%_E+8&{%Md<#|9-f`o5a)YSdCY&6_ywb!9shDT(bJP zd-wRXw&#v!i_c|K-$me`uTNZYEv8-M6pKzNws9`FZ1=%(;|i>I!;a;@`bl?~vzs(t z$m;O2v3pBweW`4|4Hx#(dEWW%=3|~o$dSXzOYwZ(ZSgXvVdA$*Cf09u)?#JC)BFTa zLgbtH@?fVu2fwGh{h{PRq%luJjzEMfBs9U`(pXfo zNno*uAL*<{X}3y8a;H6|(*90S5dl+%#h{==Os8{yZw4bjcRzb^ak1C)D%;(bl9E1S zR$AX)h+T4W^wh`kg>|krGk97)ZE$iMLp$nkyQCMszF%-cE!qVuOGq3KP)>(M-oi$) zkb~b9Tb>+p?kbK39A+LTm-L}g4RqDVk01Z?(8?TnLg|QEmLlQ&?x@r44Ug~ja`h4Y z&xS}QfIwFJ0ax_LC~0VZZyC|7jVgaMxQfc)u_6)Z1eVw7C#%xe`AHDjCEy~1%zG4K zTATIt^)Vnzn6Eh>GrP|yq&^2RCCp)A3pz5D;M)-;Z_OK5`K0?)*4Fdt8lt1s7A@&C zcJpPHdk!A_2%&kYE9*)iW-8u2xWA@WGHasfFx-lYkM zXlx=Ne`%-lj(t^CRbMlWh3tCI>%QQ%-a{H{$mQxj$B!x&wbC^Jabx*p@ms=W*o!}& zot8PL-@KR9ZZkB-=l$l%MXZF^UlyYtLO+Pz{u$k=_bnrNYag3(BoJ}J!~g;D^XKdX z77AzfL#O8Q?AhJVkGFi+;{+}QI^(0!{5NlYhsua@SEo3VB?=1n$G`u6?%oxiq@?yM z-vynw;=G+od-wJNgfn}Ey>r? zAU9MPxM7xK?X)9sS}EHn8%KBYg-#7=x(j2 ztBb8Wf3pRW+l4c&KZz*xfl7P6iyz@Wp{=6AKbDshM%*nCk?nIGj^Y_J(E4q~`PjJD z33VTMft&2Q4)1)9oh7)_KE9X}Vp^#G4xnN;S5#3{EH2pT=nU7L0CZRLmU=GQ^5q{; zU83aX4t~O0ge6y8_f8T)Y&Xu4fut3%&VvI~9W=fao2S}MS6cwEI|i6;u64?~s?(3H?UucJR(lB*?{OyB5 z8Guf@bLW18?-`&!G(X*FJ1DnqbA546&Bk*Dwfr0O5m1)^w%K_JxsGA(Oyj+oi{4nS zaEHL@3D6GtIgq2BF{rBdw>vtn3sAP8LZ=Z+GqQ0E*76QFb#)az&B0*QYfAP*y}xJI zu8-LIIq`-D2AUX{qvVJ=&ZGIL+blbjD=}yX;wR!c=NbeA=U7%1QmB=WSorv)c!BN4 z=3vLOva<5}%^Poj|7NuoU@J(rTzh-{*USmjUC=W$?0d8`{k_%1l`Ddw81eD;MhC5@ zGZZ_Ll9CsPiOS5wV+Zn13){uVPnGPXNdG>+x1yE%5zB#OMP3d$HgiW#?h7WfFcUMV zdY^Tk@A!)g@GVeOPj7paj>)7tJxJSq;NuN)-Rptj!#>2KIE6HCJXhe0u=eaTbhHg- zR^;#YxX9n3)dCirQHQ;1-(ajjA&7@hpFR7`E?QcK`3)C718cqpN?oG9@GXxisB?_k z%)>R?KX4<%yPu};E{?a5ko~rFwD*2b^1kOe;keQ#4&sScPw755fCJbBcfJ?4V4J|} zKbU4rLxF@kO*gz77KZm1ruE?SfHgr!NB2Eo+&rOZH3u$wQrrcE^7r0ehL~903ubSf zJUl#(&0zvyFqHs*C?EiofM-R0nwxpHZrvdXH~dItYivw0XtPB^hJK0{QqS!L5olQr4jzJU5x}PWyJNp$N1FiN2Kg5I_{7<>B!D)8 zf+qkM!gA`ij0}H&o-<_!SP&nUX9Yl|x+x-Z2E*x4zu-b3%Aw}9dJ3p$w=S~1DJxzC z&^rnWMR*2JmRfgtZFBYt#Wj9QXS;Eq>)rU&_jAtqJ$~n$$MMIfK3Vtue!t$Y*YkN@ z*Ymn0+V||Acuqg~bp;(R0$;b3UqmI#?-%uDr^H|HC4*~_t^tkk$&l9N57SMSeu!~s zTwO7AUw~!Nhjv4cH^`2t$vCv(=WWQ<&~ z{dZmZ^Ul5b^S;-Ta_{Whv$7^xOD#e5N{F79LinRtd4>;l7GcAKN`v%KX8XS${ucI# z%HaOViY-T%o7*hWjqUyBGMFppwKQ1l;LbnSef#!9AO5;2o`Mx3FI|e>zASzxG1L&5 zaGm#2qPmt2!xi#pS%q!Vt$eYblkt|x<(jQ7XFm_OoOVvUvDowXl_dWBvh4lMf9_+4 zOqb#3QsJ>a367cOkz@mg+Owhyv#jhC|NQbgQPC!AUKhJ%Icwuf(wDe$pQhUNA1~|9 z-!E&w^v(T@6>@hPDenCGfpJe9=KEvhnYN5(4zjOq&!RBWzSgMQ+n_$Wg6BUj+FIhG zxjnw9t-S)VX`eBGntaMIYI+^M$W6uK_?zCBsp}#pCHm4c@+re=T478HwhG>1%fC_R zobpa}KilZpP`~j%Z}H>9M~CB23V@hYvaKY+zIC-XP+n(LL=g>MF6!L>Jk==CeFfx_|!TNm5wC#4N zUua#O)tXqZ7m%9jggM`pUCEto51ZW{cs8|J@U-jfAKpg1zb#uUIG?)o%HNqU-%EE` zkc0YrQ*OD;(OI%lf`%^dLjg1Ds0Y^~LLOm}c@`+uP?I=nlcGN6zQM83t7iTUFvmD;d!`7CRSabGEn(m}Y$#4CEi9 zuwV8LGu$xz`hcylug9jgBzvKk!B@}!zP23n*o?e(F}ZGg{3#4ORqy@0_DLauQ`g49 z`k(CBZZdw86#=C?5U^v3G_15pZ*I*apr0;*mSOTZ*}gE@+-z7lqqV0aYT~g zp2pPWZx_-%s$&)@g>uLE?Ojq4sDRG-$A{a>J5}1bgJyu)z$fP2h}#!?>15EhF_VCc z?7>9M{j=Nx<2;dQ*XMaqT8|be4v&CvRHoCLN=&|J$J5)@5!Nf~iSvD@!3n*apQ9 z$hmF;!^JhM+OL>+7kF=9|2AH;h`T8L?tS?1MwlFPC6f5e^}-jZn#EA@KYt$br9|Y5 zxBkNOM~^%*bwL$P_e$G4tJBXRQm!3FXJY>IDga>{Olufl2Ipr{$oA)DWx2QKt!y#i zoi5Uh(j022MHOCJ+uH^kL4wc*66M*|)n!+|bn#-N+*LX+g{(ILW`g-4NC`tk4}XHQ z?Bn{up(I-rzwmma0i(T>r!qg^<2eKG(>!R6jH(lDl^rod+>Oq56qcJ~c_Irbc}HLt zu}XEWZ4e^XhB5rEz`P^Pv(=78enOAY+gNnCY7v$uMb)qwJUL0Va zz1kTTE*A&r7DF(2PTC>NKv(JiE;N*}inn*lKJ~~p2uiM(y(v6%_Uv|`VkqC?!}}p^ zI0}Njj6kC-*VA)!<5qtCyv#jganXZtzr&_c;_fT-r1U&{h?MVD%7WlRx4p_+U|BGY zU5y@Zp@d@T;wxZ2WvRbH4c6M|PdYkolP4vD>_sXuW8sLF!bo4Z;ZCxo8LqNt-Zzp zgGQ*CiIwv7#ft*$rxM4Hr|ZAU5&>Mt4J8i&^}&+)GOks*4jEzyLSzHTa^?lbv$1)8 zffOR_lIK_;^E~^`oq5)}BG!}VhBBtYu_R_*pnGtC_UsEJG8SF0hF8tbrZnn7o`ls1stMOIZ6FXN=J$Dwo2sZXU^TLvf5X~v83>fFBKJ|zj^~uYC z6va)9sqY1kFJ3Cm>N))ZGXdbwZDnFvpYASix9$Ha%DFz&z-Ke&-5eYdVRNx9NCf#Q zHuL>crUD$`#FllH_~*^dj9E-IPRz}9XKgJb+s3y|U41yljc~swl=-aToL<_|0}^M> zu&}b;MjtaWs4pUXW9qA#e?75Xl?!lZKV)aSS~;5(e`KA3!TQsh+miWv&iGlW_$0lJ zT&tr|^^M|EX0bxTdcEJ%GlC1O8ndUVf9*qS-2!5+=$_RB=#>a)7SAlsqAc+O2C}M)>Fx7s_*jOUT3?2&6&_|V4SASl~Ip>CEr=q<4 zEUe1eGyb54_sW@DntDq(!ehUv}f!1B(w9kQG~gS zba?0(@-m=t9EJQC)%a8NOozDH4Rcr30Kv=Aa25JMvs&;Zv}s9`hK7cMqaV#Y3=r$|ob&pzL=RD_K&27lGLt{I-KoVNN z@MhacWip$SI>a=pEksv^`aJb(P*eQ`{C@h!tf08w{4K?Jv!tXX4S!9}P!^}WQmi|K zhIR{Ms)pd`aO~xfr;Yn+7&Ial)QUjhksr818>> z*o0N$=GV~rFt9r5ZGxM_+>@pb`|RiK70+5e;GXZNcXEfnqCRx7Z51+Yi08>LAD?RI_rDnzR!RX%_D% z*-fR1j0~mq+x8g5P`%YKrV4{R)8H39vFbV zu&p=wdPqfCITsAg{7`uRgfWwAFF7f%z1NrwA)j5eynz81W`)#<^3f#9vC&=?;<@hI zOEYuwJ(`ZYLSO{5)I6EsV zllND0Rs%C-I^?KOt`vp?5~ig2FOY1gw^FJ3I6 zrqlb_b89%U!5}S%r**&o4l(b9fbZ!kOA?*VDj9BhS$y;SzvKX~FQe7m9EHx=RN~O! zdz~64Rd<`?$8C~K0|KOQ6-lP16GC;>m6hN1DU%yv4)st^Jm~A!0|Vb$eJ!nVh*}Bx zVck>5z#$Uo-RTaC_3PR$r(3KgA^GS^QU`?teKo8evs&Q?tdBJJ=X(90pGXiW2Wf6R zL}d6yW#ilU_#)5!O$pK5^(B6TlIcY3aq3QK^V+0g64V5`XKG>~14A*8ohM$b4BZV? zjJ>^|euFTd0DRn=bWdx@jRz=28@B=pns%q85xS<&*@I?NSDwX~_KRg^fr-NX@F6h0 z=IPJ5bL1@h1gJ7LSMcCjO{&q@Ry;vJIGsV?#*iLIDe)JX8aM8mAk-#C##575UK(-? zc?Sq5!It@C5WBR4@kes}j}2eewZmTi+}6Q8wHlZX68h{k*0q&hx2Yul#`$;DPS{?v7nIG)lDM2Ch>?0ni}nAe?O|V9Az__BRT*D0nUX># zJ#cnr!EkI+dcO}ACfslj*d~_b*YbAsCqt0m($3b+QCr)@)&s#Xh6YHbLI?SwpaTp| z19jri!H3b`zI`)hnj%hd<)+foWum60hcSkpH_PqOocrO!X&$L1VM&W@Mv6z6n1?e$ z?l_(}J+Q#HdDJ=}k53eRUdsWdnQjp>)8nb;X0BaRUk&_z9GKsiyS%=wuj9pgc5-d{ z{Hi&rj;Yj#Kesn}-^Rx+$_KUL-xdpUx>Kl}C%b?fD%5A_Ym7}V-pfQ>`+q*1vV&RI zq!<83nMjG!Sz_lM*{!?qU&$oQ{pW{JFM`VjM{_y8=Mcn8hnrKQlBmJl1M6N`E6@~G zTZ(~NE8pkyw^Hl!K7amRE|E2CEYR*8MEgTfaoB-#54kclOvR%h&Bo~TYz{;=o0A&N zR-&k2WBUk!rWAy~P@0B7|A?(tOZ)pS9iLb9Lf{JkRmH_sc=Fl`f2_ILKRCEf6B4Hk zj$zJYR>_8k=noz&BY4J!WJ3ZTXJkBe^(r+CfOgmk6`z_@=`p06Uf~6dnrvJA%v0XE z)|R`n8~GLw9@w;z?^G3w%6^|Opi}4M99hWVS)FTA;Wsy`S+#QK40HB~iJ!>koI#;Y z646j~o0jVE*t5ya?#v?5+$R7(i?PvO#;(F5> z^%8H@7W7rg$J{KtBfWvNe~}uxPupE;t503LxPg?AFmXbgdDEs97VDD+&BzXQ(`540 zH+xIr^&iJ2l;N1O(i%|5onWaIV7>HdFqztCoL3H#=xHl!~ zQ=UHBajm268Vi(!GoJP-kN3#FPu;kV1YMnsjFFGH$Dz~X>BQBcHDp@9ewBr0-EfJ* zuG-ZTDKID7zWs!z?!ZEAfr=R%9XdicU;Li+<6Zy$kCGDcIMT%@nUiq255FEnqNc6* z7ftU$n|I)YK?WpXv2j6b038Lfr{fM0%nK|5ykH{!G&OZ-c{B4P z`uUwceq4}*kmjvr?GaIv#W74<`xs=%QLny2QEfSrqrWQER@pacghfy=qIs}5ap4wf zx=*;STxjbFof_UH>06daNzzwjXkG@VDI0vvSIXJXD0NV;@melV123O9s3thE2|)J^ z#a#Z^uh+Ya8-c}!fYJoDXwxSv?_xofo${!8rBLyi6etCkPluj|7c zmn?Ab0FAe0rjX@Us;}N$N{pG;C*PlF>C2W=v^%zw;=M`0satRlLz0#KFqhKaYny+U zt;C;ORy=kRy*BR4e`zt)=A{mgNI+bz;~5VC^2c7)p(#RMtU6PWG1p8XQ_#Kt)CqVo z)oL(lk}B-*8%|Yu!1;sXJ8G*UJ_k9n0!n#;@=4X>i%1?DDcV7QaD-9~Wl}H858n z8cb-6&d&pZ?=x4-J}&9#ujySdv8vkeS!^o&D4 z``h&Wk*gf*niLnsEUTzCKQ=q#H@CWFxq;u&ysJwrnniE$)a+yV&&^vDNN;zx+YYhX zbjy__Ldxy5t$LilFd16U=7qt+YuC;#YJs`g+t5(0ldjkQMda6LJaBcTX_+1^S0RHc zT%n^PN`lk!(gE zs}j$knDxJif2NwD?AtaZVRG%^jLaPMuA*LO_H-1wYoRgQH<{cQR)t<)b-Rft=yIs- z*D^DgAZ(Nh?Z!yl8_=HAYv}2DcTMFg3}+q9ec};^=3oiSuHdOH9qee!z;vDNtmUp7 z6?oZi$J#?eK8fOwZ~HA@ z@QqzxOzyBJC2@D9^KFuUFlFslW^k4Y>56|o4lUYCTEiy>_kUILjfKp?#FEjBVWF>t zSRA7JSeqG{q2%_lxgN3RZqV7(O&=TORc&oQx@v$+2YLFNN^eLp2GP1>`}RA0#y3W% z+g$wmNSP~u*ln>N9^ zg8aY;Tz=Zg)2B-zsD_hWb>O@N=lm;BvKUO8&RLyFu)@29gq}b`hyE+4F2U9P`Qa@N z5a#w@r*L9c4!>1!e%$;rc3l~n&u*{y9xCdkJk+-vJBFi#jx1UI@%7Huam09C zZua^iTb<_#QlG;A+(rEDgnGrA2R_>%KNS4_MZ>07!u$}16L8+-B^$O|-O}{h1sGNs z<9O_XOeGJP#UK@dCXOa^^vO~nTWtaNGpjYWc@};m@U>>=ZyEUz%%JHYrk==CH*q3& zA*u`g&CpJa!=w$R2G)$)e$Ur@_payFYsLQsW8GK+c|~Z=7_U*sZUP9-{Qf*``Rdi} zM3dZDEidQSc3))fAVTp#4Cav3fqBohWe|j7#LDTn#rOn4p9&W%EBb2Cdjjpv=g!@2>FAd<18rFui^Wi9&@e zI~wzb(V4X((Pb{pIVvT_8@nB!dwQ0X*e~oGO6{kEMsTK2o{~{N3;!Y@{FIKFZhxU} z+!di8cV!W_ErqQ*AgyRqBlqEq&!+Uy3EmEfKX=*i7#oGgV(x^&QZaR1hWg7>jjUxB z3_0{qF40Fyt~m4eLFmSccIpeCN#Dhdu=24bRxRe4Uh*1JLmP|vJ1A=jaTv0H`7uMs zAC^Z1OVQ0912zRI-{_tE&cY5cfdFzENpTo zY4fH{6LsAICl<#iCK4q6P-Du8z3U(fj{pLLAhPuU<^T{$iHV`r&EYxXVn_WMTb~HF zzD$76+$A=ym%=$Tp+3T>cb;~FjG|&;u%x#oaw#sys4cwnt-1MmSS`9c<0U*}E4#``08m5u}@Mt!;F<+$VEJT=ElbeX<} z9-q@muepWSlN2xCroQk`vw*)`d*D1UP#a7TMkh`%LR0^8NjvqpBeNhLqOm2@)>x7%XxjMhVsgeJNb&Xp9u)6Jhe9Ilsv~FGFb__z7vkM}tF*t2k zcQbS^xh2XA=5b1VccZ;)uo88U}d__Ll@gWgM6C?{W-#v$c z_fbPAf|)c1F6hzQQu~F!7QL#VvcSqY{PS&7kpm9Im!vLXxb0bKX&&_TQ@N63LT|%{ z1gqn3dd~RL=pOjCGI96F-|OI{Q$9dyU2Xbn5j;GVFxdcs&p{HI&WUs0cC>hE*p^H; zQYl-~VwA$ei;J>y*|L@<>#Pqr31=JiuoX>z;#^RqAsA94H?9+JZkA-Oi}0*w*aF;_ zirk!2UdI(i9$j>|oZs|t@TW)3P3AE?Dp&N&%ZF7CRbRQ{MFOH&t@gmr@t=FL<0Qcf zit3ZrxKS-f`VucMy=UPmQ`1${i)8~f z_1=BbkP9z|MR)Ta4&mS&f>BL*fPHFu(B9Q0bYG5k*0tjLcya|^&%(^GYn?Yqko7|R zji`}blf`qt{n=TbRqv56^%G_ejNO_yl%@I}@BQzOz)xuU ze?Ko0zGY2!cbGFqeaugmdH>^$HZpFK?swLSmD{Kxa@iqabi+#;8?AThEp!iqx%JjX zec51;7PE0ETh40DIag|lzn8_eyMJlb7iEvD2^f+TJ1_8i#2My2$-1_J>RfL2Mqj6W z{Hp-uzopWN$LVG9TNAZZE!J=Hu({KDw^>!F_%{qBG%Rt+jt#Nt~wB z9&&Acj8E-DsvFtQTBpP_t6dtYy!x;6Fg$;odDbcE)zV+)GjLlN+44_x5iebC{r>*4 zsnI%^;m`FD@ZoSSz0_xx@B3`JT2*dp4-Z{ zJDcVGnqQ_xzh84IUY4T=g^`ZkgF^Ls>88h*=?1w4S?=Ob~ zS@H0cg!`={X|%a4ETqzv_=Rz`Y3XLv^bG&L5T!H~JUhkZ_U)t4WRIF;%9&;UufJ+n zEHx?GH~ajFf4w&1m*$fG``7&GpI7<&Z`oY1nf#wV{!e}=Zln{ne~H+dfB%%%s|Wu5 zPe`rd%BCaHuLC1^?B^%5w*;V}@aM2f1=Y>#UEjjvb4 zi8NcgF>loZF4_#>MTpMLa~c<-OC`1VdjU{ty}lZS7_+&ELl7Q?R>MdJQD5Y)`%D&|fEDf0OitMp%qlmqW8=?>f|2r0F+Uu<#4o)Qxa z&B#zD9Gp$c#SvHT!}0ecMx&N<$0dJ(2odc1%17AZZKACw6M(zb!p!DNii#5USUnC@ za`0gkhhHi(Upfr??>jl|-4m*Dcn*FJD*Z&P8Nyk$K~5M=-SP^CbpdMy4=j@5xZ0u8 z@51aKIWpq%d?rc1c~4fe2#alx&j2Qo-=e7&m$`9c$?7wt>==vy|MS5`;+H2kC+gmZ zbOXQUdC~gIW$W?T>{?9Ii(^R4Jt!ig-TuaxqN1nj^kLD_@){ZyF&V>9V|R9MUNkIl zo4E%+abK_BJEXGEp(5qPOyrymEkX@vG2}9~aHo48r#3qEzvbjQL6J!-pq? z_vGJ*Ln8PoFA<6o#K}NIlpy)!x8ao!mya$(obw%1%xp0eN!-d;=i45a{It5nP-VXO zL=BH5W@GlSYlefIx@4KrWcO+6eIZ9#+ozRqQF;xahmlVvXtRn%Xvx7ugwUp21Z?6| zc?U@a@~AFdVywDNvvdM@M(CS2?(A@!%)b2jYV5n@Dt%#1v59%gV0Ve6 zUudR635LISq_sg$x4o@xym8o05xy&ZMuNL`oi^?&s)hy~7iTLR{Z*IVva#xmu8e)8 zedC4`I^}S1tM+hHy%60UbL9ZStB19)Q{-r%TOo{~;KKy2a{lsgR#t#w8d5XnYwU$y z7Zo{koP^M<%WUqG_JtvYb8p9uffSh;8s_N~%8~ zj!dWOyUW*0&8BX89B}F}|2kO#tOqP9*d^`5VqCG(m9{SfkRsvT%iryD8BVKma&j+_ z2(}Znwm6ZT%|=AClzePkUzIYOmDhejLgF!7D6n4K)w9ylHCXtwa}6)Nyu$d5i`{Zt zmoXWqH5#Qgo`o#v;9ASqm^9JKxkDr`&s2_{zjyB~T#F0KxJ z>d@tVa!O%|N1`!7)xGqstv!6>Z*~?eh0~+yfI=Xiy^V~>o=}OFudQu2nW&QAjhnVw z&>#yg7E5s;u1Gvgdt$1=*b`^U&aCF>qs>ZhiDYCrHp5%#N^IM@ul^#^5O!5XDW@e| zFO(CSZaKTfDFD>g9m2GqQP?LOdFd_B$U5{+pIu9;v7hnpSO!sg&n)9=9+shlPylNUCJ*Lp!x z@(B_#8f7ynb92$%TsLnv zXH&;$C;V-XJ%27VT)dHyF>>+BE)>Owk0$j%H5-O7*hW2BKxxGFg6GGQ!PrCkO(|F~ z7g*Mmw&ter8wH)gd@(|RE0PU0P}4*qKQlBv{Y_2YT2f1qI_si;4yEjTZ%m%TAz-KJ zx!GZ)wGx){;^l8nt#q;WgVkXV^d#kga+~Yk?-YY0FOj_|7iDv%zs5XbKM0MTaDLzV zY;qoH@BW?@z0dMwLm;G}nkP3$_mu|Z?%gl=CaLMlTkPo%ajI@WB29l(TB=0-vuD?8 zZ!zjTn{Qq1+LO=jFM~W5K|lV^uC8A5EOH<$kN1n`L?!cn>i|Y@Uw&A!@N&ONZHMe(LWM}Kw0z@c^(HEy))tn3`Z<%ZN=6(1?i=k*_Ky^ zdZ5DGx^3G8@b8|HRwYY840@-?cpaHqM(k6+#izQ#Zjfw0SY~W#U z-(G@E!z{J}VyRTdlDFWd=h6Lh&k-Q05Pvh1Z4XK5Xz z*?zf@)YQ{JKGtJDLwJt4=X+R**iy(-dtkK)*ObOOui#M3^Xm{LiKHZ7XDn2*7+;?N zK&+@bTfW(}$@1|;+ha=Kd!1t;(5@i6Y`)QD7*6+asl#_%ID6K}^Zl1INpQYp1C5iZ zSYLO=HFLH~->3ZJ9=t_b{d@QBc^$g`9)9fD2TVp<#FPslphV$z%_|rWpY)6sYA2!0 z<^yoWI2qW@F=d?W?A+Mcm!_nSt?a#U$t#bz zO9;hibTQv`0R?GTY;34Rt=o=M#4iMum!Ru?$u28P!V=zr?(Y2S%%%qGqr19>1k6!I zgeE7mB^PFkYTx7y#@rr8aN_fHBxK-Q35I>++SV@d#UxECvp=_qB;}6MVW77AjEupj zBI&vqbq_YIc%I~SHu~7@ajukj@Ijg!uUk(i-e-C|KQwXJ6^A}HG>pVzFN!L$2EPN( zb;iNi^pJdtOx~jz-+it3?~D0-pB_)jg1@`poLv@eF3A6qaJ#O~&WXBA?pT&RdtwVm z>#j%}v{4QuH3SU|7&g`&LL>*8r0VkWFt~cSHfPUy+Cmh?&8$dH=% zPEH!kS(`;-7m;$gz`~Ywi=;I+Y1G5kB@CSd77wZ~ZGHV37?3RC`3&_e&LVfDh`rJ4 z6mv0QfN_Y>uI*x{%?93dO_3cS_y zCqL?^)xzHzBGbeA-U-k4JOv*UjDD#F?b$ z(ZLa>voi&{s9NvP=Jv=SnEEXal_%Sdnu&hyJ~`VzY9TCj@&R*c-j~l$ygNoM#_{u| zYHKw%BF_xI6R@2>bx2Y+&1|r`-IbyrowgINw53QMbvUeb5X8NE-@bh>Nl#zBV$J13 zla45Deo^^tR?XgaM)G$u&2}$aM4dO^P~qY1Jl@is2pN1tNh-$TjrbY0b;g#sn(o?T zzH4E!>!L>x8A2BXFVVt0$(+nk_3c~G?CfkyH#6S5t7_ekOGM%tcon?IzofpqPl9(| z1A7SdZ3jFw17>1L%wZ%Fy`EAO*VmT^Bbz7SbHK{;dN$B2@TL`ndHdlWWqe6FphSAA-;GMCzN5_@?w zCU3=MOijN!h{!?V_!?@(V+gRk`MpEji;Gne1rYM3(}Sh`gVB3$o&_folFDyJJR7{* zut?w?dtFmg=i>t&^cg3DwU)3)G4sjr1Z9zLX=_)5TA6z~;GL^3fA%cJ{8$`P!wz1( zYh*ljCl8GUTW@mOb6jcK0wFZp2b8V+u-)1S`(r-xqKZn??5q`|K=p3_k`SC`9{7ct zYkwndTmz<33rA^B04h7;eQBLX;r&grgM)UK8M;7KzR#o^@%r3dOyY_l&JqNg;bcK7 zmZ*RDF}s<Od35bD0;;;KXa}<7Jqn+7`GlS<`B;h`kVPF~wS9?~*I(}3( zx0P*eZB3o~E-?XCVdNv8R9*>e^ScEE6tP1=v7(Kc(p{rn-J93E_IUQ<$Z_P11Z(x7 zsYBtJQIiUs;{4UCcktMyvXM-N+BR+4vUkg1Uz# z@?3{4lpsC5Sruk}XZdo%XJX4O67S=Ga8xJmtSlkk84(_yfp+HeFXu$Y=`r1p>J69= zGu*$W6ae^lD^}d^ z{dID*AY5$8xZyga(4lmkR7gZjD!Q8U<@W1%aK8=A_{|1hx-do3WgZ<+O2~|glEQQ^ z$v3E2c|%y33#xy)iHTJi3j#(#?Q!sQiBRH@A7Pl7U=%QgnGtZLajVFPh$59jc(Sq) zc1J=lwmAj7d*^3v+TTzX5fPD|mrp4lHNQ(k^11xm)H*w+I;9RL;xl!wQTuoO4R2dL zG?tRG4UlRSiBkNGd*ZEpKD~J#AKmZd`9rijUh*xiVe zNIxS%`+VJ$n7DZ85xoXB@l@F6!NU7nq!dnWz08?0glH7P(AQGA0FN)5IQmT?Kl|~X z3tmU{^<1wkH;aDy$6 zE?MpS_^Zh-x-;&msvkXa@vYo-?q#V)n<;QR85t|-KHZzVyTk!zz>xb)5-e2>g_t~p zFr6#j=l-m8Vob~Vv@?AU0@sVTANhslIkXn>NQ&F)`#J}_H5TYA2IQ*7>m_3EN1F?H zs35=AtYP-alP3gHNPuoDHy77H3=*#B3v58yAm=$=;X`?o-BvQTm$M-R&^ z2ngOKdHE2?z*K~zJNN9^p$s#5NUo~)j;0nT=8keJkd+C1#}>4Q}%$sn;s{=&~=i&p2{c4j+%`JFd_#phn` z-n(#rb$1xdbX0YZAQ8E@A_TC)r5$27_K0M?mY4~FlAP#}8L=rzrkSi(Q1N1z`@JeRDsMx*-`A z_{tyFsqQ00cV@*NI@Q65P_$pO%+IB%HjP2g3lYAtSDyLP7U+rtPTlB&A+Au!9`pHv@-sYCQv;_i9v zWvEJcup|)+r49FkMqwI6cLoB2h{+q1yTo`&MaA#*ldW$@4CIr1OD2aJ*}cD3Yfy`- zsAK{$edgm60klxNAvv~D*c?G31hOsokkqpO*k4ev0X4jKc#N*SVAC4w^07-Q%&!d- z7)n+~L5xRk*zm&?Wv*mL9TAqyAta4$0*B|`-McGccl$O{(KV|g8>N0Ua0T0`w5dM4 zuTtRd=ptEgBqOF4Sgo>tW(o>f$;LXA0{59_pAehUW|d?mbZqahL_+6$CCe^wVWz~> z(c_`;*Ws!DoTc&vfLQ^<3+$)|qH98c;Nh6J_%MH1QWkw8c84&ad8VbiiZw7iHwf`Ah#R-Mn~FG0kxo}g`VrlMf{GB-W^fwdx9l;t)2_qDLj z5Hcxq^X5Bhsw^L=`*n5cCpcVi3Ost)tMDXCB%ET7Uh)#ixldOw+_+)IMfG}2(9|^i zuvYm=@F57e!O);M$|d5V3d-CpSet5^hGRz?N!;+4MM&`lJh4P-62^p8*hjpBLm_y7 zje|_9=;Z}SL;$a&0KashY%R_-Q9M|JmbgJz&%HY2aXrzXj)%u2;!T^G*jm~jkCK7R z6-5C#J)Et}KXa8=Rvr}RWMdn5P8Z3X`p{e5&@jpXo8N@B>2!2Ue3{mLa4fAUq0bGvhGxMKaXY^HCb~PUu?a>_m<& zjrI6qgslbAQ zu!=e&VT)wYcdp{1hQE*C*8IS^oP!bQ>#aNi$BcP-vaS-BqjyR|(B@G`rS!Es*WsVN=uw-eA>oo3j0Z zzZ=%S(CEi@_n_zd>;YO#uK5uoBkBr|X{2@C;`5~wFK@~qC+IgX=uOb(mV)FW;wG*I zDbn3Pv1(NwS{sv=>|=+I9$jrEf;v46cpAf$QfKFLq!&!ka{PS#BL~3~d+oYSa#(LO zxQNRF?@(C7Q_08;%ffc!CZ;WBw*EX?Z%(@u5#Sme=MKI62*L|U_E{%&V$a?xBCME4 zUf@R{-pWly@+KzNJlkVq%MhX<2M`?%Mqooj`my0(3&~-9%`4KHWzz%^zKk@^x@Kgl zssI%&A}bt9ULxKb-r5^+eWaa~%|-|^kJ!xtCRVm%Ymuzez*g|7s z&Y+GYI^q#cdM9LP2ln)wSxg;_V-|=92Tny;21~x=f>V2|m$0oDR+S0-aF6xgXS;VV zg-v|%;(PoiyOV0h5|haE*N9($R&PBLi_v7+WSa3YY}%DTEy{VW;#o=eN`fO7#A3HG z!!Q5@1BY)E-8`V0`OM+Rw{aB}`PsU(wQF=vEhP{U-CFlRQI=AT#`yTkmPIHFBN6YK zw0B>4$7p3}%*cZ#JL?1&AdsJ~VvF9>SXV!2M%2L^?tZFY~6lkH#*Qp3zeGyDjoZhWlc^#DC;2WT|DkB@PAqTqBX;nvT z!4ZY@k-_intq?o`Rbmq_$d5&u%1F?xdcu{B>)M{NVTEx&_;C?P*~{P8GosHz-_Y{h z^$8EvYcaeivouFhlB4q?QVaKnb#0aHu37JZjeJ3X-DB1C%fQL~rDkn7EG2wG7Dr^JHw3`lBLX}n&Z{q?B5ioA+t3T_RQo6JPrP(P!WK5Cpg+qVz5V1RQ9b&>$gY~ z*DSjiHz@#TDZw$?>Ujnc07qm+N?Ycqt3(XllP8o=I7=|i2?z?#1(AW(Y?@1hQ_rzq zo0b$#6LhuT|I)BLywmEGPOy$oCq5_VR^JD&$>L*9-q%hG~T9+`a z1BOO=T8SVx@YKDXo=)cIc6D(n2fvnZt9E9#ad?59_aP;vTcwh(yGTY``w_5C&i*EA z`-V=(Ggh<9lnp^7Ld8e;i&r_ zKmB@KEe~K?W&8Prv(n4~ARX?{7Mt6>#@*{2oB6>C!UI71u+{i(Ws|bSR#5ToG`-eh zJKwMR9AQ4-;#919J2`5sM{=GYqCJt+G`kpK(x(V^8i+);*5mg7E^C$+U-;!r&1(B; zA=ILEbyx5kqI>Z0f;2b@s~xM&-VOO&??Sv>=S)MR7)oIu{e?}K#H z{`5$K$9_Q&8`?zz`ogpqnK8-Z*BUKFf@Tov$}gQOz-sQesMK&cv|c+w8_$<}kh{Cg zV(Qx*okU>bo;^aHb|yn7Tc(yGb|w&gF}$eGZhFk>AFXU^YFd{x>;STA3(>^?{7`!k zw}!eUP9yH}PH|y>Y2f_N*!J-8iOVaS&Mf!sM(ytY^+p9!8Yg^*=g#ZYM9E&b5R2@| z@j4y-9xOvPl$=;Ah#<5tw(TiZ&sdoCb`RR7mn?;X&OHcEFN&@*)UUG@{!IOeMwwb( z_@5PvilpbwU)OisE%^XuavW3My+^ZV^odOyZwIN8$X65&!fAH~DOky%PA@3eHCnWH zqcXu3ZZe!9QjO`1NIbSg2?r(jN^~NgSP5nAhh=5lug95oocrH%OAOB44?hlG%Om6$ zB(8WgoF+Zzqu8{HeT?s{AI2!ZXkAGOn85$g%SZ^sZXW$REpm)>@49e`n)Nlok zcu8F0P{kA|LK1Y6*s#C8ZJsg;YyTk%ps&O9+gk!gvC1F_OOAAdSHwL)aUqLU=)$n4 z+UxLe7{-7~XV)xSR0&2vG#ioeZq-rBA!raT0hvoBdQ8l9ZgJw#YoJHZ$9?nHdc%gh z<}@|QVC(##zBB>Fpz}>?UU+MlkY7;X&W3kRL|@fdrJ0*YFwkQO!Jko$aR5TF5F|?)#)9p??Z6Zg9~4Q z2@6@p#Ey3$7cfnYxBRB9Z5^R=sj9&Wg?4^#T4QncpEC5sGbnIEq>&sB2f|a0Mun0D zLj?D}n(hvhUXk!Zj6U~4JlvPi#Li9!j1{VpMHFkw0?ic=Hp&*QM!xn7>(II(_w})j zaC6K9MIaCUU^O?o2Z6+Bi7n2b5p$IbCjiMrG-r7kb^wEcuIvH12mlbC3$i#YV6!GY zt+M2*;E$JfLKa_xTv`_IuVG+n2sRt&R_BCOCkWDxFK&3-l^-9rZ`{&b{rL$qt+u^z zhKEWBxFjNJy4yGD3@fV?wyJlK)KL8?*_~Lh+A9W#C|p9E1GbqUI9(R=@N#$9-3-qfi9Uq`S+Yt>N+R`>Dt<3s zghktQ9zh)uP+#DTcMsyd8g#aFkIEA5U+)K#L|%NxPPdMPW26JxJROuFj-3e!OjXr- z@*v=El=xwY{UTcZ$rOPGHGZq{cXjpi?`tE_CbIpxTO|57sJf-Npwj9sYW>uCp%6?ls3g z9I29V+TEn=)aKnkil;%L>H`odR32n))K2iLoQO*4+Dqv9!otqNR+ zK7<+%;2;*Rb)*LU>5;8@E{qzaf9{n7>!U>^wFfY((Y&PE%o1J|hNDIWeW_42tQ((c zdA+Y6^y2RJQ7Q2RgjiGrC2?7&1^OVo;R4s_86V^!2Lj9lb6`8DqsmliJ)kt0X?$lP z1ez@DQ_NF>#O_>JHTLm7Q3Aa@DCrLU5tw;H!@OoN7MS|%n`pqp5R~^1gigR}dHj%$ zurqkbGXAV8OF<8BAZo_+lGN5##`TnK+q_d5{107s2jcN2aK~Zo$}b*6g-|fXqs~Kb zr0wr7pquFOalCyeAmZO2ytY`GP7lx*5Pj-SahRaUfdY4(zyeJ$8{`)+hkwIjz_O;{ zK)5Hq>Nf>Y#_XBO3!bkw<6DT-wpcJ&R;UQ-NW? ze*pZPnW8Tf!b&K#hGT7hg62cZ^9C>eTHYo&Z#$-zvWde|a_De?0I(kH=I%idg_-RU zFpD@iZLXowECQp@fGZZ-V` z;#8$AYc{DsREZULm)E)nY5LnriMebLcPEsAP{c{wWvN0U5e@j3Qyeem68Hk3fuYdk z-fT>r(AL!*tQG;BXk6mE4}TOC?1d@b-b3Y$y7xXb@$fKI;8(rCnck2B1i0q4Xm<4Y z_*#N}h`;*jEx$p_Yg7~{PD4@om}uEUZ&h$34zb3n-9Fs1moIO@k?bA>VOMWredfDY z+ycAyr_X&4uS?Xm_MF7jHc>u9t42t!pxA{+;{-s;Tvr$hT_&a4`Dtz9hKHr6%SeLI6tChx< z-)i9VqTiL-{{S9BXcBY8=YqAMJvjxq68QPngWHvZx8Qm{2gi8sT*R((U#gLXcs-UL znwtbDJ6;8E5!AP|Oac0b?QNh&Gskb1RUEb^_)aJVPW1Nn=I{c8)dGVFwono6={Z?K z1A&cC#3OmehS9%Q_Xv5*OtPRNkhs#S8OR417ty5C{X)KI?ha>gZGcFfD;{1!l)l#c z_B+!urkJyY{P+ok!(^(_ocQ6kU>+wGhF@te1eo?$OSm68RBnnXD{=RQiD>y$Nd{uC zIcz<-AK|OLE&`ch7|5z=EKY)!jZmOEJDW6Gb^{xO94WQkMSyIo5BR?nJrmdw8Nii2 zLuqM=*62$i--NJaTDT-myGj6s)tgNmKG6`*Rz=Pw)HGGD#|w15l>2~Fm+pN|fm zC#a~bc?so$@GzG?m^V2x+0T_RMf1Tn8sy9+`1{6kqz$xjbfU1k5_cm~FQqehJ?@h8 zkGrJSgAMT_Wa;ol;!F}quTk!Xvn*jKi$gMvVQR)^wkPmJNW*H}bO0Y(3v-sx2xv7V zAKZFW@0=&UuC5A*;~mK~Kajm2`;kMyLq?Lpl~@{4^E{Ws1*nE0-F3HWq7ro{WGL8< zAOZ$);sFg5kV;F-d(b@vfH$}R1ifPPWYQJWW?PZ-=gv99w|ku2Ou2Ad^mXA3sx(lE z)$r1P?(QBDD5i5!LE+n57cDPHm<|ALx?o|EjND~_HI+`QwmI$_WiFW<6u^27fLjMz5qcZ+0+LaQ3zWTo>Q2~}^5Ajkn#9M-alR-wj4rFxzn@}Z}N!lEG$<{QCoQ+t5zK= zS&%5#=0{y!VMTEa&uCmd9clg{=B$4{DB%IgG@>EMYumWN#3pl+O!Ho0{~_APTerIO z_LON4LLWSdmRZ> zcK>~_+5sgrJxAu4FEgfkP-n0C3CI8WZ9b+r8@X=5dt~jOYV_x)eG>NH{qu#t{^k(i z`tPs9XZ}9{&Hs<+b@u6B*X{Sa=<)uo)Vc1pi;9XQ4y6tkEsB=Qk>@0q2(J{Z`2CeX z|LnP^L+? zdEl_1XYgziP^@q?106etp4{&JHCRA=W2tX*Gn3EUumSI@xz!}07=;L6VTWkj+kHuO z%U5u{EaCe_PB^p-fh9Eg)1?cZ^BR2(Ki~s?npAxAv@&A~`z# zzEiY1z9Oj!Nn_W)8sKoJpnbj5p2X`{TvJf|?{8AwWu2jtd7fzr zu;ZHg>g!-Zi4TW>N5c$M4mDD0?^u5qmAPJ3+5}CbwFHe_1lpZU1*SV7GH}XaJQQMG z;Jp!Y+kOJKKYof7DJ$mZcdLEFq4V=PqnY2ya>55csB!2gMf2lpvzKrG=NI|?2UNH# zjYOMs5a1JL!4WS1V;U{P*-+3nk9Hxz+IE)Iy#} zTpGLvwd6CBOrKw`O_q0F^-}v5O~Bo|Yd&PO@-L=d{ zaXH^UFX_;WX{hqPKG9^>J$1kI!<)8U>dUiKOWN5{Mi=>v`CdNd?K8~x^Yzfr;)(nB z$Nv%k@_+wWI7Gu7(g3YozIMVoYz3KbZvFL$^O_xPws9l~2tY#Uw@a20&yT|nFCps} z;D>jLqaNBPpZNw^EP>iO30I))xVm`BlC$opqluxend1BR?)Aa%z)hXL;Omo1W|P6J z+(XFMJ8;G1HX;o!Dk_FU$h@kRG6-M_Z)!s7VJq{gJG^ASuJXKIq(*0=>iPnm&{l0K$*5o(3{|)gQ~uVJu_x z@`?ZoIvBks)@Gsv0b9+7ihc+9_@kDMm4GgrvNK4t7H#9LTh-7+0u|`DRYnBoJmj?& zK`05%JMn302ix1-?f1>19Ju$-(9_=zuM8h5-fXkvN1N9ZFb25c-KV)Y4`ilm;z=bG z%6baz_kAj*4lw7LX!F&Xk#gzpmRE+omLFh9cJ?acX!*{R-e;Dpe_3op2t;*!-uYJA zqwn9Z?FgF6!?<*_k7JjBc3O{}j{^Gw4C{P{R?l=5l%B7IM4TtAbrmSjZ~f<8d;shV z2_enrqxtBvp6KXk(D(8Gv5y}cfAB)D`Upz0TuWIvD8;lwQD&}vjT-wMsK|HDgNBKw zgnJlPYiwp#T@u1Wcj#LRR`bAR=<-C+!TjsN=8aNfV}L+4;bwAj#(Q}wka_WSbwQ9D z#-jqYKFW}m1DmboUmJ4_u z4rsGO=@L3VL{NZ1E>b-@wslcRt?)70M$=vF#v!ayLH7Y2(RU1mfLEVjO-b}g zX(sAk$Wo`0>}oU?0l@B&z!-!I7>Hk`LLPM_UOmt1y?%4Xpng;&l^@f~Q9)M6sm3El z_f5ez8PvM=0sB;gqNmGmSYhBYH5Nl>n;j4|K=xPliG2FBMk*|@AtVX4IfSKP(}L!W zw#R?N zd2xBCHH*p7?W<@z5RQYxRUf!GjI{3f?a~FFicdipf@$X1Ofx)rB)@@yf%(pQ9&gH4 z8(ME1vrQp!U@b<-9kU(bgS?Qv`vbVnsrvZ}g!gs(_A+2Wg~i2wR224;Y7Dp(I={Zs z#cOP2bPFY+lT)y5ugKJ|i=|3?hDRh8N~6^g9VR6Up0VC$4z5w2a&=pM>*^?wtht;ZOSDp<9ECRJTl7J~%~u*|WlsVV8^ z&BvKT6;X&7ReMK2#uDdFr0HUDBZyERpRpsd{tEJy$(tMPnV+ul#6NvHIxj%*S&O76 zggbEGd4N?J3%7FlySJi12v)&Gg4e4jHaxhBXY*`}{GHXix{Oi2S7TmL;@7Y80P1ez zrkW%({YiZfNK>Q8zcC!MRk+2l=+Co*H4l~vL@iLvw%KM)9;F;sR1Ba(M}&7*Sm|N; zadaITJ>a$v6>Q4-v$}rvOw5xfY)eq_Llp63$1@n~d?JCF9O>5dqoYxRO1h%Ex-YbU z%*tv|9s%0wtcK{3HN(dkp19<6^)}*1eI>iU@foZL-$VXUm`lMf15Q zz*QUb&@ohnKqgoe1qEAjSBz(=zh`}wuI|`6k&mG;W_3>vb_Ay!1DBL^?liR;aL1`M zt#ot0+Md0iCci=igq{JBUmZDe0}G$DRgs0P6IX!_V}w_i7tsJsc%Pw9?sZ!QrcCEQ z_4ikE?tkHq9SHHUPeVwP$?WHk-{v&H4H_GnNPd82SACq)_-1qP%_;OmjL;f#3a7OE z_OlUy&~xw$ttYyyHqziW<<5-+zOq`4@Oy)v9FEw2N{2(W3iX|4%0EU6_Z zgFfdhT7CA#_~tg2IlhHDNU#tsgFe<`SJHl=&^#TSb(0>4)WoEu^5I%KU50O(-1X=u zQ&UcW_KuFQekPWeBeMx|l84}kBf{(i^ z?G0vZLr9HDh}(RQk-A)o$Lpn}N|Li3Hy$CpUyH50`ljAbk4}?%MnPLnE*@)9ipky5 z+n#l>ws{<9j#;^~rZ3Oc)m68l_v83=bd}&v(S9ML zs;({;XEKM;%^cliz$dY!qej$?s;Yh{WlpWaIx9!EN1**ehC<({xbvIl(~rkapG}{? zNOO&oIh)d*w9X|-RkM*=ZE8VP3i~|G|09wVKE`Om=jxh zq(Rrm^l2z7{ZoXuR8o-n#C?oXPCNbP0^-6s9D?m_U(0I}8zyoHeaST<03a}uzzl5# z1S$kCO`qR>`z`Xym88Z@H0jye0L>>lhxX{sYCgT^sm;{``!A;%mCs|=jDIei0_Ub7 z4JQsjb{!vxQ?<|vaUNj;myzrp0HYJ?)f}?QzS?FHBLiSVkeMTIG5+#?wJ>``t&6P{ zHV~SzNIZ;UAUTL=p6kB+y5orxcd4;ZujwYImyURP$~*n>9~%cl)i%<0?Xq!e!YJ%R zK%en4tIKwnet2{oNor>oo+S>G{pSNnrgZLk{%u@PyXG8ioXL=j$OQ(jCclyN0)kI&r+$}4 z>&nEqL<3RsWm@df6~Oj3ICEz6#*G?UPfd{^&uE#E4US~Zo+^OVbOOL|^AB(Ha&z~A z2T<#?k+b0Riv2Ux@^)!J1^#N^cjz6Qcng%8l7wQ5+EITMEMB|zvWh++*umD9eRqc8~5kU5x<7J zgW{&VCj;>Q=1tKi2j64wd_S`;gZNCUj6RF6SmiV&GqXhWW*3xMI!9kGdwJE+_|wZ2 zB*YCCjnALU0Q5ZUgVcjrV$=6tO;fX`r;Sd#@y7z5{%N$=Xg&ZeU{*bm&|w=r_-NKY zPmLQMa;c|Y9imkj1n9(pal~zd#+(g$4PBo-0y@8@luCXXf#6}HzE;qmNSbvK#n=*9 zi#S80khgBn>?bUS5E}!Y#~X zXxku-q;A={Q+bK(;pFB;%a_v%*<6(u|Lk0_-v0A-7>d+9M26dlxfhzLokVNBAF2$^ zXZ-^BD`)WMRB)#;tTHOXT>4zqVbFoDPQ2OPt9s^4Bydn70%A96PDv4skBB$`zdX1M zWbJ}U!@=LL5Jfn)XL%{zC7o2=h|QjBq+3oAKxPgsLJwmiF*(FRf3EFW*B_GWr9OIY z2uuu|j{soRAS1lxWoT#^ZObUUO?~tFcXZuSq#2HX;06KF#_48LvS*Q>zyDSmdOxl> zb*GXlLrmB4@I)g&+#*s%T#!H-2_{|Ny;Y8TEPzo4M}S8TWhY%=&8;QhOh zr-J*0B!ckpujfL@9s|`CR8}BCe~E53yf?$W@4DMt@5hVcY8mfGv>L`Inn(yWYs}1% z9S59%`Wi#-E|Y#b%EFqcQs|FpWgx=HI>4iWvg*7E>nfKtCVSJ|ci#eB_7 z>xDe)DPmV|;p6;xu=^kr1O~()6~n#VW^vHhl9=@E+X19K9&j@;Ly%vm>{uyc(|PRb zlN3?o_CodfX8S=MX|So3Pw#xWsI(UIN+7-8Rw;smFA054!UIt?Fj&E{8t=2JrEe*i zqGLlHQyVI`ql1DJek;F8HqOcwYu5@S*YalVJ%(Q30r7_@#_>hs2U>R$CBLgHr8xr- zBi1ZV(?)Udj*>}<4na5M9=DNTMnYGFBoK5KBs}54!HwwQai>mW>})(_RT>(tE7q*x z$E$%h{ZEx%1+@>lQG`>yMLT-ZNP<`*Rmt{;z+Le|#SOXvRizpG^aY*+mF zXY%`uf!bexvFbNu99U#C553jfw!Nlo;*t34pa1%U5c~h;Z~1?KOWj`=W9ARcL3?qa zgeWTio84f*CB=W(4Pwxp^15{lP%lU)ZG4^ay@%K{s0`5-Fj&QQX%^eEpHh;Uw-~zb z_$}|$Dr_Z4m^N;v^zXrjT(@o=UZcCyNd07ZNI1pq-Tnoxz8FCdE{Dql7+I-tNZIGX z)dl{9KRtx5*h_}w7O*Z|vgKpVk=ZV=GJf_P20Cn&Arx_R*#3YI-hmRL)Ofp^I2aHJ zvis{-6(rI)P=~$*S%6}mqj%jh)UIid=A#yNnvzH-v>wj9H(0w+cxIM)6MKv{Lc5`t(WAlSf(sS>Z7r zr~cd1WBKmrmPmYM74;4#sO@h1w|BVq>)*zQw_(R(W9>AOwfuR@$+tVMT>;^$(XnrD zj>0tSL0yVrcZmd@FUZWEb(}fU5TADH)%%8^fVBIndzMo^M&dYhgxCRVjd69Q7@YO01oOt=v2}aGO?+k|XMi<$-6@GLIFq4O z&HMc6?`GTgHxS!OrL;uKDJoWisO*#v12AZ)wP3jLmERFAfe^0>V6+t@7e@CF7x(?~ zdpwNw@`j(46#8x7EF>i3Ls+)S&Wu9c2I>Ci$%Oeu3Lv=vK}^DpLl%piEIL5fK?BKQ ze^xJN18X>$UI`$v6TZ#mFxVo_4H)+|s+lvHX_h3Zyh-tU^QMZKSqLzE zQWqp@4tt?4a`a3@n+F~`ahMLW6(t#RT|(>wLj}3C9%}tB^Zxm5uPywQa=rq+`muG< zQBj3m)^WMHxw4Ipy&0oLljlDqOw^?3#zOS=QvJ*MDqn4^5)Sp+7#@(0>B3Xp@A3JiC(1eS?RwRv zEKmFMDZH=9=n$*|^WgwUOKY;P{Cy*4{`6evga5K~oJd}DR2zBW{B;i7{)-uY?RUdJyB<)^*>_@nGwyWOPxw5U9U2ucsfHF8kU z!MI=&m`59b5cEy{+wDV z)IKp_#X|YnXGD+>bU8@(2_H2#)g{EScRzB*ET7@i+84;$T8-o7Jg{sjoahoUFg3*2U$f1YxrKKWaz7BAXnNN3;?FhE= zk4&Pvg2LJZhl9;%H3AH;txW<{0Y2v+HHli$Xe$vSB<8MHW=+$LG0+?c`4@x# zSOG%6QiQ0I!&Q|RGJ?ffQ&vp9V?nAK8i9mcEShT>h2Mui=qnmACr0PzD29Y^BT-ib zV#-H@D9%&dI%a?KWYci2I9Oy%-PRZL=@ICcI%<#dz@DOc0L`#?U{t07?kq2sB$jxD-H^)izO$D;QT2&ccU;)D(hqi%D7@_*>L$|%|z#?rA0*&_a{Mo6xXq-_Cw9)M@4*u z*}8x)Y0LHy`>LmALAy=IWFRBSwcWBMjB(`T<5lp>M0iiSg1a%~USwTaE5*W^t{zShNq!Oce8 z1|U~IcIePG)Zhk>op!UKGgcAhp{lGLk7+{t+&R>@N`Bl(`(~f*@bz)N_ubU8ii$#y zf4evAR-lVr5Z6Jg%|E|&!+HwEY2IyAL%kBs<4+IWJU{70AA3b=zuJgU0Dv%T-wqBL z`aw?8cD57A&v;g^u50Cj5b2i%t8|l{Wo6x^CN^vFIN#Yu`(??J3JjC5u2xk)hgq+= z4u+u_GPq`!0cMCe3>~IH5m=6;r=p?p#)DMi;o&zmOc`cQ++~e|oIc33qj+AV75|rmL;9Jg!V5z$xh& zw+?g`i#97AIMBLqbR(~R0-wA%7}Wr}V2-DwdlVk2r%6DD!A*@M!PUt=t**PI&>Bjtow!0N!~%c@kDTP#v@}(?r5u5uAkw{5|80{=Fi~tbne333 zPEgllif-rqaRu}5L&=mk*~sIZ55N>l1pqQhxBNmw9|HccVKGO$pcuQ45z5K0pGC_D z#d!#3%77tL3pM~I6QXL@N2v=X^&iW6xfjKZykRJenoJ&q!yb6Q5%7@lKKQ#L`iu`q zZUAaEuxakvT}#%A#Q;%)uD=Wr*j51n_>5>J+rW*9EE^h7R3(Ly-dU^N!Agam3*$Mk z7Zaa7JAtdeGZ=d~%L4KWvL0h+N7( zzwvM~0Khm=?(NbdQBqv&o8LMRG$o~yGgMJTj}P2hn*!+!pIciUrK-hp#&h{*DjO(JlMUFpze5|NRNzE;a8h_QhT&wQ>eY>ym>jv z_bTD2MY2vn8EaSWs7vFQg|^bQzCpstVAibN=-7?RPg|IpR$x?cGH4~O{0*>BWPS_a zfONX4@19=pR2cHw2J2SPstio_zE<_q1!bE{icvcqOZng}K7Kk1m z)u!*4r7z?bQdaFI$J|?JNweV=V6#m(`|#@3`oQ4gv4U)@tz)vMZWR`BbfH^Tfrtz- z)#TW#XU9dG>{D{5hl_R@6#j;J)Wont!p0tNMTQZUq(iJq>PXIP z=K}Hq)YpbocvLZJN%ExU2ojf^phg^Q6>vtX!9uI-{x1fG77(W-1FXuaos=4Hi$Eez z?!P8F(Up5Tg5h;qatvEsTw=zJ5soLZpbdN@xaG+YpfUd&(WtIZlKX$68Ko<0{C`g~ zn&oj3e(Fe5z(B%%tp+U*WCHBJJE5U**cNF1i&WhoXwB!x1pvQ*nD)hpCBOkQHY%!` zGw3@P@EfmGKxxn}lZR;9fX)06CMly6C7|3Lk(a*>Q&li-VBZY;AnO*Hq-G|CqGv{> zoIH$)O%)ghY`4D_MnYwTw}OqASvv@G9@*q}_)*nn+VptaGhtox^-4XD2@@Y}@8nmj z{1up!=0Nn6!~x$v<43p=yN)g=S?C}n?MC;bh@nsm7j4I?H9OCy!W8Qe8W@v>IDybE z+GY89?lx_Ee{$l+J$lsP^$zsA%)VSleDN>pq3G3usKI4pr~gchuB4<;0%20h|~MSdqR z@Z!hOv=i(hmWR||o)--&=0hU_?Le$YB^Q?$;a)i?crfgm7%cs^di4f~cRqg9ra>{2 z4N3=$2R<@J7N^EcKHo!;{~4 zS>xTI$UfeeopQG9^h%f>;M|UQ_wL>HJM;OeR1I`i#O?dTp_P5r6Em> zR7>pEtg{;bwgQDqt?uMDs8Pp>6%p*1L%A7{a}qWHct5+qLqgvKoFQ(6Skj^@*eFN* zk5=&e_gq`!k^oMF?&M<-Z3zhrH33iy2N1tD!_L|;EJp^$Rpcy%|E|kRkE7%^>Y;y5 zDm#R0sF*SudoeW%TVkWlHa4VEo8ZLUJLv^aaj3xwpK~iTYe=l&fC(eyJ5Z^E0Z2mm z$Ow#Cuv}0Y7fQn;1joJcaJQYJ{S=zO#O4sepFj!dccbfF;H!ud=sTxs4p$%2KbjH< zBgxq@G5ia8#l%iP8;r7aRHqVsWWu&V^7~(@QV3kDQtb@>?~$)M9OqKTx*z>CbL3<{ zx}fooADdLT;Jo!7tkoWrhxIt4Aze>;ya21?-h&l4|iI~~OokJ96a9V=ZRWv#AL+qNsn9@Weu4hg2vnQpw zH*tHD^QIq8chFsM3>K;(9VNyFEBIZahI^W!E7Wzm|MJzViv_sHLZ;S=pZj#pq`woh za;j3s)RI`H2GgyIls`ai!5KPC_;MN=Q7~R*H08*y+3mDG)@1&Zwzl8$@>p3cn{}fC z65OB)!7vS+xIbxGAozeiGegT7o^-K1DiCnY(v&A$q&!wN9y|IMCL;Wm$6e%(GpAo?*M*lahaK# z066c%e}HPkc*%zQ_d~`&c5REC(s9cZ7%+$8dYE5PUY=+csWgmzQ%4;(Y^0^66bD7I zGBCTEuIN(2Gh|3~T-bwvwUL&VX0x|m4U+>Vdh+Nh%dH_?Mwyb!|4L}6kDhm*K0SC< zpW6_olM2$#Nz|@4oO&P#8+(i6_(wXaTVqq}tYsLwM-Ouz38USi$^=fLJ4+>NBlC^_we2{KCTMFGn!} zmNDGdi_ruiHWrbH#?DlFs|(T`_)sw1I$rpGZFEgdjba}EZuwza-6_W({#l?@DI;9|`LOK7-$v;IT->?4ZRXY4OE|$Vsn0HXM z%NV`^k)x!T_)yGR#__qFy`3H?3z?EDCndQ`v@yz$s~fDa=k;Y1jajXZ7Vq z=W{!Le)hKO-+5te{LR{L-rTu3ULNOP42U;L-{GC#8s89f z>2O)6qFyN>fQ1G&a=&x`1;@zGy(1^uX?=Yv4W5oJ?Tx-iu`7n&@ASq*LWxTv9X7D<`1yu4YSbC5`v2v8Fm6wp|!1f1qkt&p+E z%tujL*JIAshyabBi-KE&?xy;~-8MEAr9HZ#7SDxuZY1rYUTC|d!WVzasM1m z2|z?&-$&4{XJx3%$(e+8pfuZPBfnXCC9qR4IWD{O45bOvA;Tf;-PJoE%K2QlU>l#2 zkx`nPH}EznUosb|KQ7BV5qZ4ms8}p9+4(y2s{t1!DTWe0gQhcxL8=OG9n7O(QQRaR+?ASkOb@f?~H& zL9&q}%wl-Kf)Leb7yU?Ie@Vsw-9`QKwC(18haA}{m$D!*iJM0gH_8cir<=p$0a_Ep zoXNt=Zf+ZGHVTbK=e2b#2km+n=2-)u7~6PFPUrf3NEvhcPElNwrT!`$P=asY2eo`( z2MjjHL$DQ1{3b!VY;@>h6D7DEL75oO4RXI-Hp%%B%o`*r^s%B=T zjTB^(yxvm;#DTxEHR#z&K;jg^E0g%*qM~ZUINEYy4{An<@lS(UtDSUz|J^>1fuXij zy`+`KE(+g&X=y#MxL~M8tZ2rf##gZvlKS` zoO`*w7h;E@O}h_ft(*fnek^4Bwrze?5X_-HDr_AHE@L7YCrubaNAnS}Xwrr^4F^&F zppnoukRR4v{^bp)dN&!KfCCL70X!=)@*L})#Prb&6B)fDM>5|6H%_kaWl6k+Frr0<-zjhmupB%|_) zx=b%@p~(aZ6rF@(3(RKwtZ)E=o?LY^r%cKxiN&e6Yn+Hx%pj_$@nu%oj$^Z zBX(%pH+(|Jj-O)Q_F2RyO>g4K5f!Rz>Y0qoC+1|bK z*G>(IadP)ofMD)mmJam{$fCE0>aL7$7k7GQ;zI{k?1HI?vAFJV$U{~m4}e(g;ehQX zvAJ{S8bN{VTq7~~ejGxPuq1oUGLsN&`hrgjx`wsSoM|J&@>=5s`dHq1rSHV*2G6*& zuU{|x`^d3n%Z{teHH+8FRlA`!nUc0*e#woM32rqtnh7q65vN1`_|0;|eoEbex;0PM zp9x_XE}@m|$&=o%r2p$7p98;sbCBYeqK-Q2j5;@l^<@5f;h9uzBC4Ll(1AZ$WrR!L znTl0&Crs}c%Wfo7r^mwsZI`+Q#}-xR9NYk9KEe!ge6x|fn>Xv5X()}_`}*|go<2VH zqA{yI-%d35-17+zuKJpRwhc|`PLrtLGmYsf+YX2*Jm zzsI1NUnO4`70JPvN*XS>5>#4XpoZp?HjhK?7p%NZ#=lw9Dljx5PhPM|DDWtDWfqX% zoj`Kc+^p2KEi(XC@IdCAkJeOGOp>>^_vzE;>?%qN3-_31aqvhzKq?~VLu`(WE6vSR z9>&Gle!3o}*ZO9>u5Qo7NW(68I9UWIz|Q250eaE^9iT~anAqC>h1=rEHgxqS!dMv@ z$1B_l&Qzotrx%_PhE}ErmF8)}1PoV}aC&AN&BAFg@w)MqySMcpPpcWheGEpm@n_@5 zC(fiD3Y}WFaWb_%CB+JC`ZGeSx|h#Kf?a|fLBP2ITb@R70m0N5b27rI0VU$kTScXcSaeBtfcIXPTkXB+Ph zTCr+XOjXqxK(I=1w(|kQ>R-hnT3IPB%1zFr&Yr7w9R2j^)Wl#|SnYfsr$|ITC^L>; zzdisd39Y+PLf&VnT3t^xChOEIKKU@0ps6VVhwj*XGL{2*jNClfEHFA1rkq zEdHgvZ7qE8MLpNpU7Z+V@X|E1$96&ywv&{{WwCI2F>ZP8(bm_uU0PZ?Lp$kg^BtQc z)MAHyE?>TU=S~%wFC@$*FK+qycXv;cXR@=A!5B|c6vGxU&Wl;22?6W*&0AuFY#H@B z^xnz7bU=wmrl(ypKi_x^W5oc#IBo6iQLxb+?roGq^nq~S?91pqx9*y4Fxbt712Q9I@{5Y&|W|5{I@oDVqO9sX^++}qMiOS7G zBW`T2Ntb^*sKZwvx7meNA1#n#(_=?w_Nl6zF?o8kSSvu)L^|C(lER=+>AHfY1mX7ql*KX%o&4vZtP|l0~c2L$PpiSaoE7=rKkTB zFFZ~g_gFC}JQ0Ic(#@|=6kAM(QDbpS>>7uIeCdKPRg^}K(u<71+Sg*)yMjG&;B*|{ ztu^Q|nm5sHqGNxG2hMs*ByF~y#tp7@=Mg-)9_ux{5*jo3+&+XSFgC&+UteAf&Dc=y z9}*IQBmrDsqYsbn`$T^G_RBWiDP!E9bn~?9^~eiB+?R|HM_d4ycO2Oi!J$&>6sB{} zR;D*6mBWk|laocTrWSW2bv9|tTzpUHl#_35aZyq23%B`x7(wMqp=13gycmZQe4*)X z(Ll=i{+12o@W7lWW8=Mk{xvD(eQw0Q(RCIx@OMht!Jqj=sT%-TK6$bnHAe*oUXuzR z1uN@j_gSpCFYjfcJ6XQ#%)9kS$qLR06C)F1j^VR0jGvb`r65x)-6gu2+3TX?JgnN? zknW8N8&WC^o=O6q63&`3e2isP+N}Z1=}QUIBh=Z}%gM=U==q${b6?))qek2Uax6M| zJ%-X*H0I=}GB)5^uX9kO0I#;?EIZ)7q-T1Pr>3o-)}$=lW5o&szXnFlKKI;2IP(cN`)YOXTRLABs}}IiZTLi#8=+-!+IhB2qsX{Pd8?@376%fE9qw+JBOw@GR@u zKc`uL{#e<b@0;x;>I?g(sBpY&B7noDs{t;8|KP)x0nx# zJAN^-V=gZKg6kIf7Etk@g~j%HY!h<7_!0NUxX4H-r#HsMS_+fo`OgQ(Uv%QJSt)f1 zF)<6SUSlgdDTKMYn8|qpXe?wDSeE_(Z>VHl6`#H6=vagg-Q28)>_LZ5&BbNq__zi* za~pyZe;*&envEH4Wisj$84G6K!*x*4VB-#%$-mx6Y>Tk4wwlSan}^UUE`-I1imGaL z%xt-=A6x*_i_w)hKL{!Yc#Gx(xgp$=5LvU1e#8&Ge05+27gs`d_H0yuJMRAYCKL+C zUqL`8G(A1w*I!S!cNiXrlNAJSDmpri4@^*EVn~(}PH1AaKRDPUY$?L!dBcln#f}9A z%4)4W@b}Bf{}q$04e%Xp`a-FCdOV1@TQ_ZrmS349v33dO`1Fhov_g`tBlvKy1GS*E z^d;r*I8eXzN2u+5GR52maP1ZqKN1f)Q*j?8ln)XT1TachaD|p{LFAn~KupGVl>PMq zTz8*Fq!qu>-!H@*iWZHvXkLU#RS6iHQ5-ZHhjdT=e2G4C?>o0{g=4ZKekBO~Xo6TcG+zcIGIbp&Nca1L~Q zK=N!|XArOzvUg14z#3FmDA@s=KwZw?De2p{8-l9?ZrwV$ckumMsJyCp(5wWCWFFx0 zW@_BxU2Uy8CIQ9)9B|Q64gY zv-kyx0_PR3Tw{aVf($@5UW_J$w&CULM7#W*ay1r9&g!0hm4xC zIgyuR zWH(_@F49|X$#0Wv11>1u(2o4J+p*~>*C@H*CEHJ(+Tarj#M;(E4vkh4n9uMa{?F93 z-*1WQO2lHZ`CjXa2&;|kO1q{VB9r$Vqbuv$PPY+vXf%*Gwac{N#vx`f`+3Z9UMh{K zsnJ4ov*PnT4vMQQ8+)f7{rx%5JJnpVKz=&==qz`&B<;pF8(&{vSWS;^#^mkkyUEFD zjD+_#Dx;{WH7W@<#IV0v-uacy&5BlEBvJXsoGlWm)}s;-nmwhM6^A8#1odIX0gk;7an;khQqo5< zG%LN~q@Br{Zr)|DOG9(15_O%3b?4G;I+;h&z0-8R*i_>+GpVD46NQL|KrT5;fn1J` zfJ{KTR(SJuTNNgkaK1ZvYyV||8w-X5UX(pMdMR=LQ=eZl8kI`h{z%Epee;=rrjA*{ zMh5PEf1LM68eDP-aevFUL__B10WglVFtowY#&c*$HM8Y%Q+Ihp7Nn8D$I4=E!dTs# zyHU~KB0K!z%PRxjbt&#rV<#`=vRs0Ii&UleUBxu6f^P!@5EeGZf!7g(p|tyQaP$<1 z?v<00lG@5IaUT}s-XH@Jp`dO~1?IpHlP`^SS={QKXVLTRyBUhP2zA22+6Vhb^H{1d zE14M0Yp&fCHq~)w*gVttMncWu#1oH|hy^il4Y#W!#c8!Cg<=R8^XXa-F+YO30Dj|v zhhDXSXbQWPQM4 zJ2CJ5tVu_S&T#$`Zpp~^?~j5!auo8xa{wkZpPF8Db3pJB;NjsxOt`nJhoi7yk0!nM z-EDUGzi5<7?$r7|hpm7x87(2V&uSdDI1n?Lhw8YfUEE-A{4OO$X=dg4ul<6gB`D@_m z>4Q~VonpuVr=pFTc`o|StW0edqqTB4anr=(s8-^F`FuRTwDe!GwjE5b2QZm>wUIKH zZ7e1=!S)ippnz4oan_Xm06jcUana;U^{ZEJVua@Si%*YG2mvLj{<_BXd+}JJK2u23 zuq(ffjBHr{e9uYhT-OdT9$@jicAIAE2`nCzOC%CtWQGE~;p3+J-8YeO2jdeHyB$4& z1mVIS^uheAe!ilc&^!B(IIgO?tLeH$<-=`@SMIB=d(xgY@unJj|HUOZ^^8FI@QIwa zXyxt`S9GGo!;gVPa81{FIBcT-)jV$R4&1eSI#YB$MsZ0=c|Ol}AFAhStJnlJ6W>}S z3-Zj*EOF46f<$Xa+~6$&eS2d}6He$J)>=-^2ENjd^&RKTq`$PSg(r*D1Bt%utQYtR zWF^f2ScCRjX^rU1z1@pT=sM`@?VS$u*iJEtQoG2fRo8zRRd)@uW7cjoP%Y$_EH@g+ z3wtA1etXuo%=}oXIkPC?Dd)2Y)k7IsQLw@$kMBl#G64XJ+O2C~V6D{NZg3$>XYRay zp(gMkc|m7)m}JmR${#3VdQHSGr!gTU)ms6mH03xFM3(IDFQs&KezgSCZ(RK9NfrH{ z4iM{6fS1U-Yr;Idy_JFS`9vbd$=68R_n%B*6ammfr2-&pmsn_UFcqmSoHMuSg*KTo zZF+VGr<~|*NYAUYGOTa1$kn(X#&U`~%IE9jn+4D-`FP;__X&JG{{H?n9|SY7%qu&c zPMtc=3~M;YnU8g;HQdS(#&E|^0Bqj~Gl5Ht>FmUH-w#5?rY7Ctya>C<(naE2c;62( z>(>?Wt7=>{yS%?Kh|)c#k-dU*1=a1o!KhG>Jo{maOtd=8d;{WbD|tNL=pn2Mrw+OE z;_8zkxEz=1rS zOl;9(O{fcVd6ER%v)jDxTS#G{0ud+i$}XwBJa17?X?4zu=h#dzBD$BIUaa=fG^@L5 z)ydtWQ%{ej2RZKBcj>FGqx&DHlr2QX8b&Y{7Vs$!;+nH|3DVWhk@cbyBBPx5p4MP3 z6}hBp@`9pq52P@lc97~{0XB!3MdI%VpW1#TIl7oMx+}`lQnlRTN?I-gZ@H+<^$Wul zOgLGrN88c0Nm#qY5zF@0EuoduGdaDhASpQW^VOT0q`*hSpzb@bP6ec=bG(=(d1ZyS zj07n_943xLMJGcxlQ4rGZ?vfd+@1s~R_BMuAKBVbGs89rV(xt7ws)tbk5E=^ppm40 zw~pk}Wy>~THt-SggGWmr=Ijn)w9OuQH#nV9|9}VmJnKnDWmR>Ni`$-_yLlc19Zh$>Zn}Sw4+&5wkkd>!6_jE zAleZ#f6DpX5we4uNVb#2Ir%l`8LqSiaH+95NQSk3?YHC9EvrfFpuwEDK z@(GTA=#Fu=ljPXq>4xjTpSaaq$ow=pr@KTVrl|Nl>T%{~T31(mLpIZ9;XIrSq&HOTzXpC&4;6AWavY-4OtMQ;bM)V8Z%wJgyu!vWwB_pt zaFBb?bhI#Bad*a8o^8UWN^f$3#YM7mc4vHOXvlh%8q3?u<&+&h@R@b@oyA455`nJ+S0M8d$fO6ntsj-tRVcxBI~HTLk?I7K%gbPb zkqi_TOt7Y}C0`SVM;cf);rlq@-E$OK%bk@1W52_V%nzM;WQ+HN+u5$VyAy8qqLl)s zqjyDXbrG|_XR^d{0h#%czU)Es=+$zG&Pg>xtq7MSogeP0RR?o7UWzrf2=&x&D-5c` z_sxMFh4PtniMEbf`(^TH&-zE!r!UZU=rSUS50*)^&LjGd&8UolYq2AXoz@+ck&$ut z@YPCNvtsW2iFaI0&z#F|Ujj6;b?+&Q0e+{VLIt6}v&BDaD9lXPKX~X+=eMHm$~c2u z27_3&rgccsyCFxBV(hA{RF5?*<>nF!hej(D+?|+w9=g)bvmY_>%}74T)+9n0{fv8i zCj*x}UNngtjU9>d=O8k|kh5#kX6hI{=ixNA#hE8Kb*l6T`x9hdu0}g#Dj=h>jIE2| zinEoMSGh5hY4?>A!@j_1t=u?CgdsAM;Oe8@<%1$cPfrhhiax<1_>i5o%Ad4PGQ9BG zxajwTb2o2&U{J6K9%vWD;#U8?7GxIT&%tw$jSPOtc>t#3A<;$=4K%mlS*A|U1))~f z>kJ&$6frh#WG940yG({X^rp1=d}+vedTK3(I(M!Ww>|;w!XrM#TwOOdorIXp@c>Ev zf*iF`#MOXE83puj$@0O6^*v}{P1%PM0;Hmph5%Z5U2m089z-!aZL@~o?=0=P!7o?~ zI1g?J? zr&q3Au`ZC>ERecm>Gv!X7tM90@KBH4;~=5%oICzCz4hyUs~VnuA%PPc&Mb(5=yInX ztQ|w&8+ZIND&9m+y(x(~zjWLzH@Z`BM#*NE#BOpxb!ubvJB%Df&mh2S?H<@;mJ2fa zM@H1punh2^W5~@&?_O&9OG9@w_dlg^`Do|Vht&_Dk26>pd6%(isp z*(~rrzvy@N8A3do38vdGchdFNd7 zR)6|8yPgrPM}}#dS!br;j+piO#{r3_JXb~nBOV){oO=Y>H8>d%OU{Q)HXbeP@T0-n z(MIfruuiIDlw-*f|FAH<01rnfs^EsS+Lb(S<{`rm=)COW>$e!Sbs?V4%EfTIcq$Fk z+EA(di#R`GDP8^gRlmEO7o&t!u|NRYb+qNK^oWw{oz_Fufq!I|oOvSoCESmEu-lV; ztPtcfJ$X&J&e6Hk6Kl}nz~i|F2&m<^dFxPQBIyW5Rnc}{OwvKo!omVsdm(HgVozjg z3mTkhi+T9)+NHl4kEy>dL^AiOuP@pa!n>*}LVu4}r^kCs>%Nu_oq6%H{n!e)v|2RU z0CD;R=$YR%_vGUfSb6-u1yxa}wbRGomV0B?PcMu3@2c=1J9|H-Tr|!lx1Zv=d)j%j z|C4}C&q~Nb=3>`C`|?b_ZyDN@@zwS1w$sUIU>`c z-B?(}4;tX&IWx%n`KH4P3ToIx5KC{*YE+OR?~^L=<5Wdb5Np}};c+Vx9(7E@1Dlnk z)A+cT2YF$h1^SS0vD&|)D`_)77;J|eY~gTUb6-LaFuop)VB6@*Xkm^v-%d_W)^#ur z^%vBsi8I0a=-f`fsOz&2g6#;hb!YXuGRb$e-bE#!fIQ^SL!i2Ov(mnOw*iE=b#(C4 z>C)q4_C*a1a)@szGuhleWqY}y?}B2Sq{PP)k^>l-yba^2#sK);D8mLY1UG7-r?M(WB7rm zS2N_^043Ig%MPDX!!;qWYh*NyAf4-}H`#>J-&ug&{QjKzOE4a*BMvkX=i%xKh3b)! zUc8YdBwnr^e@FJ2Pj>}S+3t(ksj0j7ef$&yp4|L}RToWR=m^Ae+ohSOocfPGHU4@X zkHz=T`{%FyLUcMErg*;*xD{XkN~HVm-wTjgbbzd{VkT0GjXa<4+nX6jk%q+~rAA+k zB=clkA4+D@n{ck%V-;F)m2)JPCB7{&8dELT(?~M_etVyGn!|Lrrai#BytACw4}PT} z3xF9&zVgJkqNw`J;jBY8O?1{e6#3ogY*zzb-sLjo$0ac$3_=E`xg8=jjOZ}Ia!jYV zmu+a$!@3K|k~NtZuyHl!@gpVOOp{T{ps(D8Vv$clnIzPn+tLT)hCy6ef= zhKpci*o?OaKni~Zu6hU$2Y_&XGHzbFZ1w8<1Tn!8p9kV7mR>SQA)Ps+QYsKBuN0h; zITS&I;;ynj)p*c2Y}9nJxwcjo$z08?4Q}wZ+BhSbY1K?O&ykuQTMk4yg{x!RYC4~9 z?3)3T;%xDdlt8=0b%vp#9osyW8^!3LaHbhou9OeF;D$LSBp2I?qyg#FiFozoSRT1r zZL2iFoFU?ITW~hT7@oJ_x;G(dUnWhK+TU%j?>CT}@T4F&(nT6m!!w9Z4JJ$j6OM*u z#D1%e>4Tt?dUj8Yj}tm>cw1W}TmEv`N}{c`Ltn5`S+Terq?7v8V&I7mo%iQgfd|Hx zk6C~s01y`QNFCL4$xs>m!i*@GzzM@4DRcm(vB~*tI?JWIIWG*iIsxElR^8S7#6-PK zV7dT)R11^hG#cu>9j$$LF9uQ4;L+RA!)XxaRd9yzh2Xo*bqvUJS|R+<%fc@~0ovW5+fKG-xIU%aX;uV5@^>@yiF`JlL?x+|EGZNd;6Y?HL`5Ci7db$t`J z$t~++5-z>I0RaJEyd-Q2bIN`(>Vd58&uR;*u0Tvq+bm65CiM$`^cw%X=s468vF3fS zv>)qd08R2HGmis{bu;^4F0vjhmR3bJdA8W$=;+6t2T=7a?gk{JgC3<4Oe>q52KBIB z+)#NF;ZTD`*u&n&te#KqJY_>&b|i-;(gkE64;Ay|mv7RIK$pq{w4#!@;xv!GK4q8+ zgHWD!rl12UL)7KV`=MIvndnKbhTEiw%ajv#|Cgc6!*5HObB4VDI>age1bb z7GrPJz#6I?uGQm57uc@pVtT>u)Th%Ni6?F+NjVE1!{|qi#M=nl7Akz`&!FTv?Bl;( zQM&a640Nhd!Nh=h5keQxE$6t(%8hHHI4lN9dS!6MFG1p*ayHAbB#@y-y@QO&Mmw5}RYg(7*^i zW_RtAx*H8c(=5;CxuE6+|H}mu(n>x*zYwF!i#Fnh5`CHyC6c>J8@4L6=Ig~`{h*!8 zL55`_`6DPi5oZ$uX?J5*IubdU3I5CMyZtGb@EPQ}p;S->nceDnSgEC-=i?leS+nEc z=`*EwcQZPKgNjKT$Yru&HK5=OVPRon{7qoY(Pn979Hj)kzq3VDB*sKIP{h7}{S1jX zs#Kb#1TlfCsx4{Jpn(EC`$H_=ZaYg*opAi3s$86#G}(6)Fpg=egL4>DM~xuc z0YjKb(q>%J5kGw*Vd|YwU=kTMTt(s|?7@S{G|Geo(?m^j4lwt1b)`vsMoTjdyu^XS zOrD7mZ%yN23g!EZfQB^WVg6?@!khP=fO0xkgE?tHmOP_FQ8OF3EDsqHL7bGxjINae zCt^B6gZOD=guuJouhvuti4U&?ZGj9L!}3fuDnCtn31~FISD#g*thhH3y)fFf6fO(H zdKM&>D&u2gm}g5+i0YSDJqR}x!y434F;=|~^d>+fiW^|+6<3laYkHC8V#7u9v^_gni{t~Rr;pU;7G^dY9c!g6~g{UW?nJqynmc65Tb z=t~8gKZdOXM?`yTD=$sH_qi^7=8Y?R%fR^81uxY!#n#ZU!w4-%QbsAot0kISH!*BY ziu@COtS{Vl(8pzhJw)Tgyh0mo!GP)UQc=4TY)K!s;2D{zjxi~u7+u9B*xgGqh#OP(cy0#eg``D-1>m>XeVy0^nn|F<$ zz4~-1l-hFJ*KMO=nAE(&k`iMTK7M|WCsu9fJr53{^^GSvfhal_mp_{v#&d^6?R%iQ5XO zLmN}<-;g;hK~uuM2D`D_8$OQMjKBMcnAIm@>#0X%O6#s~_Qxg(k~9|%{B4a^)@E30 zJSq@I6I>Yq)3<{Rp0Lzs?C*jxtalabF#^~|T5N1ASfA$S1)-w@JA>Ltzxv-%Ne?J+}c9bv#y54c(7dv|OB3m-^^b# zvu3TiD}0{{m;1i&)6Us@pM6qBy=!>)MmGu{K76=|H4{Qk#F<-K-fVrqKCmNl8H%bfbL5E{vP|mbUskjB;0w zQP-i7*M}vT%*pOP^9>UsL-~9uShmJD^H3td5qC!2AsEqMH-SyBUVSh<))Oi2Xom#Z z2@$^Uv84Q!QJ=rqnAzsbhyFRLCto&pi1p{lhJ}EZ5Oz zMIF!X{9@EAbX`g7wgXb2mgnG#M)NzQ2+Y^@PW^bT{$n!La(eLEoBM3>V2S2}JlVWD} z7jc+;E6mI!EL^~bcJ=o`qm<-XJy*=`hdXd+j#C(F6<|aiu&=YPFaGV@n_gBHrS-N| z)guY1t#R=kQ<-;3XV}thyLOPF`T8=j$CghdbG5zUa1a+%=YfC#s$)QXcS@lfkFuYr z+}(q@QJ$cg%{FIq)It5!84o`;kcZ)gZ|J1_!=lJ&)fU0u0gX^XR-*FY4bvKLrR?o> z>&5~V(`TliUrQZBZ-JdsG1|tCJZ){2JP{M)@c>&-&?$Ua}vYNs{!6 zNiQJiKd9=sF5$$Es;(64reK7d|MeV$=n1k9A!?ZRY>OZ=071@+eEwI;#Au*o`B16K zANeAaD{*Ti%3vb(%A6Elyf}&&etNocz&q66zwwg>fCaX~X5`BC!J*pQQR``Fw|tsK zEX$}eYHeiB4P?xwxmJcxB;O$0MW5-F5R`)1c0}%h0Sg)(^`VBPq=caIQ3XLYQYOG) zR;BrG5b9ZhX^<)}5u&FQ=21|v3j04b2T#Q@XJzFy<#;umD21}7N|5_M;RDM`{^HH% zI6}$7E!FqV_le=478prjCx=Nx#o`M4k3;r2VIgs>5qUuK{P>@{WpdQWzV6}i9?&nG z1--f}I)6ZmS8a#dhy7S{YWLYz2Rc?< z<3Km-xsgyaluxv@pe899`KtxWFt`K+&Jvs*t;;WAC&_s;aY&O+gWnB;3-SO)%INYn znnLo8*^x0PJ^NuMW`y32&gcdC0Fe1;qH~Ga$V_@CcIE1K*}fk9vZa=?`D7RFD>(D> z*A+qj|1j~?e6gIhdg+>Xa==>pGcMYBwWABhlv>{5+!xQFvO>qkvab6lS>QLF!(ywW z_r#8n#$DmIuwyuXy_Lw%?(bqILLO8nut<@!0U5|hiphM7d*VTzx91tRUcH}?YyB8s z7p{*83k$=D+TS$0uUap02$qT14^~=Xc?ewja_>YZ6YsndiMR^7LyLynyGYVsCP()Rggsbm+8nJ`k#OP0Mm?CyHD4caq5d_ zp3=O7M7C4=UWuO3fALh@zQQq!&t?ra-%1bWHQi_`UjwobRzcjz5_576lfq1QCSIVB z%#`Xz7-T~*m>zIwXft6XkPL%c=djt-90_DG4Ey0lkF|C@ay_=4pjit1FXMWod9W+QXj%xPj&c zFo)TtmUHzMQnXJWrX!Q=#x^&a7hG9fuc))k)67TNyF)n2C5So=tmb2c$t2>27opui z?i#C>-&Nfc9e2+;BmbD|x0&dQ2;6P-_TCGK?x^*B%BKD15VRacjE!Q@iH~#jmRi9w z(w&;p1^yhJnH;TnUM}N*e5o0@AoRx(dt{4_8$#c-$nIZ!ewUk~;`aH0z;Pv&6t{1$ zqp}fz`k0<8T~-QB>zx^(?E+x|YpBD}YxTwrRMk!E zcbhreAH8+!mKqK_a3qP_`1-G1L;CVQxbsfY=?e?@w+%YPnp1p0k>#45Y4MtM`;9-!At>ondwTwn_}pmn z?qUrjPt-7wW++R3Z|=d5_ZPtS>!xnI}z+*`-(=Q{?MoFx&9u%~ca`GxWsH^Bm8B`^D2PFMkc7xR0!K2ezeq0k+bgIgZze*T zZx26zvevL)eno{MBnv}A(anPjI$e7aUS)78Ue;{? zC{I^k`yQL^)vIe)4Q`ElGY(}(dF|qbF-cLxxVnbvS~myi@}bbk{^!f(hUZWJ`ELvi z2Y=Z2-~Z#owdenR#|uAlhhd>B%D;cy;Ky_S{s;26BfFmeD=J(3iOow$T>T%f_dh@V zkAJ~mT~0jz+6wUDqvEnM#iK{_P$0H-_3|Z`2v+2A0wjL2h9);0jK993mVN#04_{au z>O~$%Ez#Sx=}sQ+wxrrP{KvWHt)H74QXwt5Z}!VdKYhKY_vev`p~AJ$;9yZ>Bi!^P zmtDX1{NOQ^F;7j|zF8@fl$_kw)kQh~^#d7PIM2ItFaGV|De^O3bVtXzwvLYcHu{No z5TaZ#_ex9*MWF!<_>hMGOwhH(m)uWZpZbyON^H;!uzhRk0_gZw)u%5H~8M^P3M z0=Wu$CtdyfyBRH;RxM+`vl}HOs2uA4`TI8+T3DqH7W~~@mBA|i)V~6Ug%32C{NFNV zUA_*>!iOyW&;P#F^>8g|q=$k{D5id1#t;Gp&i5~kM;bpbk(&X(5a%>EO_(VJ7AIr8 z(OK?yXZp+tsiGLK9~i}#NW9iaM~QD>U?9R~r<M7=@M_O%#+k zY9Qv-S;D}hJ|}Eo*t^kr zCk9ckJPO;>n|-pg)iZUs+&NJaH1!wGUj!%$9Ag&BP7Dk&u@4`*Z2$YNUDiE=%;rZy zvw3*OILmHl7+km~L-`{|T#%}GguRp+=GQx{c=*!L+xt)Ia%VVz-&+z#SnYX>NbCNf zeef=W$ozE7)7fiFXNn67PEtqTFuA*X+S}O?K`ss&ZmZ8`l+_VZsu_I6dzM;QO$hwys?Q+g~?G_iYACGgI7uH(2(E-MxSCEn&MzBY&2;9AXbPcgJfLt47 zAp^Xox*9UiY?E+0Hqyyk2^qC?m}7S|2RfV1v^W>MPO1L$r_j?>;skn<)iG&!%?>6e zMwY{JbJJs_c|4M9_`gL%PfRBD|xAtT6bmii#))J zW6($M5elg)(SBV~aa^eRFz^T~QcD9l-Id`sDY!o$2cj0!(D<8CT|dZ5v{wAk-INP! zfB>+XnaBn*6em=<{oHRVmSlGNCe+k0rH%v~a(16nB^u*nH?|C}HwKLLPzU=<$-BM@`tMT@T?s zAI3nCh8*^@Tc3#Y{ITduL}K^)H5+p9D6?j9pO8Jxk+Qr3ur{HNPIaz49kg=g%G@uV z`y*>&1?#_UW)DrtY;F^=x?SZsLGktUv>AE^Lk5Tpp%&^VUAZ{-y)ro1{oy35LZpoO zn*wAqh##X8G(~%`XeuxmL0S_oE(~IW&y`XQtCC)ugLWYCR<7MxC0e_p6C$g(yxDbZ zR*#|I^*zM0$cBLyRsf@M$$#BVBdP@UAMyjwpS!eN#1p3kP7}vT(uNB@7?j{c=H*>| zK62ntN;_a3l)Q$m3}8|XE+ zfCaqb$7`9uYdlgIsbNdlU~Xem!(aAJPDx4UR%=P1TdeKKWisDj(M)xkx0MaP+j@IC zIS)sW*!ag+>>Jnpe)8m{>CqV-!N63L`qgmcYd)QVrm5#(bVLd$SZv$OgT;f-b-wDWXn*SzpT8P{bd48l{=;y) zwrHwWYU6^p*WzNdLNst>*G876GvLu~BGxDkE?$@-;7kBhC~9b&B&HZ^BphfSCoX2T zuVQt&17Md7c&hz`C!*Hdclx3ZTr~BCJ=R|h}#KZ*h8f8gu z0Ic2A(9o#Na}>qSthRP-$=GD8=NDA{^E}Ib%wH#__l_F@LZwY}d_{=Z5K>gmkn?>W z!)|M6C_0QU-nyo>z_SAPg~CP6ouM>ZC~-;y$byZ=0DL-O?-8C=rI~CYE|mCVg$J`I z2Gh+7Z3rXZr1Al^kp@AIZn;$rnRGNql-MIGdJ7|P(XV3W~R$PtSAQH7yQG5eMc ztTb8JL*87q?09DTK{FQg=hla1++@o|w>7LEZmr`O{qkf@F{+xt(N-7vG@n94H#hv( zYkhKv)@N<+)6KGRBPWyJ%aiY6BBXhN=_L;M-0?bfkZ4M0&KP0+JgvM{fiVFf_)AI1 z+_SBBUuFe~_>hLO2E%PMLnM`(544Do(jHLxGQ|?64Xo`gEsu#<1ZLI{tY{5o?mBsw z(5o;5VS?Hv5)IJ}`y1$oQX7Hc!1lurExZ%dZW+O(wrJZLltY7q@l#IJQry{$?FfyO z9^*EBnqpIaC#F4J;k{8cFSR4sLHr#C;H4Ytip5MuOHR*F6`VQ5Wl)R^Yrnzz2Olb z=&28Td29G$!QJ`xThSP^W3zp|-i5(7&Pg@L60ZTH4)MLl3SPKKc7Wm9mgVb}2L3oars8Vy5(X1HLQt z`MIE`eoA1Pw}@(kYP*X5;lEs6H>O*mvXFf@oe6TTs^zTjs_h5n)UopRnI}Y;$DhJJ z2+A+y?S5aNJuy@xW}w3atV znd)<>&NT*7av+fW23v1mkNwYGB5GYYkcnSmp85B(G-cb>ZzuNm5Hm%b&kcv zTQ4RpWc!R_C2=Dv9ZyNQdYRE?Of~(xh`QNTcbm9F#yd;Nb(z<%UpETh22w1XMacgQ zIlS4x==cTbf$A(mFX6F0^$!2_m-p5+*gp`4V+RI%ZQ?(bj!xA+T(l2Zbk1JQ!sgu4YHD^vzx$fE z&PO2x)u48yuRPjqxK$-WqNf6jQCbW*$Gl%!B%~$2TfE$Dw#K{9lN>IlwZ*UV?CjL1 znvoM1r_36&$Epud!&(bu4SK3syK}TstG+uw#$F-QzN2{R)aS4kxCANKl<`m>JW%>W zwX2I+H>9|vgxldemNBxC53N+zh~;Ow-GY9<3jJ62x%0QG`PL>&R98k% za3U{3y9Onc*^c+#QgN6SC)2#ax<)UDt3Grr{PA>c-?)OOpU|@?o@tWWM#X3|-P}?c zc1t!hbS;loTR?EIre4;^k9W~?FP^Pyq^wiL=(9Pc=j@ih*U2CAUAbSi0A%dtoRI|{ zB)Bj27aKudSqg_hO~l}!Ue-wI3ILUkw{GPrd~TbCh&hH5_<(ODRMbz^bgHv-L;qy| zz(8lpY+fFPZG+4iP?|o5k;tAD>ox1m34?oyaEFzxb+TMa+LkNl))H>!71UPB8`SQq}ezR>T8Ps)Ugw1s+3< z**4e?gW>%IaF0r)F=%?OnYk`9P;iWUVlyRB(1#8F!Xn(x78ak?m%^|t0*7#qS|_@1ap*zJDf{f%wyHcw^*8y}Aod<+UFnKLcOn_ZNbx8S z507Qr2J#aU7Dwtfp5aFN){PrU#jB5h+82sBHg^%{ywO|3eRUh0n(l>7jW8)0O*rdU z7T12it4Hcp0WTh%X|!@6OSkzDNTlIYOZU6beu zRh5!n-Td5)6v})YoldZBeKgXM5l?#`ieoyy!z?iV2dMj ze82th(413^;Zt{a3|Lnm{{#q=8I$Hee=cE@f@k$UtMU{!9PfVWC$RChcXi2k3nPlQ z>Z?ot;9itba_Uwj(1uCdmLZ3PBEWrNoM@(^!-Qv%hOVrFbCuW30DP#b-}(8d-tkBz2U zuKOCHjn`gHQ&))77i|jGGT0k)Y?C1aT`RRk)#J4*r!Wy^{qkLz>SJ zdK~L#!`7`~(B>Jwdq6BEc-O3%;440a*c%4$u_XD-n;REpXA4p$qr{l4hV{=TrR|t{ zhD2&5bU+9&7HL8fPyr>djpO{(4@8RQ@85~mUFb5tIo!JM7n=<2%;7DO>Dg(mYMKyi zp2W`Ng@7DL%O!4&jB|+DP}dkjf@0GA0_Jl#V?RJX#Z##5m7%PI3?i%b?$GeylUyVko33O70uwH;YZ{O-%{-fMY|Z$R$?Vv$IJcvn=R7Ev-_|nds%K;2R&tn|Ce_ z`Hnma03oY7hAi6$0Wi79XBSU0@v_W+x?YQ2ffnXLobF(HcXSCRUmXn$2H>w*o42k5B@x z*xVYybF&+(5*jPw;;lYyk5atl1pNRV7jSrrMangMi%ig=%$GS_Do#%@EYZ?_G5||H zlP~sC4z{3b(7@oVx3J%)_2yJ z-I&shN}vz4+0wuS6wzu%8|mrlUi$Eu*Cpk&QId&I*(z(BlzOQe1F6a5uPD`O?y z4S+ddm)0B_vM09~EaCj9I>98l_Mm0QJ~T(W2plp9@C>H}?Fa~&4O%syFMn}mnol4l zBXH?B1JiG86licly3vdQP^*Hf@t2-KIA(B(J0;#&y$v$fmjIfrM!y^Ymv>BJ_Gx_e zaOfd( z-t6eEh#cg94zLK1`-@JbON z1UXdyGF4fWM*z9{^UvEHC%*&wQtZY8IJILVrg~x<8J{`)x)6Qya_o%Wm znaa~V;5yl~a*SIv`|@X+n;X*$hO(oJqx)P6-(XyVH*FS1GKQK3zA_{fyz^6Sg^G-6 z+mLTqXV2a4q1BmA_-t0mKk(0_SolN6)`b)nhukC4{s#{w-Sa8|iy$C>eG}()XQ?hH zJG;-rZ}&>xw7u|iAFomJc+!p6Z<`LDv2H#uyf1|M=J@LCLrJFDFaGcwPSSl_Og*qm zHGj0iLaL6}@2_0GApL|L@9!;q7|_E#60``i^&oE#_u*0@Z8)h%feWFf^OnkRX$~Uc z*th%q!XFY-<{QsxhIuiyl zIZaQ_zIS@Ml_x<(V}{a6ZL_mTe|Kx9je37i>r^t|#UiH;K@#*O9zv;5<<*!UNB}X^OY4h=~q#qw7lSANrrezS0<}heV zV6}ias_UJ9GUokX^Aj{(P??juRZRdtnO7|f7WIn;3?fptu$ZIj2N-APmafRx-6Jp- z7gjuBzawwrm}7Bi-gc?s!NHxIJ_#=pGzkW)uggz0p5RQZ;kJ0tm=Kk=WvjL7Y7^>= ztafpb!^6|IE0109t{75lPwn2NI-)z}bWJ1Onf>}JCrM8Z{L16cw}2yko}ej#1b{X1 z!T4^D(CC`)&~ZE|mm6jM>%w|_B8oPaPv17m?zyEoT(@7Hr;{4v(;Rf=NJrSxBopfC~3hB#?LUL+mrSqgi z6UW==?*4o-#S^jm?YZM(wM(B|!4K&&8Wl4v?OyvW===NEU9NrVnyxZV@htq@Zz-8t z|G+Cc!d<_}v3YZ(UmpuiEze#56gA1r=~(s6bIUf%X-|mk_>T*D-u`^!<|lFTo`ru{ zXFsmfJT&EeL!*=>I@Rbw8O#0V7G{N`2}vi#E#Bm6E-}~xUg)3q%kiU4P4%Z2*Vk{{ z7z3MG?5J8RR@@@)tSCTAh>Pnz(I^h@H$XLcY;a`hMB5tAF|A135j|vv6dVB|09GvD zc%d}tGCc9SU9xm1hE>KH*S!7QVuu?#U*a`T-l1~*H z4*{K_nam@Um6q>)z3^-k&Mdobk&vfuT^6CDQIT6+mQWQ;cP@4qznLTC6!z|#4QFS7 zeS78?=EBeCSN&l1*SDaH;fMf84v28(3~Q5I5la&S2Y|zSWaN-5hokiC65ty^#t0^D zu<2@M+tAxa?XG-BG942gBJ;$BOWCRZTG9!t%$B-7yY7>j1F-$KR5X$qS7+x`&t*3y4CG!)C=akv(4sXLkA2cBRDOQ$$8MMJ9Td;j zzyn2!bf4n!2dc8GH3&_b_@xx^kkOd_=f&SF5(`oSG^CTcds6 zfBzprgcHN4LM_h?x1*HPLjayoCb0!>t3sfk2!|~^;myDs|MI&bm&^9R!RAr)){xqZkE&c<@n`Vw(bK8IL;{q^Cqi)JJ`#pC<{7o)L} zvLSSJUJ10eC%LQxCc9mbg%O-yy3g~!Af{&K;Aw&8z(%Jj{P6W=-1?E!DpkX`%{L zwM~y0F54xy9AWQ2FQwxbE>M9xAQ+1ipL)IB?UlTtNMMQb=di{H530$kMk;^X6ZMt? zCf%gyi8uqJb*hk6%j-h5OVa74ng?;owsv+KSy!$xBalpYb$l#DR0FBX&NenSFbiA- zp|kIyrX1Uh0HHNCpI$75jF7jhGju{JOAIh+HTDTVHaPmxh>;o@>+&hs6+n-_9uXw? zB?$C^`Hl6}t0(47N8DwVkk?~A@dPez6#0QBG3l+Ipf521h^L}EN@h|N+__F)+^>{4 z`@bNulsI`zO{plMR!cRECa?jXcNAj8v(en)V>NI7XAD}-jmSthqMHOpTw_S9L2>p! zeaiXs1zMXq13c-cpz{IEr+Z2zpW`6G(W{YI+ zs*6h34br*kyECy4LZy&bw0= z1BwU40uki&LkZnu@WTo`JUrl}%aM&)!IvpBBO}Uj#+uN_J9h^33>C0`n46G@1G0OH zs#hAs4o8HcR(e=ZLbft7GQa3q5;Z)A^6ycIuu$|&T0}t)^#NueP|QSRWZWf7(P|*q z*~)It{Y=nRKhnY}FfbMsZ%^XYo#kLW@fc(1G#g5yUa`qf2hkx{6}rp~X`RzOZbrQy z)!C$2oevY7K0zS|#)Suss?T7W;ZVbZ=KX;E0B(?#37YDt06hf*2Y>|r0f%j~`1npc z$G*BFbXN`>1^O@&6i5ZCQWS_n-FcoQ$%rjUu_S$dV#M$c?enWdc^#eKeTrb4file7 z81B8ONN6usF?@C74v0D*8jW_sBSQw{bQN)JLG^gkFPS^wZ21Zv8 zB4nMDrqh#QNP*VzA%-Gd=P3fh-ozY!f1w;p#SfmdbtpKp0mmDBd3 z%EvF4^P+VGTcM@R=eskEf2?)sDQskXvUKZef7xE&_*eT?cZn7YT>RX z)fV~48f_{vGUQvFQqy0aP`zjqV7h@uN5tC3vG@AvOF> zC+C*LdNUdYunzF<0O1j4032X>VEac%A%1;v9!NXUEIPd#+!1#w&o}PMe5ig05Ty4o zJUp(>JDt#S73Ok@qJ5E(`d?COn$RTT zAz?%ZKV4(r$l%T7hh57EEDhQ#suJhO2M2_DLg}+At|ogDX}24!>*G;QKvc!J{U>2z z+BVdNWDc#Np&3+ydA>cr-`hSOumY6D(lF{*iS7)p8V~?DD~jG7(l{!aSVe*308V%W z?Zmlnlvr!Z%*WaZ5>Lw27(Y6Ys*oT(eQAovo{}Fl!hUy4+!XcIjT>bYd!zdBdS4M`|DHA{if;UjnP(+}*FEpk$xw!&d`uoAp zH30VF-|=C?h=q258b;c@ziyk_2{J0xSoJe&+04X1XQklp;Fr=(UDr8xmT8~6P=5J- zs8ih&h&HNE&jljJcyr-Co32h!Hk+B6TGsrqpFP02iVZR%{S}dZgsKHW4H&LQKa@Ml z;xJri+es`=gLk~`ZY!XV}>^dr8)N`!l(+^L}i89unbfb^;4k=Q~g{t(TGwIfSS!&VFgq`}U^>22{ zdn)_5t%%Lt3de~?F8Hv47?c5P7_WR7n>MyxG^$TU&kVi_$C*AGly-vn0yw-+pahV! zkC&HXccx`09|;IS#HGhR+1>6ZcvOS4VTCw&AtD;nY|k)8r7yw4pi2-5r#*iB%SEH) zTG);D6m@wDY{)15&8^A@1aLNe<}2I4&G7Sz71rI3y>W~2j8N0r$)MiLZ+m8V*B{c4 zIc&3!doEf21T}!i{%n5lyWa{d>lx+rn(H^eZgZC6(>i6cU-Q$jv}SLJlgG)2JpIDQ z76TlY8`zqW{-Sr0>_+!3OENvy_pLHM7yt?0r=H3G=qoQs$+sQ|`O%L&XAj##X86Wwo{OhqKt6 znA0ztKZhdGSR`j90RoDU3e_zxeDsQy36IqGuD?+lEE;W8Q)*#uE`K6lm_$9XVyc-@ zV))tcypo5fOidFAzPWX)(uK%b_h4bmhz29}-Mi&q{Bu3Szf99KZBMjG97pNLv!oKHOtt(1&uDt z3XKKP_7d7q^@N0t*6y@3=-}1frn6xJ(2w7fkm9g#dA+r>LZGPHJ*d=ldEBop|Sf-?Chp_*L5z9U7xI7#-#PC znP!*0OF4b^8&5dLPP-T?YD=oAxdby$uWQcEILflAcjI+b67Bos{0Osr!OnZXnkFnrRp`uap;|U%smoB^1 zUAf%n{(brG0cKXG$@?VN#<~6l-M=akvLTKr<*eBykUCiMBPC!`=|P&o&~a6>i&2Ln zDAF3qF)@mSb|5?jutj-s?BJQZB@cFf|SD})raO$Hk zCOv@H2N}>PMn?Y8SQ%A(zE%_2|}0`$90*` zmVTLd{LJi`ckbI%DX-m(!{XNYi?LtqNHkTweIvuUxj?SgteLj#Sw?0{-u0|D&FP=1 zDU6Pt&e?u6k4(naf!)fy&QjC^Tz7_ku3WN<1Ppi`ISwOiP?6k1LN@+qczWlXqh`vt zdlgEWn)XAt?fc@niWh@RJ~#3SQ2Ui}s{BB@A2ppCi zZIszuR$5vOE072T$H*VM=Vu~eE1?_<Q&6%?&c=s#YS`qm4$TIi=ya$!3<;; zeOd)^az(s5c(yC?@lOmOm4Ush`0I`jG^d}KxW+%7`^99F?j1!S>8Sfuvt_9o{bvX` z6xELTl&g~gs4GlTFKUX4ctj3*qY6F72%fYE^q{$KM6+M8V}ly5|;)VB5NKgeK?f+(PlHRw#-~xx?DO)_Vnp$c%E5RoxMKhOrPK& z1z`wy*~=fC*-Z&JC=b^FxZ^KJ>cM|HsO&5Gnz;?+S~WhQ>d|r0MvLM-M6sY>7U6xW z0*E)X)v1-U0`YWWZhULqfC83zf38go92=$EQqS%Cg^|0VYrd`UHpi8%Vs>Z9E<$|j zA^keGZnsATWI);FLn2n3N68LNb8-~G4NQYYM9(UXofMcTnP%#Gvt0se;upl*f*cXF zqF^q4-VHb7)6L>{5LQGOGN8#ZXpn-l0yB#z7wU>knesYXx(S&6<(9gp87B@N%+J1USB8vJ1Z z6i#aXdx>U!IZGZ!Ogu{-IF4a>nBf20MC?NfjkEpPvfsZn zqa}k%=eCH9-jE~`YXNP zmR0(}r4B7BT26c|N2~p0&s&-P=bsKz)Y{(D`=47r^*t9)@*u0;k6J`{@Zm|Uh2;oT zjq#Z9P#6(8rPpqXQfFx}m|5rC)6GsZjqJKabx50Otio1Ie0+RDL*Zb>gLP_BpZ_J% zIaeK{4_}4pE`35|-I_%}f(e{XHW(mnOgtKL5NTyy-Vv){B5c*|4VrAHtgI|49mMH@ z2os{H4`dEx_fIDiiShI2FQr<+)b2SjmAQLN7ODs6N4bQA++jHJxU%vJj`m`d1Awls z04ZM;r}_YfVIA-M)i0R8C=v3cVnqT{OMqBp1FHlC0@wqg7kz|C5j+97a5SPDv z`6+anppm1{z5!rTcTDUuxL@Al-18J$4XmQHiE8_n6Aw2}NC*pYM~9u@NgNe~$3~}n ztHQ}xQ)eWZWF*>JTjL@2;DVM^+2|T9(<*7s5;(@$5Tu>JC{V+IU2z^b5dE^p*P69D zteKy`4AqWDaqK|T7zrO1=wa5c{h;yWWOLZsT?sXSIH1gm3JcRAzTOaZo=emc+kj_> zCaMtW7G9b#r}QsO*d6=Z^!Cz5201&E?Wc?C*iM-i*vw7aHcM!9CWL(a#6g#)zG`9j z3{^SkvU>lQmo5^;e++rg)UDBdTap!5u%(&)WXGq!n-7s)>4?C-bAzq`_O4)u0hRu! z&}(2Xe;+VPlsGpilp#_j-shDF-YS9Gpph7y!S zS8o%EQ_-@ez*a~ekxO?%_Pj>REWr4&?pU)gFiSJHo8#x_N3=qJe|!xEX;%h|)8xGL zuxh+A+CkVuTw)MD)6r-nAqRB;DL}@vjmEU<0@3Jm8`a=3Ko9m(Ld7K^8A9K*2KIKs ztAj3<@BjS^xHfrAfrICdNMPd3QAg-A%@!r0w5N5g15Z3VF1@{X4J*(-yqHKDNTG>l z)|GNbp;a~bqJ?Qf-SHvA+&L#Kr|3017ngLhUank+`r4QZZ6Ft8kh~i}w?bsg;1c}a z2HwB_2wHYUxcy(a)882|ZjS(su-`;Ii~^Vl3YRS%A1;T~6w5W%r&FHN-&&Wo2DFJw z)`g-|-g~ER0tJi-5=zuv6U@JegK-NlaN*r)jB5M zn@$2bA(x!%(H<~@yc4TW*VnRNBZ4?51Kq|FL0dWy=|pdVud{YXBp1wra{_)upcFpN! zE&k9_p?@LlJGg0CVclc<)TFwA8++5O%ybL1xS8+ViEZTBsCw5yJMrw>Zu{&w zr;_%xDSrP_t$FtwQ}e8hE%%wevBEY53#{&4}t0)))c8X6i#(W3DZs)`u15@0F-zXo71cSJfM>ki=Wbd)LwVEz!* z-~7bk)P?I#p=4)4?rwXpPh2sz%iJ`b=(*Yv9u;F2jz$%i!<(mVn0dmA>`NV~@t=}B zg~^_@|2vlUxo~MH?I8|!{wdZwe>R$$t@omHZQLjU z+1o~Gug+Ia&9Ce3n`T-zs|q^Wbc;mpP9$fH{}hQX+%cm9cGc02z(m8zL8GEG{1;wZ zQNsXVz+e9Kd;Ek8mv>K-m4$Fx>un<&r;$VLDXeOpH6>m9&rFqwylwv?<3ACv&+voQ z+pjgQ3%_;qW7rxNl_f@FbIbuYcnQwY(1UpE$c=P--Yh(P1I=+um*&KE&t0SGUu;%6 zDt}yF4liUsIHtrB_F3Na`Q+lMc}Hue0Vi3ur2et5m;rfybaf;-T-#jGciu zdw=HN_iELvceC@KrmGTN9^X7PXg4R&=}=}F(&t23}pQQXXsvx72qt~C9zedxa0nb^IW!+L5>Hg{Z?v-1B_ zF7B{%ZrD$yGqCwEcXprPp5r%qy>=WQS2f9|(dXtH&|hWo_g@-&nKE53n>6~xz2aPx zgBP>SMcZU077HzrJ6U^lefVp7GP^}hLyF3Ry$%Y7wQrMV!vuE9tjBELpOx^5F zlBR9F{M>1(GBQmjQYKhITN{mWI(6$(YAid0Z8}qHB38iMQ|{@7k!=c&ZBv)x44z5d z$=0cTd?jOMSm|AGj#EoruIxsZ+2F9pwrY(|wndS&r-kv{H2a}jlL^uc&ljus#ns5w zAPt(?j%#}wt^UDsMu~NrUj8v=Znr=`bwhE5^*h$`mNzrvh_s7#4r`J@0*qGH;~UM1~~@j)|p9 z7ZnNlKdVXa2?+?kp(p89qL>!Prz_3m;PTujEa7DHzS@yuRlc^c%5;O!jTcR2+?OX% zr25J!c9f|`ciBHJ{>~)vISl77DwTh{*CE>+qQ@%{6!79?xM}2E#kpsfjGIjN?WLH6 z<|@|f4|sEj1m3PG2(OJ(QP2|R4|nejPcc=chCO<$+g)!h<>*$DoO80d(j-$Ff2Bxi zQUW})g-Sv<`%}9)-B*b3oj_BTWrDvf-BR>e(r2Nb@%f2Z&Fs~GK3^uUnad_s9&>if zi}Tm7_DncW9K}_A@``vS8Mv?6oL*@{v+2$@@$&Zm`Lw*tW<^1L1x~GPUV6M@LDT^D z3&X3OCR)58LizUk$mU(SPijQJ{|xy$9#|UPoMYB)Z|paHSFGZFp8aO^6w1Y9U#UyA z`P**ZnD*YM?Mn@Kvo}7#E9obG1ws1@MNL1D)war@p=FMkN&^Bw!Bv^2|Z}v`^6FI|0KOX&Vy$cHeeRPViNNcnX46^OG)K#HhKVgi@ZLdsZw2J7uY(Uq4 zdoQ;FJkhZ!Amne+9_yzCv5%m9Rh2ZA4Y|qMh4Yr-<4rWI4gDEPvJ!Sb4e!<4>S$*5 zpd!VPH5A)+Itp?`;rq_>BVAYe8}=?RVn}u>Yic;8@Q6>9icRz$n~{Ig|JJHzPS3~b#GNeml7O>p zQoh`=g-o=oy@sB&mfNB2aGol;x5K{k=C0Lc%IYTmuw^{s&nJNH5B4GUrVWM#6-m18 zt60VNU0*)nOQI9SNSWxkxFS@OjZC&)v}kr*6PA@_ms)`EUi>8Moa?HshxX$U7h-IO z>x?S+bc-rIw%QssIanT*p8aBjLU=d=V2mCsUj(D~W&Dqe?&zGee zd}w(*OfCr3xw;=7OU9<;et9e{p2vIAR&~CwIWGvF#SwBfSyr*+_Q8_83!T5BXqq=w zCRt!io3oyJv4%$`P%z%TJKL&0@47ohJW4 z%kI8q*$KhcbfMlcN@>_ zO=1m`bl>Qj)o8uN+nqP>yiW<8kN;W=V;0E!RFtI zU;+fq7|vf;&$((2V=i?|OtuZ(cB3En?KzBQDB4eAR#7pzk)YQ!WtmgI)Cs`?) zjki~^9NwcJWUjV@xh17SrZB_2RZ&wjc%+QBU&^8@+)szBFmV})xwtcd<5_RMyR$88 zS1>s2Y`EG=xzwDed1H-4)YWUge!67zkdr;&b?o~1EorbOVX(?O2o z!v4aR%G9=J1^GI#JrEwNG+SS1oT;1mvKjUTJU|R5JJGkxhfOubK;CIA)`-u%<#o>d z^yr!3X*Dz;4Ps*!G&aC9jJw=0;AC_BglAr)oKx?!18_zt7VZoRW`pg6;tj?v0rjTY zjW55S8Kyc7*14;9|%rJcO#Wo(~t3gKV1U#Wpm1QxHnkJpy7g zy_T*ebTiww`zPItunq2+6|?DYcwBZDGV!ezZ(nrbJrD!xObxeZVzTmM81eH`Nq~hn z%$ph*yhC5JoT5|@=8@lhc@w$3Aw|&t@NEG--<`h&`;={eraAdSZgJMSHe4H)eSVrY zjqK{i&urzh!M^fqPZbSKwX&M2nbq(C{5snW-|(QUEJ)7IO;zEpxg5q(0NerL1_iV$ zl?^y(Syv=ljPBD^3kE^cS*ssf((371;=#r+t+RQ~LSidpH0nDa}tfO9+Fj zR}XJoEjn6)#igVqgyun2^TBLOm-SMy@oucz<}f%oCU_TyC|n#tgFYHpKTl;&wyaz^ zR_t5V=C2=8!s|3t{CFI7b*HIkLJo&VIZY1!5j)z5>-N|*bZ6BTYq{ysTIPPQo$tGM83X*cyN!>y!JM*E-M{Y2R?qOuSvzMED>TSU@`uvP8 zx(n{{mKEuGjXk9VX(5s?Zr+tB{Gy28evhBWGq)`oz6!nSc`~|cJwSY&W zZf#QcXjcWtt`oENxQDdMy#h5Fexm&uv2t2Z&mWa@g6SJO=2tkyyjkbI+}@|Hr4khzwMP~ly}KZt zS2gLNipEey&g?LkYu15_`5j5cPC+p-l9G;j_9Jxfy^15j13`XSSy_*#KRg*I!7#^J zP{3kHWm}tYF8~OO7x(dJ62Wak(4)Noems4(TBS`f0$j)clW6v9zG$?%ZzQnRC5TZ3g8kN3$tS-Wa9Cju#YEJD6RX5Ax` zQbS&$8X<^P9?5~%P~@1h&E%Z^Dw?Q9_Yj+Hd(W0Ul za)Xuakm#OR{K>&br~ba{^SOcIjwkx_?5|M6(BQQTa`Lo>Boz{*u(Na3gF5U0J|_k{ zm$JWBB>u9QyzP1RckkxcmjS%3lA{h?r>{(~NO)2bCpL0&G!{Beh~2}qOwF6` zC<*M;m&o3kYwsK*H-XcxeYn_}`ZXXfI`FT6IDXg`NAAcQUMF#cwr9{=LP5S`@12mZ zS^)X`aL(v}Z|OV8=X2}QclBlu+zYbruXP8VdJ5J)YF=s~!;(!T zasc#O;81I*cBJjh(>avK>L7Ene7H4|w5Xua0|U+GEjMr3A~7i7^wB9BQ;v0haHiH_Bt&uyjKpbh>PfA4 z9Y?}>xA_e?4$RmNz3~&5b4aU=upwXKBmQ%iNZLA>Xp`+~o_%v2&#>Nv=SJ5ui;VJ1 z7NAXwM0Rhv1bwbqCDE!E@toxcNhUpn-x>oWG#+FN!)EmH_W#D+dk00CZPBARI)*VY zGiFdQfJ#G+%$;Is5Fr_S$Q0ah}(Jk)6 zFG@P-w{NEl+oc=T@J9rT@38OBJSFRonU)ST$+;V5T0i-`4?HL_(6qY+ifiiD^^BD$ z`NwlRP#I)=ORmtoHRNy3`;OgvW^buCA3eX<=(MBbv6fuM*|;fWmWqYrvjbWgB^?7c zn9wc5G=K*J1Whc#6i)FR4WU|1rzm+tUNixncjBzqf~;F?BN%JUk%me5VZy#e!=A5M{6#h$Zgs}&6YkSo3 zQKs$9=ID_f&Ki9wRS!@2(_6(l_?#y*Omat+V%`iEEFRaQH5|ah7&vG{LR^jn8CfN- z3pf1_+GxsV;y^ml4!{A~)xfPQrlzLx+5I-QBOg!6E2r-u^Yxqc1D+st+eMK+*ys6x zSy&vlClo5kHK7=SxJ4^^V7o&Zwyww_h!T5%!%!VEf$J2dU5mcujtAL(zJ90nTJH3> zWaYe(Fxvh2PS|8$gvp3X!_`hcXpG zV!xT@q1mGYFo?B_GSq0+IDKr?zAGdc4C%m??VUl)!SmncXmtr=48A0)Bku59JjFH? znfZQf7=}gTL4&qEQO>$;?;82dTV_@UjB~_>?Q@w`j&p^yLhfym^Ans85nPl2p^&HnUF7 zB*c(Ik&`RtN^jhABpu&I`m!C@U162%Nx}-ai>qbEpgULHER|{b$%5vaHkH5Uk?8%U_gROR#zrTE4nPZ!L)D|t*%_iT^6gCH+zQzZ+_|x^)FAQ@=S^1RhL}?6WA^>Tzt1$N@aQC(yOw z*2>FyL7B}JqTBS=?k92N3uTxxR3y>jQ^dlYEUn#YmMwmw9T?&B7n9RG1R7OP=0l-B zQm^N>&wjLqa_j7rIZ(Lw7-UjWAa#TD)83gEv$eIgdSBmAGQm>0GCL}~PKdr6DRf`b zK;E(Y4G5?`Vl)Ax>Q<$D6^j`UdG^Lnn*t`hfgH!X#d4V5P_B(9l4Gpd&yCPk+B#>g zk5Z_P(+O*!gcBaDMOgOw!H)4S06s#>#z1y5(A@FbxPv>>X!@%TdOCWgUD(~Ulf=XE z#lyez$<^^VB;Y;H<>}3HqW9h>vrv4z!Px!T5XnYxOy$Q8PqZQk`9isy)6~e= zSio_Lx!!5o%m1yvuz3)mKTLUL#-wOeH7?&J&D}p9=$}znm^IdzYV1vtq;90`cB2hD zz>49(1lqldwqg%u=3o>+X-YJeM%!;6pI_UucGnq|u(MWHRxQ`GPo_1ejZX*J^i)T& zmg1JwjAjzFGW{wcxb2gUIlmhU{;0Y-)ZUV8!)5>Q&jMU116Q-&t9ACx9Dd{US-dgD z)?OO~UtQj;E~;XXQ4kxcr0H|P<@a_6J;DbRjR+VT^?VZFoc}Sc#jf;Q-t=ep3o~zN zG0|!%4c72$IMI%so}ieW-pl1$f{!qHxNh>|G!F+y@!daK-;LJMW#%(2RFDf1t&ASy zikhM3RMuRrpgV~t3aDnk7`bb`xbRXfFam{K5kI}Rr`eqKnv}LSO-+;D(;1PJR5^co zU)X9((kSv`Zkn4OIIrL|H@VTZ1m~m7oi%+PYyc}KX9wsn3d`P^tER<uQqjWz}ovY+w^fSy_#8_JISgrQl@q?9KU>dSwg8JI{t@CWj?HSRoyPQ7FxF;>(?N zHJG^*p%uDSpn}I>X*FO>=Qt||(W?ge4HFK(8w z{F$8NRafx^0-8$`Js2xQA*v;2*5otyp8mVSQ9w@4Z}REL2`d80$l79_47~||Hj1jM zAxTl+2h%&2iNhyUBgkPW>L?vULGRWa{Pqa2wa~%7lw%>yi2u=hxscVBcEd zJX54vZ<6dKqcwn(SXyk9c@oiUEJXYJRIhm`FrAg{rs>VQkcRUbRpr3G$OvBF|tn89_L{z{SO@BJ1iYNgh`g(RIP-cC)9e}C^QkUUy@K2JN))B`#2`cy;EpOGSU-(Cm^ zlDEiB#Ew|qUKQLT;;k|E`k7lXTpP z*%Xvur3sT@$FY(XyB*j!YF=~V&6{|2bT&zMzio%F{xH0~k|Gn3j>e7I4P+0@gcZ1`@AM_?FUU6IR2sbAVLUpU=3L>_2x8zTonSUt#vT3GL1(K+Xm1(Li7D*- zuK1OdQk_y-qC#-$5Sc79k1zJlyZVi3`h25pz}_!4&uDAJMl54SQh{gXoB#59TD5L6 zSSV*Oq4J2cY&$4bZvgEbo6%A;f0$u)ENvW&H>NO&5mbj0%{8@143Pgu~#**4> zZ2a{?GQ!5S+@zQGi;2&&^P-({&l4tZ1vr+rdNnRg@nZPRW`0Duq@7r>Ne`8^4}tKgKw#4ka2Mc6MYh zp{2%7*z>Pfl@V$v@nxrZwj6axMEj+_9Iy%Z~z=CQt7)PDMQzvF- z=HZ!PJ{=gMP%yhE+5vegUi9H)5HN*W9fpw<9ZF3tb?x{PsI)Pdv}H-TWYpMdQKSKU zu0zeOJGa9EAOa~-NXatblfT%t1Z^jD)ig;DAY}gGpy;b;wsGf`)cJJDwal_sHDY54 zLd;o5M@L!e`%}8e1u}c%KhCd3D@ajGAx~==+!|kom|7WAx54Z#2~oXI6$nEKuTLK^ z_`DN4dVHv0F=Jd}na@6L%X(c2X{7PbrfkgTg86lg@`eM4<&Z5#+N0VYdd{lxxV^MB z{%-^{@Sh0ifPESA0}`DiwP}r3_5->4V~ysgWwZZ=J{yHWM&lMlLsS+MiW>&&d%B~G~l*rlT`e=azcrE0p21~VAPAlr`2{Vepx z);V$5F{ySA6l9gtS?Sm0p;eaGKzqWi>W7Kn5>zNE=B-~a@hoFI@ueo;DkO1V=2VZd z002edgSc@nR&76t*AB5v%pMpx3`IYOFMmc7rqWuQ502dv%(GlJ#xz4?b=Pmo=(Mbs z)p{47z2-E5yCAMMIo#O^sJ|_5n&lnhgD8YV+74JzcM5R2OMx7b7hvh&E{CLv8 zd4)-N>!BfPS#{RA9LILmhjaNYd39u6BI$UdA7m?J-yGy|6YB6~~qSO#O`|&rdc#Mxo(W;BW>l4^|y- zjj8n|Sc7-pW8(V)`Ob-VUcdc7o(pdysAkB)9)y zoB#O-f54Y79zQ03#)~=P?@Jo9pZwz`h*_C%4blG??Evk%;;g||b~MA=iN^d({JnaN*)MDBxYY1&b4qf=z-fy1%@aQ;AFTTp zmbA$bQ-hV%XlI_+RN0it6>ameDNDoQPoo?OezPGD6MSZkIQ8=VrktChhL`um&oPgh zWx6z?ri)8H%OL(Ie}pw;VKZEiPkW}{$}KXNbk=Oxx%hrViepz@_vJcWRy)GaQ7k`m z=OFLd##8Z9$Live+a^krp6P3?{L#M^Kf3UFKk3w%Cu&Da(3=I*Owz%rz6wtD7AuI5 z4t+S)VpHnPa{7+!Ms`Yc{^g5GCXuQaSa z0fKNeqlArzefEzEG?uUZCcECUE7RV?^(`1vj%q0ekB#Fqc^MCV|8P>Qmb{0I(-l?pw1+<5 zWbEvTNwD(3!x!JM+Eg@R>O(T9?)qL!#usf4O(ZBWQ|D$S0tqsPu|L+K zcRSt9t_)7T+9)23a~>^zap$S3GGCNVI9B*!mX~tPF9QuPj$C{5z*{T12>(ZOL=`$Z zL=S=uC8yg3>@!w(Ky1_BI1CM%Ej*a*{GHYFHG^m9X6uK;L;GmLIv?}2Dv~bhhmM*` zoMvKuWew&V#=mtP57Xzjf3eLfO;M-t|unx``a{SOF5 zB_wYkfeT-LY|r{%ROm|?(NrC(mZz)f4%5#Q_?zbDEKNl#ogFo36Pvc8mX`TTeEo|S zLPZx$=}jwk%bt8wB(J&O9`A4R<$<8TpwMd5Y`w`f(`t9;-<#q4cA!cQs~Xa^Ca+Gb zCbvwp_JP7yHCb*`E<;sNRNT-*K158yoGw|G1pS7ng1(z0Axlj*)JdP#*4CC5X@9`2 z@?slS%qV19PsC?@)hEz^B{~SDXhKp*Qi)2gYEHs_d@HM>7u|VAOn`D*@bth6wh)`& zm*?KSyJyF%q$ekoxwEHd`x?%DTfQgblB#-LQh!!}kGmhMci*%e9+R z8acH^ zx6_>lA90n<( z?#;cmf({esCa0%4c=`aAtHnag?LhoKI9;x06+aGJc8q)0pg9CLOje9{7P0q6<bBnA=WypF^SMOg57Uyy0j=1gUBeX;;DsH!b{af~t6|q*p(+8N zmER)V>Qs9PUU9fouF~;=RHIEP#iOWLjPu*RaEe=_CEP%A7&Yzlyu)7q?lrb)r+ag$ z>Vt)~K)y-r5d`mV$VXJdq|g`wHOJ6CdDLu{kQP*96lX0k7n{0dTB?Q`GTGdGRcqxYOD3tU2EjwsNt>P`RFdB)5k>%(>s|*S> z&&o<^5vy;jw<;g&*tciTX*56&hYd;+MZ-V;T)JobMHdVo#;3Q~Wfwn45BYHmFAXz# z?-wlB?eo7<)jr;*rOW-knAH#?VcQre$B!s@gk&84b#}MVJq!Qx@KQ0_2ljzG_ESfE zhh$>71vQ28_inbVQuX}b-Q9}RQSioDe<}jgT6yK#8SbfdkdaPJ=VVjT^5d zJ26mb(BD*#5zLYbi3q-Y^=BlR4-GvIun?M*!h2wAovbGo)m_C}1In85{_y(bPKd3Y zrb6^Eff$Uz`|V!d%$4F_EByI&lkgNVddS&VpR7#8kc1lQs-6gvO_fNTq0v* z&&*D1g`hR|4#L9YO_mYp3U#JfRe!M9ufwu>=}p+}%JelB!SSZ2(cJk1ut;blhZPhY z)_@BscF2pu2b+mzhyksz?BQfC?P259zSO!dn3dZN6|1@lwcL)kC%2zR#;{SG*SOKs zpOJKim7)Z$ zc5TDV{-uwFZvN4pHhm2zQ0dkn4cJ;l^>E*VQD*GmNVW8_nu6;qAhUiVY#6ud1fHvi zNT#3Iv?^Q|L`tyb<3mGv?B*sjiTMyw1)1t~PEb^by(7(V`FiID6CsFXt_<3UEr+h} z5#UY#W0IXrKTB-eTyJYIOolCDL_?~Qv2Q%6+zScl;>mFyg%l;K594Q+PkCk zmj^Md{d(^WW~W;RlCM| z=AlDS?ue9JxpDKl_l|{|=a6SHJ-QC$XF7{8K6n}rBxMyl`vz31 z@8HrfvE;)1BXW6yV zR!EF|OHL-H!FuwU=j#B2oN$YSg=GGrtNo#jr|m{l<;T95Rv(YKCjC-a>ci zppf#Z<9{i0y53!0_aWpM8)fB2-sqGS*+=#Cp0qekOH36>%!T3T=^DBge?C2=u#BGC zJy7fsHTBi?Ej1J#M0?oSLL1UB0Nwd%M(gFJM1#^NL$)u};$XkV8WWI?5#gfVckh-* zJjle|?K%X&81~db9{@uYN&3^dKJ{6fw&uMy)VA(8RIA@i3Q7at*hP<}&8x7m^UX>&+4r?lNr@+`NyU*Oh5?QLu4JgL9j)m))?syOU&QE3~qR# ztH$Z#Z{c+U7ggpXi_{#iKdnb@JhsaPab?9jC8B9E|J&^t@`@ir0?9 zWgC;IiZyA8P%uTy`6(1Tp?km~Ce|#w0Xj@+rrK+}1rV`14vl*@D5Xr^6R zq!aSt=;YGcy!d9`;Ipo6ndV-<**}y$(%Kt6r?E#^W3H9^QR3c&%E7O^uRVn)p6p7* zQ2c|=B)|9TGG?1L`r9z{{=x9!8;tAT>2c+EyGKN%!%Ab-*|zb8`*>J8v9XVnBN6t= zhcPOC>(;N3_+sDdvXX@TB%I>#3r>ZfuNtJjdK%N+m#&sP*P55xj%_J1+f9de$tXT= zOaR6vtlK+-VGQd|^t8b@6Di>g`t6a2M+^d}vVC7bKoirn;@}$w;q(&LmFsORE8f5N ze0$08&wa7|-Ak?d%;6l)FOa;BiAj#OwU_Ve)~K1{HT!27-IDiTRWA=Hdi3Z5D6y1% z`}RSX19}yYAY%#N+IpSB#t&9Rll!S|QfA%U08dL}zDHfWZhJzy6Z_3nh0ZCNtDeH% zWpt_zH;)m&<33N%@waAUmoPcxmrDK9ReLx;Sc`#~KA*T2=$2wznwYUOGA3WKOx8_R zQ(nPP&iP)QDkNXu!D$>8-w}$cpE=VQ<$SQDNIRp-H_OPk*DAI*EcQnmPMIa&VJ?e30WuZ^ng@56fFXMN?Aa=`RGuPNIE(T0#mjaXe0=s+ zu?HWd_EVzvy0vScLpe6^kZ&~h!HMI4Nl~FO(^u_;l}e#Dq!>1He^v3Go0?38LZO~s z>V(DqtK@=5-wVhP7b;F}?n*>^==Teei?*}7jYP<*Y`^kBo<&c?%6H)Y$x^ ztla~|gg>90boAKqJgmUty>Zbvzsheq()IPRLiENaG2N67;d^mN&U$DAe|r=uUd?c7o%Hl7eAmmbwR+1jyokG4hCX@)(+D?HgYuS`;PXK>LgGfS8H z(}qrVIRnE1nYT9V>stdEF0UqM0hdr(U`KgiT&AUd46O4u#`gC0K@D@rdAWqeR~@%e zr8v%3lMfLx3BmMlJQT?@>a>wLWwv!0+1bW#?q1wqi*r4a9Lm^!S)qgRrq0k>-42Ht z#LbA^X9eH>c!cZ}Wd1SM!_Jdx?z${w7YG`Lf6HQD<+#m53Ii9)3cir|7R=9gV3TgwG1<8H2BHRxpX#RkORw>SI|X`U@oCOTxQOUz%@dq|6e_$Ic&BX%>U`PIS9)vY zu!!!FeWLbdxzv!JI)huyC-+Yx9w;!?W)_cxvBg$ZSX$iu^#@jpZ>qk@jQbyh3k`P8 zJ1yKi!bKtvXygKF5Y$0dDWhKz1TEa)uQb}#*Q@JdaJ*1RaaJ`*Md#F}pxzrY0r*Q!ODv zT=bo@Gw&Lb3ibpt9|$WZ51-nl**=?7?cTV5lLC|c+`41wv_=(FUO!$xsxZ>%#=grM zDtUbW-o1~I56x%lHLFh|n)-7m8qb_jk3*b@v>DKR7_7mLO$w;tBkCXyZtgQx;mw+1 z(h!91D0j@GG~LP-nmvoKb>r6r&fUAy>to3_+&(-3|DkBDd@dqE>BcG{4G+wiE6va- z?iy=!mJcg~HO4S2v?%x)KYq7eqpPNhBwLc>u!0xUogJBQ|;??Z|uvb zwOp-__wSXgual_c7J@ub>e)!iW1{cGXrI~pP8q7~R&~4yjel-!UKxx3q2WC@5mf&` zZj(D$cz$ZID43|?S@l%QLh<9_5LBy>N2;&f=oE#`R})=^2-#bH(3uOGd~gQA6=q*u zMdVEIQQ|2cX6N#ql=nao6vREKx15u!+yFIEMr7v({QDB(^I;sad2>W6k~_!Ab~#n< zCwl4R@lTaM#~#9nTqJt;a)@N`u*-m4FtS+~nW#CUwa9c}Z%Bi&TAWf@keD*OfKPy& zp#VStxJWx{^qCn;@Ag9kA?oCMl(97yBY9* z;SOu8d9}Cy02J{}qdHyn!@nK8SP(|_R(7iEuZ^4K%}$)2n%c8>?>Q_(w1Q%knVly~ zS7IsDMk^Xa!X_d4=?4SkwYW|kPb&yJ!KLGETlh?)*5kOdUAp^CZZ?OzxU*6@g!`!K z`R^qpMTB$ryw2pF%(KkbF`aY{&I!mLKU#H8Ma7BsD<2>0jYZD-kfWj$;8y5F<;fp_#|Dli8((HzB_YE?L2FSl~}M zG~sA+gE=?4^l6Nufn;FZH+DuLpKUMYe-|z0Sc9Y#$&MWCnm!qJID@jGT+quvX`%K;A z+7 zr6jML-FAy6UxHX`so3mOorLyd$5t=(x@{$QaXc~U4Wp-|RJGCQ^w6g%uT|E}EC1)I zav8JaKVFoj*=IX=T-y`P!|pGekqm1-sVQ`i!TP4`lQqY5y7wLrpQ*YcQ@`C^e!BgM z|1Ryh&6}lM*(gFbG6-Zkqpk{+Yx-V=BTs6CRc=>a^0jf`8xFt4zb;63-@+oQK5AkT zd+E|MI1HS`vGfbJyNenY{KD&id&u|LL&|efaY7EysPQ`$8w~HpZXcw+ysY}5wTF3! zar!>aexZ(6>-(&I`PanMq?xxR+Jvoo+o>|YjLx~iXGg=f{q$&e)hUvmegA$=TKeG{ zR%xg>_NG9>q~3U%Ev@teW)~xofObPt{6ms%>5AoQ5ANQ*oI6zFN?ir5(cQUIJ-tgv zODOf|&v)@?rh|@I0xPF@176BpKM+3uXvlf zWApuC-9!G{<*lR7bl=et&6Fv;VY1;j@*%4WV7=Fn(rDFeMbnvi+qxD0pX-^JqPHJg z$|WMAx^hEKG!(fspI8w0Ya{@k9v;u%ys6>d^0n#NSG$lae0+SAcHsaBNp1JR+ePmG z`Q%(&_Xd?x2Mg3PSyiMK_T$EO$Uowt(ubFTvuTkj(sa9&-VPr+&8auOQeFnBNQy2JY9k2B=6 z%nbzmMLyKeSAi{90m2W<=s?J8OZoV4_szmY0R(Wy|68XhMWh$OW$lYCNC zR6JLQ%jB1DBVYgd213X`UM?PJJ!w*p2>C10=f<-U_BO`mW99X=cfX~fnxSbAovqM%<#6hHqp0+ zEjjwtx%R?E6<{q^e|@`>odT2F>YeU~G~2g8D|eu`&Soa{BIHS7*9n3DqksJI1%-1h z(8*Mr0dX9@m*9_ju;=z)OCWgfAWuDl+{~OuV`}u*x=Ib3vn2i1u$h%sRjs$m)6}3f zeX!zpo^zFyY=|!QFs}v#)jlwgP+cv^qdsv9;LC1`QB6rKF`d|Xa+Na1E66ENJe$W` z?m+t2%+uDOYbrxU9ka&9>&NeBz@3^I9xjs2~QaJgX0>X3v5Vr$7m>FZZ%=2^2E6ktIE_(RmBiD?&Jg%s_J%0WmfM=K`;5gZHt;Il@;1{hhV0KR?-`_8RJKp>z= zOq?3$O;WnUl;QO`$TV%hzZppQTB6cPQ#pP5E)+7WfnLHKD1m@AysmL@#6cr1swLN6 z(S8=fg2ymr7dxh|{~&)CQZKk<>#t{SjISJo>N{LTjbV9d*Wqgmzom4x?vZYRhGhL< zaKEB4_@ItH09=o#p-9n0gy?mnc2-{=9DqJJ>@y-bO`YJCQuAOlBLV2Z3;!4(A^_t7 z`%|_mDn4)%@UPro8@MdR{LqxuMl~WO8as^x=t+f5S`{VVJ%!;WE5wARrji7!QXXNB zUAs;u>q~@9_xs1g1ITFlTC-JMw0y+FsR^14bbhUYQp06C2zDhL0OGTz`wynt4sQT( zRBiNLMr=QEAFye*x>M+$FHMY3uq|b^XM5wBBffwCzEa)U50eU>!OrFEw1i?-`ouES zc=9M$(0dXiQimr_+`8}PM%)JEL70Nky}(tNz@LNrJR2VEab(Df*l7yzAjATd4{JvF zgB^z1t4MC_BRTxltDdk> zkBP&RIORB6Q)f5bM}LQ6p9-@I7?{;{UtiW=bN7$eRwy5P{mt_frKRI(IfhkE&~+7t znaE+(Meu{L@MPb;+ZdMIcI{r?>tUfpg2Taq9Ob@IjPgZC1o?$&WY2kjx{L=6Rc9F6 z2YW&zmLPCg6N$Cj@e>JO_5I6~v}b*Mx>jnoB5^x*d(}tM#OXey@0KqLFbJ$h54PD( ziGiN%0jJBJAb4tlat6clp&MAfj5y&7mU0(^X>_1k7>54u9J z`rJTojZk^{eLUSk93IQOf`YbFNKm%!Zwgb^nsvpd5w!lcDR*`(pG$1=^XHexI5{{z znmbv#q657hrzY$ovK&~L`1>2)r1JJ=?;3S%JsW68K=7pGWVm?>SoJ7mJvXU~7sD=2 z&?~c(q`r(AMBaUv_D^|497?x`M@Ox4#PRikk$V0>e%16fvB<<`?wOm?ej)6skdXr6ggu2Km=uq1WI zjveY78XMFl`1y0>dE`N^@2fo(s!A1 zf_tIbc)mj`Vw&N6AclNrEHq+XK~OlxvGOig9T~|FxHDgcECg-*x_fVcjex0tnP!9~ zSN|F_L8fRPt$e4O7zd2zIcPr?D`d{wdX8o7+P(uU8#i)MpjoW}x&PR~2HXyBHf%3s z0Fe!%XmG|4&UoxD72a{@)~zh=wA5@Tl`vZQ7H2Cw883f(B`Pea`g$tEEWJeY&wPr6 zw#hR#4smhKFJHW-w{G1Ehuj9G=(-QR8g~U~S7)wCrWOqkl}tN!oOyy>8ttjCrzfI0 zJw06)MIUu@jj20Di<>SP$o}-nn#vYa6CLcNCQF-?n9FGD?j@7lZm$EUBwkFtl&cdyesk~Gj&%_PF zrZLsT`(beA*|VX8)o6j4F-w}p4|FI^PT}*NMTex-t}A32K>7I2;NS?D#zOt+Jh5(t zKMqnq`99n8X(o!e00&1$NH_lux#^>)RIx2AaX`b%B0_!OXu#%(`w{D_Lw9@(i@pu# z8yR&bZAZbvEPDGi@1dL-$|hf5UrydM^$~&Bz6+la@WMY|yWhP#K)a^ly@Ua_*BSP+ z7#)d@gV3zaOQG^0o_uW^*zVALg0+}WP2=Q9?QxCJkHLse&q1fU&iT&)H^b)v0b8)2 zT#2Fi)2G{rDbe$jZl1_Pu!cr4N&Er13s<22yrGGj8?%iY1hJ=pUT>#{BEMA>dS5qg z=PfE7uN0gic*mknzxmEzOQbmSJ?OV|^g9nYY5*O1YVkinh+O~YB}l5kShx<^+Zu#t zpw00$wu6HfNcKq0?YvRstM3-M4+Qy_Iv4Q)VELa?~CB;z=!sD;qeK@n38c5g5oeUzac3@Ke?%)1q$@`3yXihA)6BO|31NPjj~|~G z1=!_={}~a^&&V@6``8b0ZrzqG+|Ls`;x6Jd^QuDPpW*U<^N6-mK5uBM?D7ado2{|* z=9e3zP&SA_oEEKj= z?kqKRTFzV)U{*)a>kk8iS^50e0n_hAnpWP^~t z=2(E$%=0E|WuE|hZHG_-TeEHFR-pe0mBb?*DJTUB)YKqnC(Y+YC^AYAEczqZ)kPfZYKXMfJ3JR7;=L*cLwJk6#ab#0gHi zViYRIz~Yd_o)~X+PKeJo3&3d;ZCGViC&ee0K%8JePe5y>8if>xghYO!5F;vOFa+aJ zryPf#t@82Xe_@x#LjJ<&`{$u-2R_Xl1+*)@%BMfybXNdt0ki{<=vKmBF7>{OTQKj(ea_M*zoy}1z?xrY=o*RNm4VQHy09lwPRYB{F3IH8JP=06?_ z%E>$IQy5*sxHq_?%>E?A`Z>9{s!+Q}o6@SIu9CzB`p2LWo~0gv1Dc$YQkr~%P2vIJ zQLC@fC{Z%_HYh764Dydw*@5fyAHZlUfZdJo%%q zTsYgMyq&__CFW8}1`!U$hThTq_GxD!Qdm`p*(f&7*$+5AUC;F=vzStEoq09hss^@t zV&4lO)`ZZHgn1yaGLNgsdCVkeZl-hN$eXq9#8wbw2m>!sRH4N0(K8@GUHc%H5*w0h zX_PYK6%q+or$%``&UXi ze+21$qj#J!)=b8l|FtH_5|UO@QVPdj2%hTjAAmi^9)hMI$nyJ(;Y5l#c4v(-DcO_t z0>4>LpJ+rBgUzNQA;V}FK2Xxp2{jRl!A1`clgh6Jzr*OzIPmhb!E<-bat4>K-g4mZ z#fvCx&xkrsrL5UZ74Oiz~2EhC=fUcSDzFNILbMqp4!3TY?m7Tjdq8KbqG;W^Uk zA_x+=GYy-N`?Wfb-yHi^AA>l#hnH6xwlXMkYx|pt+gC88M;yH4=kLtJ5d8|SZ+|WF zmekaoe7;OfEO#DK#!XUt@a)+y6uI77rzMNMk6-+PFz)Tm__Baqc5v2NYIaNPCant> z_Ij*lxSWZJ%yUr9sKoqi2-MHlKHAV@?tK2KkI$w!^-Rf?8)m#*3fghJkGxzqAV~$= zCkDKVKh`n0$m{3^KCT|h-}rUfSzYoZ!s>P*|WzXb68ge^|p_w?b<>-3T*Z?vO* z{jd&L#BxBJhXuZ#T>gPH?AHD`?o&3MIPqrwJ04*ei|Fg4PzD$m!~h6t~moz zg>(7_UiDDo?%5zJ+;lmYt@~SjGQ3#X4DfAb%m2Ml4)45w_b!-l@}Ra|ogJ-{q>9rW z9s~1!dE_QR;Xrii!Ze*64r%y}N$dgVZ`D%NiE3+iw>*WK%}h>z-nI+mjaU8mjR{6% z)F@OqIE)t5$ZN*Z<*Nd|LcJ$^8B2yTDqg`$Z!WuS+LzN{M;;~k1NU7J2?YiI9SH?x z$6F;ds7El2vgG-#?_*<6Kp#L#h{@8t{_pGm{hKc6 zStI#k-vb&)O3HB||FhQFfi4VZA3$aQqX89J?V&^O7djO4KR$BVkNOp)y7Wc`6_sr< zHIjQ>cFk(0mKyPR;I39y{)uN&dg1e;u)i<(u*T2i&My@mE;Qjmsqrlf0^R^N%(lI} zp5ESE6g-w)n>If3vbudBu*fVuCiKnM)1T1Ydz7Becm01KzsKdg$^4&O^vIWdni=Tp z;{rQUh`#u&Coa3bNz%z_5zHas!vc27?+cv(axG8S{JgbgO7q+YlQA8d#D_DRRxO3& z0eyyrmwg-7!1VMPPUlxYIQAuq4$80c8yCg@l$cY%NN z&qMF289LgE^Un!{Nr(08+SV>eW?xnn@I8YD@2=lnT>qI-RX=`t!81KQK~j<%L^!W9 zy>^a;3;dj<4bwtFzqbDV@<96alYhhK_~&ynV4}@gEVR)W4nN=buXK3f`~AfK@u3#} z3WToz4_EvDgDo^aDod_0MIDN6u_MEOt?*bekMYl6_=huu;-rmqhCp5f&7YZR*aLPJ zsD_L%l1fl&=Q-iv5P(iO4C6w;Upkp>28FrxTelMN$kI!RFShY*)$cEe7+Biif?*cY?3hr33S-RGX)e`waAWGUI zXSLk2a`kGwon2hX`TIUT24eIXb#xk=o$1Hio-q6lGQ>u$ndDXAS4 z1O*ZL=kZk$6E-D1l0$>vEH}X9bE~yKGIq^Ay*R&Nz zl1X1h)RsTBFm2b_EZMm^Cv3kdq>@)Z7my$gE5it-c5gY5gGKo9*pin4Y_OGlC=ixln zxYi$bAMWB)FOX!gQ_w@MBMjOA2awe_-1_S;;LwYDK7{0c{d#G?dCL~4qXq-zypq~S z%%i9&dS#*j*{uRg`3U*_1FV7J=Mu8i^c?Pb6}YO@P?QOIvPF*q9FAik;yzNpQ6S-| z?c|TbIs7i(jz&EL(DJk+bngf^Gd0xV|1s-#NOQmrXnUC}) zXywZy8Pc(+lRNRt;cM4?@bSp=xbdG`bZ!|AP&a}ZqgIMzGepYeCqdT*iI#H|q*}sJ z9vQicnPUx%3E-(D0e+ojYD`m$+n6)RDX~v}_MV0E#Z7Vg%uY%r7+%Q5 zW$Hx3k-H)gepPSz<{(?tgy-)C%zOR>&(0`jU~g#qm}mz`nSVcwY71Lq?}^fcgY73?^Ton zq--aEoW){?vwcCRspcY~3U1Vxw$)E~VAAewdi-$R2P^ILMgpk2Z5B`i{jLkDykB4c zCtl2-ZR+pQZ7FbZqJ{#@fG}yCQYX0-(%S&v5#5$-V=%|12mB)o#tT0o~qcxPu2}v^;%Inb6*FoLAx*MnS}&Cet0FG>RlY?~YiR3OJE8X->KKlYk5G zx<7+vZ3_F~Uw^$Nt!kX=X71RT5Yl^+3Xc8(%_8(d5FZ?Vrb|D!clDnu7+hR$-M%fV z87%6h**lED0n0U*&xWDtQj~aq_1sTpzEMT~xlGWQK_+9TU|nCwxJmz>#(cVq=Cv=n zq)Nwt3df;CXFz7M@`Nj&Iq|$l4~vl4y@Woq!U!D!ZXV8XK|≧0PFSt&+3p^>f0v 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 literal 81810 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�~FdI$`nYOeyk|@0Z)P#T^qvk|t!% z{3~8?QW5%Te^!uU=gFBz*F%AnRff4vuCCUaqbtALsKMyO^XBwE7UT_ih9_UfEEn{9 z#o6c`fkWasSJn{iYJgU==6*HPgpG%ucleeM@YHBxW3zA7G{X&|lY9=E|Ak z+@wSCh_=k&wcy^A8z}&fQto=(j98wQH2e3mbVTK`gXpfm!+JcKf>rC&dQPH)Q}bdk zFaATHYrl<9t;f8#C-~p1wt9Rdffy@MVV;!gT>U>BWjiTp9Uj>yNe;7Czvv=H^EikU zvgelf^sJ|!{k`Vo1h!WJNt5M*7gVK_B!tVHY|xXtkb)7BtU*2OsJIAMfv9$UvlH=6 zQ=|CJUC^dzf_l1mBx7se+%CgPt%%k;Te91z;)kD*4ii>n@`N3>LPm0{`A!>R8QzqC z69AL{9bx^c*CuD!VWw?nrTwTs>Wr#+dt`AsndUM0el3?k70SS%X%Xd%VL+; zG_$$mze6n~(ParFpW4=g=@&k>F+MSj7;5*6&p7ODQ`fcA0A&0@0J>vq*tR=V2hfiF zvg6eI?uy(+5A)wj_L|fAy$}b-+%CH3T>*yeLS}`NQn3HKNjY znpS^-LXn7UlIqMi0l-(=9yuXG)?6p6BgF+7_-5O=Y=1&ef22vGW7mi*K5$fG7OuOZ zpg$4Pn7F%Q8j~SF4`u>bEh)zh@=%jeM@*V#?yA;b9Nabz73ZQ0ef~SVd}}bMbR7OC z+WhB<>E-UD-#fCu9+{3K{+o^B;(yYj`VeLPVs)Yqh*H(qp;fdag5}#<*K}@i zmzT4eP}QZ%m1F&`wQ14z(fPw$Nb=Bje;5ofG&H1JpgjW>Aqtl9yVW2i9h(dTrP&4Q z{uRbwvUH*C&uwk@GzVl+CG8U=u^-(*eK?-~;)IHN{BA~cQPJ*S+0GibmbJoZoSfr- zYf|Q1q3xOGOt+2Qr+#|N&%aXih5Ub7yUTxCv-_U_+rPxW|NlSx{Oy*Y3Qe~hv&Ycr zfQIObZ3B+=NaB|O@u5kD`Ki)Zyqa4;#5uS?l8<dO8^6V ze=vJ9q-u@#G7#?O5~%g;`_~hP2O~;AC=oXC77$)brp=i?;6LW^So*7oeFaAaYOfPr z)_JrsvU%isd%r@;yKZwBb(Q1iV>g_TUjy5bv+W-e2#e#qH0PK<$rscOe{<65r*;y9 z!KC~seI`|a;fYO*f*bl5RR^szb*UR=B2nhr*AAgY4ASyS%~GCT`-80HO-tJWRhln- zwxp#e)l*`q?^JB4pPETWRRoFoShE^QHN4DyJs6bebIWT{;X*ZiE zp{L(K2Dc2q`@Z|^*2#uAh=A*MftbRy zZ#yOf60OB#NpWjBAVL)rCxoGYvNQAi=v?OvtWe_5hB65zA+_KB@ExT6M&BJDAvg8K zRlo>f&tStXW&6q=v~i{9iJT>Xy6q@&L#Uq@(H7+_&*1&kp_i<}BRL^96NQx$Jajj{K_MRJEM6;ZucZR~dgTS!;*~r7mgtu(% zChu);LNn}if|>IKbV;G$gZ#JXw)q!4v2;52)`1zYt_l}#rP>OPQ?GqN1eU1Y(bB5q zk(RR(Q>XUDDOO;w=N41CA(aY3Q^#&9s<1o^ucgP$*I<)E0Q8I9v&@k=0&k$ZNg{_b zi_#B3Kg#LNx~{<4saE29c#tl*1J`c7=_n5sUow$D+Eq!J zw54&a?izRj1|2Y5owZN&&L$MKdt0t>sWGFjhy=BRA(LiRJ|PAWlVb}x8( z0#?i<5e=VjOrbY)>-E|fo>MFQ95neHB65TgbgGsOX+@Jvo!Xj9ZK=;_T%Cx&j2Pu$ z{?JU^(BibOK!3?qAb)s}n}u!*J&U_!yXvJc`+-J!p8o(QG6WY}q&5={l=?U+R(=H;FFd%%5} z+k0(F$NRADc~&+Hjdy8M`A2cRRP4!$ji;;qe)I(58?$@FIMe1^i2hBt~K zy*^S2pFjT2_hp6Mpa$sD4Xp?1qUPGbv!S-rx)@<4>$CN#n%9%6f&sgYX?#k4xeV108ljQBTjJoHQ}y35Bd%7-DRNm%H(l zyWeKRBm2fph*i4&v9(0oVY|S<-fY5>{pl>@&C8uy5R2VS0>4ic>3Fu(b#i&`Koq*C z0ObCBe$V6Fo#~J*7yMJB`7~Sj(7q~_Ex9#Z1OX^2$~*GDKf3s2r@@Iz)vLSwLD8dR zY`G!HFC5p{T#F-#^QIjqOs^3%=cfyd%H~`wc|FF@Z_kB6;J%!!5mY$0U*GLgmB4z@ zW%QZ=8RG#tww|$J=UGqin3NEmQ+%Z-h{gPct8mbxpV@IYZbZ506SmIiH zTDG-}aLawtMf|Vc?(+`3y+S+6I^n!FFxx%W_hw=2#+_|WrwxDis<#%C9k3r_K0}r6 zzGd>pE&0LB9!G}Hjet*qGW$G*Y-|L=b`{W{YhcO)O>w2XgnC7wbmJ8`_nzVP7ThYY zJ7zX~KOm{&1h3?jg@Y8Kq!{SYeeY<@)daH~qku!srEsFVC5_PN6^ zGK&1!XE`Go->T`us=opHJTVpPO$e@IGr()oq`lX@o@;Ns1+3b_y`zJJgO=vbsEJiL zsgE^}FFdRLNydEy_etu`Rs%A0%iREXsc`w-A;|KD37gKp-G3!$hoBfjaU#M{LSgg z3_kXV@HfJ&orYNd{ec6AUqg@ScZGFq)gk84p&iz%qrM`}srtz09=xhCShmeS>BDLs z#&{~9o39O7k)1|JCFanxxxv>CmWdq{=SqVyEKx_2UZTj%=C(j5vtFr*5@d;sZcIU? z7U@TkA|PnU_<6kyWQqv~q?Hs+P0vN;G+<2-x{rpCewpLbs(z?b2J#^}`OM}><$O2s zG@R9afl$A~Udo26Un(bSUcLvv@ZqC%MoS-L04uF?u?WM*5eIdRC&VT}vt12YZG=drtTJ*JS8GF>a3#F`T7ws{`< z;Y7_uW7jsvE6px@r2l^3IkNs!4*kN5jOJKS2FP&ji~7i91#6((V-L6Uz#a%tK=h=- zkohwQW}RS@$y&)m0dhIs=!9X;bRgNt^)UL{wb2`Zn?!^`>;5!huD5_RK@rPHD6B)+ zb~mkOQ@y@5<~q1g1*^^_pBe1MhCE%sF)4`O`LKtBJr9tI{!WWWYy?kxJ6>!b91udB zF7sZ;(%lIcG(O<*LK^UDo)|2yA_6^C8b|O07?NcX2Xk3G0v&EIYr>>V=1Zl55 zpqnSRJl+4iQ}>Qv{pQl#ncjOtI@W9Bt!~AWaF0$Snae># zeeXFHZI!7b5%IQF(RN7oj?=TSz|T>}oLdr--7V9+LA*Nj?K}Dj4FY~5l&195e$lZl zVJ;(#M{b4T#GkcxWjzyn5$n_$R`0Ra_7CyZ1>Bs}$QA0RK5Y5Wo*Kma0?w_jPFM}k zA+$cbYTr*XPi_~NxmUTLe(&*}3XQp98LDFuFax;+OwKt?mNW+;P^bD5%*dxNw@A7J zChx>Nox9}rBEO&?l%wb02pJg2>4>%Yz)wsy2E|9X8hozy$EgJC5r5>oh8ByGm@=A88KgkGzAsetoMCANt1 z8jtz-RYPZLaOkXZLUA9iZfgh*K)eTJJ(K8XEvdXLkR+$qsnDEO6QvGQWE;3sboT5h zT>L<*V>(;JD|xc1*K84?r5Equ>4`7w-HABl?+GuefcRhuR|PoW1H7-4llo`)Ph*ef z&pgeZKsjX{x7D=remRBn9(MHzpko>VGO}`N?6Gk)HJV5=RwjYx!n$Fw>85$3j_2EQ+qd6;Q4)q9rm+-P!CDD~%KwmZ6@bu&DW2qusHQH@^VMu;77qe0%D1^ZE^AR>TJcZFNs+Ozf~JNiJEG^|i4XPV@>#?0>>2#>Rw3|z+fD*S7jR+4*ICoqyJi~adhyV_ z2@ON^!u$Ss4k3`jc3W5e0O}H0GM`lXG5;_Nmk|0a^j-j=$LObbnO+aN-K%@jBKxv! zeePO5)4Tp)u^x#|)#!ajvs#|m_nNK&_>j?#;B2eyL9$*Z8<*sS)%SBr<`=KXmnIvhuzGFu-&x`I5Y2%*Dg|g z2nOTzByyX3$=~40Q!DnB-lNxiX=FeRpVHIaPv|dC%dTTAj>$dB^#54rU{DytVX4c> ziZ3duyOWY?mb>>54`j?luO&! z_M{PJE|epsQBWWqH`AxGAK(EES z>R+?z#-G`ABuKzRqQ}h2d@5|fwN8_#&}%`OTh-#}6`+Iv-5j0Dl=nB0?xvBRvXug( zJi^EyDg{8-#Z}1YK6RSaK!RUU5ivzmQli$)dbEs3e_w&|8wwE!K&qK8Dbem)h;o>n z`wr~GxMQe=YSouSU@iV+gB8s#Y#$wF&GYJO9w`MXGN4>&>23IRWaHEM`D*0OH|+-T z*d+)5Ly^O-0TFckxw*NonAqK(u;Qqe?na|my8RYtnCj}0FzfjS;x_>j9 zz=?d6*~;Y`oA1@BhHkzvVZy6(v;5q>3P*CSGcWYY3$7PWuLxgjezm&;Wvx{nU>4%f zCf3pCO$^r(dHL_2uw4$8 zSS2j1x#V!32$crLW@awM>{t`?)IXUT-aE)#x?#cIz-K=kZFzk5zKZc7U-Zc~JbJQ( zxq#X8!U$)-z0skbwnfPIcBHvwIs(U|)R7eX z<$Gu|9#iET>ky#Dk5ee}~ZRQ(_9X);25K z%%z_6xmQBRY?G5gfCc}7c88UFs!JlBWZ%n(cRaV#A-l|{^|kTz5zag-3= zopD(oSL1_8>s+@n-pk0sc?UoEJ|p)_m+VD;T9Z)dbCARqcOmhRU2FvpsYtUfZTo%e z;8DE(9-667k2XV26Jh3bUMB$j?c4Ob1udb%?Qhy{=cpH?J zoh-AVS;{gqSx0F$mkT89DYkH#8+o3XZMDnsR({aUlwxeioY;|~A*BW0P2K7fEw?SN zb6k1KIR1eOl~>@u3un#>DW>QMqsVn^ z__EQ`DM8{NzxqkN>!=r-RjB8cc@&QYoim{8oKjh+3el)S9eXQq=y8FINbEb zJ{g>F>BpkJMp{{?!s$1=K0lP(;x)+xA1-mjNjGnMdkl3h(Cb7O(WPS*1Ju2j-wIPEj0O)? zrK@ZGy%W{?^G!LYpDgC*OyguJ#^I*xpGewXjh2|+8CngpTwgW!`}#?;UL<#DmZP11Xcdoi!g9}>b3{dJ zi9Hr9x31}aOB5~gSsl`Rw{bb|2{9nTXTV^}Bc`jD*XoYHuP?zfyM?xC?SitMf`Wpq zg6ZknA5Pb)uQ%sDGRd6Smpptg#g98xLw%Zlc**<|=ONR*`%vlKiJplb+kpmz&s8JdCPO$eTF_Oy_IpvUDL?b6&#O>$i;{OszG=heK%vTq5=Cq5-gf^dry zv!WWWLbJlc_%Iy8>oK`swBs|EN|_yoPKh^Xdn4{Aegg3(xke1a%!=Q$3Wub0h&8iS z-%aw%6{+`FmLe4ze*L07EyDR2p)Ft&X#Z7hF#92i`1I+-rij-MWPQ!6_=J`DYbyg6 zyIp5;3IRjZH|dG!l#S8Rd_mn$Qh!Y3rWT}|vvX{kMT#JZbW{-O(rW-gKzd6E1OkHe zD!ms)KtVvM(m`rM@0}os^iBu_0!SzH-pPr+`mXO;>;7}^@0N9c=ge9_67oEI_RQ?r zvu8egKSFwWo$N#LI8W7F3D@wGtmKRvsS&6U+^O_5CngI@d=a{VHk#u;3-4Q_XKsa$ zz+vSTo(PbN%7VjGju(gCMT)}e8E@Dg*1g`;c?4EcA~Tid+YmcaJXFuqkIa*b0JDmmdTaMz7)u~erx&#ZI*p#ozK9h5r|6T84-k7L%9tl{8`JW`#QPV-_^Ukb>2_nKe9!(N~BN5r*yDe!1O&~cX2|9CC0s#!E8|f3qq`Jw zlFz`?QqRD`-UVP5sRsCsi*48Pqyn$1hT_u;iuBXX)9@1)nyk)h;-UE*9^*J0leQT@~t`oKHbSd7@)yq zm>*d9X*(9~%WxRSJ&3^Zs|;v%FKPo6Dq!e((bD43sh1b~! z0*q7Z^ZoZ5nfyiAO#VbV{2F{Ynl)`C#xC_r7r1iG6>tE_+c@g|5E?3_xn$t}wQsz- z(2aY5zu&j`nZLtga1nEV1ke8W%!|6?9L27WD}^7xd!yg4z)O{C(*T7Q<`h+tv_IST zk6_wAhuFN_Bw9cd=DvNe(SD4pop8C_0 zuDx@cerqKxCh-e-(VKX~{NXCeg8u5N$gwZK6>IsAV!;TI(ZxD@VXB}aRWd-0)r^I0 z#B5E^x^)K#d$~^Ddp7Iq`?Sze{o|q@T=&8V zvZ&L1vR3ll1rdYpy;=bOQ^ty2cf_dGI5n2S8r=8@k|IM~IAvCO<{`&18VQ1d9Hw9# zeiERiG;uZ7{SA1{)A$C;W5^-KrSTB$4FL)&$tL=ifsgrdMK(e`!{bY;10_u>N*`{; zc01*N^++1M5K%YsKTBA&hm+?U(ZABE9QEBH#WY&is3pBFJF#Hq5c|$j4u6pp*FQ|f zs5Us1_y9W%St^ERRx@}#&t6I^{OnuLF7!R)x_6d|4ADYdWysV^m`|Jd$?E#F&DfD6 z4O&W;jn|m)lfIdpe#PRc=ZP2A$F4wPj8>+xO4VP+y_ojvuo^Awja~{REtb{6tZ5V{ zqMYXQRMiH4!&2k+QZeK-gP~#W1~Ij`yzC8An6g35TWH**Sr9sTH}js#DP-5F`+NL2 zX`o(lB3ucy)`bd2a#Xl%`{2C=`pkPb^)aTPAGgiA{^fPVVtC;searhAP_OUucxPXwtkx+ zATl2gk7BMhD01`k4d#E&>!?Xc?9!pH4I7$$7>nE{%Wf09Eu~6|@U6ct%D#sLEUkQQ zOP#CY+~41i$|{1^4;5uRa$V8}!>b!1&KItQsYck0@=Q5eVf!_ax%R~vgfcwej;Xng zEIfW@<|X?Tf`Okt`$%y6p3hu+qyyE0`SqIw1eVS^ve}_kVEB9ZSnJkqba|25{teH` zdlQPKZi+hDT^z9Dxg02zTNJxWT4(W|i@nP6m?K{)7Bo3~?ckMAUR9hme(Gz^DA&A( z|GWMnEh-qAp^%utE!PW5oUIq1(my2~?y!Fj1vrzRGd zFPTthV7;*#u4Rfkz1J5uUjF=bDh+`Mc@M!QJbUW4pRvv-D_AP3$8+fR{pTp*y&p@r zE39o`5*K8ls+|J^<$n2{tnHolNSjtFMr%c4V|{L+$+j z19c5fo@Xr-7+BKvk4ae{0>7F?E9hIOA^C)nzfQ&_PIoqi`GCWTpqiD{}cYJU{>N zROKoGf!KAwUA);}!eed}quS>lT*X@yeW+C;I~Nyb^Vjvu_m6r>38Zh#xQHPK2AGBg z7PdVO&bIsc?%-`2oR9;FS6sAs@uFgq*U`CWbmbaB`jrw+W&3LH zews1780dp~&9$Ya35+fX2+{+Me+@4BcgFV#iHLx*vVjr|kt)NcqMQT-Gs9`Vwn9mC zBsch_@EoN7^83p#@t7cCJa>2s=zn$B<@YQ6uNmiG|Ne&p`XBrn691572m!u>|IiWL zWjw$C(Eo)CJ`N0Mg#8-D|4`F+W4(FCzwer>Mas&`@_r5O-!!8=hBu=>^j~cF|M{-{ zFW-Wr#x+ZDvZfNFQ>eW8p{9KG^R{=_yNpNSWfdCw&R}eP?Xci!y981fNcl&nGczC8 z)@qUh$ntHA&3ldYCPhx{4GM=Qkx0+KW)>1oaMi9qE^D|*1Z?HqLaIE~#RcKB zY0|Odh;EmXNvR_p*oq#aSb54!?esVTwP4YYv~!s6k|qA@pc0t~o+Xv%k_>l3q26(g zW$^gbSSg7tp54Q6A<2>4-QvMO_XwQ^%qOCH@?a9}$ZDs`;15)Pnh$tzxBm4@nktA5xsZqqmiE)V#KlTqOV(kd8%@HI7RaoVT6)Ke9t8s&l9V} zgT3kf*{>$_7tD91vOhNJxEl%qQ_c>=qaWTK78K!y2L4DbGINm1VU>hrDrx=oGa~G^ zz)R>vi&qgsUI$ah)p8L7;r{hdDiU?@N8E!P+8lf_8Jtt8{`RF_nH#PiRdLW$@>J%= z3S7#t)c?ph0q$Ope7WJ54=YnV3rT#i@A;#gOik?nb$CBY(}!9{t>u z)R!!WQnFwJ&p5T46XzcL?kD}d{wU%4`%!?*uYt=<94i?+jk4TbVG;X3l*g+GN-*nVK_+ zPUAKUYdU_J^Oz{1fZI*6jP0SI+|M8E>t}Mc?=ou0?g~8ha5pZX;qqO7007u6ZBRcn zLzit41FR#5UkQ_HetAIs##hkIGTGc$r`eC`FN5!NFW+95J$LK%ICI174A`7_>7~LO zdY=;nKfsMmiLGN1D{1bk8u00#DP08|+84o;5Q){>jktrUEm=NO(ooc`D?^mE{T)xw zuFT_<52<-&Vv)J|bW#h9`y7H6Kl>hk3(hXvT(ZgbK19&Cxo#w6ybRp<(>Q@bC_XAt zzyh~gbGj9x=;CbUX>7 zHR1m|y^6?OWwMNKKwj(8(@Iaqhg?l-glgE_(rBK++F1C@i8sa}W_nRX^qM3lSJ|I7i+s$z#_{P_DD|6Of5$tGs*iZH=mO?q zY*h57$P01Cfl7zn0u6BVMT(?XgY*yC$d%cRgCDtdb!?60&|x=Ezi+qBV~+FdUDnw? zcncX+ODv$P%wwH|?1m%kk}CZa8n``X$oJhCp4D+*L$-Frl4p&Y%I&^hVHiqxvNxa z@ms6eypQf41T!v7ue6;q41*`I2ZmbTYaa2$>lM6xSX|(tKUayKM2npAt8$syar|jS z#NxM_cafd;FZd{Ux2yp>M|XOSYP9qTyFr_T zU>}qujn~kvP{(y*o`z%P3XgL4O=Z1Gr+Th+J&&$?`Aw~-R)+g-dIw^Z^RZpp`h_&b zETT013o6~C&C3pg4!H_Zst+*uWqh~7ldsuyvv>N2nY2C2bF5dg?8SHoJ`u$aJ)VZG zt{M%9J39k)7eLZ7QmPGSG$|<7GDrE)g~8xz`(X^DEmb}~H~5>HKl7HAm+M8}u$#Oc zh&KGyj3Q(fK*4mlfXKj6W)4`?+>w|EPGFW;fjT%e6GDx^Pnt9X}-Z z;#d(n-tOP8LY`j)oT#FJJ$Ry~n9?%81I$MgYLytxkxdahU`OkvMy5cuBtIn#70WpM zCNW+|@C!oBp-6ZB^~m|xV~69Gm?&0%I78E_99N2v$R5a6GX*I+@~I#t@ffWS(KKEc{jn9M zp#-U`!*6mii(NTI8IB6qL+T=AMIxCy^WR!Ut`_s~Xlb@eD$uxzrksW_R_Y@L{TaMs zxBi9=5#-)lT0`f+E9m3}or}=%L`jE2LYs!D-Usn%+9V;W^0I~SZo*2defPxO<0P+* z<7z<%vpED@PiR28h&73D8en3*^zhPr-iS@d zPevyHcx|;La3!T2x@=Lr_iUL3a6U^>$Yt^K-|+y!d(l4zN^nFM*ZemEA^5*BUjJV* zsHMY)8(N;8qOpIZdz4pF@|69OUGTpym!NqGzo1>0F)*O}_e<~b=Y`_G6!D*5`u}(h z`w##B#bvcf-e1Gw+P*H=MW2*Y_r>1&W_UcSfR3R>Iwv@Qv$Y!W%1$@uqgVABv7i%> zqEkx1c0|{_N>u>gXa!KHK zEdD^b>pqv_4##*wdap7?gJ0^JE69Z=J>}o!Xi11LlR97r%dsw#D1-Jt0}9m;s$Ls zfajm^h!iY|-yZGMD^Z);oB}Uwbpyp_e2`gt;I+x6g*>$4(q;4~02|wiAN-PCc2SX9 z6a^ifirGKPtayVSW9VY^u9wKzriV`k=c+v@Hv)FFpv=SxPu<6?ITjH1MYe+3PPyS4 zX4M%xJX1^xH!x2c>*^p;^P8LfOtML(ztd;<+ex-imt6gf&C23kCPv@UZjae_fzUKg(Z$DHdu4JckeHCH= zA+n^JOJOH~B*~r^`zZAzw%(>TTD%oIZ_%{a^s2J2T_9I&Iy$VI8~R2FfP8zCnal0D z=GnN_!e8g8TLO`ad`dB}B!lr=N~t^ldI?cOCqH%*v(t0i>*sO%-bBHx8s9b`qNt^G;_ z@8vt`jif^X1jn@D)tHn^mz=87B8dpq8FP4FwOjWz1FxOg^37;e_iXI&tHjP1fIcfu z{2nO-LjFUvXwi8sPw^SzIzTrSqT@a+&JgGt8 zpU}(hYgzZ5+PmJaHBR+aJPxq{DZdCD+zP%fA-xgf2ggPg&V=7ydDqMMStbg6h?D$!e@yz?7Te&I& zHEXHAssm}&GC@f?R)ZC6iM4gly;IHJ*?i|BU77vZ=)hRDLACsCiRTlu=O`lo^g=iBn$|dU4a8h{>)J$Ke1zY#U6z}=^LBn#( zf?Nh?wB@Z|rwOnqgmg{AL7v+>3!M5{4(8m0qu4kl&v)w&I~hi0W!pavq#I&l?@)5q zd&d*v!*3@#*YE#m{AT@oVUqfKjI_c z*&~1dZ02?9Y=j$^e&^9yWxlYN-ph9K$J>o1FgOQOHWzQYvbx7S#I=pfJiErTVk6Z`d_H zQb#Gh^zh7Y8%xem%#Am-lIZxAMhl}M;R)>hzF&eL=%SIC15(AJt&1IaI5dvp)w^`G zA7oZRkXQQcsTQi@sXFw&Oe~^)a_X{rn|;PlEO`%@b^5vg6tF&Q~dCM5s9vhtwHuQDMB4VtR--S1$Z}2h^1D zlY>sQ_)5gc-I#lp9dO-T!3oljQfI@DSI}YVz>l(Ujx){SrXzV};rP5!vWyYKRsrKP zCg{lXDAb7Rz1BN1xz3_O; zs!?R=wai1=!PY*oyltv^lc=hcEq8QFz4goyzra`hFJ5V`aeci?!^`v5T)0_4FSJs% zzTunF20z5&<2r1)*&hEqyqmtbek*oct;&e+jwk1pcSkTrJ8O_kJ?)&;iAfm{ZTPzQ z!5*2?ZFSW5)#A9*O?7LprlsY|FlO-5hq?{yppvT+QlH8iJ8}#u^~|+i&rs^<7(M#% z2nnc*xQznmHAzHj&BbV#Hm)=6bzA(W>OewZk@pc zgTfvzveTN!!W(z>MEuB7bAe zwqtjcRRW)?O+U};ZUHk$FT&5qyzZfG++=NjCCp0Zhrgfk>t$$c1JH90fxK-)+l;9sn zdE?heF3jc5(a&!v$`nxlsh#?%7g{@wpiTAaEOW8!=B!|_xInuNUoSeVg!j@+jNQA+ zB%P11#LRfmHzK!_>GgNeA$#ID~f6YDe9w;xLOw^qjZZpbwhkQ({%vCE?HW&okl)QLu11I5BSpUJZ zKiD#4-u)B9tH2|PM?lt}K4`pHFS-(0s#Iz2nyNzW)b@j;OQhs1cG|B%omBL!gw3hh z!DX)aguNvXRYl#uy3#+|?K>7trLqp;Qw>v2H1IsXcV5!K`?}0J&ZciR>aiI=sKNzS z<;60dNlDx2zdA;)KC~quMIEQ#E#;{$6~mzGy;!ulx53&CdPTj{EukknYo|~MwS~0` zG?Z)a*p8wc`X^b>#=5mdz>NKU(N<#=6S(KDRs2Q2k{aoPg6~-A_ED4NYoO?@Od;nQ zcv-*0?v`v6otfu)4)L0qI1O&iA*hPrH4}bfsxf`i;7!_wX3lpDZ-N?neo8v5gdCm| zf~q{6r}7(Aladf`95#T)pB3VWL@x)lk%l*z|=GpuSEM?(vfM)WTZ|+Pj>xQDpbCr1hN_q(;VRg@X1PG=$H% z^?BVQ2^SGrxl=}%7FT*a;^!x!S1Yv-4&wTi8%L#q{a z)~&e=A&#HCDuJagA4W$Ye6}CDUfjkss<(fx3R4}lvcmIYKIO#4!$*ofbSr>lYH63r zxoF0}2+Y72eet%}L3`hE`G$VnTPpv&FJK3q0a7CY?-#>n#Rrq&9dt#Z(cIQl_}t1k zTnVj8E8=DpCd~Af$3*&!0m-glRudm*s-iwR=Cg%|ji!?D@uC#5kQiCAbHAd+$J8 z8D!27M4B$;?zbARQ?EMcsOf#G;Cnk{bbVm-q4pImf2_9I4ufO;7zH)`_?Hq^)e(St z%BV~wdf_Sa_*+UE+ZSzXSAK`%g>5cJj60>zlo47pp;qBITHS5T-fp!IfjgL{Bbq{ntDil@Sm?Kpmyx?i$w3qi65F%m3&=3XYsI5wkeZ2r!0o zT7>WPTMocx~f^s?Pm38NO_W*4>U5z$LqxXW@8kOHg ztYyYSKb+rKKi{I@eZHikn@7y(Akot(1*!I5gMr;uyVo6RL335i;|CH;mK9+(hcOhb z=JCUBPi*vS=bd=}sfD6%TRhwFle)1nHPT=`Gu{q5x|IIv5y7Ph?fre?sLRapMq$d@ z)ZFpOcKfxhap^sKug5v7olv&+Zh@;ObzX{>_%2_bpB@q*#t{e}0w@)RV09O9igI)^#|;a;;uA`GI1 zFQ7QUGP$W;n^s|cRjJ{*UydQM|Ft7Q1`Tk%JL8u}HdM-$g7$iZpM($T&yS7xfi2&E zm;NoCh13fh4rXMq88F&YNn*>GT*bd4MI!X zusRws=GUB4hk2K0JWSzVD;%Ajy;WG-D({$~O=c;EcFxtwR*)I+{GKkX0&HJriYYY z1dg{mi^Iw>Ot#C5nfpw59V+J#3ft>svrvE2!^Us8f10CH+Q4XQ+VKq$2W45XkK1?F zyM~W~gzLNOLWONL6472syC@Yt{!RM_ObRFiei>~BWkjpW>nwP?lR!#q)dt7D6%1CR&zR^a6JVVuo-huC5DsbS7(={ zlg&I4%O1Zv`(v7Em}fb?osP8I(DNbrL~o_XqbO#@BBQZ;1SF*RXeD{4z$nWhOttgo z@QmVJ#QeK?3+lnslkx5K|nN&DSMo>Ir~*LNA~vg;;g4h3?)na9*< zgzYqzePr4fw~6u!ru*ddq@?}1Dh=IekLr;Z5~&y7{#>4|B%vQtG|wyMtMMh`puOaT z%Lto&r~@D3n@26UK>ZBk-s1Nw0h}i;_v#r<>lRz2WlCn;Fia*JRai~;?-KH{lWtUfy?1GpVtW!a{^^-BbhSX>`5 z;_O1!CA6!3nn|#{PDXV!Z_cDYGWh7Dn={w`_DU2pVwU)q!e`v>z9ynBdfLXq!UoI6 znaGmZIj05_CmwW?vhx#*Mz^n=h;t7gU0^5}sdKizP?&{(DbTkUSBG*CR&?8j59zY^ zacBgxP~Qp^bbD{0^qXgm+UURq~busx9&+f2q`0R)y{k3D&XmT z?-brAsvmeihhj&dSAO8s+zq7U$@Eb+A=N7^K+E2)UTgd!{7_OIoRU;%&-=`2oPLK? zU8`RcF=|(x3}Y@YqC8lB3KBRJY%I-toK#i-oPJ{0%r6MTTImkrtKv*>bFjyQ^T?ZpT$ zPyWFxZ;$k}y2Lj>8hmY;A4V1qG{nE^B=6;#0m>lY2CFWk_w*B!7f6pW3 z1>9QiOJ%d^#*C#`Z(Y|DRtOclMnzGktI56$!W=r-LU26%a2=tUb#58|Lkk%>Ea>hN zC+{AL{M3Ds_aLh0Yw>=E@1~8jR`8H4v7X>+g?U(Y8wzH)UzF;}0TebEQ}|r!>-vKd z|05act=xp{=Hb!Coq9cSM7;Y399*m3w@TA@QG?_SwV$iGhfm-tX$j3&_m6o`)@${| zPCyzN*$#~bR-M8&23lWEpnKxsn2UEg_70X*=Y_@-V6R0zf2j8Y3`>sGp5s}8ZL4CZ z3c8T-{ZhFr;t~p_P&fbkeQ8A&X$L4lRB}J%xLg;6K0=0hS*ewF;88*N zn95a@gKz;{Cg-XNLmbt*Vy?p{pHhgef;=;$Dpo&=M~30Us|I67>-XyqEPmEior?n` zp;MpkAII88m6v_NM-Er6GBt1azz2ib)R*5>vRbVzKfp%E<>kG^7d+e0W!9xRzLKgO z*4N?gHYo@pg-xjohuBoty5K`>!Sc&`nzf&yBxU(x09jrk<^5HZWo!T9rF}H-souF+ zt8_TExXL+S6y@DnRtHdq5La3*TbggCEAo5pAM*Inst(1)L^@~)v z#DdRhxa6r%YUruqw3n(zQog$3i7s?QMBVBQ#&wi3y5jirVT|^x$`F#Tp-9G+&))G? z9m}6-Mp#ul2Qzl6C)uZKRafJGl_{dVN(gsqZ2R6|rxLOsnw@ zci1KPj>+G)`S3ureEEGduZgLJg+9IjrR3>Zi+?;kcSM(E;WGw472&hFYOGc9=-b@Q zfqV{$_L-~%poczP-Ce;HWw9n+-&sjsaacthIuqersK%(KfT~|Y0-6x9phuyuJ$>=S)fnPx4 zF1y#w+pcVPSjvqv>mlKAN%_wK{)v3`BBozFAxYYPwt+XxpH;s52eBpKpVqv`?laDc z<uTYcG^^qu0(rt^TatC2X@Hq+-vHE>%$B4a2cJd(1D|W!DIoGo2Ro1YDkGEi-Z& z^DVR-kHR#!>k${aO)Oe(3J*a%a0W+=-YYBrr#!c=xD|YjaICbUHMU-|wtABFqvYa} zt3^1-*Cg(;J12N6N6tkWKd@O@STO2>>4hUmq~OIYF-Z=eADe#GNt%19+6oSqju2K|$T;sp-rCi{%?Zk?W^XMv-gT$d%PLk>dq@a(DiV`V+;OY9!>P^zgId3a@8o*BNkc7r)YdD}?pAtEJ73$5UWrkU;&7;3Ll*Mi{eBlEn|*il^Upo)wI0?5ql%{1eI9&c zfL{f03V!L|Hz7dl*x9;MhSwNQ1q_gY>|3>qKV8Gc;uFsb`>q(hS0KSX@^LICH09hS zgh+}Rf4T4fe0f}^SNz*5pZvNnMLXB!+>+l;tihGni-Xmuo$fh&Dy-UhZ`g;o*HA~{ zZj4RCnY+E#*++#1_K88`Q%Zj60S0{S%?^*^_=lPGK(jHRV+)LZ)!Dp#g6ccp0tBJ) zCO@YOUtcLB*^Yx5=RJ^w3IfzY&}v)iR4+MB955pv5oheWw%?I(>8%@Y)h+3PxW5%D zG*z*GUYA!|2EIroW^m`B;z8HLU+ESO|3drC@4ttceIB8G$8Z8UBUMMpy=F;D|cV|2?B+jv`;tocS`i%O1NeEGPQ+?>B(1- z841@Bv~@nRYScP+0=wQwZ=YXzxYSrVWs~n#WamJS4Y;FU&i~MV$ z1kH~BVTW`7(V6!Du*v`3z+aON_-`Ph8rWr`HgoC}=MRg$eW-cIN3j%lvr7o{>3jF# z82yYWE}Q+S&~WtdS|+?tx_M1ue+XsKr5jX7#Qf4vuhzsg9o>c`Z}@X|l=y~JZj-97 zj{C>KGupp@2zUppTj(amE|&hp6bohwuHFsXH~;1UTFid@w{^@->8D3;S#7pssht>= zr6k}--I4qA`Sl~NL&^X_+WlPCG*FLrq_v;R;nm0BA%kAVUDjAiw-hI9#8_z}V%e!T zF(!BK=tWRXqqSYZaB5U9r2fpV@QI{Lm!R6DK!fsXYLmXyc{31Ouecs0+1MPydgDx=ufp5YkiK*3Se+sl%*9A|9W)BGTi0|r5Qg3mKNd5Ly;ywa z>u*-Wjo8(ONbu`__?aVw+mSpsl~YD^{l#mwl3luaJ;i^+MfHP3)B9N0Wx)CNKGc_F zenORY|6m82=mR<%6r5BE?|2`t=OH~>3cmKl>|6Za*wPZaX!_D+y-T4VNi|J&JuRphY&CbSAVw0~;gv`geB}E2)aP@-f@CexdtN;1AP~~3rLjzdd zBCQb;GbbC__ihDST7f#|ApN5$q8oU_Gv&^X?9^T^<@Hq#xh<(-wX_nk4VzVuTuGJM z-`~tJ;W-aYt?|$Ks#Y!fo-BP{c@s5v0X-Sj&Ufj+o|}DpwJ~sIx7_<3BcPuwt7nyQ zASH=$bhj;vGtEa*HrT35AcEoLM46p(9G6~P;nbmxFh!hyn0?>vbu+2xU44c>oZKhD z>$~G}Obng3%i|E{iClpAVV=~4=l!4Y%SGPibfmX!BM*u%G7WtyrM)46F+%6^nDfqB zC1L?)>d-{T$c-k`uv9MuEdF&%;bb>=ET#gw*>I5>YTXdpm5|>S_L!}&`1Eoxb#d+O z$JoOO!ixDDX(Qy1v~D8~Iee{54rg`B4zR_M061dpAZ4)#sze>lF=3BvB4)Id^$dqV zzgbHTxTbdhtI;cXjmDD|4BRPiF9;zK6xz2qe=K`zw@Bxrl#Qhd9p;zM2-vN%j_7+Y zvh#!g#Mt6X>dEZS$g0I@az}4 zMvW=HMI);8$lw}$FXc34qKT&PtZmNAO%)nR(4jFqyQ}xF;22ck1hUFfOPu$A(ug~n zMiL|SD=rFS+gsk+$6<9EVXmr-(C$y-&ToGN(Kb%0w~xA4!hg88YzyXt^G3YS40}J7 zOvQJIg*mxXBH&U5h2o9}-JU%ES_moLLJZuJAZV|RFtWUor#QcgWe*nCy2$<~+v}(Z z41I1>k#n`%8i2w2{>Jn07t4j>W7e=@RHuH_7(JKuMy+zaRTmNwsxf?VZe79S@^{O^ zOOKcDC<1#jv2fY;D|cE8D?Y=P7#`pMMo5C?-Th{-t*_5hTs|>^Hb3+==#M`TV{02d zo_g6@R&a^!U*2x4U3&X$ad=~P-MUs%5yK&r5Za%XJ?Q^r_@JmM!qI9ZMQX_X9t)l7 zmJj+gvVH%1{;Apcy0uMpc1LC)PQK)AAWLPk3*jT(2j2iqRTFiQwARTw{|c6=hu~ZK zD%voeOBHZ1{GvuCt;XqjTDkPcEm+;j&gamZx3zV3zqH73(T{;1DMuAR=nJ;#(~^HG z4d#7p)>fZQ%P6RrJ5F2AAN+=XQ1hy0_+Ni;LuVsa4-sg=GM)a-*rYjcib{~%OYQ^GCALd8F6fTAF@l0BI)Vwa|ba;3>JLn z^`#prh?0_oQ3+KhmoV01wwesRjN_ablcyS8gUQlIJkwBfyOPrriX$Z#a*aoRt)7#^ z4cf7k^$SU#xvC#@Zh=Slr$>iT$~yZtC-KD%S$xxaBfaVI|F$p5`6lQ=rVUODaGa91 zyqRRPAiBQX$YrD*GS-Bpkg!+czOK64v%?aB2aw(4ESQ3ekx1q{1jXv z;868%$UvDfK%l(dOAN=9LxX5hmdByJaBC^3((GVrw)*N%u1)NYT)fR_mO*x#0^9du z<-+|+biHrbD7U|UcNn(ML=?_%A?z@;i`#j3Fy&UxoyG_02m3+HuSRMF}BJI@kCwBUhJf34+z2eE%e@qa$fchtUiUnM*|{MYu&Uo@kE zKWGei`8qxr`u!gND_{=4s*{zGk-7XAe=G7_Rh2k4;8{D--+e;_Gye@%750A<0nIB% zGGCDlXYj;ECh*(%Fh)EhwUoP?2G#W2VvS8)oU{sZtT z8O@ES@5loF$W0`OhY84)xtJ&Ts!oEJy0wbIwl#+S&O;8S=g*W@_PM|=ZV(--Fx{gHdVIOxDpOTektVQw5n@!#;ul?q|3G_ zdK}5ESaud@7WAWwHX*AhOTslrZR9hoI^TGfm=IGd|2e3*6FK$b(dFQq|86BMBi2@Z zMFlf%G11!yFvg>At0+odg})7r>nP4?=tm{c_wtD+E=X1=zY!mO5miTCj+C_joLIgD zV_7Aav-MRaV^KC8yBAJ)A0Pk!)79puOT^*Y>)A#ztZwrq9QC*EHV|K-m6zmsavhR zVO*!_Wn+`i%=Yx@C$->bue7fHVQ_2Y^QX*2jwWu7r?&We**a*AaHv1AJoR2WpM1vB zO>x{cS7xV=1WSCyZ)z71cv*6S2j9N*aOQZtL=Kg7h>8j%h6gVFPHnUXvvMmVZ!<8s zo%*_jFh+Jm!JglWeuBZUWiUg0ofy!092~qbWYVmG$8O%AG^%KIyTz%!4ffNP@?I;i z`+2hJ;%XlH+}J=H<6duX!tI^uF>k}d3`r{a?S-6jmzPgb_(ZP z1;bxDEUh5=ooSMn-rT)Uw!61AJdFgPjB@gz-4&G);rN}&1OXX+v~<~64#WcvCR2|_ z|7|ad{S!pDuj%GBMBMlwC+ZF^ zqt;pp{iQHz|0#A_F@aV4MOwy;4a^R&vq*Z6- z569K#&oiDZY$gc;N}((qI;$nBr*xqwet$V=uC?h)&OVsmZY`R;IK9o&k;=%(TH*l{ zoq5>7wlVz0{xA@iX*WC!3uMP8AM>J$O;#s{! z$=HF>#ox{y$@mEuQMnWRJr6(9XdXV5{&MLukxOp(mmJu3j_tG>rM*o|anp;S8}=g| z6&|YH{UfXO?s=$wf|~Y~qBO~@@eE13)Ad(gi|6;o8(mgD97<&0Fu&eez0LwS>A7JI z%31`RJ@REg^l%qez!Wh`y4N$~kAyJ;T$H0d+xv9;C6tD2>l-gVT5x6rJMfNFu zd$)LKf!`^XhU&2($i{y`sL*TI&Q8K3alH^T*p(^@j#o)aAME4}CEAWh8WzJtdm-gs zv7@mg@YXofWaC;Wqfs&Ih=NMZnXjst0XVZUd$rQ!I0SCHvyb!Ze?x}Qhy*z1ml;Tc z8qRzHwQHZeq+&D1u1yb++B0&+R~z^rUuZ-8a%_B$+pN|aI0PIZseI8U6tfnv%u*fi zYKI|gc6S8~K6fN|{sUVsbrHJwZbIy6G;+TfH|9JPWgl!(>;aUj@r{{uOCt2!R|O!B zvn=f1SuS3Y8eDpO(hc4Q`{Fv?T{||i&;4gcv(K$i7N>NPfd2d8wP)5)QRn2L*%rzf z8?D|V6W^LWRW2UUg7S;AKI#1==XDey6*}{t4N~&DC}%O7jax!mN4e0=K|izF$X|T| z|1`x!4wDLVBVP64_Q;|4Uo>jbk$H94fCF2jV#<7>e0Z;<)cUVEx7kWCGS%O>9e~ZB zM<8_V=BP+uPB-lI`IZmw7&JUj9V|ymc%`kQt1b4i-uGSTb!?w+)-y2Eh}hdPwV zi6~HEOW_SyUr4A)&OFCzEIs=wO~ENYMVxow2EyTUnT#s^bX>Q3snsjWBq90o#r{EB zgqIqwz;ea6dGHev0?6et^9&P5^>}w#@$xY13f7xHcK(p@1f=<~$bZWZ3gA0B5}X~1 zrHU__+!poPUol$l1*GJT8ul<_d^RmAnfUj<16o^VV?-B}%+ykIyLAA?xwsloI8}wD ziNHev`A2-a08!rXTzc^evnH&AFQRco5 z96S)}O=b9cG-=S5;0+vhemQv)OlU! z2PiLxv|QY8T}!9oW03g|iinp>?t(y$okCp9_$YH`CaCaOnB;>~Jx%@sSetkG@Fy6` z4R$V+C{4f;hQ%8>bA^-FG~)qQm(Ep%m5!sonxZAw$F=fgUQ8@GPcfH+=SsGVA11kuzU< z(#a`qJWcEFm0A`^+zHp*uAq=rZhg!Uf1^?rWu`o3>{f4*fsuH#?KIhmQgXJ*g7uDv%C=QML*XGW^o=6R%S zkWlllYsFLP;lXV0Ve#xcgJLbUJUU&rg0LAmml4<_wpG4@*sMInH7z__mbPvnN2DX! z&a_B4#3Qu-Ab+UA32og@1sa8^vX!|{fll+*H&5I<(4kO_B4|+ElfVy)4C8($pk!J=&~z`_jy;5hh*v zoatlWbiH@@xhu0wO%FJ=*j+|V1D)OR@X`F}J(Qlh$;+EsJva*u>N%;NrpJO~aW*4u zjTk`H@~FkWk-9^S@#xMs zN8DJ^;UhJcKKRt(FJqYd&H`{5cWm31TMyd1W0okZcz$E7if};zSBaqGK)g7>Vh|Nu zmte%9zIB}}_?r*Jr405LyJa=>Eo759w6lxW@B|H2EiK`;k)z=W&<#SQbuX1^p7RJ)Pv#fSn?mR*&l*-AA z{!pDWY1r4S+;8-$R+bE4xH`it?xS9TGc?K1n0&*$+zmGO%{D~3DNKrptcyvjt|wiy zclzwDrS(H=dd&`DfaM# zHhND04EB8(E9;5w*IFFhnz<}?)Qw2^DU43ohv*!vo3Y(ZBC_{QFHL|1kwYh^_FuLt z_4I0;H-aw^6WeV2(xEcPwsY?_9n+!HQYdVr`a8G72eyG5Z-{~o8F4PlUu-U&$(;H` zP_%Pi`0ncyWj1_p3)s2N$7uD2QeMd(-#-^|+j)1}b?|2$`wQ&QeV6fa9r-cc;g^fd zEMjLBXySzX##bnqe6iFP2M7sVmh_G@+emh@g&;W1h3`61ze|0Epz^wa>$C=X^_NS$i6!iyNTUW(avCc zj7L=Et0&Ryw(){m8K05w)|(%ZlJT2M9GN)L5CMIx+%J+-H9b7L#tbv9KbpWFp|Jbz z{kc>TL5NVZp~kc{LxyF?lT)uiU&OeL9o3pIMm}16!PcR&8G3t$FJ&e7utP3!TLiod?*bDA3CT zvTf`iXRr%|)4L6<9$*5kcy`VT#b#0Bf<@D9f&zot7+fJe`g+gjxo#koh=|m&Q zsHeJyuF4#g+%`%!w_AR{=p`oEth2s4Boksj$+dqMi2pD_m6pcYypPBd(PAn)tX2eM zNYSty!Rj&DBz(Nn zk#+HA^R@%2wF@p|S=Fl#Fvmw{Ds5gy864JJq+Q9P3d^nVO0-w^Re3YyvgpKd3aSOA z29H{H-i}X9W1H-RnZV^9AtqbPzi7A zgVxE`k`Bvt`abE?4oLFB=+qMp)sctpN^(=8_IF7~{^*fW*U z_BQj}U#nv5Ra$}}3B)9$L*|q;pIh8_K6@r4FU74~O}q+$JAEA8YLin@TQ70MuTC~! zT7K*3*id2fm5uerkyjo5e4iV63`MJC6Rls$KZ4{LebhhHw#J_51~Sxe1G3OoGB~Ll zLUO2`_EP(1210-6yS2%F% z-LX{aX0IsT04Ud$bHCpDpIOZ#{Wu?yd;i4AzWL%4kFPUQv&(4BJfInAoEWW|>*crd zHJrGKobt&NQK549wz)<<@hc~l%K32**!e+}CP0&KG*>8qMa@6k9x_Qybp=Uq8Wu8Z zGgWQv%G8D3ZKu2ih)G6+PReZ?#L?xMdl(jRCU4S(6H{drwhh|Z5L~%V)}hX zN5vGqZs?2ocs@^Jm3``cacb~&$w0zNTq##tRoVWntA@)U+!*SrU(Nvz7+(w3rh& za^M_(yf6Z+YESm;pgEzFhVFg+s{r9yhpABry*b=7^W>ZYcl(MXhcws2j0w_{)29Zm z|6`SZb*p|H-N{k(SW#p=&wKAe)&QZ%-~TayxzSh@kyxlely~SE>A4l-aFauOQLkc$ zk8uE=l(rbA;y{}A^djhLjiIP0R~?l`>_of{L1o(^Q0t|qNM3idT!s>i=GER-0^+ej zgHY`)lXin5zD0th_s2NvLi^DK?vx5J_QO3HAa&)df;v*xfDSWiFgj9rV0QED=@x7I z{Zg9fEVM3$&^O(W3z!o|!M}fhWBCdK$&XVs5|DCz>8TvPjD(-rwfV_6ptGKojHocE za0G$-9`g$ZR4KOsL~R!kmtVpOT4;t$1b9gPBY_-c>TEy@sC^*oR3B&0VhnL*!Ds5m zQJ#T5%>a+WhUQhOjpU{#5A#t@U^<^2t|7|qPA`AYOG~YuoqDSGii09d^2Ei*6pT4n z5)^L!ilVBcJz|~Hi5R33Sf;Z7iZfIR49~yLM0uZDc7k^}`rhf&-c26|`tCed{Jffg z*!H!5bPzx44annX1=n!?77EcU^QTo6A5Am@pVUKDe5$A zc}_wc1>zw>#7pH*(N543lXjBb)=L+vSwP!fTgd0FdbkV@s=qoV032U4HrF8dW($4p(|GGYcDJF z^$D`A_ETVfAA&_u%vHF~Ywos`uO)9nXz@XicWws?DQtpmDngj1kPfGC^0x~DV#>B{ zy=U*$=iHg-$!*9ybB=~W;y#s-7?*zhy4S4R@cQZ_6k6s&F&qw$Jp!Q%vrRKFoPNjt zx2=U-U#v;2klvNFi}=8KpCS-fiw~U!Xhd4yywF5LckeY^D#_1(%v1rks8SwF4Pg03GI-)S?*CrP!*}bF=z#=myYO_X1PG9;Z&O?; z4D`r?C(D%ij%E6faV{~-2hTOf5OT}-ZR$Ju-}g5>{D zoJT;mHl)lqfwd2WMvj-90Y`W)=0SS=aok6hL02id zX@P);P^P~4M1>B)=54sA#ye(h8H^L6);_*N#)WCsdrn8=?xY&hks#B{11)?~*oDvk z6@OIjE?~Lplgi+$YP_M*RxPy9bC4;ZK_y9VkHROVNNZbFwmLfJ@{d7Fp40l+Ng1^1j?Y=(d$NKa z#0GC^YsIc0DbA@!Nbrm}x;g9awG-;{G?f@KD!MK)%h^SV?B`=Do)A{o)`GAeSarHb zB0nm{0za#sW=>j)i0lz5T@1ml?n#;N0}_BGI&Dqgw;-)aj^}$=w(`61Jl*uEb5JI_ zjKEFuAU5nH$}erleIr{*p0HZrK2U~QnkF8A6^@2*>UVmq{*lJ>kBTxqWJWjVROV}P z+*=h9_s51ig(Bn>>MnbQe{1l*`BOFS#FB6SKj)mOZrGC|%>mVF&arAJlv*KJ=K{7? zHLXL&rn4YnKPY;qIC+!+GOvaRVyu;aE|-N9`yd0JiJ9+u7H7jko$iiU#o82B{CF@+^c1))qBJA4 zSH7IoUa+3;T6dqw8`G}`i@OCaS)1f)31cduad@%#aYn7 z)jFOwd`F}0>OLb&w=9aZ><+S>*+8SE6B$5)IlZj?(RrV_e3}-emwaL(_ZO{%aTyj3 zMjJDlBaO_ko%_O_bR$U6gdsm_KT*^Qo=X!8itsDmc*#-*ad1F7`z5UxwSKKyf>gL1 z8Hb6_PnIccOG)1k*+aW!O&*L5((<`k?fh> zPJjE~rj7PR@9c&2nB@o!qnUlI&ROaDJN(CHztV?kf4ikGIUZSIIb~I9z%B=WeZ0$U zQ&0+Vi{3XVviWK=yiS-b{VdA#8j}X8`JkCGbCd77L+bj#VaWkjPz_@ud1MwM^tFG! zu#NAwf0%2nn{w>TD0sKWZcF*Q-DaX*L*^sFv?<(@k`?+ozj>uRiLEQn8rPVYC4VRh zA?KID+<*+ZXO=<(QTn#u?h4j9rC-hPrb84waFZhmGz31r9?mR?E8DL$PunSX?WQy8 zP9!a)8D&1TFvAIKVK4mH9D%lGR)M?Q685}9zGvKr4I>jx$opOa^DoK38r^;YQ)R(J z779ycZRTPUR(xFqhjUxK7<;Ri4HpWgY!;mSx^(wn12$?X@P8KnG`9Gc+Ytiq>%BcX z$*h5Kh!r-s)*l*2aI9GpQQA}UH7JSj&2qs?D-h~P^9wWw%Xo}Q zq{Wc%5q(+s>ign_9W|5vS868XGgGi|pg=*>2%JAQ*3eV9B$xCZ8?fDUVyi&d46!oo zQMV*IP)T+n%+gbx@+1L20ea(i(Ksyp|8X*7~GTjD8)f-0I>gXCi zdASdBk@kFymADmR;O17Uw=P&D<)e~vxV?E~a6pT9T-~8*39B2NivT;n&gr-bjYAg3 zg)9_JO~H-N|8ydMaV}^L6X^{QdO7UZY^$3XrZWJwE5l!o}SYcJz>u6MnnP zWN#AWBHueSze{Lt88!5&R4%BsCJ5^}43wZYSB3P9$AY@36HPSEqc==|CHYf#kl64*Xo9 z)L%1Pgqdr!0Tli6je9fpmNo+RuRl`UvF%Q8e@}Tv%gQQ`o1c?2wBzH*odfy>yUv+4 zbJmktCw-c1E6NVKn-;>v47xbv5yV5=NNM}uNpPO!IS&+^lsr@g5bS0kBa#b0xhM9k zxN2H#V4glWq^)Px5nnhqQ>NXbEMr~?IlqZ2Fi*53-(iCt7>2W|7^iG59LJ1V(BgxkeJI)BPe8gCE<@-mTX- z*O{5LxJ85T9J@a)?K#r~7m#0mZq^L+Q^ob^1J6By;N1|=_g*1p*4t;JQbg_6IW1{Y zTU(XY^pBYw|1fE8pOyZhQsO)LV*T{13kXk^N$pq2UF3<#rvTfkt+>8H2?rWg2eAYby{y&sEu3eT3 zqIRvDRm;jP%QxM{5fVoF#!&N6rhL0Z#1#INN@%ZbeQl+QW)s?XiK{r)fEJ?yH*;~M6hw+uUrrJ9A# zzT*aZe@Kd zqf5!Wx{DrcZ(7SfK?eb4*J-Y9pJAr{PwI)FAGBc{JH&5|mj<2usMMTK{m;(;%02LZ zKFj}@!hRaqT>f&FD8APNX|Dc`&>e_7d8`XmuG0NC?quUX<4*pYE%skC^)D&t{|f%r zUp^ABL;kmr|KEiSP;Y8fcZ!^*4=je*1}+bxoeIo@ekvgmmBoMaqA#32=KVX3U)x-{ zVkFSIa9HQG5wbkVA!JmkHNk4fN3Ov7^o-xyWr=Gw&!dtz%grrP0J9{X{PTlFKyHOI zX3zTVga*It;`mJoeO?}Fv+BJ&|aTxlwPt0CNc z&^L?z_MTqD=2ps*IbWwfL7@pnWx^-}8~6CnH|Dp=D;Tv?ww{}c{WrSe=W)bYs2;@c zs7-;?Z5`L%sQuuC@vzZ---oB})6@HnJ3^sIG}^>z&%U|{P1vZ^SspFI2qDd?(xA%` zH`2~lyi(fED1Z4jdZm+FG$k-3^aT9aJzZ3Fp{qv!f-D)LrRtGUuIsP*0Dj|&exkU2 zLZPV_8Yt>+6yR^;QJJHJFK)g=XIFJ*Vw>&2eVamwu`QF=RYFjB(>{T#>gX*!ZJMdcSA41t2!G?+8SXgm%A#RvZU9R$!o9~`oQt# zsD%$?a%`jTlO0Rwx_`quw5^}AIiqCpf_$md09zX~l=AcmO5<%0{^u^8^6MnZ&Lr66 zl6&s2Pt}WuX=ILT!K_EDt~O?VO|Bf5)k%L8s+Z@^iBs2PxyY9%d`Nd&*cx=*06$rO z$P$WZ>l6|VU9@uRHEO)A*6^7|E$m0@1QKOhVXhNm$d7%s?cZrWAV4e~JREi3V)aKh z2F+XB)X=uO^DXuZFOp;Ni-~N(YIHW{u<)Ba(#*{lu=kY^hlTTpB06Jqd)5!F7uHcn z_effsUoBOYA1QRbm)GUkcZg(O(TD9v3NKi384iT3=QiG{_gLpQrrP|O7rU?p3*9gY zk8ff=V;-Ec(m_Zi9rBKXhqG%a!wd)EBYJY=g3&Z8sfw$yL=Q_Xidrj3RVc zCR0#mDwip-woUT8q#Ir7?$`>}IBSp)m)VEbt85soKASd7z8R?KdbHpHGkuzWQ6S0D zrOzs0X*I`_B|6rFw2A<$U_4K3KK#>tv-6Z^g`AbE!f1$sb^|^~j>yA>fx^hc=vxfJ zySj)~#+;Hn(Rm!{#@8I|Hv>CR_Js%Gk!hb}tq4as*SZSU*@h7fd!7(euN6u|SnWC~ zK_H~(CQ{mCe)hHMP`2Jl`jBz3f%1E(Wf(X1JT7N{Hsb@N+A=hW{*1Q0MUD3d49x$v zGCR}hC&~}S6_l?2>6Nz#FsZ|uvHkk#Z9|i1SqE2PU7BBK$BHJXPNYhge&}TBrZ2de zrVm*j9h;ORujI)Uja^dOu2-FDr7>tKrP)%~(0lTr{>Ke7Pex@tN^!Sc@vbu@IkDYu zeQF4T=n&?gUGUYCT6pzWh(IF|j4LL%A&HH7PO=eIFUN1Rn?G;^`S{v5@oIZWm1(vm-ue2xaiq+(=WP3Y!~yFja~+{)HHNe+JI z5v~WjW_5h|=kb5OOYxlMSWt%V*3X};2z(zspdb|hce8yDo|RkkDAU|hQy7{c+{;;y zEVUgYwNocX=%mVnN}CG1n6I;qqhNca<;VA5ExD-WG<&xs3|dXAv@kd94~wRzL8k@> zUt=ql|LcdM)XurzuM|N0Tg5QP&^@_*Lp-3>nkS9dcjJqisJKv_!z=gG$HW3^?8vs2 zt!C2v%k8ksypy?D*Q1Elkl8zOYuMzi&17;XXZ!1QzIND(KMZtxiDD8lm*? zOJ&05rLXe{Cr@{nqm3xll+B_YPhw`Bomu)r>RY+XhU~&wxKkpQWXwpDqQ)LY(4*$E zc)SzBqu`=ip$gYcv(g?%x(?q##CP44eY;YVz~w(0L-7eXiOpj2h-mVpPMOOtCGFT| zGF3?Kg$QO9q2al##l$Af-j7tR5<;PtFX8yvz|G;=z*GlkM9`MS7QUw=ZD`#Ub714Q z%$qzhq3NX&uCRxl92;R&8y1Id?rsM}v$Nk+j7tHWjvHf~b^amm_Aj+Bjc_TKg)!p> zRro}z3h2KSrJL>1Gvbd_V}9soEe99dq2f!QlQyTOf|X=W*p)&5qq8sh%P*d~#UOYX z9lX|W*MU;#nhV03?{=E^3kPq!(Kg-Ar6nXE-H&amQlHaWY_}8)n6nrKJ4l{Br);0z zzjr}5tLjnhiYF2_*F(-9lqVd{3kMlQQZs9xi*RR;M%-WCZG<;}ZBoNG5{8M=o6x%qSVVj9?-G?h~-v6jFGy zdOW{`YmZ-$(=_G`s$;{cKvfY`*<lUXWGqY|BZIJ=zYA% zIi;jhZv1Ia-Xm6zwwc-*Dw!WD&*HGoIE$bgfRQ-nsba71nu zg}J4Hap@$I5IH&b<+F5vC-mO4Zc1;(istvk@1~#`dV7iz_({fdp%3F_2wwxQCC-=U3*H;&OYg~WX~A(_0pSfIU1iBv=7dPuI4bj!juCK4Jq*I8Q-`Ms3_5D7>)vFR(DYy*BrM0JZ z2c!J=?0}Sm|GZeopWIpS<;%kn4Dtol1$afpdb(R)ZtjEH+S&YAEhdwV`M z+68XS(9_wSXVvOdjm%}t^2i1JQmqB#ij(9`+|dA5W{Llw9d3TO?^koht+}5+JLWfh zhA~S^O9^Rd2=j)3_Gx$TG-j5toR=?8vB?M3C@!DR_6NwFyR)wie-^9Nd4JR0>QU7* zwJxTyKz2mZ+4l_jm^6AP`X=mPZ5%Xv3dpT_7X9V+GsD-wr3LV2R@U?#q#W2!ZY}$! z@|mh#oXXa?9j>C}w`(dpnw2j6$IOh)7-oHay}Pr;KdYyxzFu}~38xWe>78c6L3vE3MMgc zeDD9xgm<#9;vBOm7AH0$d9a-}FUg5UqZ2|zmI$`ndU*pA`n%eK&`JyQ%XCY>lS<7$ za&|5SIz&xP4XBFWBnE0^RP^J=6MxxESBTqy7y}0fsyY0^!0xk+*A%DjUWj^~Q+JSq z6>pzOU+gA+(% z@PT3E&FUXias=En%5Ss(5^dzvJAc$W#?pQO58)^Wn3(x?6YyA`1c?vdi-hJiPDPhPZz?z%@$bfk(a6$l)kO(j55%nz& zv$?*N)-F;^~K;w%~{>F7}3J;D->`S!2QfFLz~k%r&0 z@^mms@M&*h9+1XNp>|)*^Z`zQ)1>TPfqKMwpT}cBR@f?isl?DB{BdkScu0v1RpyR( zg3rLwLQ5L+k;2=(vcstvuLQfr;U7~f=4}?9BI5o-xKwXFH=edIdm@VhZXi-!ySVe* zUK%6vHddRVg{sP`Sshlv2c>dMEqOBF%Ut#I!iB{PX_v)*bU69U?EtB>tl)Kzs|`c; zG4iHqr~s(QgLrZ04oIrBYjyySl3LGze!8uIA~^zIe`9zH@clsoK4#^r}ixGj9( zy;i)FaG=%uy+joF*p;cC#0`bPTqI8sOo8prf!JC^JF`qFO8?4@xnD`}@4A`WZWhQE z4S9UdsITVdt8w|9@u=R}z848NuKSlbla@dc-jDaB1v8p-m+5fg4Mv2eDIVW341QF4 zj8JM|x5ah5A>DnEcWtV(vr`6U(b3tNrkv-^J3T!OFDc0pJuy#7dA7H&6a+CG(U0Qn zc}A)J-b=Sdkk-?_SbsXyfEZjJi3bJt&@Rb+EGgCFN~l@*a=uC{>YvhX1oL*JcI9_25(6WbOfM|JhD?_dshJuG*xk|ZC# zSyW7TFaPLDp($KSxH12NFGRAbDa`uiW`ETlN3YNZkiOMVP6Ke#NgJ+K} z+Y#pB&CUMrZyLnxzdaJ%oe?F^hf$9Z2vc?+8ir)3eCjTekE=mEb8TMq261ygl+Pm8 z3k6MHM&SjTrciI+z7>KLWdvU6yq!O6UwwJzhIZZ0-UWAKWCzI6W=#L6^oxXCQ|DaV zz#>q~^kl~6g~u_Oa)F0YBH5LLcu8}ysHiBK$!iWq2#J7~H@9Q;R39kNYL@ne%GH8M z=sA7oj1E?q*lw=%t1mB0yth2(#JuvJEvDo{T^Vzq=9#C>?<;1_k+}!*E)BHtPuL(h zL5g{zCrwDx(15)Ok~nDqJ*sz6_ld1=%d4>VfvLRp#F5dE{yT3)2_V?s^zxwOxNf#L z_Ugf&c*7x)B<{Az>>>k3y|41-`NCb?^XnGQ#k3$DgoU6Sjyf)g+jXYaAc0(;|R)@((oE>S;6<(yI_eFl zcDErNXA>QP(w;9Q&G9Tp{yN8fb=eJWv9ku<5mHhNYvp&_I>S)KbMnp;@x#?{Z^a|` z5?fSK<8H*^dUeQBw4Z!`zt(AyfK3BK{pTWQc;W6XCUdyz%8+XRKxC;`;PRlu!EX@7 z7+8v$;D@8OkEtnr~?sqk)<`2xg&dB92lfwjDK4*|WeMMAx zO*kUQ%8j8IB1DgnQW#SKspW)@xiaNmvSecR@rb(`Y?^Z3u$Rmr3tR*0rS~HbD{SyAfSF9hA=iG7;c0^AjYM=;ugB* z^6P1EkTdeCJSl2&eDd2uwCIXkUk3Dk+WB=yiL{NdN~hS6WG z#I0C{Hsw=^KTCUAdLaC>R2F(o5oeTmUaBTG`fd>`N6npTE&0vgN#bvjR!sChR4jevS&V=m3EgO zB;vx4Nco54c2|gmsvc~y#1 z*LUl>#js`$7BTADuXU|!5Q{ww5FZezM4o5=tY0`E4}XOj@$|D8AjTq{*B6#)xW9bv z;8#=DVAj;(!(~!Zad(Bydsm((4h3vNAH4F0RFXoOCR3DtsQh|AJ7sc*Py}G-* zUt&=sR{6>WQruX57DJbT5>fv%-uA@CpUvl%%c&!otvhw?AMSW4Hq*3haTL=VR4ij0 zapa^SQaQMORk3T=yTMa^$%MVZL;Do)8l|{`fPoVUZ#YMGc0p9yymw$8RxnW(MV0V1 zsdhzom7v_}0SZrINqub}94+oxpWIrYYoszX{f$^8D*K>prg8ns9?2+|-#A>t(dr%U zhu6HzNTG;^$V^27gIiSqsMgAA@`b?SV-|cxMmpKAT2|HP(aRC!WuNFbX}_ zO21Ej9iQ~F3tr?&thm84>FAA_6D>h^r1T0qbZS-E&ZbXa|CS`}rJp-gpB3gH(QV); zIm9b}r*Z9oAf=%Yyt*{NN|2fr<4$=O5hFIZ51;Mw`Q?(jx2jBg^g}5^n+YWh3n{ft zX763iz*afowF$!*#XacR_HKAcwN;>?OtsI_((ko>kL0oWq`}76%r>j8zcIZuoYw>d z2Sd8v%ufL;x~f}b@9uO1MehgTvZXz!n}H$-Y@lItDgm9M5Ad)pAuZySoXN`7-oc&_ zWbH05+o?e!c)L!-%+tTVUpX2aTMHP+Y9fJ-n_t;QY)b51Fxyo%VTMrQN@i*=tc_|# zJsQ5eZsagl-h?qin?vJ927i7Y*p~d_W6c+8DNX+b^V9W8vS}Fx+@`-~C%kCHV6+tG zB#duiy5q?UU`{VJY13|-Va!l*E*e|i%S4b&(;@37(bpMeu>9Ktv#@SAfw4|4($1c7 zXS~rwAw&Zd{eDSY~#=@0XBZIDV}>4!*CgI(6F}+nVKw#kZ+Ej^_>eQ2!G&V0*XI4_<|oOYGa1z zP2xrrxxz?q`3)MBqu#b9oS>>iOOs6L*wA2o)7)p=qP0c(*nR0!F2fc^@PM0XaW0GQ zeU`=(xsoOz5MP{)M$9a@;I2$?pijXb+J7#n;h=hc3&Ej~n|0*>ikjJ(>D>#Tt-;2k z{9lCSDVHg8eDUwQUpj}1;)SBh<@5#b0+^Kf{k1pKDq!p4TrS15LsN(WYX1k^x9J*% z^i|-(kV8{@W~!Jdw_eN++YB~K^e1!paNRQI_lW+WqUEEtk$1V&)CMJ=|BO|=!M->y zy`*j-*E+@b#Wo7aHRu(y{ zI3!PqIq#FJV#PYz%1)`8iBiATDV)w26IE=y&zTag{`jF zcz*vZGt~Y{HQL?pUR;TNtcq)1!vQv9Y`IGMc)R(yJ5Q4A=3nvj$&g`HR8+*8W>8-+ zLR65y{K`|&PtcFc)uy=*Uxqxbsr$QYd-FljW7T{`pOU_DYrPj&lY3zDwD=N|Q_>VM z4fIXD3I@G@KJW6aIaK>l=ozRjDu=n>?sZuH`wAA%goeVM^jPb1&t#|e<8Z+T*QVU# z!&I^Y3h+@ZCChH2hLoW#OB@bTWHI72cO*A`c60Cx~rf1Adld zExrqP#SahLW{xG6vabP`^~nfNf5P@Aaod@=>9acgdqVEb-wo)SAo%*FzyJ@zvZoKc zR9bxh?$YeV{EE86Qq1(m?!w!T{vYRuA6*VMa@7Bf%rY=7;4tKl|uGIkv4ajwvr2b^w=D98<`pq? zZe&v+Ec23-sl`sWT%G5`!nh|l=$X<=qd1cnx5HO)3ET$0*}4MB1ZUrd)FIOGl+yUD z_Wqet;83YA=eTsK&t{unM5JQbtn-~U;9|^c);_BcqplXAuL*un(|mUsEgRE#yq-kU zPO=>$jEe|IhYg49TiK1brPbasUGdp~UGed%j0H;G5ab#*@rfXr31SiKk&_XjKN@zX zr03&g903=$vISqrKEHc7UK?=u>h?qk5z?W~2xs!6#YM%_(XOPjc7^Qnbagr{Y{pgF zh9H;B$O{G6(Ano#i0$FVxGdq`ekMgRWVp(eMlzSyTWf}{fh(~M1?gVpufq0E2Tc1} zl3OLq^p3vd)GcW!`rz6FEsX^1Ry)Z9ahPaOMdY>R#3q|18NcXwUY}CiDFwqyonTGH z5{bqwm4@mu{OTcWdrU?#<0KoD_jtoxprNIuUEe#PK6g&<(W6I27BBs<6K0;YZx4;% z*ac~NKFN=}(j!#Aws%lU30O?We$4N}y%otvDpF2GOC9_(;`MG7H`0{{$n-#%HP0S~ zFR=ZDpefo2VpkvMh}hq7cFB^{ZGJ#IGKuV%)SU=jel!dpCu1^q7SCwCmr$|_CmEr> z@YU`^K>R|zp#-O@r+w5wO*4?fWEa7$>a#NnL^tm^9|j>?PlE`E)!gLLW#0v)T?nFL z8P%6>nW7%${gwC{^5kVs`ly#dR;n3sIVH=r_dUOXnClk`8}1g+XPb7YUg@|QU@AX- zXZRBgClHGZnnyzVjylayov8Q4kyO?o9{C5Hz738Y)Kz|a^CoNUmtmPkfvJb1Nrw|L zgp9K8L|-cWZ@P@M3gEm3EP94(*NXP{_q8XIhlhtK%lf4Zf0v5foNA>13nGbuj zLyl<^_rlfG)ZR5u_cp@zq+JB50q6C%Z{J*v_U>KJe*XNq>zc{=^XGZg?%cT(w9xBt zd`CQi%~7^_B@S|G^I`;QZHVC#R;XPbp%WvU&w@7Hehd0;VqzlTk2KKNj{{uA(l#8j z>^jw@2YqRwl<6F|p3|AWeJ~ij4cwetX#`r_Q>6x=p{hSimRF7w}6H<`JP%Xog}tf6bvfYw6kH z?~+gU4eRTk{<7@AgTv#qs!#V#xcXJI9$Y$m3T$Yo+;*~C6ksPku-xvQMIGtli)3Q< zUm@X0;sUy$ltJmHgXS?vv_`cuTIS5WnNZ{k- zyx$P8rEhL-9v*$l13RIvrIiSHSq;U3PXa%eff<(VonQhG#QC2l-l=)#6?k}g4SqYm zDV}Kq7runIZ?8As2Ai6e0u$^--UsBf{#16tbvE3_ctU!g@768nfTPgv&wuf-Y?h7P zAV5#_gM#X1*<){TaRD&O;Oco202Q&v7D0ucu5RqU-=@i12@$D;3nX?)fvZ~QpjI40H7s2)nmx7Usa_tCWvu)E@Oai68Ij(z=gtF z{x6_Ip>?ZMUrFf|&;y1`mvVmna&KvE1xZLG{Yd{ZztO(D1;=2LzMoup{7Ow! zfFdD)LcjlDVmUcEp3)hfcUeWW48kl=9f%nLh!}90Pb#=~{d&`sFaTzd$pH^8WJmrB z<+z)K-n$1>-sxHnrMPD&!v9+-j@9(6#J@-w#r1`MhfMJ-`#%zWKmU*9-e;x%H+(@` z{aM+^`3=3lXy`|&{|9^uc$WUZ{`~Ju|L+4@r~kq3(ggs~0y+WIiUv-c3YWB8if7!- zw*e#%@R{AL9usW7%}3q)>CXs0N?95w0f^&ZZ|}W36yLdj1El~~3VZ=1B&1!~eoF41 z%8ftp9>I3Z*I;Mb{VqKN15a{i3tKmZ`#358H&T+w%*+hzE`>WgPaAnd=^lRhhwnVv zwY(+qieqhUjhdErE|;Bxwe2>|tFSPTyu3M}n#X5iKm+}mg?oQgBzpn?__)=8s&JZ% zCn$;lTozcZIyWm$A4n zRYnxO)GAE^vB7>P78w7RYM(b$n}??6p#g8Ku1U>(seeX5af$(et)&mGB-SVGe5T&( z8t+XF2_KTU=Aao(Mlq9;3)A66omT2-#lzgJ#&Z2cUwldGB~jz4-6W;OEEY9hKtt4c-BZ2#B;1-J(Nq-Q z0m{O&>+<}s|0e`P&$JohN>ZxL;SVbXxkfV9qZ$mR z_J8oGpO-1i5HOdciZ<#AwGwyuu@|uR>H->z+2XyIBgeZeFjb?(B`3tzB>C=~oH$=j z(V3Wx{By*H>}v|6c|S8HxLx8J$z5aO9alU}_b#>+Y~$Y#1~bb!H`kSEn; zzgaHc?BV@|6NL^X+GzR1+w^yy0=NmDXX(-n|Ba!g_!b0uMmO=>0(gr>Mr%MhpD*B} zPu)=_^}#wRYtdam`8neUtIavLshoEo3c(inT^d&%N0JUeWgdJO6^`h1-^82wDo)?G zrg}4!j`EW6;7s>RQ)fAHp~R!-$~;o}qbE)7_+=Wdel?2bQsxKDSP!x_ZB$P`gT-E5 zN610cPY!A^i7Etol_S>4ZGj1N5t!bo{kYaI>Wvj5kgSC3>08@aRbbdAFDOnel&v_< z-GZq|{SH_7c>1$u9k}}2x42Frd|hI=nEn3a+MYqa{A$~Ac_n^M{kcN?<~NP3g}1~7 zh1LEfv;cZ~l(;l)Y#hNF&``!yp^S2d%QVMJ<47GWVxXY}N53Tn9fhJ;ujRDEt&fLh zqcyH+>g@jDN3)AP(%7e0Ac8X_) z>@vFl&~tm|nC>vcHhh?8lN=?Q5J#m>T~(@Kxyn7gHtmJrgWAcbHftW!ZF*aydwpr- z(&4x$ds+_Bdu5_>$dtky#mm+m`imVT^skyq{PFnj*#vLtK!vwANRGQXzVu-u}if!+Gf5I1bKw(&-~_+X+H(z zUK^HSct3*O-!;W?#X#rbXMGjN(M>gGaXvG(zMKkpWR=^7XBX_~ii=yzTQ3z&1+Drg z6|Hp3h{2btQuPI(y9q@HV@6JEaXmi8NybkAOW@h}$9zu~XzLsvCV-nXye3U@^mUF5 z#UcmG^-eO_K9a6~5;_FIxX1LCs}SXP4PZ+W1!VOMj|!f>a>IIZ73MCtTc5djlV&xt zu0jN-?wR7M^pZt?@f{)U9d)HT7;Me&*G7qx9GmQ){@h%#LL)Wa7vZb!Xm5iI>*-C% z)Mhe#W7uuxF`m#SEjdP9*`}bVx(tMVat7&MQC=tvY$|myekT%>^-~77Ukh;%}e-a!;lkYXSpy|)C2 z^xi~zFQErSY7zk{p@eo1zVG|H_q%Q8e)FHX-w?5N!_4x|s~jFBgA*6e0dB4~w;7wT=2N86(;+|I-D**Jw24BshX zNBe}=2Pn^SHC=I-=fJ$x8p>0NEUmL@{Q2oRt;z2&DekXKnh*_1f~}TW;_U`mW04K< z0lb?rov3@w-J#^8{^8Lo549P03 zaL1l%$LRs|o@ItrL&aYc=Zff{i;l@7d>ax98e}zULCSj!KC`;rpeJDS3FT;}mQWL_ zOfX5R*ef~CXJ?d$i++`*4{B6P*{3x~V>Bwd(go=(X2+&HGpRwJUxS@*nc;ny8D%c! zd6J`11p=(b4k$X^aCpCIdpq#R*hi*aO+`0GOYYV(?p5IPTj~=Ex~0R*eD7e3AN5~m zs&o*0+Mn)RGl~t!O!|zo8Tvq-Z3x;+9Q&#dl)n_N!S@W1M^UA)hdThm4f#zaMpx#v z4!XGlD0~OV-Bl) zBc*(*o_n4Qxp!r0=^a&k*um`+TF{aB0JL-vc!n@MJWJbV2{uj#Ea&dQwpl=F*6J$#o29I7^&xpdQ&YcRdH3oI$@r@!G#NNm(%SOy=K*aArn z3r_}SU90=TGFJ8*)PVJY8c>S{n>=>@Xd38W^zC&{Uc{|5*WGAvzN0Z&4|P0qBCEp9 zu=>5XSxHi+iMirdQ!u05!G;-wfSth^c;C?rXXHbqv)Kb=9P!&PREhRF)*r^df_6=f z-AxYPsL3trH0@$6Nt;>J(?93Hjx?e@-D)mU7+n_mehMunK*mM%;Pbzu=jXLbs#7D2(;zjC@TtcqzSt_;g_(PB>CcQx!%b%F1ccMvflGu>3C)F zUsRrX6N6xQNX4VmH`TLS9Dw0G>&?B|8ro_A_EA`RvR2?9!MLm(5zo+bBSy-nA2!v}a!Il;1ho&K+)K@X+L{PIH!b3CaNGcAm3F%2eKp0#S=$W}4`CBq{B%hSoJKdB z8miuO_&4nbwTy2)pp9P;CKvdrI6#e+67h5XUU)Fo=Ygu!jv8~Rf->5LG`lXKdT+x{ zh}ST@&W?6ybtgqAPm-v{oBWcnxsK$TGDRCV=Q%^bW2*!_Ht$csCjMdmH_0Sy3aqqp zTrbc29yyRnmb+}(5h@NqBD}$qvFpmQ>^&TVx^G)nl&;^})hCb5re&>;(Ujol$X(+) zJ*-1$y8YgY9gDS8|^oP+i# z5l_5H`xHEOTyHsrn)$t5&?_FP{d;3N5M)b6)Y=31tffIy$PdLm^+(kZK`GAs?d-s@ zx4zHkM@<}gKaB(zKck{-h1~pu5Mi-;LG?>7&C;+bM-WgUVmnDKTvknqvl;{K>-ZCU z`0?$h&P2blAm2!=extne;B1fqj&NiTLA_FCP<$?mFhG3GyWNqIGb94T?G$a_QXSHY zsM9zev?s6`CmiK}ffZ%d3?b~OUdjpLRvZc$Dd@e-MS3eur07BA4W;%N+L(EkS!ES znd@W{GAC@1BMFjqVtOxge`ep)AHPQKcjSflHb{L$*^1jn9Rqk$E&7%?`YY^d&9`LH zq(TI~H^KNV7>Q%ma^)f}Ak+0(SiJ^_;^^XM${f<*OS&-M9gCl6C8x_I`VJ~^ zog9bhc^!&)lu(-W%M~k*8s?f44o-12fuS1C0k`Bdwf25Lm!Iot=2xR%b#!H5R!YX} z&K>Q}-&qkUW>Y7kp9B=*nmt>r@t&$@az-cNYeF{8V1(SK*yb_8fahOsHyEU>a*w{P z&R5u&3oNK1Cd$mqc&I|;ZpA~IEDUaHzirsjxAzlyo=;l9m2T55IJowWzWNuVQq~UC53-bZPrB)1n|XsL z>^1QnecnU{cC{-`C%lrLOLladzYsV&AGJy4ouISw=3`mUF&A|UF7;A6848d%BRz*bE=eCvc=e#DjS|2C+ z{t4C1E0sALuF&`O4g_zOF@`gqc^cCG0aZ(NA7-gy&}KvMR=1iBdAIM>QZajl$fZ7m z3b^l;rL&j#^}9TB3BAJHldHX}(QvtVXoCBhV$hT+%G*&n|6W{N^7*|t`#RQ|N&>pB zh8*)1N-G9S{>=a?RsGZv^yPZ=qwH?ovk`-pQd%*~Y5wdmyS>)02}5u1`9WR{Jq&$% zOab)7aKMpUrB67h`cW^nxREk9_}WdHOuqJPt8PG%FEyc{SL_?#4};T_o`St`-5AWo zTZRJBf=Hd1_z#^GS#VeVG=Ket8ZodMuNMmyCY5?)tv&{m`(`<1 z>IfwHi8|IP7dQRw>ZM}5p!bNtNt$?kl)0R@f5^8eaKWRe4Zh$kNN1;D#f|!s=b3L% z;sX68!v;ubV3?=DTi4x_a>*=}hms16tD7S;D#!1Uuw~^6L58v;fyn2Bw@Lulf)_=lZIE3_PzP6vLD5 z(>18jJg`Bye3imcvrapM$+fbbwaK#@5EK$_jN|KjtB# zaEh-UXKwt_Ey3=%&2^fu2rKX!Zmkh9ktMl;9TV9fFCbgCZ!_)_+;3A>*)f41H`C|E zEEs2c_>mz7sgV7PaYB&QhaGfNC5@i~Rm4S=%K9o#@CQQs#1$y%75;!F;+sZ$BeEs) zp9^jU6~6X63)uuU2DlLmN1gD`q zqk0C-;|Ln^gmKkVC9|B7rgp2uBB;LedJ|ZEl>Q=-
    ZNlS!kqN>;TsLMBSEzw1STNW_z8*fD%j3MdtYQw5vPc zY?+JJtka0rRPHcSS7Jh)*N;%@53~hkg}e#g%rm4(c?h8(1I2nbophw1!$vf}z;9^2k)+#v6^04}w7M`sskteHN4GO(o=*zQ4{ zIHt?T;3+i4NIo{8CF981<>1($qFUZtwV%hTZ|ahkA48Qne{=EH9tvLUQZT_CsJS~y z$!=$WFjEPo9~!yu7Y5mhFQZPKmMhDW+0m!8+ge@mb>6(U0jDZv;FfMHv_3GA+-)}@ z&3G!qNNmL>BrJ=*tX{_%jrp-TV6;2(x`d-JK8E^YY0TV=l{y={KOCN>Ar z88w>OFUYJI&i<@b5A2b22S{gKMX6RfjAdCr(68w;-u-Ot@l7XF%Y8zJNOfOmMX zo@A!}U02IEunGlR_{5*1r0nkBK_uX>AI>j=|9%(v-6HqD6R8eq z?>+waAFW%l|3u4ycLKw&{zvxXw>Z=De?Jtwz;Nk5r#-oI^FO?;A71~TE4Onef2O5V72@qPf_-e{dn^DpI#D+GJkmM&K(06m#1yO zbrQ)T!T)yU|BQhETJvAW`i^XHpA69V7h#V-hdZ@m@INmB;{mWHlLwctT)FwL6=aS* z{U2aYKm-5lZTufi_RU{^H+I+%z%TzDHkg&+)oVmdRACI^?Ern|0?=%KdgIn`$G=8& zL9P4S8g5=EO6@4;5)u?F1c-P}HO7EVluv)jBwknfkI5P)cyJt<*UVB-Q^Q+ZpU=Bo z4`$i03}+y!a`^%}B0=+qVE}f2 z0Z}!ec>tb4&8+&XU>^B@y4U>+U~WvI@83VoBO$8%W?jL~#I*dW`u=lDurshtqlLhm#(wU_QpA~2A9hG|2uHQ9giXgYgO)dk?H7s zm3j8}EfATI1I&2$Q!C+Rl9rLgFyfxMb2G{9WX&FYJ&dggaHU!&nwkL{;w z`3S#5*YK+e5vy?z6>D9cj>K*|xW2Oh&4bpoTGBUTpjv zYM&6m-f`p4v~|XoXLN z1)Zw-y&D`u(GTki(A68aGv*R@T=g^7LOB?p8CTFZ%gI@6=xkgnNo{$K*oiLeq$_2Z=cWV>j-Fiou2yGM*~%}sahL6pBTBv$;(<(V0&;l8~=1sG3sNPD&7yj z>6|_?ck01<=BY)zQ)7=NND@w#$ZX~H=+!em=UDMNKnpN;Ejn!{KAF1q=uOWg?)6bl z!cQ!(|71b7P` zKt2r6E}*VF_?L3>Q^(ADss!xL18nETUiBB3x>7hp_^NQO}myH@Us?y&0 zD_4JDQ<%Bk1J^PPjj;z(t!MzhNQznHFe^!9J&RWZwDs34Rpd%Xt|cc+UWTIPLxfMz zN!&ady_51hj8S`u-dDcnASQNWTq8R^RZ>I5hE#7A(K4}1PY**T<%sS& zL$l@}s7^@K*c&nxEhG7mQ3C166v7SPnMzr?{E8Mu4)jj#LkF}6evjc69~Wwkcl2AM z@Lc5azWt`I^zhuSgjc9iSl?47M5&^XI+RTDr6&GUm9jyJ=N6k*o?c}kYHtBhvQW6B|HJL5pq(pUDt6WU&k zc8QSlxe{dePEr4C?P(>hv(TpIDL%sk(dlrOmXMI)Gy7=#Sitvi{&R%a3(`E}s&%x2 zQA@!~C#75+Vv`a`0qNu~UPX+zu@O10R_bgZv8vytaOfB7-qd&7B)|FLn4qQ?%n6o; z3B?-q5U>1&-0-bO`7Z&zsY-2%-=N;O+{Q&AMXk}Gedt1EXJZ@;g^F2F9U(ZJAWuhsFE+o;Z^bQQ^MdC8rK zNCWUPP4*8CMyS1TYIsi-YYcVM?{QV5Ap7#^*A(aI41(9fMybyjD^ zA$=S+c|%WyH+)rkH~y@q%MCk_`R&waCa_Ru!EcYcN2@((s{V-sJ(0E2O3X|oUX z9xc?cTqP&~Yvm{rxP$D{^S7<3-sG7Sp-+R;dCEEZu5_1M8s)2viQyL#?0SFor??w? zsn`01{G^2*bSowAA|@-F2>q_kJ)C1A&3r(rX_~QU<}tB^}660Y^o-u+6V;1RcAfZCl7t#eQj&u+1#@ zS^IOjGJon7kEONi=|{CTSJ|F;e6XHdFnh;uHoA3IXPU=?0v5;zfTa9Eq#%YPN|g+1 zURQOrAyS!jGS~33!XeEx$gjelTTaFh1aX&jORQ!-$Unf#yj?494piL)(_`Y^N%ee1 z_{GRir_f3J#CPUi>;5{|8*r@dDCU&buz=p(%h2!g5Jj8K>L_C1 zLtP7ST!AM-!Jpht|!Gq z1b1(M_!KUi!py<3->X8ZqgC@N%@i`EC7;n8QK6jR7e3)sYQK0$w_((xpl^XRI9$0` zGao>15m$@_-fF52b)B@E40D9jiD;PHoSX}HtqppXLi^bV}z%j76G?`E5v#{#?6?(h2)npCB-EVZ_Mj6MWRahz}p+_c}iSu)w z6YC^BPc@M2Q~T_Gq(wcRw4%++x^0bSxZ_>wzSn8mAKGV{7QcEr4}p4eV(hGW3r6!z z3m7s^3?XoDsY`#meThOTuYcxP#aTX}ckm?t#_ka+rsZI73s>jc<}1e>ibf{+NpNqp zLWgY98!Mdo1%E9!YdmU!Rb6XRy5%v>8am4xSKE>HVYW<`)^UZD+ic`6#c}S_nK*&zF@7p?2FekO{t4oPOavF)Mz*oQsgROVmfO9oLH7mHA zMIzOV8{dW)fnN-{HmsEKwAcDb*yEFO=5y+;GYl`&99ULxK7O3J5_HFSNfoS^dHD+I zAMbpax#n<$TF4?k+abX}JkkEF6Mo0*7tNq){pKRCt^Wa04>;2+BS@PwT1c8O3(`d& zN?1l}S$gBZ?E4>Hgi=9^sr5m|X|5;L_ER;6v(YKgyM?)QH{A(DM5TWaK}dpxQw&q$ zr^kt@VMc@I4>jsSsHI(YHgX5G%oZN^pbj7CLdeM8zP(lZiExg?VQH3D#Wd$qc|=np z{Ys1zOm;TTY65@b6gXC@*a36;0lm2{psdTE%3o~cX!!LdaU<ennY-aSgcgoLu_sMNvSg+irwPU~J`nJniphAZN zl|XJ4H?~5Kw7o=B>fU&p$YeqdM#l-$gmOz6ek`$ieEB}?k#iiEE^`NSTIJ)qqTZd( zj)9FbG{u5S@Av~6LqBpO#UsmtlTExx~#nKd8%5uzp}Qs zrY!7nHrwU{%+@g8g^S;Cj0?E|ud=iI2N6Xg~pY$luFe>n3eLnff z=m^cX7Porof8uR8JFJswLyCAAgw4xF-#=o5g!?Hc(hT>5D3c8 z^Q(#udM$aSVbBg@~~!+!o({*iolHdR$?f^Pp7Hoxn23HMt0vC#6r#b-LRm z#KdX!^3xrZrxNK`Ozk6i7eGpZ^~=^&4j1%i`#5)OMOCe zu>SI8<+o41v@e^q>Ixpv?iISUfG{}(c42;fxv<@kc7Te=16+9`mpmYiAG5b6u7q_*iy$(9)2%e^X0L9%5jmG(G|6fC4Gu8x zeY|p;HtRc7-^i=mty4g=ziRkr&-qoW2=u)6BMiU{1DkR(jb0eSxVx6W z>3Lcq>2i0vUUR&CA!7<_<9~dPU`_WoQ%YWbN_}T=a@Q@@_mE^P{sG!-Y-iypN}p=)qOmz(B*QBh{)HaC%WHuN2EgSL|vY-nEBL(@Ng4hy5+yMh={Haga@-e?yTUw!iJ z^B)K(=gIAYpZA|wt{-BC#ILW1iHC9YPCRpZ!nO7wfN?Fs;Ld!eI;m66`gnUP@Mm_veO2=pJYUHFJ z|7g5)4rNqsTeYw6rA^tWkC5CtH8^)((@*BNtGu4i$}YyF)tqcG)8bh5pt(WI*ghQ6 z8oD_dS0EC!D-K(5N$XtM(^LBZCf&c$;Vz)3Wv6UVH_^P8+e=b9w#Rp6T%5t=ZL<-K zVspH{W6SQ0@Pv85euD_lapE1FJ|$ohSMUk-qn|E&j>IGsuuFi_!GDFt&-AToVK*4wXSh?nG66{ZhRpD8lAoN=bY zu_=KUnD4rJ@g z>^>7+8W!9AlF;&-*u(EfBtgwHSEp-mqTRwK<5(1-p#*BlmL5POu4i9t1%czoJw~8; zjm0yP$>(!1FmadS&KT<4{`8L#cih-p;UM)6K3a~cEOkz)3D((|qI8!FF90}dZvz3H zVc`U0C1LJyNXmnIB!9n8lqd=8`2KnQ{{kocw-K-lj477MFhSud(GLlYY8dOR1`+t( zKS101Qviohh9i-z4~bmp{?8$L_b+3Z_zP-QkD&VH%S7By)h{%@Y%0@;>aYI;!VQ}P zq%Z)m0?;kMAp>Y-YT?(2)L$m#)z^yw#J(PYaJA^tz2bWJVI~P*=ifu@{sqwE`}9fA z$LB(14GRm4KZv5S8>$ind)B#Evz#jw73@~3lUA`22AGn?N z#aN(aeJf9nE}2~Y7Y!-kyDit&)&>AyEDtaI=GUbEU7QdYjsIs{=f6D=z*+w*+Sw&@ z!$q_Z==*;`&;O!H`NIp)r0kOgYG=s&YaRa;6#JimsQzDi>H?;RE5?8jp0SF3E z_>=j2Fl$2|{@D%X7f~0F^$d z#sTf6^=w?!Uqs-w<$8L+%C7!1fk2r62v50~io~7o;soVfs!)I#`S+CyQd8NNEf?+v z^VI)q(ZD}`i~M7-!0Z22z&3EI|CI(y%y4l7QUNvFe1XAlcz0R4O(1(g1i zb0x6xiODj^eRZ(3eHRk1lTwvbfJ23voZ5u|!Pv(oUhRM;;g1;61u zq!ohJ83=A!-?ov~4qZ9NpFjhgv6p84ayCBkmfSf#7GyiwlP9_KIiDj26~r+_i3jH4 z!z&jsf9Cy7wx2@&`=|8~*RUtFom4@$K4=(NyO;BatB>P}6L6@O6J1p@Z+UtZW2%V$ zdLu@^>wO#xSyqSxOhnMlnk-X1P{|C@yx4pD?EnQ=;)r+2wb~GhA0qfX{7%hDQxWm^ zC7sEZ=lBd!)hpi|%c-O72aJ)B?b0Rw5Uj`7@p`o(%1IhvrMO(rc`*S3f(mrWC*2|d zjpfBOsp@=0(@d>>TJ;vMLEdCh;UN>A$`uxdzpd+nMb&R@KMOs>+BG%QL{C+HR4U(5- zHlI!RSB$Fhxx+R#?Ey!MntrK|I&Wi*OnTp$|C=VDP3KA%=&gIOE>#8H=*AUBD^S|4 z#8dFlIpj!m_kGas!Jzo34heLPK@q;8mbMe`L?A;k=XtbFPd<>?pe7MA(BkVTA(Jdg zR|D9Nw6E@w{}$)T>&JA7>WvrmU8$j5FgkYoM|t~p(q`klz$8xWZ~-z`CQ4d`Z6-r= ziQ4t1;Vsyr79L38XT83h9EjP-SddZay|GwH^AIO$O4fIOWz!ZDd{Kt>sh1Jy-bA(i zGi(_#z~~a0umFT~0Lbbo`o(^KyxqLJ*a$IsR;9R7()`J}$bKwH(0PpwJ;wVYK#5d$ zE_|z~+X2JFtaw^rilnl*&c@B7_I6%{7N{0SvDK1u%~*AO=HA@?hudID$81G16_Aem zhhLjIwA>Q8O|u4=c4j~vBwgX|udF6PUn~D0BaK#jX14C;aEPRDMLHUTlNf)|qow zb;?=;;*-JZmu+eh*RT9g3-Y`7m@2B(LK`ORj-bp0OUP#l);rGMhlUS=0#gWLjWb8c zF8p$c1$XgH3pP)z7d}#4VEOmvcuVtc?t}Q3I&!BU*}qa7rC;WJs&S<>DIcP^58C=} z8+!GnE9eobc>}jMa!gWLI*e}iu;sCAd3(kEd@RP!zc#PkEo1m#e#&p+NSIvw)Q_-2 zi*bD^WOUSkgbWfYSO)lH1y>ydIH%YA+d3r9!9V%C_sj_yP;!7@2~UK+mf%A{Qb zwxKChVM?uEyaD`iXo_%0Jyii#hZ zR{2N*{@9q^E6~A8%Voi`16}o}NER6_v+4*)d^vZYQees~B*P5_*OATn$%@b_p3P zsv9irpmEo=7DnZ`=KZgmkN#pf?lFHNGosRylu0-J4u+3m#sA7~A8?PDA{Sj3mL&Yp z!{4q>qci`hribj7$77{UK$>%zpp4TTDT(1ZYNoJngn>~|i-c}~T#5toA#-RaTai~# zRQfZSE$Q=O(*>iE{b&`&mjO=xdS*$<@aG7Vl(RF)XNvm^yqqj~a*W6FA^&9^LHtOUyOQTr5n)}02A)KQH#i8+SU;%a ztHyVN#XsFP9f&R+hl`w-=!=uV$7$f-KYgy>7XTqZFKVyP z`POu z^8?Bf!;E>eIxuk`j^eM+aG5b{ zTtZoqO0r9a(`<5qbP3|K70eDDkybC{7JS){baJ?sY%g%64sB6gYfe4V$J4%Jd)$jJ z5ZA`-R{hRvv5(U)mb3v$FzSHNyTPTH#dv*iCbM%>Q7G=9u+Zq%mZ;vCa|>9Pz+(69 z)Qi)3XsfC`I|`k#G2@)(xw=~9G_ED8TMnbxPmdPfxOqnfIH7~mzO63^H51~>4v$d; zd&RNrM-BfltPm7u)g9A;#2@b?jLNNAdi}Fhs3g=y1|DWk{b;UVELAo-t~eM{Gw`Sk zz`%WdOrzH9wCrI9O-H^YYZxAI6K2v#$MaH`!;nYN=U#N_{?{h_*0^VwC9Y&z`aHc< z{j1*Z&V#)%A0;dJhDVLu-m}oO++EX-UlmN)g4DU6E0-LJf{im;AQ&_|;i)X(J zB~7cfX?T6VG5H`e0~3W#*G;ny-*=jvxI#+UuE}R>OUfE)e_iDrxQ)>eG7e!`@JRE$ zZU~E=e5+oG>HAiOwIci!UXubImA*30U zs~ezPEw5hh2(1@q+FDfb-M0ZGwc&9=Tm~a=B^>9q;a&7Crgol~Uv%Dn{$w2l`|%%$ ziO!Z2wICBiUxGRs&JCneF_vd%j7v_N1I(+;`VzA&`#znHFxZTzQgj#)q4u{;mGa*D zH5iccGdxBs86B(Npuj0C?DKAlYb1I_wJN91mkOGrEsD0Rn43B5b>6F4DOiZ-889ma zr5EY_AZy9oTQUvpy!wK|(O5n=;J8Y!fg5y0Di?o$Saq6;huaYBSMQmN*H!$Q6_&-o4<71ZMCJX=stA7nPkY?epG2pAq9n={SKT!5W>D=8jtc3KK7I=8U}gs%fD$- zkbSc4&lGsX=@jd`e{;Ce?4%O58=p7Qo(-&{P+?Z~885WidsnYqNeAcCisDYkPb}PD z?0N;&lN`@wHikW>=RIrDlg3IxUiGzsfVY-7l9%;rr+tNZWYZc z7VSS|m`0mm@5M7(enm>zlevIJNQ2frqzR~8`+_94(NAcLo+QOxBYjnp@Ol2F`%9_z z()Z?!)Z%-ZP74;Pr9C&G<`ecyDM)+A={hi|8LIDln&FHoNz51%Ksp-WR6kCUOa9y? ztTxF}SOKo$wU$ZevxZ}dS(Do8_*pJ+4rqQRmwGH#;Fvl}y;A7o?8_*1kM5_ORfH&! zsuJw4%SNtiLnxZQzT}PmU0RcDQE6Yj7>Rw0rds&koSjNBzvHYCn{L?U`}LfJ?^z{S zb)&jEgM4$)(A{?OpnY&rNkdr73mE#TewAIGa7|e>RU5;tG8*WLu4Bns>Ky@ub%m+# z2`8b2bbY?sDsKKA$Pcr{r1RNJp~CQL{^)o*kvoi}YXJ!0N8nBS~o zcW4C@Iw`x@1~*ZQG3SLgrn7Jk#O{#nY;VBp@1b2#b5(L_Asj4D#^!AEw(*u$MqmJi%MPQtVXsD+s&!TM$|_1EnA#|XG*Rp7EthTmJU%zx|V4zc1ckD3W6R=TA_mT7}4#3p=PK$07smm~+XZVDk zi8I4gp!N$|cH4kp;@q&ktW$ zrPBmQ2JQN2x*tER?hG~MRxW2};i)fkV_i{{+)f;-EDthXl0_&Mev@;&D0-w`wp|8f zu|(cke+5?Rb=Dnk72kWg&&Etl&99n>$v8Jcx>j%wwqJ{%b<;YIREv61!70pOAPnnc zO?ka!VHsyhK|8u=;5!wdM51r0vdG;mWdU;WPagFvfGfF{-}{+Oai2D)cJpS$Ezj;@ z(F&WMCdWKsz37SeAIM4RC&0V&>=N5l4N#>|TIFDV)k(XRXp(0P_}RTp<2q{pg~y?+ z(Iaa?PgQDQo0FTgKE1QB0@~SXi1SA!N`JALCNtfR6cJo^v8hUQk50?glpPXvDuyI% zqJ5%agRwZ7x4vP6Zm4xoo~0!_s#&=qKu62BnsA-Ed`=ve0`hu;Q%wYhCVa>%ox-y? zA+FkhSyUR4uASre>ZRc2YU}(70Y}pcW6GtJ-ldte7ZWHqX&K zP2{%!WNp@Ba^$?)H-=dtT<&$O)1N)`Z7|`PEV}!cwdTM_0uFIJCM29W6&i1Stlt=< zao69vaZNCwV{)gc+P$TkK1#~~S?DHGGMlB3>-E4d+u|QeseRmffCUK3^MH;hYcG$k z0>r@n;F>nm*xc^!t!PZ%+a+JSAGK8FYB4I+LAfGl_yhxr32^)= z;g$$QwZ|s@QDScKCzkYUFjwVdcq@T-D}%5(u&=0QM z2YLcPgX`pZHr5=BjB^rC%D##j_MxDhd_ zks@sDoM5y={{BWcB$axgMpJypUT6hwX_X&tZ~CT|U*MZnMdM6d!^XD;vN4H@1B^psw!@|=`fo2{04 z-)EWn5EdO>8fx!e!;5p(5}sJ9zR-5%oF#VGl=8}Qy#_xY$6$e^?FYOlH)$Vj8jiuu zS|Q7ds*`zS%`2DzkP(QxA17$}B70uSTV68kwss?UXTvN{pV*%^BBsDSLpZ2hGetUy zmr8>r`2SC5OQmXN{^}@L^f>A=k95()zx57+WLij6#kZA?(?YQVEsa}nbTA6QF_pQXe3cFdUN*_g0lh1t9 zqYZnlh%Ox(N{4^O@ZGZC7s%&O=^KCC1D}S2)*4GL$1odDJx3q?P{aQkr^uQ$-5i!- zge~zi?SA$AB@vh{ht}KPM01ERw@;ff5?5C?sh)J}`i zf{Yd^oomZ+Gh;7tJ?)W+%iE{vjIc+7JKbt&?k`Qo}m!0fx)}S^_n_iE5GA-2f}%!#Vu&!=A&oJfA6cG5+K9aPVw^f zx0~bCifemEyZjbrLiu+7gF#zL6+e<&`VytLSJnInle*{eUdsg#&w>e;7uHRVrW*5I z$26UdJc*5`A*pWL;yb0Hx(9EdyB+%yJ30RNlmi>%D(EV^+wR#yO2XY^AJ>Y40+A{v zSVDqe%a7SvgyB~2dQ#GPwV`NkR>CH6P_nqNg!oPqWUD`o#xKL?oH^0DvzxNH1-gh# zN>R0mneU?PlALa8NX~`I&CKxo(`P`Yv?(n&?Q+akRc(Z5f|{9P_QywE#`n}x#JI;g zMe-*qgd?}67esY>rbJ9(NPmpL|JL4>1~rvs;i$CsR0rr8W(2DVh)8Q;1GZr?1_JGd zG%Ah=QFg^Z1F{(~gpdS8VMf`vkU+qN1_S~ECg}hnAUepFC=f6Nf^1<4BtQ&%l1b41 zGrzj3d;ayQdR6bf^Uk@a&b{Z>yRW`;E+e+p@a7#6%zfrVBxL+~(m`%i=tx%e(0(&| zh+7^-K=x?6*Cedc0i&;)LE)4)4bxlQESfB#DyE8*wDJrhD)I00n(Zl_>XM$0j+l1# z6{7L644I*+4CK2z*hec@@m{iLCj2tFz3njxFIynULerb$1PZ-CKz!=~)jEfT^K)}Y z8RnxtJYujG`xVlHQ)a)q)Pz^uhityMMnrcKA(AKb>AG}0tXRJI8WMK;R0VW!a&H_G7XD`Ep{A{uGC-bE?J@J<0dE1+hcImO&fKEf`JT=K~)8- zO;(JMr&&{O1G3-rP|S)C^%a!rM~XL>i~9I06V6wy3T$AROlryXt@&=E9VC?Ee~cFT z3d}l)C(6P?igSVjIUGk=x`amh%j|A-Y&hCkg^`EcUo{2f|H1v7L=`^()#Pxn=$oasNSPD z0u(>BPB9{clPMs(1Ie_suJ8LeJy84GXV`}P43BU}af6&I2q-tq^WVi}D4Un5a_-QR!6!a#!CBd<%mtD%~YUnasF5TN$(=!x1JReONJu- zVOTD`j<)Jny}H6(ZzZsD3VdD&sPj$AZ`Q{(jgeE(0O9k<`sKV;PN!#)RLOKP?||3% zl3Za@()pj_6xIt@qfYH*du2GM8|DuB#9V{n#-s%1>e89@4UoUI2;JwianB~%s$KPJ29pX~w9Gxs4;u*a{v^IshH-Q1Xr`^YQ{9L}r{=_*z#k;;=- zfaAAAcnvqM8HnwS+Cgy%>N%2c>$lQ00(<{R`Nkf#@3_8Q(PL)qSNAbG1Fjj$v z_zV9+?1!B&PU7}bsmAHm%@z;CnIDUi6+CLz!e3x=SFS{)VUQ|#s}VN>YCO{-0FMG@_Wjl zaL%eMfL(}OZqP~V95dFw7`<6jztYTKZo5wxwt~ROPT1(iIo#H|3u2;>K?HB!(;pF# z#x8US7SaQ`S)O%^_F-K@BD{J04*#}fyo!W68DI&&%%|EuRAMlO65Y{)9%qG7aojus zqP$ywOhnB_zREv!tcnJO7U2$v4Av0ht(r3oR9m&&3n%ZQ*fDHZ!}AFf-&&P6;Lz@O zn%8peMD91aY@5mMQ`z1}2#5>5?E9;c%^%xsCAt=L1vGit0nS-MJQ7ZQJxh?|KG0mf z+uMu^@X_-G*{yUKUJ$Dk0|3CZ&Y&`~@Wz#-^MQeZStU#+^9^V4-Mh?##G}{mrfRk% zJRW;wsa=Ucp*RZio6!6W20r?NIiw*g6y;rz?!&V5KC9Cykkr}%v?9K-zIE=h0$uyh zr)PQZf&1X9b^a~B0@F8=3@vmUDn)E$YC1)SsAjSeu4TvbQGZpzE}*5h3Vh@DFHnv@ z2WpdDpgNBQ?IQM|wr8k*T3oVGt2nA*3V9(f*C!RFoLK5XudXiyRV}b93c@>1VN%sV zIGK(E0H7DAIU!Bbjx!~k58fKZmk014NQ6mzYet}|N(exHQkCTH_ts5|n7@=Pz7Wn4 z%*SjjRr$pE?^Uen@@B+v)k`0Bc4z?Ne}MCw4-U$CSzdvMRS)&{8+=ar`@7@kMEM8C z@hXOjUaJB@P4VMj?%%#~h*W)dsOi!1ou4ozm-JOS)pR%w@CnlJ8`bDJ^ADru63bZlw)+QAQCWo2dJ)X>oID^n~MALJB4ckWIC?A%q(U_hMeLix1O z9IRSa%ZnRqMJAJ-itJDtK;RCI-Itu5ok=88Z(m<_T3XutFvE2l@N*pCR>_?oq8plPm`ulSR2HZJ- zgapALa0jp|DJdysANX5uZ|_;L_@awTdh!!BU_;-}H1|h!&%?uod3k%6cI{38>`eT) zCv0tTY@g~(%vQC%06mSO&x!QE(OKJ4zt`s^;0~p3R8*ASrvckYJ>syfH-7w=o%f8a zg8L6AZnqs+$S;29;Qk@@{$W$?PiwY4@c)eFKVAGkF5c3fiXiopZJXb!8BS*|o~}OW GclW;-6&Z5? diff --git a/auto-dark-light@gihaume/src/app/handlers/Appearance_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Appearance_handler.ts new file mode 100644 index 00000000000..03c293245f8 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/handlers/Appearance_handler.ts @@ -0,0 +1,55 @@ +import * as mobx from "mobx"; + +import type { Twilights } from "../../types"; +import * as system_time from "../../lib/sys/system_time"; +import type { Time_of_day } from "../../lib/core/Time_of_day"; + +export class Appearance_handler { + private _time = system_time.get_now_as_time_of_day(); + update_time() { + this._time = system_time.get_now_as_time_of_day(); + } + twilights!: Twilights; + get auto_is_dark(): boolean { + return this._time.is_between( + this.twilights.sunset, this.twilights.sunrise + ); + } + + manual_is_dark!: boolean; + toggle_is_dark() { + this.manual_is_dark = !this.manual_is_dark; + } + + is_auto!: boolean; + toggle_is_auto() { + this.is_auto = !this.is_auto; + } + + get is_dark(): boolean { + return this.is_auto + ? this.auto_is_dark + : this.manual_is_dark; + } + + get is_unsynced(): boolean { + return this.manual_is_dark !== this.auto_is_dark; + } + + sync_is_dark() { + this.manual_is_dark = this.auto_is_dark; + } + + get next_twilight(): Time_of_day { + return this.auto_is_dark + ? this.twilights.sunrise + : this.twilights.sunset; + } + + constructor(initial_controls: Required>) { + Object.assign(this, initial_controls); + mobx.makeAutoObservable(this); + } +} diff --git a/auto-dark-light@gihaume/src/app/handlers/Background_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Background_handler.ts new file mode 100644 index 00000000000..8504f922656 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/handlers/Background_handler.ts @@ -0,0 +1,66 @@ +import type { Applet } from "../ui/Applet"; +import type { Settings } from "../ui/Settings"; +import { System_background } from "../../lib/sys/System_background"; + +export class Background_handler { + private readonly _settings: Settings; + + constructor(applet: Applet, settings: Settings) { + this._settings = settings; + + applet.on_button_detect_background_light = + () => this.detect_light_background(); + applet.on_button_detect_background_dark = + () => this.detect_dark_background(); + applet.on_button_apply_background_light = + () => this.apply_light_background(); + applet.on_button_apply_background_dark = + () => this.apply_dark_background(); + } + + detect_light_background(): void { + const is_slideshow = System_background.is_slideshow; + this._settings.light_background_is_slideshow = is_slideshow; + if (is_slideshow) + this._settings.light_background_slideshow_folder = + System_background.slideshow_folder + .replace('directory://', "file://") // https://github.com/linuxmint/cinnamon/issues/12374 + else + this._settings.light_background_file = System_background.picture_file; + } + detect_dark_background(): void { + const is_slideshow = System_background.is_slideshow; + this._settings.dark_background_is_slideshow = is_slideshow; + if (is_slideshow) + this._settings.dark_background_slideshow_folder = + System_background.slideshow_folder + .replace('directory://', "file://"); // https://github.com/linuxmint/cinnamon/issues/12374 + else + this._settings.dark_background_file = System_background.picture_file; + } + apply_light_background(): void { + const is_slideshow = this._settings.light_background_is_slideshow; + System_background.is_slideshow = is_slideshow; + if (is_slideshow) + System_background.slideshow_folder = + decodeURIComponent( // If the folder was chosen via a filechooser, it may contain non-ASCII characters + this._settings.light_background_slideshow_folder + .replace('file://', "directory://") // https://github.com/linuxmint/cinnamon/issues/12374 + ); + else + System_background.picture_file = + this._settings.light_background_file; + } + apply_dark_background(): void { + const is_slideshow = this._settings.dark_background_is_slideshow; + System_background.is_slideshow = is_slideshow; + if (is_slideshow) + System_background.slideshow_folder = + decodeURIComponent( // If the folder was chosen via a filechooser, it may contain non-ASCII characters + this._settings.dark_background_slideshow_folder + .replace('file://', "directory://") // https://github.com/linuxmint/cinnamon/issues/12374 + ); + else + System_background.picture_file = this._settings.dark_background_file; + } +} diff --git a/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts new file mode 100644 index 00000000000..5c4287eebd8 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts @@ -0,0 +1,36 @@ +import type { Applet } from "../ui/Applet"; +import { launch_command } from "../../lib/sys/launch_command"; +import type { Settings } from "../ui/Settings"; + +export class Commands_handler { + private readonly _settings: Settings; + + constructor(applet: Applet, settings: Settings) { + this._settings = settings; + + applet.on_button_launch_commands_light = + () => this.launch_light_commands(); + applet.on_button_launch_commands_dark = + () => this.launch_dark_commands(); + } + + launch_dark_commands(): void { + this._launch_commands(this._settings.dark_commands_list); + } + + launch_light_commands(): void { + this._launch_commands(this._settings.light_commands_list); + } + + private _launch_commands( + commands_list: + | Settings['light_commands_list'] + | Settings['dark_commands_list'] + ): void { + for (const command of commands_list) { + if (!command.active) + continue; + launch_command(command.name, command.expiry, command.command); + } + } +} diff --git a/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts new file mode 100644 index 00000000000..652a3c144e4 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts @@ -0,0 +1,55 @@ +const { GLib } = imports.gi; + +import * as mobx from "mobx"; + +import type { Location } from "../../types"; +import { metadata } from '../../globals'; +import { Timezone_change_listener } from '../../lib/sys/Timezone_change_listener'; +import { Timezone_location_finder } from "../../lib/core/Timezone_location_finder/Timezone_location_finder"; + +export class Location_handler { + private readonly _timezone_change_listener = new Timezone_change_listener( + new_timezone => this._timezone = new_timezone + ); + private _timezone: string = GLib.TimeZone.new_local().get_identifier(); + get timezone(): string { + return this._timezone; + } + + private readonly _timezone_location_finder = new Timezone_location_finder( + `${metadata.path}/Timezone_location_finder` + ); + get auto_location(): Location { + return this._timezone_location_finder.find(this.timezone); + } + + manual_location!: Location; + + is_location_auto!: boolean; + + get location(): Location { + return this.is_location_auto + ? this.auto_location + : this.manual_location; + } + + constructor(initial_values: Required>) { + Object.assign(this, initial_values); + mobx.makeAutoObservable< + Location_handler, + '_timezone_change_listener' | '_timezone_location_finder' + >(this, { + _timezone_change_listener: false, + _timezone_location_finder: false, + manual_location: mobx.observable.deep, + }); + this._timezone_change_listener.enable(); + } + + /** Releases acquired resources */ + dispose(): void { + this._timezone_change_listener.dispose(); + } +} diff --git a/auto-dark-light@gihaume/src/app/handlers/Themes_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Themes_handler.ts new file mode 100644 index 00000000000..06ad8d3f7e4 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/handlers/Themes_handler.ts @@ -0,0 +1,49 @@ +import type { Applet } from "../ui/Applet"; +import type { Settings } from "../ui/Settings"; +import { System_color_scheme } from "../../lib/sys/System_color_scheme"; +import { System_themes } from "../../lib/sys/System_themes"; + +export class Themes_handler { + private readonly _settings: Settings; + + constructor(applet: Applet, settings: Settings) { + this._settings = settings; + + applet.on_button_detect_themes_light = () => this.detect_light_themes(); + applet.on_button_detect_themes_dark = () => this.detect_dark_themes(); + applet.on_button_apply_themes_light = () => this.apply_light_themes(); + applet.on_button_apply_themes_dark = () => this.apply_dark_themes(); + } + + detect_light_themes(): void { + this._settings.setValue('light_themes_mouse', System_themes.mouse); + this._settings.setValue('light_themes_apps', System_themes.apps); + this._settings.setValue('light_themes_icons', System_themes.icons); + this._settings.setValue('light_themes_desktop', System_themes.desktop); + this._settings.light_themes_have_been_detected = true; + } + + detect_dark_themes(): void { + this._settings.setValue('dark_themes_mouse', System_themes.mouse); + this._settings.setValue('dark_themes_apps', System_themes.apps); + this._settings.setValue('dark_themes_icons', System_themes.icons); + this._settings.setValue('dark_themes_desktop', System_themes.desktop); + this._settings.dark_themes_have_been_detected = true; + } + + apply_light_themes(): void { + System_themes.mouse = this._settings.getValue('light_themes_mouse'); + System_themes.apps = this._settings.getValue('light_themes_apps'); + System_themes.icons = this._settings.getValue('light_themes_icons'); + System_themes.desktop = this._settings.getValue('light_themes_desktop'); + System_color_scheme.value = 'prefer-light'; + } + + apply_dark_themes(): void { + System_themes.mouse = this._settings.getValue('dark_themes_mouse'); + System_themes.apps = this._settings.getValue('dark_themes_apps'); + System_themes.icons = this._settings.getValue('dark_themes_icons'); + System_themes.desktop = this._settings.getValue('dark_themes_desktop'); + System_color_scheme.value = 'prefer-dark'; + } +} diff --git a/auto-dark-light@gihaume/src/app/handlers/Twilights_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Twilights_handler.ts new file mode 100644 index 00000000000..f8fdff5be8e --- /dev/null +++ b/auto-dark-light@gihaume/src/app/handlers/Twilights_handler.ts @@ -0,0 +1,58 @@ +const { DateTime } = imports.gi.GLib; // Preferred over JS's `Date` to take into account timezone changes during runtime. + +import * as mobx from "mobx"; + +import { compute_twilights } from "../../lib/core/compute_twilights/compute_twilights"; +import type { Location, Twilights } from "../../types"; +import { Time_of_day } from "../../lib/core/Time_of_day"; + +export class Twilights_handler { + private _date = DateTime.new_now_local(); // TODO: could be `null` if timezone is bad or missing? + update() { + this._date = DateTime.new_now_local(); // TODO: same as above + } + location!: Location; + private get _location_twilights(): Twilights { + return compute_twilights(this._date, this.location); + } + + auto_sunrise_offset!: number; + auto_sunset_offset!: number; + + get auto_sunrise(): Time_of_day { + return this._location_twilights.sunrise.add_minutes( + this.auto_sunrise_offset + ); + } + get auto_sunset(): Time_of_day { + return this._location_twilights.sunset.add_minutes( + this.auto_sunset_offset + ); + } + + manual_sunrise!: Time_of_day; + manual_sunset!: Time_of_day; + + is_sunrise_auto!: boolean; + is_sunset_auto!: boolean; + + private get _sunrise(): Time_of_day { + return this.is_sunrise_auto ? this.auto_sunrise : this.manual_sunrise; + } + private get _sunset(): Time_of_day { + return this.is_sunset_auto ? this.auto_sunset : this.manual_sunset; + } + get twilights(): Twilights { + return { sunrise: this._sunrise, sunset: this._sunset }; + } + + constructor(initial_values: Required>) { + Object.assign(this, initial_values); + mobx.makeAutoObservable(this); + } +} diff --git a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts new file mode 100644 index 00000000000..505a768c891 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts @@ -0,0 +1,308 @@ +const { GLib } = imports.gi; + +import * as mobx from 'mobx'; + +import { _ } from '../../globals'; +import { Appearance_handler } from './Appearance_handler'; +import type { Applet } from '../ui/Applet'; +import { Background_handler } from './Background_handler'; +import { Commands_handler } from './Commands_handler'; +import { Event_scheduler } from "../../lib/sys/Event_scheduler/Event_scheduler"; +import { Keybinding_handler } from '../../lib/sys/Keybinding_handler'; +import { Location_handler } from './Location_handler'; +import { logger } from '../../globals'; +import type { Settings } from '../ui/Settings'; +import { sleep } from '../../lib/utils'; +import { Sleep_events_listener } from '../../lib/sys/Sleep_events_listener/Sleep_events_listener'; +import { System_color_scheme } from '../../lib/sys/System_color_scheme'; +import { Themes_handler } from './Themes_handler'; +import { Time_change_listener } from '../../lib/sys/Time_change_listener'; +import { Time_of_day } from '../../lib/core/Time_of_day'; +import { Twilights_handler } from './Twilights_handler'; + +const DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING = 2000; // milliseconds (ms) + +export function initialize_handlers(applet: Applet, settings: Settings): void { + const location_handler = new Location_handler({ + manual_location: { + latitude: settings.manual_latitude, + longitude: settings.manual_longitude + }, + is_location_auto: settings.is_location_auto + }); + + // Controls + settings.bind('manual_latitude', null, value => { + location_handler.manual_location.latitude = value; + }); + settings.bind('manual_longitude', null, value => { + location_handler.manual_location.longitude = value; + }); + settings.bind('is_location_auto', null, value => { + location_handler.is_location_auto = value; + }); + + // Views + mobx.autorun(() => { + settings.setValue('system_timezone', location_handler.timezone); // https://github.com/linuxmint/cinnamon/issues/9336 + }); + mobx.autorun(() => { + settings.setValue( // https://github.com/linuxmint/cinnamon/issues/9336 + 'auto_latitude', location_handler.auto_location.latitude + ); + settings.setValue( // https://github.com/linuxmint/cinnamon/issues/9336 + 'auto_longitude', location_handler.auto_location.longitude + ); + }); + + const twilights_handler = new Twilights_handler({ + location: location_handler.location, + auto_sunrise_offset: settings.auto_sunrise_offset, + auto_sunset_offset: settings.auto_sunset_offset, + manual_sunrise: new Time_of_day(settings.manual_sunrise), + manual_sunset: new Time_of_day(settings.manual_sunset), + is_sunrise_auto: settings.is_sunrise_auto, + is_sunset_auto: settings.is_sunset_auto + }); + + // Controls + mobx.autorun(() => { + twilights_handler.location = location_handler.location; + }); + settings.bind('auto_sunrise_offset', null, value => { + twilights_handler.auto_sunrise_offset = value; + }); + settings.bind('auto_sunset_offset', null, value => { + twilights_handler.auto_sunset_offset = value; + }); + settings.bind('manual_sunrise', null, value => { + twilights_handler.manual_sunrise = new Time_of_day(value); + }); + settings.bind('manual_sunset', null, value => { + twilights_handler.manual_sunset = new Time_of_day(value); + }); + settings.bind('is_sunrise_auto', null, value => { + twilights_handler.is_sunrise_auto = value; + }); + settings.bind('is_sunset_auto', null, value => { + twilights_handler.is_sunset_auto = value; + }); + + // Views + mobx.reaction(() => twilights_handler.auto_sunrise, async () => { // `autorun` doesn't track in an async execution context + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); // https://github.com/linuxmint/cinnamon/issues/12362#issuecomment-3195498976 + settings.setValue( // https://github.com/linuxmint/cinnamon/issues/9336 + 'auto_sunrise', twilights_handler.auto_sunrise.get_as_string_hhmm() + ); + }, { fireImmediately: true }); + mobx.reaction(() => twilights_handler.auto_sunset, async () => { // `autorun` doesn't track in an async execution context + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); // https://github.com/linuxmint/cinnamon/issues/12362#issuecomment-3195498976 + settings.setValue( // https://github.com/linuxmint/cinnamon/issues/9336 + 'auto_sunset', twilights_handler.auto_sunset.get_as_string_hhmm() + ); + }, { fireImmediately: true }); + + const appearance_handler = new Appearance_handler({ + twilights: twilights_handler.twilights, + manual_is_dark: System_color_scheme.value === 'prefer-dark', + is_auto: settings.is_appearance_auto + }); + + // Controls + mobx.autorun(() => { + appearance_handler.twilights = twilights_handler.twilights; + }); + // @ts-ignore: wrong return type in @ci-types/cjs 6.0.2-5 + applet.on_applet_clicked = () => { + appearance_handler.toggle_is_dark(); + }; + // @ts-ignore: wrong return type in @ci-types/cjs 6.0.2-5 + applet.on_applet_middle_clicked = () => { + appearance_handler.toggle_is_auto(); + }; + settings.bind('is_appearance_dark', null, value => { + appearance_handler.manual_is_dark = value + }); + settings.bind('is_appearance_auto', null, value => { + appearance_handler.is_auto = value + }); + + // Views + mobx.reaction(() => appearance_handler.manual_is_dark, async () => { // `autorun` doesn't track in an async execution context + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); // https://github.com/linuxmint/cinnamon/issues/12362#issuecomment-3195498976 + settings.is_appearance_dark = appearance_handler.manual_is_dark; + }, { fireImmediately: true }); + mobx.reaction(() => appearance_handler.is_auto, () => { + settings.is_appearance_auto = appearance_handler.is_auto; + }); + mobx.reaction(() => appearance_handler.is_unsynced, async () => { // `autorun` doesn't track in an async execution context + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); // https://github.com/linuxmint/cinnamon/issues/12362#issuecomment-3195498976 + settings.setValue( // https://github.com/linuxmint/cinnamon/issues/9336 + 'is_appearance_unsynced', appearance_handler.is_unsynced + ); + }, { fireImmediately: true }); + mobx.reaction(() => appearance_handler.next_twilight, async () => { // `autorun` doesn't track in an async execution context + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); // https://github.com/linuxmint/cinnamon/issues/12362#issuecomment-3195498976 + settings.setValue( // https://github.com/linuxmint/cinnamon/issues/9336 + 'next_update', appearance_handler.next_twilight.get_as_string_hhmm() + ); + }, { fireImmediately: true }); + mobx.autorun(() => { + applet.set_applet_icon_symbolic_name( + appearance_handler.is_auto + ? appearance_handler.is_unsynced + ? 'auto-inverted-symbolic' + : 'auto-symbolic' + : appearance_handler.manual_is_dark + ? 'dark-symbolic' + : 'light-symbolic' + ); + }); + + const keybinding_handler = new Keybinding_handler(() => { + appearance_handler.toggle_is_dark(); + }); + keybinding_handler.keybinding = settings.appearance_keybinding; + settings.bind('appearance_keybinding', null, value => { + keybinding_handler.keybinding = value; + }); + + const themes_handler = new Themes_handler(applet, settings); + + if (System_color_scheme.value === 'prefer-dark') { // TODO: clear this idea so the user if not confused + if (settings.dark_themes_have_been_detected) + themes_handler.detect_dark_themes(); + } else { + if (settings.light_themes_have_been_detected) + themes_handler.detect_light_themes(); + } + const color_scheme = mobx.makeAutoObservable({ + value: System_color_scheme.value + }); + const system_color_scheme = new System_color_scheme(new_color_scheme => { + color_scheme.value = new_color_scheme; + }); + let is_update_from_system = false; // Temporary fix // TODO: improve the model + mobx.autorun(() => { + appearance_handler.manual_is_dark = + color_scheme.value === 'prefer-dark'; + is_update_from_system = true; + }); + + const background_handler = new Background_handler(applet, settings); + const commands_handler = new Commands_handler(applet, settings); + + mobx.reaction(() => appearance_handler.manual_is_dark, () => { + if (is_update_from_system === true) { + is_update_from_system = false; + return; + } + if (appearance_handler.manual_is_dark) { + system_color_scheme.disable(); + themes_handler.apply_dark_themes(); + system_color_scheme.enable(); + if (settings.enable_background) + background_handler.apply_dark_background(); + if (settings.dark_commands_is_enabled) + commands_handler.launch_dark_commands(); + } else { + system_color_scheme.disable(); + themes_handler.apply_light_themes(); + system_color_scheme.enable(); + if (settings.enable_background) + background_handler.apply_light_background(); + if (settings.light_commands_is_enabled) + commands_handler.launch_light_commands(); + } + }, { fireImmediately: true }); + mobx.autorun(() => { + if (!appearance_handler.is_auto) + return; + appearance_handler.manual_is_dark = appearance_handler.is_dark; + }); + + const time_change_listener = new Time_change_listener( // Throws + () => mobx.runInAction(() => { + twilights_handler.update(); + appearance_handler.update_time(); + if (scheduler.is_set && scheduler.get_if_should_be_expired()) // TODO: need of the same logic at startup ? + appearance_handler.sync_is_dark(); + }) + ); + + const sleep_events_listener = new Sleep_events_listener( + // on sleep entries: + () => { + time_change_listener.disable(); + }, + // on wake-up unlocked: + () => mobx.runInAction(() => { + twilights_handler.update(); + appearance_handler.update_time(); + if (scheduler.is_set && scheduler.get_if_should_be_expired()) // TODO: need of the same logic at startup ? + appearance_handler.sync_is_dark(); + time_change_listener.enable(); + }) + ); + + const scheduler = new Event_scheduler(); + const schedule_the_event = () => { + // logger.info(`Next change at ${appearance_handler.next_twilight.get_as_string_hmmss()}`); // Debug + scheduler.set_the_event(appearance_handler.next_twilight, () => { + twilights_handler.update(); + appearance_handler.update_time(); + appearance_handler.sync_is_dark(); + }); + }; + mobx.reaction(() => appearance_handler.is_auto, () => { + if (appearance_handler.is_auto) { + appearance_handler.update_time(); + appearance_handler.sync_is_dark(); + schedule_the_event(); + time_change_listener.enable(); + sleep_events_listener.enable(); + } else { + scheduler.unset_the_event(); + time_change_listener.disable(); + sleep_events_listener.disable(); + } + }); + mobx.reaction(() => appearance_handler.next_twilight, () => { + if (appearance_handler.is_auto) + schedule_the_event(); + }, { fireImmediately: true }); + + applet.set_applet_tooltip( + `${_("Click")}${_(":")} ${_("toggle dark/light appearance")}\n` + + `${_("Middle-click")}${_(":")} ${_("toggle automatic switch")}`, + true // use_markup + ); + applet.on_button_open_os_timezone_settings = + () => GLib.spawn_command_line_async("cinnamon-settings calendar"); + applet.on_button_open_os_themes_settings = + () => GLib.spawn_command_line_async('cinnamon-settings themes'); + applet.on_button_open_os_background_settings = + () => GLib.spawn_command_line_async('cinnamon-settings background'); + + // applet.on_applet_instances_changed = () => {}; + // applet.on_applet_added_to_panel = () => {}; + // applet.on_applet_reloaded = () => {}; + // applet.on_orientation_changed = (orientation: imports.gi.St.Side) => {}; + // // @ts-ignore: wrong return type in @ci-types/cjs 6.0.2-5 + // applet.on_panel_height_changed = () => {}; + // applet.on_panel_icon_size_changed = () => {}; + + applet.on_applet_removed_from_panel = () => { + keybinding_handler.dispose(); + location_handler.dispose(); + scheduler.dispose(); + sleep_events_listener.dispose(); + system_color_scheme.dispose(); + time_change_listener.dispose(); + settings.finalize(); + }; + + system_color_scheme.enable(); + time_change_listener.enable(); + sleep_events_listener.enable(); +} diff --git a/auto-dark-light@gihaume/src/app/initialize_applet_settings.ts b/auto-dark-light@gihaume/src/app/initialize_applet_settings.ts new file mode 100644 index 00000000000..e0cc7124393 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/initialize_applet_settings.ts @@ -0,0 +1,62 @@ +const { AppletSettings } = imports.ui.settings; + +import type { Settings } from "./ui/Settings"; + +export function initialize_applet_settings( + uuid: string, instance_id: number +): Settings { + const settings = new AppletSettings( + {}, uuid, instance_id + ) as unknown as Settings; + + ([ + 'is_appearance_dark', + 'appearance_keybinding', + 'is_appearance_auto', + // 'is_appearance_unsynced', + // 'next_update', + + 'auto_sunrise_offset', 'auto_sunset_offset', + // 'auto_sunrise', 'auto_sunset', + 'manual_sunrise', 'manual_sunset', + 'is_sunrise_auto', 'is_sunset_auto', + + 'manual_latitude', 'manual_longitude', + 'is_location_auto', + // 'system_timezone', + // 'auto_latitude', 'auto_longitude', + + // 'light_themes_mouse', + // 'light_themes_apps', + // 'light_themes_icons', + // 'light_themes_desktop', + + // 'dark_themes_mouse', + // 'dark_themes_apps', + // 'dark_themes_icons', + // 'dark_themes_desktop', + + 'enable_background', + + 'light_background_is_slideshow', + 'light_background_file', + 'light_background_slideshow_folder', + + 'dark_background_is_slideshow', + 'dark_background_file', + 'dark_background_slideshow_folder', + + 'light_commands_is_enabled', + 'light_commands_list', + 'dark_commands_is_enabled', + 'dark_commands_list', + + 'scheduler_timer_absolute_time', // TODO: use to get the unsynced appearance state properly restored? + + 'light_themes_have_been_detected', + 'dark_themes_have_been_detected' + // Commented entries because: https://github.com/linuxmint/cinnamon/issues/9336 + ] as const).forEach(key => settings.bindWithObject(settings, key, key)); + + return settings; +} diff --git a/auto-dark-light@gihaume/src/app/ui/Applet.ts b/auto-dark-light@gihaume/src/app/ui/Applet.ts new file mode 100644 index 00000000000..e9c1a2304a4 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/ui/Applet.ts @@ -0,0 +1,17 @@ +/** The names must match `settings-schema.json`. */ + +export interface Applet extends imports.ui.applet.IconApplet { + on_button_open_os_timezone_settings: () => void; + on_button_open_os_themes_settings: () => void; + on_button_detect_themes_light: () => void; + on_button_apply_themes_light: () => void; + on_button_open_os_background_settings: () => void; + on_button_detect_background_light: () => void; + on_button_apply_background_light: () => void; + on_button_launch_commands_light: () => void; + on_button_detect_themes_dark: () => void; + on_button_apply_themes_dark: () => void; + on_button_detect_background_dark: () => void; + on_button_apply_background_dark: () => void; + on_button_launch_commands_dark: () => void; +} diff --git a/auto-dark-light@gihaume/src/app/ui/Settings.ts b/auto-dark-light@gihaume/src/app/ui/Settings.ts new file mode 100644 index 00000000000..30bf3e2b629 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/ui/Settings.ts @@ -0,0 +1,71 @@ +/** The names and types must match `settings-schema.json`. */ + +import type { Time_hms, Command } from "../../types"; + +export interface Settings extends imports.ui.settings.AppletSettings { + is_appearance_dark: boolean; + appearance_keybinding: string; + is_appearance_auto: boolean; + is_appearance_unsynced: boolean; + next_update: string; + + auto_sunrise_offset: number, auto_sunset_offset: number; + auto_sunrise: string, auto_sunset: string; + manual_sunrise: Time_hms, manual_sunset: Time_hms; + is_sunrise_auto: boolean, is_sunset_auto: boolean; + + manual_latitude: number, manual_longitude: number; + is_location_auto: boolean; + system_timezone: string; + auto_latitude: number, auto_longitude: number; + + light_themes_mouse: string; + light_themes_apps: string; + light_themes_icons: string; + light_themes_desktop: string; + + dark_themes_mouse: string; + dark_themes_apps: string; + dark_themes_icons: string; + dark_themes_desktop: string; + + enable_background: boolean; + + light_background_is_slideshow: boolean; + light_background_file: string; + light_background_slideshow_folder: string; + + dark_background_is_slideshow: boolean; + dark_background_file: string; + dark_background_slideshow_folder: string; + + light_commands_is_enabled: boolean; + light_commands_list: Array; + + dark_commands_is_enabled: boolean; + dark_commands_list: Array; + + scheduler_timer_absolute_time: number; + + light_themes_have_been_detected: boolean; + dark_themes_have_been_detected: boolean; + + bindWithObject( + object: object, + key: keyof Settings, + obj_property: string + ): boolean; + + bind( + key: Key, + applet_prop: null, + callback: (new_value: Settings[Key]) => void + ): boolean; + + getValue(key: Key): Settings[Key]; + + setValue( + key: Key, + value: Settings[Key] + ): void; +} diff --git a/auto-dark-light@gihaume/src/globals.ts b/auto-dark-light@gihaume/src/globals.ts new file mode 100644 index 00000000000..bb23e92a17b --- /dev/null +++ b/auto-dark-light@gihaume/src/globals.ts @@ -0,0 +1,50 @@ +const Gettext = imports.gettext; +const { GLib } = imports.gi; +const Main = imports.ui.main; +const { St } = imports.gi; + +export const metadata: imports.ui.applet.AppletMetadata = { + uuid: "", + name: "", + description: "", + path: "", + force_loaded: false +}; + +export function _(text: string): string { + return Gettext.dgettext(metadata.uuid, text); +} + +let translated_applet_name = ""; + +export function initialize_globals(applet_metadata: imports.ui.applet.AppletMetadata) { + Object.assign(metadata, applet_metadata); + + const translations_dir_path = GLib.get_home_dir() + '/.local/share/locale'; + Gettext.bindtextdomain(metadata.uuid, translations_dir_path); + + translated_applet_name = _(metadata.name); +} + +const icon_size = 24; +const warning_icon = new St.Icon({ + icon_name: 'dialog-warning', icon_type: St.IconType.SYMBOLIC, icon_size +}); +const error_icon = new St.Icon({ + icon_name: 'dialog-error', icon_type: St.IconType.SYMBOLIC, icon_size +}); + +export const logger = { + info(msg: string) { + global.log(translated_applet_name + `${_(":")} ` + msg); + Main.notify(translated_applet_name, msg); + }, + warn(msg: string) { + global.logWarning(translated_applet_name + `${_(":")} ` + msg); + Main.warningNotify(translated_applet_name, msg, warning_icon); + }, + error(msg: string) { + global.logError(translated_applet_name + `${_(":")} ` + msg); + Main.criticalNotify(translated_applet_name, msg, error_icon); + } +}; diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/icon.svg b/auto-dark-light@gihaume/src/icon.svg similarity index 100% rename from auto-dark-light@gihaume/files/auto-dark-light@gihaume/icon.svg rename to auto-dark-light@gihaume/src/icon.svg diff --git a/auto-dark-light@gihaume/src/lib/core/Time_of_day.ts b/auto-dark-light@gihaume/src/lib/core/Time_of_day.ts new file mode 100644 index 00000000000..3403ecba981 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/core/Time_of_day.ts @@ -0,0 +1,83 @@ +import type { Time_hms } from '../../types'; + +const SECONDS_PER_DAY = 24 * 60 * 60; + +/** An immutable 24-hour clock time representation. */ +export class Time_of_day { + private readonly _h: number; + private readonly _m: number; + private readonly _s: number; + + constructor(hms: Time_hms) { + ({ h: this._h, m: this._m, s: this._s } = hms); + } + + static create_from_js_date(date: Date) { + return new Time_of_day({ + h: date.getHours(), + m: date.getMinutes(), + s: date.getSeconds() + }); + } + + /** @param hhmm - `HH:MM` */ + static create_from_hhmm_string(hhmm: string) { + const [h, m] = hhmm.split(':').map(Number); + return new Time_of_day({ h, m, s: 0 }); + } + + get hour(): number { return this._h; } + get minute(): number { return this._m; } + get second(): number { return this._s; } + + get_as_hms(): Time_hms { + return { h: this._h, m: this._m, s: this._s }; + } + + /** @returns `(H)H:MM:SS` */ + get_as_string_hmmss(): string { + const [mm, ss] = [this._m, this._s].map( + value => String(value).padStart(2, '0') + ); + return `${this._h}:${mm}:${ss}`; + } + + /** @returns `HH:MM` */ + get_as_string_hhmm(): string { + const [hh, mm] = [this._h, this._m].map( + value => String(value).padStart(2, '0') + ); + return `${hh}:${mm}`; + } + + /** + * @param value - The offset to add. + * @returns A new instance with the added time. + */ + add_minutes(value: number): Time_of_day { + const date = new Date(0, 0, 1, this._h, this._m, this._s); + date.setMinutes(date.getMinutes() + value); + return Time_of_day.create_from_js_date(date); + } + + /** Gets the delay from `this` until the next occurrence of `target`. */ + get_seconds_until_next_target(target: Time_of_day): number { + const [target_s, this_s] = [target, this].map( + time => time._seconds_since_midnight + ); + return this_s < target_s ? target_s - this_s + : target_s - this_s + SECONDS_PER_DAY; + } + + is_between(start: Time_of_day, end: Time_of_day): boolean { + const [this_s, start_s, end_s] = [this, start, end].map( + time => time._seconds_since_midnight + ); + return start_s < end_s ? start_s <= this_s && this_s < end_s + : start_s <= this_s || this_s < end_s; + } + + private get _seconds_since_midnight() { + return this._h * 3600 + this._m * 60 + this._s; + } +}; diff --git a/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/Timezone_location_finder.ts b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/Timezone_location_finder.ts new file mode 100644 index 00000000000..dca26ba575c --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/Timezone_location_finder.ts @@ -0,0 +1,39 @@ +const { Gio } = imports.gi; + +import { Location } from '../../../types'; + +/** A finder of timezone's city coordinates using a local database. */ +export class Timezone_location_finder { + _database: Record; + + /** + * @param path - The absolute path where the `database.json` file is located. + * @throws {Error} - If the file cannot be loaded or JSON-parsed + */ + constructor(path: string) { + const file_path = `${path}/database.json`; + const file = Gio.File.new_for_path(file_path); + const [ok, file_content] = file.load_contents(null); + + if (!ok) + throw new Error(`failed to load file/contents of '${file_path}'`); + + this._database = JSON.parse(new TextDecoder().decode(file_content)); // Throws + } + + /** + * Gets the latitude and longitude of the timezone's city. + * @param timezone - The timezone to get the coordinates from. + * @returns The system timezone's city coordinates. + */ + find(timezone: string): Location { + if (!timezone) + throw new Error('timezone is required'); + if (!(timezone in this._database)) + throw new Error(`unknown timezone: '${timezone}'`); + return { + latitude: this._database[timezone][0], + longitude: this._database[timezone][1] + }; + } +} diff --git a/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/database.json b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/database.json new file mode 100644 index 00000000000..d4277ec89ef --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/database.json @@ -0,0 +1,420 @@ +{ + "Africa/Abidjan": [5.317, -3.967], + "Africa/Accra": [5.550, 0.217], + "Africa/Addis_Ababa": [9.033, 38.700], + "Africa/Algiers": [36.783, 3.050], + "Africa/Asmara": [15.333, 38.883], + "Africa/Bamako": [12.650, -8.000], + "Africa/Bangui": [4.367, 18.583], + "Africa/Banjul": [13.467, -15.350], + "Africa/Bissau": [11.850, -14.417], + "Africa/Blantyre": [-14.217, 35.000], + "Africa/Brazzaville": [-3.733, 15.283], + "Africa/Bujumbura": [-2.617, 29.367], + "Africa/Cairo": [30.050, 31.250], + "Africa/Casablanca": [33.650, -6.417], + "Africa/Ceuta": [35.883, -4.683], + "Africa/Conakry": [9.517, -12.283], + "Africa/Dakar": [14.667, -16.567], + "Africa/Dar_es_Salaam": [-5.200, 39.283], + "Africa/Djibouti": [11.600, 43.150], + "Africa/Douala": [4.050, 9.700], + "Africa/El_Aaiun": [27.150, -12.800], + "Africa/Freetown": [8.500, -12.750], + "Africa/Gaborone": [-23.350, 25.917], + "Africa/Harare": [-16.167, 31.050], + "Africa/Johannesburg": [-25.750, 28.000], + "Africa/Juba": [4.850, 31.617], + "Africa/Kampala": [0.317, 32.417], + "Africa/Khartoum": [15.600, 32.533], + "Africa/Kigali": [-0.050, 30.067], + "Africa/Kinshasa": [-3.700, 15.300], + "Africa/Lagos": [6.450, 3.400], + "Africa/Libreville": [0.383, 9.450], + "Africa/Lome": [6.133, 1.217], + "Africa/Luanda": [-7.200, 13.233], + "Africa/Lubumbashi": [-10.333, 27.467], + "Africa/Lusaka": [-14.583, 28.283], + "Africa/Malabo": [3.750, 8.783], + "Africa/Maputo": [-24.033, 32.583], + "Africa/Maseru": [-28.533, 27.500], + "Africa/Mbabane": [-25.700, 31.100], + "Africa/Mogadishu": [2.067, 45.367], + "Africa/Monrovia": [6.300, -9.217], + "Africa/Nairobi": [-0.717, 36.817], + "Africa/Ndjamena": [12.117, 15.050], + "Africa/Niamey": [13.517, 2.117], + "Africa/Nouakchott": [18.100, -14.050], + "Africa/Ouagadougou": [12.367, -0.483], + "Africa/Porto-Novo": [6.483, 2.617], + "Africa/Sao_Tome": [0.333, 6.733], + "Africa/Tripoli": [32.900, 13.183], + "Africa/Tunis": [36.800, 10.183], + "Africa/Windhoek": [-21.433, 17.100], + "America/Adak": [51.880, -175.342], + "America/Anchorage": [61.218, -148.100], + "America/Anguilla": [18.200, -62.933], + "America/Antigua": [17.050, -60.200], + "America/Araguaina": [-6.800, -47.800], + "America/Argentina/Buenos_Aires": [-33.400, -57.550], + "America/Argentina/Catamarca": [-27.533, -64.217], + "America/Argentina/Cordoba": [-30.600, -63.817], + "America/Argentina/Jujuy": [-23.817, -64.700], + "America/Argentina/La_Rioja": [-28.567, -65.150], + "America/Argentina/Mendoza": [-31.117, -67.183], + "America/Argentina/Rio_Gallegos": [-50.367, -68.783], + "America/Argentina/Salta": [-23.217, -64.583], + "America/Argentina/San_Juan": [-30.467, -67.483], + "America/Argentina/San_Luis": [-32.683, -65.650], + "America/Argentina/Tucuman": [-25.183, -64.783], + "America/Argentina/Ushuaia": [-53.200, -67.700], + "America/Aruba": [12.500, -68.033], + "America/Asuncion": [-24.733, -56.333], + "America/Atikokan": [48.759, -90.378], + "America/Bahia": [-11.017, -37.483], + "America/Bahia_Banderas": [20.800, -104.750], + "America/Barbados": [13.100, -58.383], + "America/Belem": [-0.550, -47.517], + "America/Belize": [17.500, -87.800], + "America/Blanc-Sablon": [51.417, -56.883], + "America/Boa_Vista": [2.817, -59.333], + "America/Bogota": [4.600, -73.917], + "America/Boise": [43.614, -115.797], + "America/Cambridge_Bay": [69.114, -104.947], + "America/Campo_Grande": [-19.550, -53.383], + "America/Cancun": [21.083, -85.233], + "America/Caracas": [10.500, -65.067], + "America/Cayenne": [4.933, -51.667], + "America/Cayman": [19.300, -80.617], + "America/Chicago": [41.850, -86.350], + "America/Chihuahua": [28.633, -105.917], + "America/Ciudad_Juarez": [31.733, -105.517], + "America/Costa_Rica": [9.933, -83.917], + "America/Coyhaique": [-44.433, -71.933], + "America/Creston": [49.100, -115.483], + "America/Cuiaba": [-14.417, -55.917], + "America/Curacao": [12.183, -69.000], + "America/Danmarkshavn": [76.767, -17.333], + "America/Dawson": [64.067, -138.583], + "America/Dawson_Creek": [55.767, -119.767], + "America/Denver": [39.739, -103.016], + "America/Detroit": [42.331, -82.954], + "America/Dominica": [15.300, -60.600], + "America/Edmonton": [53.550, -112.533], + "America/Eirunepe": [-5.333, -68.133], + "America/El_Salvador": [13.700, -88.800], + "America/Fort_Nelson": [58.800, -121.300], + "America/Fortaleza": [-2.283, -37.500], + "America/Glace_Bay": [46.200, -58.050], + "America/Goose_Bay": [53.333, -59.583], + "America/Grand_Turk": [21.467, -70.867], + "America/Grenada": [12.050, -60.250], + "America/Guadeloupe": [16.233, -60.467], + "America/Guatemala": [14.633, -89.483], + "America/Guayaquil": [-1.833, -78.167], + "America/Guyana": [6.800, -57.833], + "America/Halifax": [44.650, -62.400], + "America/Havana": [23.133, -81.633], + "America/Hermosillo": [29.067, -109.033], + "America/Indiana/Indianapolis": [39.768, -85.842], + "America/Indiana/Knox": [41.296, -85.375], + "America/Indiana/Marengo": [38.376, -85.655], + "America/Indiana/Petersburg": [38.492, -86.721], + "America/Indiana/Tell_City": [37.953, -85.239], + "America/Indiana/Vevay": [38.748, -84.933], + "America/Indiana/Vincennes": [38.677, -86.471], + "America/Indiana/Winamac": [41.051, -85.397], + "America/Inuvik": [68.350, -132.283], + "America/Iqaluit": [63.733, -67.533], + "America/Jamaica": [17.968, -75.207], + "America/Juneau": [58.302, -133.580], + "America/Kentucky/Louisville": [38.254, -84.241], + "America/Kentucky/Monticello": [36.830, -83.151], + "America/Kralendijk": [12.151, -67.723], + "America/La_Paz": [-15.500, -67.850], + "America/Lima": [-11.950, -76.950], + "America/Los_Angeles": [34.052, -117.757], + "America/Lower_Princes": [18.051, -62.953], + "America/Maceio": [-8.333, -34.283], + "America/Managua": [12.150, -85.717], + "America/Manaus": [-2.867, -59.983], + "America/Marigot": [18.067, -62.917], + "America/Martinique": [14.600, -60.917], + "America/Matamoros": [25.833, -96.500], + "America/Mazatlan": [23.217, -105.583], + "America/Menominee": [45.108, -86.386], + "America/Merida": [20.967, -88.383], + "America/Metlakatla": [55.127, -130.424], + "America/Mexico_City": [19.400, -98.850], + "America/Miquelon": [47.050, -55.667], + "America/Moncton": [46.100, -63.217], + "America/Monterrey": [25.667, -99.683], + "America/Montevideo": [-33.091, -55.787], + "America/Montserrat": [16.717, -61.783], + "America/Nassau": [25.083, -76.650], + "America/New_York": [40.714, -73.994], + "America/Nome": [64.501, -164.594], + "America/Noronha": [-2.150, -31.583], + "America/North_Dakota/Beulah": [47.264, -100.222], + "America/North_Dakota/Center": [47.116, -100.701], + "America/North_Dakota/New_Salem": [46.845, -100.589], + "America/Nuuk": [64.183, -50.267], + "America/Ojinaga": [29.567, -103.583], + "America/Panama": [8.967, -78.467], + "America/Paramaribo": [5.833, -54.833], + "America/Phoenix": [33.448, -111.927], + "America/Port-au-Prince": [18.533, -71.667], + "America/Port_of_Spain": [10.650, -60.483], + "America/Porto_Velho": [-7.233, -62.100], + "America/Puerto_Rico": [18.468, -65.894], + "America/Punta_Arenas": [-52.850, -69.083], + "America/Rankin_Inlet": [62.817, -91.917], + "America/Recife": [-7.950, -33.100], + "America/Regina": [50.400, -103.350], + "America/Resolute": [74.696, -93.171], + "America/Rio_Branco": [-8.033, -66.200], + "America/Santarem": [-1.567, -53.133], + "America/Santiago": [-32.550, -69.333], + "America/Santo_Domingo": [18.467, -68.100], + "America/Sao_Paulo": [-22.467, -45.383], + "America/Scoresbysund": [70.483, -20.033], + "America/Sitka": [57.176, -134.698], + "America/St_Barthelemy": [17.883, -61.150], + "America/St_Johns": [47.567, -51.283], + "America/St_Kitts": [17.300, -61.283], + "America/St_Lucia": [14.017, -61.000], + "America/St_Thomas": [18.350, -63.067], + "America/St_Vincent": [13.150, -60.767], + "America/Swift_Current": [50.283, -106.167], + "America/Tegucigalpa": [14.100, -86.783], + "America/Thule": [76.567, -67.217], + "America/Tijuana": [32.533, -116.983], + "America/Toronto": [43.650, -78.617], + "America/Tortola": [18.450, -63.383], + "America/Vancouver": [49.267, -122.883], + "America/Whitehorse": [60.717, -134.950], + "America/Winnipeg": [49.883, -96.850], + "America/Yakutat": [59.547, -138.273], + "Antarctica/Casey": [-65.717, 110.517], + "Antarctica/Davis": [-67.417, 77.967], + "Antarctica/DumontDUrville": [-65.333, 140.017], + "Antarctica/Macquarie": [-53.500, 158.950], + "Antarctica/Mawson": [-66.400, 62.883], + "Antarctica/McMurdo": [-76.167, 166.600], + "Antarctica/Palmer": [-63.200, -63.900], + "Antarctica/Rothera": [-66.433, -67.867], + "Antarctica/Syowa": [-68.994, 39.590], + "Antarctica/Troll": [-71.989, 2.535], + "Antarctica/Vostok": [-77.600, 106.900], + "Arctic/Longyearbyen": [78.000, 16.000], + "Asia/Aden": [12.750, 45.200], + "Asia/Almaty": [43.250, 76.950], + "Asia/Amman": [31.950, 35.933], + "Asia/Anadyr": [64.750, 177.483], + "Asia/Aqtau": [44.517, 50.267], + "Asia/Aqtobe": [50.283, 57.167], + "Asia/Ashgabat": [37.950, 58.383], + "Asia/Atyrau": [47.117, 51.933], + "Asia/Baghdad": [33.350, 44.417], + "Asia/Bahrain": [26.383, 50.583], + "Asia/Baku": [40.383, 49.850], + "Asia/Bangkok": [13.750, 100.517], + "Asia/Barnaul": [53.367, 83.750], + "Asia/Beirut": [33.883, 35.500], + "Asia/Bishkek": [42.900, 74.600], + "Asia/Brunei": [4.933, 114.917], + "Asia/Chita": [52.050, 113.467], + "Asia/Colombo": [6.933, 79.850], + "Asia/Damascus": [33.500, 36.300], + "Asia/Dhaka": [23.717, 90.417], + "Asia/Dili": [-7.450, 125.583], + "Asia/Dubai": [25.300, 55.300], + "Asia/Dushanbe": [38.583, 68.800], + "Asia/Famagusta": [35.117, 33.950], + "Asia/Gaza": [31.500, 34.467], + "Asia/Hebron": [31.533, 35.095], + "Asia/Ho_Chi_Minh": [10.750, 106.667], + "Asia/Hong_Kong": [22.283, 114.150], + "Asia/Hovd": [48.017, 91.650], + "Asia/Irkutsk": [52.267, 104.333], + "Asia/Jakarta": [-5.833, 106.800], + "Asia/Jayapura": [-1.467, 140.700], + "Asia/Jerusalem": [31.781, 35.224], + "Asia/Kabul": [34.517, 69.200], + "Asia/Kamchatka": [53.017, 158.650], + "Asia/Karachi": [24.867, 67.050], + "Asia/Kathmandu": [27.717, 85.317], + "Asia/Khandyga": [62.656, 135.554], + "Asia/Kolkata": [22.533, 88.367], + "Asia/Krasnoyarsk": [56.017, 92.833], + "Asia/Kuala_Lumpur": [3.167, 101.700], + "Asia/Kuching": [1.550, 110.333], + "Asia/Kuwait": [29.333, 47.983], + "Asia/Macau": [22.197, 113.542], + "Asia/Magadan": [59.567, 150.800], + "Asia/Makassar": [-4.883, 119.400], + "Asia/Manila": [14.587, 120.968], + "Asia/Muscat": [23.600, 58.583], + "Asia/Nicosia": [35.167, 33.367], + "Asia/Novokuznetsk": [53.750, 87.117], + "Asia/Novosibirsk": [55.033, 82.917], + "Asia/Omsk": [55.000, 73.400], + "Asia/Oral": [51.217, 51.350], + "Asia/Phnom_Penh": [11.550, 104.917], + "Asia/Pontianak": [0.033, 109.333], + "Asia/Pyongyang": [39.017, 125.750], + "Asia/Qatar": [25.283, 51.533], + "Asia/Qostanay": [53.200, 63.617], + "Asia/Qyzylorda": [44.800, 65.467], + "Asia/Riyadh": [24.633, 46.717], + "Asia/Sakhalin": [46.967, 142.700], + "Asia/Samarkand": [39.667, 66.800], + "Asia/Seoul": [37.550, 126.967], + "Asia/Shanghai": [31.233, 121.467], + "Asia/Singapore": [1.283, 103.850], + "Asia/Srednekolymsk": [67.467, 153.717], + "Asia/Taipei": [25.050, 121.500], + "Asia/Tashkent": [41.333, 69.300], + "Asia/Tbilisi": [41.717, 44.817], + "Asia/Tehran": [35.667, 51.433], + "Asia/Thimphu": [27.467, 89.650], + "Asia/Tokyo": [35.654, 139.745], + "Asia/Tomsk": [56.500, 84.967], + "Asia/Ulaanbaatar": [47.917, 106.883], + "Asia/Urumqi": [43.800, 87.583], + "Asia/Ust-Nera": [64.560, 143.227], + "Asia/Vientiane": [17.967, 102.600], + "Asia/Vladivostok": [43.167, 131.933], + "Asia/Yakutsk": [62.000, 129.667], + "Asia/Yangon": [16.783, 96.167], + "Asia/Yekaterinburg": [56.850, 60.600], + "Asia/Yerevan": [40.183, 44.500], + "Atlantic/Azores": [37.733, -24.333], + "Atlantic/Bermuda": [32.283, -63.233], + "Atlantic/Canary": [28.100, -14.600], + "Atlantic/Cape_Verde": [14.917, -22.483], + "Atlantic/Faroe": [62.017, -5.233], + "Atlantic/Madeira": [32.633, -15.100], + "Atlantic/Reykjavik": [64.150, -20.150], + "Atlantic/South_Georgia": [-53.733, -35.467], + "Atlantic/St_Helena": [-14.083, -4.300], + "Atlantic/Stanley": [-50.300, -56.150], + "Australia/Adelaide": [-33.083, 138.583], + "Australia/Brisbane": [-26.533, 153.033], + "Australia/Broken_Hill": [-30.050, 141.450], + "Australia/Darwin": [-11.533, 130.833], + "Australia/Eucla": [-30.283, 128.867], + "Australia/Hobart": [-41.117, 147.317], + "Australia/Lindeman": [-19.733, 149.000], + "Australia/Lord_Howe": [-30.450, 159.083], + "Australia/Melbourne": [-36.183, 144.967], + "Australia/Perth": [-30.050, 115.850], + "Australia/Sydney": [-32.133, 151.217], + "Europe/Amsterdam": [52.367, 4.900], + "Europe/Andorra": [42.500, 1.517], + "Europe/Astrakhan": [46.350, 48.050], + "Europe/Athens": [37.967, 23.717], + "Europe/Belgrade": [44.833, 20.500], + "Europe/Berlin": [52.500, 13.367], + "Europe/Bratislava": [48.150, 17.117], + "Europe/Brussels": [50.833, 4.333], + "Europe/Bucharest": [44.433, 26.100], + "Europe/Budapest": [47.500, 19.083], + "Europe/Busingen": [47.700, 8.683], + "Europe/Chisinau": [47.000, 28.833], + "Europe/Copenhagen": [55.667, 12.583], + "Europe/Dublin": [53.333, -5.750], + "Europe/Gibraltar": [36.133, -4.650], + "Europe/Guernsey": [49.455, -1.464], + "Europe/Helsinki": [60.167, 24.967], + "Europe/Isle_of_Man": [54.150, -3.533], + "Europe/Istanbul": [41.017, 28.967], + "Europe/Jersey": [49.184, -1.893], + "Europe/Kaliningrad": [54.717, 20.500], + "Europe/Kirov": [58.600, 49.650], + "Europe/Kyiv": [50.433, 30.517], + "Europe/Lisbon": [38.717, -8.867], + "Europe/Ljubljana": [46.050, 14.517], + "Europe/London": [51.508, 0.125], + "Europe/Luxembourg": [49.600, 6.150], + "Europe/Madrid": [40.400, -2.317], + "Europe/Malta": [35.900, 14.517], + "Europe/Mariehamn": [60.100, 19.950], + "Europe/Minsk": [53.900, 27.567], + "Europe/Monaco": [43.700, 7.383], + "Europe/Moscow": [55.756, 37.618], + "Europe/Oslo": [59.917, 10.750], + "Europe/Paris": [48.867, 2.333], + "Europe/Podgorica": [42.433, 19.267], + "Europe/Prague": [50.083, 14.433], + "Europe/Riga": [56.950, 24.100], + "Europe/Rome": [41.900, 12.483], + "Europe/Samara": [53.200, 50.150], + "Europe/San_Marino": [43.917, 12.467], + "Europe/Sarajevo": [43.867, 18.417], + "Europe/Saratov": [51.567, 46.033], + "Europe/Simferopol": [44.950, 34.100], + "Europe/Skopje": [41.983, 21.433], + "Europe/Sofia": [42.683, 23.317], + "Europe/Stockholm": [59.333, 18.050], + "Europe/Tallinn": [59.417, 24.750], + "Europe/Tirane": [41.333, 19.833], + "Europe/Ulyanovsk": [54.333, 48.400], + "Europe/Vaduz": [47.150, 9.517], + "Europe/Vatican": [41.902, 12.453], + "Europe/Vienna": [48.217, 16.333], + "Europe/Vilnius": [54.683, 25.317], + "Europe/Volgograd": [48.733, 44.417], + "Europe/Warsaw": [52.250, 21.000], + "Europe/Zagreb": [45.800, 15.967], + "Europe/Zurich": [47.383, 8.533], + "Indian/Antananarivo": [-17.083, 47.517], + "Indian/Chagos": [-6.667, 72.417], + "Indian/Christmas": [-9.583, 105.717], + "Indian/Cocos": [-11.833, 96.917], + "Indian/Comoro": [-10.317, 43.267], + "Indian/Kerguelen": [-48.647, 70.218], + "Indian/Mahe": [-3.333, 55.467], + "Indian/Maldives": [4.167, 73.500], + "Indian/Mauritius": [-19.833, 57.500], + "Indian/Mayotte": [-11.217, 45.233], + "Indian/Reunion": [-19.133, 55.467], + "Pacific/Apia": [-12.167, -170.267], + "Pacific/Auckland": [-35.133, 174.767], + "Pacific/Bougainville": [-5.783, 155.567], + "Pacific/Chatham": [-42.050, -175.450], + "Pacific/Chuuk": [7.417, 151.783], + "Pacific/Easter": [-26.850, -108.567], + "Pacific/Efate": [-16.333, 168.417], + "Pacific/Fakaofo": [-8.633, -170.767], + "Pacific/Fiji": [-17.867, 178.417], + "Pacific/Funafuti": [-7.483, 179.217], + "Pacific/Galapagos": [0.900, -88.400], + "Pacific/Gambier": [-22.867, -133.050], + "Pacific/Guadalcanal": [-8.467, 160.200], + "Pacific/Guam": [13.467, 144.750], + "Pacific/Honolulu": [21.307, -156.142], + "Pacific/Kanton": [-1.217, -170.283], + "Pacific/Kiritimati": [1.867, -156.667], + "Pacific/Kosrae": [5.317, 162.983], + "Pacific/Kwajalein": [9.083, 167.333], + "Pacific/Majuro": [7.150, 171.200], + "Pacific/Marquesas": [-9.000, -138.500], + "Pacific/Midway": [28.217, -176.633], + "Pacific/Nauru": [0.517, 166.917], + "Pacific/Niue": [-18.983, -168.083], + "Pacific/Norfolk": [-28.950, 167.967], + "Pacific/Noumea": [-21.733, 166.450], + "Pacific/Pago_Pago": [-13.733, -169.300], + "Pacific/Palau": [7.333, 134.483], + "Pacific/Pitcairn": [-24.933, -129.917], + "Pacific/Pohnpei": [6.967, 158.217], + "Pacific/Port_Moresby": [-8.500, 147.167], + "Pacific/Rarotonga": [-20.767, -158.233], + "Pacific/Saipan": [15.200, 145.750], + "Pacific/Tahiti": [-16.467, -148.433], + "Pacific/Tarawa": [1.417, 173.000], + "Pacific/Tongatapu": [-20.867, -174.800], + "Pacific/Wake": [19.283, 166.617], + "Pacific/Wallis": [-12.700, -175.833] +} diff --git a/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/generate_database.ipynb b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/generate_database.ipynb new file mode 100644 index 00000000000..116a76acb81 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/generate_database.ipynb @@ -0,0 +1,78 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5e81f3fa", + "metadata": {}, + "source": [ + "# Generate the database\n", + "\n", + "Source: https://github.com/linuxmint/cinnamon-settings-daemon/blob/eec27984940dfb11904b02228357f430b585c41f/plugins/color/generate-tz-header.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ba83ca8", + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "import re\n", + "\n", + "regex = re.compile(r\"([+-]{1}[0-9]{2})([0-9]{2})([0-9]*)([+-]{1}[0-9]{3})([0-9]{2})([0-9]*)\")\n", + "\n", + "d = {}\n", + "\n", + "for line in Path('/usr/share/zoneinfo/zone.tab').read_text().splitlines():\n", + " line = line.strip()\n", + " if not line or line.startswith(\"#\"):\n", + " continue\n", + "\n", + " coords, tz = line.split('\\t')[1:3]\n", + " m = regex.search(coords)\n", + " if not m:\n", + " print(f\"Skipping zone with unexpected coords format: {coords!r} (zone: {tz})\")\n", + " continue\n", + " lat_deg, lat_min, lat_sec, long_deg, long_min, long_sec = m.groups()\n", + "\n", + " lat = int(lat_deg) + (int(lat_min) / 60.0) + (int(lat_sec or 0) / 3600.0)\n", + " long = int(long_deg) + (int(long_min) / 60.0) + (int(long_sec or 0) / 3600.0)\n", + "\n", + " d[tz] = [lat, long]\n", + "\n", + "output = \"{\\n\"\n", + "output += \"\".join(\n", + " f' \"{zone}\": [{lat:.3f}, {long:.3f}],\\n'\n", + " for zone in sorted(d.keys())\n", + " for lat, long in [d[zone]]\n", + ")\n", + "output = output[:-2] # Removes last comma\n", + "output += \"\\n}\\n\"\n", + "\n", + "Path('./database.json').write_text(output)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/auto-dark-light@gihaume/src/lib/core/compute_twilights/compute_twilights.ts b/auto-dark-light@gihaume/src/lib/core/compute_twilights/compute_twilights.ts new file mode 100644 index 00000000000..5ec7d269fea --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/core/compute_twilights/compute_twilights.ts @@ -0,0 +1,15 @@ +import type { Location, Twilights } from '../../../types'; +import * as system_time from '../../sys/system_time'; +import * as uSunCalc from './uSunCalc'; + +export function compute_twilights( + date: imports.gi.GLib.DateTime, location: Location +): Twilights { + const [sunrise, sunset] = uSunCalc.compute_twilights( + date.to_unix(), location.latitude, location.longitude + ); + return { + sunrise: system_time.new_local_time_of_day_from_unix(sunrise), + sunset: system_time.new_local_time_of_day_from_unix(sunset) + }; +} diff --git a/auto-dark-light@gihaume/src/lib/core/compute_twilights/uSunCalc.ts b/auto-dark-light@gihaume/src/lib/core/compute_twilights/uSunCalc.ts new file mode 100644 index 00000000000..85143ed2cc6 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/core/compute_twilights/uSunCalc.ts @@ -0,0 +1,97 @@ +/** + * A minified and optimized version of the SunCalc library containing only the part needed for the `auto-dark-light` applet. + */ + +/* +LICENSE + +Copyright (c) 2014, Vladimir Agafonkin +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +(c) 2011-2015, Vladimir Agafonkin +SunCalc is a JavaScript library for calculating sun/moon position and light phases. +https://github.com/mourner/suncalc +*/ + +const { PI, sin, cos, asin, acos, round } = Math; +const TWO_PI = 2 * PI; +const RADIANS_PER_DEGREE = PI / 180; +const SECONDS_PER_DAY = 60 * 60 * 24; +const J0 = 0.0009; +const J1970 = 2_440_587.5; +const J2000 = 2_451_545; + +/** @returns (seconds) */ +function _to_unix(julian_date: number) { + return (julian_date - J1970) * SECONDS_PER_DAY; +} + +function _approximate_transit(Ht: number, lw: number, n: number): number { + return J0 + (Ht + lw) / TWO_PI + n; +} + +function _solar_transit(ds: number, M: number, L: number): number { + return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); +} + +const EARTH_OBLIQUITY = RADIANS_PER_DEGREE * 23.4397; +const SIN_OF_EARTH_OBLIQUITY = sin(EARTH_OBLIQUITY); +const EARTH_PERIHELION_PLUS_PI = RADIANS_PER_DEGREE * 102.9372 + PI; +const J1970_MINUS_J2000 = J1970 - J2000; + +/** + * Calculates the sunrise and sunset times for a given date and location. + * @param unix_time - seconds (s) + * @param latitude - degrees (°) + * @param longitude - degrees (°) + * @returns Unix time, seconds (s) + */ +export function compute_twilights( + unix_time: number, latitude: number, longitude: number +): [sunrise: number, sunset: number] { + const lw = RADIANS_PER_DEGREE * -longitude; + const phi = RADIANS_PER_DEGREE * latitude; + const d = unix_time / SECONDS_PER_DAY + J1970_MINUS_J2000; // Julian date + const n = round(d - J0 - lw / TWO_PI); // "Julian cycle" + const ds = _approximate_transit(0, lw, n); + const M = RADIANS_PER_DEGREE * (0.98560028 * ds + 357.5291); // Solar mean anomaly + const center = RADIANS_PER_DEGREE * ( + 1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M) + ); + const L = M + center + EARTH_PERIHELION_PLUS_PI; // Ecliptic longitude + const dec = asin(SIN_OF_EARTH_OBLIQUITY * sin(L)); // Declination + const julian_noon = _solar_transit(ds, M, L); + const h0 = -0.833 * RADIANS_PER_DEGREE; + const w = acos( // "hour angle" + (sin(h0) - sin(phi) * sin(dec)) / (cos(phi) * cos(dec)) + ); + const a = _approximate_transit(w, lw, n); + const julian_sunset = _solar_transit(a, M, L); + const julian_sunrise = 2 * julian_noon - julian_sunset; + return [ + _to_unix(julian_sunrise), + _to_unix(julian_sunset) + ]; +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Event_scheduler.ts b/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Event_scheduler.ts new file mode 100644 index 00000000000..ae4b3a7e409 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Event_scheduler.ts @@ -0,0 +1,63 @@ +const { GLib } = imports.gi; + +import * as system_time from "../system_time"; +import type { Time_of_day } from "../../core/Time_of_day"; +import { Timer_absolute } from "./Timer_absolute"; + +/** + * A single-event scheduler which call a function at a specific next time of day. + * + * Under the hood it uses a monotonic timeout delay and so doesn't take into account system sleep or time changes. So to the user can check if the event should already have occurred with `get_if_should_be_expired`. + * + * When the instance is not wanted anymore, `dispose` must be called. + */ +export class Event_scheduler { + private _event_id: number | undefined = undefined; + private readonly _timer_absolute = new Timer_absolute(); + + /** @returns `true` if the scheduled event should have already occurred, `false` otherwise. If the event is not set, `false` is returned. */ + get_if_should_be_expired(): boolean { + return this._timer_absolute.get_if_has_expired(); + } + + /** + * Calls a function at a specific next time of day. + * + * If the event is already scheduled, it will be replaced. + * + * @param time - When the event should occur. + * @param callback_on_event - The function to be executed when the event occurs. + */ + set_the_event(time: Time_of_day, callback_on_event: () => void): void { + this.unset_the_event(); + const now = system_time.get_now_as_time_of_day(); + const due_delay = now.get_seconds_until_next_target(time); + this._event_id = GLib.timeout_add_seconds( + GLib.PRIORITY_DEFAULT, + due_delay, + () => { + callback_on_event(); + return GLib.SOURCE_REMOVE; + } + ); + this._timer_absolute.expiration_time = time; + } + + get is_set(): boolean { + return this._event_id !== undefined; + } + + /** If the event is not already scheduled, nothing is done. */ + unset_the_event(): void { + if (!this._event_id) + return; + GLib.source_remove(this._event_id); + this._event_id = undefined; + this._timer_absolute.reset(); + } + + /** Releases acquired resources */ + dispose(): void { + this.unset_the_event(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Timer_absolute.ts b/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Timer_absolute.ts new file mode 100644 index 00000000000..98bfb5daa95 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Timer_absolute.ts @@ -0,0 +1,24 @@ +import * as system_time from '../system_time'; +import type { Time_of_day } from '../../core/Time_of_day'; + +/** A basic request-based absolute timer to be set for a next occurring time of day. */ +export class Timer_absolute { + /** Unix time in seconds (s) */ + private _expiration_time = 0; + + /** The next time of day the timer has to expire. */ + set expiration_time(value: Time_of_day) { + const now = system_time.get_now_as_time_of_day(); + const due_delay = now.get_seconds_until_next_target(value); + this._expiration_time = system_time.get_now_as_unix() + due_delay; + } + + get_if_has_expired(): boolean { + return system_time.get_now_as_unix() > this._expiration_time; + } + + /** Ensures `get_if_has_expired` returns `true` */ + reset(): void { + this._expiration_time = 0; + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts b/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts new file mode 100644 index 00000000000..c954ecaa63c --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts @@ -0,0 +1,23 @@ +const Main = imports.ui.main; + +import { metadata } from "../../globals"; + +let counter = 0; + +export class Keybinding_handler { + private readonly _name: string; + private readonly _callback: () => void; + + constructor(callback: () => void) { + this._name = metadata.uuid + counter++; + this._callback = callback; + } + + set keybinding(value: string) { + Main.keybindingManager.addHotKey(this._name, value, this._callback); + } + + dispose() { + Main.keybindingManager.removeHotKey(this._name); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Screen_lock_checker.ts b/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Screen_lock_checker.ts new file mode 100644 index 00000000000..5a673871495 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Screen_lock_checker.ts @@ -0,0 +1,91 @@ +const { Gio } = imports.gi; + +/** + * A gatekeeper for the screen locked state. + * + * When the instance is not wanted anymore, `dispose` must be called. + */ +export class Screen_lock_checker { + /** + * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. + * @param callback_when_unlocked - The function to be executed when the screen is unlocked. + */ + try_now_or_postpone_until_unlocked( + callback_when_unlocked: () => void): void { + Screen_lock_checker._get_state_async(is_locked => { + if (!is_locked) + callback_when_unlocked(); + else + this._subscribe_to_changes(is_locked => { + if (is_locked) + return; + this._unsubscribe_to_changes(); + callback_when_unlocked(); + }); + }); + } + + /** Cancels the `try_now_or_postpone_until_unlocked` procedure. */ + cancel(): void { + this._unsubscribe_to_changes(); + } + + /** Releases acquired resources */ + dispose(): void { + this.cancel(); + } + + private _signal_id: number | undefined = undefined; + + /** @param callback_when_changes - The function to be executed when the screen lock state changes. */ + _subscribe_to_changes( + callback_when_changes: (is_locked: boolean) => void + ): void { + if (this._signal_id) + this._unsubscribe_to_changes(); + this._signal_id = Gio.DBus.session.signal_subscribe( + 'org.cinnamon.ScreenSaver', // sender + 'org.cinnamon.ScreenSaver', // interface_name + 'ActiveChanged', // member + '/org/cinnamon/ScreenSaver', // object_path + null, // arg0 + Gio.DBusSignalFlags.NONE, // flags + (_1, _2, _3, _4, _5, parameters) => { // callback + const is_locked = parameters.deep_unpack()[0]; + callback_when_changes(is_locked); + } + ); + } + + _unsubscribe_to_changes(): void { + if (!this._signal_id) + return; + Gio.DBus.session.signal_unsubscribe(this._signal_id); + this._signal_id = undefined; + } + + /** + * Gets the current screen lock state asynchronously. + * @param callback_for_result - The callback object to handle the result. + */ + static _get_state_async( + callback_for_result: (is_locked: boolean) => void + ): void { + Gio.DBus.session.call( + 'org.cinnamon.ScreenSaver', // bus_name + '/org/cinnamon/ScreenSaver', // object_path + 'org.cinnamon.ScreenSaver', // interface_name + 'GetActive', // method_name + null, // parameters + null, // reply_type + Gio.DBusCallFlags.NONE, // flags + -1, // timeout_msec + null, // cancellable + (connection, result) => { // callback + const reply = connection.call_finish(result); + const is_locked = reply.deep_unpack()[0]; + callback_for_result(is_locked); + } + ); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Sleep_events_listener.ts b/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Sleep_events_listener.ts new file mode 100644 index 00000000000..d24f7b10e69 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Sleep_events_listener.ts @@ -0,0 +1,76 @@ +const {Gio} = imports.gi; + +import { Screen_lock_checker } from './Screen_lock_checker'; + +/** + * A gatekeeper for the sleep combined with the screen locked on wakeup. + * + * When the instance is not wanted anymore, `dispose` must be called. + */ +export class Sleep_events_listener { + private readonly _callback_when_sleep_entries: () => void; + private readonly _callback_when_wakeup_unlocked: () => void; + + /** + * @param callback_when_sleep_entries - The function to be executed when the system goes to sleep. Will be called again even without unlock. + * @param callback_when_wakeup_unlocked - The function to be executed when the system wakes up and the screen is unlocked. + */ + constructor( + callback_when_sleep_entries: () => void, + callback_when_wakeup_unlocked: () => void + ) { + this._callback_when_sleep_entries = callback_when_sleep_entries; + this._callback_when_wakeup_unlocked = callback_when_wakeup_unlocked; + } + + private readonly _screen_lock_checker = new Screen_lock_checker(); + + enable(): void { + this._subscribe_to_changes(is_sleeping => { + if (is_sleeping) + this._callback_when_sleep_entries(); + else + this._screen_lock_checker.try_now_or_postpone_until_unlocked( + () => this._callback_when_wakeup_unlocked() + ); + }); + } + + disable(): void { + this._unsubscribe_to_changes(); + this._screen_lock_checker.cancel(); + } + + /** Releases acquired resources */ + dispose(): void { + this._unsubscribe_to_changes(); + this._screen_lock_checker.dispose(); + } + + private _signal_id: number | undefined = undefined; + + /** @param callback - The function to be executed when the system sleep state changes. */ + _subscribe_to_changes(callback: (is_sleeping: boolean) => void): void { + if (this._signal_id) + this._unsubscribe_to_changes(); + this._signal_id = Gio.DBus.system.signal_subscribe( + 'org.freedesktop.login1', // sender + 'org.freedesktop.login1.Manager', // interface_name + 'PrepareForSleep', // member + '/org/freedesktop/login1', // object_path + null, // arg0 + Gio.DBusSignalFlags.NONE, // flags + (_1, _2, _3, _4, _5, parameters) => { // callback + const is_sleeping = parameters.deep_unpack()[0]; + callback(is_sleeping); + } + ); + } + + _unsubscribe_to_changes(): void { + if (!this._signal_id) + return; + Gio.DBus.system.signal_unsubscribe(this._signal_id); + this._signal_id = undefined; + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/System_background.ts b/auto-dark-light@gihaume/src/lib/sys/System_background.ts new file mode 100644 index 00000000000..a91dacd5dce --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/System_background.ts @@ -0,0 +1,34 @@ +const { Gio } = imports.gi; + +const settings = { + background: Gio.Settings.new('org.cinnamon.desktop.background'), + slideshow: Gio.Settings.new('org.cinnamon.desktop.background.slideshow'), +} as const; + +/** An accessor to the Cinnamon system background settings. */ +export class System_background { + static get is_slideshow(): boolean { + return settings.slideshow.get_boolean('slideshow-enabled'); + } + static set is_slideshow(value: boolean) { + settings.slideshow.set_boolean('slideshow-enabled', value); + } + + /** Irrelevant to get when slideshow is enabled */ + static get picture_file(): string { + return settings.background.get_string('picture-uri'); + } + /** /!\ To not set when slideshow is enabled */ + static set picture_file(value: string) { + settings.background.set_string('picture-uri', value); + } + + /** Irrelevant to get when slideshow is disabled */ + static get slideshow_folder(): string { + return settings.slideshow.get_string('image-source'); + } + /** /!\ To not set when slideshow is disabled */ + static set slideshow_folder(value: string) { + settings.slideshow.set_string('image-source', value); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/System_color_scheme.ts b/auto-dark-light@gihaume/src/lib/sys/System_color_scheme.ts new file mode 100644 index 00000000000..7366c6fdb9a --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/System_color_scheme.ts @@ -0,0 +1,42 @@ +const { Gio } = imports.gi; + +import { Color_scheme } from "../../types"; + +const settings = Gio.Settings.new('org.x.apps.portal'); + +/** A listener and accessor to the Cinnamon system color scheme setting. */ +export class System_color_scheme { + private readonly _callback_on_change: (color_scheme: Color_scheme) => void; + private _signal_id: number | undefined = undefined; + + /** @param callback_on_change - The function to be executed when the color scheme changes. */ + constructor(callback_on_change: (color_scheme: Color_scheme) => void) { + this._callback_on_change = callback_on_change; + } + + enable() { + this.disable(); // Ensures only one signal is connected + this._signal_id = settings.connect('changed::color-scheme', () => { + this._callback_on_change(System_color_scheme.value); + }); + } + + disable() { + if (this._signal_id === undefined) + return; + settings.disconnect(this._signal_id); + this._signal_id = undefined; + } + + /** Releases acquired resources */ + dispose() { + this.disable(); + } + + static get value(): Color_scheme { + return settings.get_string('color-scheme') as Color_scheme; + } + static set value(value: Color_scheme) { + settings.set_string('color-scheme', value); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/System_themes.ts b/auto-dark-light@gihaume/src/lib/sys/System_themes.ts new file mode 100644 index 00000000000..45c798f03c2 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/System_themes.ts @@ -0,0 +1,37 @@ +const { Gio } = imports.gi; + +const settings = { + desktop: Gio.Settings.new('org.cinnamon.desktop.interface'), + cinnamon: Gio.Settings.new('org.cinnamon.theme') +} as const; + +/** An accessor to the Cinnamon system themes settings. */ +export class System_themes { + static get mouse(): string { + return settings.desktop.get_string('cursor-theme'); + } + static set mouse(value: string) { + settings.desktop.set_string('cursor-theme', value); + } + + static get apps(): string { + return settings.desktop.get_string('gtk-theme'); + } + static set apps(value: string) { + settings.desktop.set_string('gtk-theme', value); + } + + static get icons(): string { + return settings.desktop.get_string('icon-theme'); + } + static set icons(value: string) { + settings.desktop.set_string('icon-theme', value); + } + + static get desktop(): string { + return settings.cinnamon.get_string('name'); + } + static set desktop(value: string) { + settings.cinnamon.set_string('name', value); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Time_change_listener.ts b/auto-dark-light@gihaume/src/lib/sys/Time_change_listener.ts new file mode 100644 index 00000000000..91c73983af1 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Time_change_listener.ts @@ -0,0 +1,147 @@ +const { Gio, GLib } = imports.gi; + +import { _, logger, metadata } from '../../globals'; + +const EXECUTABLE_NAME = 'auto-dark-light-time-change-listener'; // From the Makefile +const EXECUTABLE_TARGET_FOLDER_PATH = 'Time_change_listener'; // Relative to transpiled `applet.js` // TODO: find a cleaner way? + +/** + * A passive listener for system time changes. + * + * It interfaces the C++ program whose API is in `backend/Time_change_listener.hpp`. + */ +export class Time_change_listener { + private _callback_when_changes: () => void; + + /** + * @param callback_when_changes - The function to be called when the system time changes. + * @throws {Error} If the `make` or `g++` command is not found in the system. + * @throws {Error} If the compilation of the C++ program fails. + */ + constructor(callback_when_changes: () => void) { + this._callback_when_changes = callback_when_changes; + + const executable_folder_path = + `${metadata.path}/${EXECUTABLE_TARGET_FOLDER_PATH}`; + const executable_path = `${executable_folder_path}/${EXECUTABLE_NAME}`; + + if (!GLib.file_test(executable_path, GLib.FileTest.EXISTS)) + Time_change_listener._compile(executable_folder_path); + + this._run(executable_path); + } + + private static _compile(executable_folder_path: string) { + if ( + !GLib.find_program_in_path('make') || + !GLib.find_program_in_path('g++') + ) + throw new Error(_("Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-based system with 'sudo apt install make g++', then restart Cinnamon (Ctrl+Alt+Esc).")); + + const process = new Gio.Subprocess({ + argv: ['make', '-C', executable_folder_path], + flags: Gio.SubprocessFlags.STDERR_PIPE + }); + process.init(null); + + try { + const [_ok, _stdout, stderr] = + process.communicate_utf8(null, null); + if (!process.get_successful()) + throw new Error(stderr || _("Unknown compilation error")); + } catch (error) { + throw new Error( + `${_("Failed compilation of")} '${EXECUTABLE_NAME}'.\n` + + "\n" + + error.message + ); + } finally { + GLib.spawn_command_line_async( + `make -C ${executable_folder_path} clean` + ); + } + } + + private _input: imports.gi.Gio.DataInputStream; + private _input_error: imports.gi.Gio.DataInputStream; + private _output: imports.gi.Gio.OutputStream; + private _subprocess: imports.gi.Gio.Subprocess; + private _should_run = true; + + private _run(executable_path: string) { + this._subprocess = new Gio.Subprocess({ + argv: [executable_path], + flags: + Gio.SubprocessFlags.STDOUT_PIPE | + Gio.SubprocessFlags.STDIN_PIPE | + Gio.SubprocessFlags.STDERR_PIPE + }); + this._subprocess.init(null); + + this._output = this._subprocess.get_stdin_pipe(); + this._input = new Gio.DataInputStream({ + base_stream: this._subprocess.get_stdout_pipe() + }); + this._input_error = new Gio.DataInputStream({ + base_stream: this._subprocess.get_stderr_pipe() + }); + + this._listen_input(); + this._listen_error(); + } + + private async _listen_input() { // thread-like + do { + await new Promise( + resolve => this._input.read_line_async( + GLib.PRIORITY_DEFAULT, null, resolve + ) + ); + this._callback_when_changes(); + } while (this._should_run); + } + + private async _listen_error() { // thread-like + do { + const [line, length] = await new Promise(resolve => + this._input_error.read_line_async( + GLib.PRIORITY_DEFAULT, + null, + ( + source: imports.gi.Gio.DataInputStream, + result: imports.gi.Gio.AsyncResult + ) => { + try { + resolve(source.read_line_finish(result)); + } catch (error) { + logger.warn(error); + resolve([null, 0]); + } + } + ) + ); + if (line !== null && length > 0) + logger.warn( + `${_("the subprocess")} \`${EXECUTABLE_NAME}\` ${_("has written on its error output")}${_(":")} ${line}` + ); + } while (this._should_run); + } + + /** Enables listening for the system time changes. */ + enable() { + this._output.write('enable\n', null); + } + + /** Disables listening for the system time changes. */ + disable() { + this._output.write('disable\n', null); + } + + /** Releases acquired resources */ + dispose() { + this._callback_when_changes = () => {}; + this._should_run = false; + this._output.write('exit\n', null); + this._subprocess.wait(null); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Timezone_change_listener.ts b/auto-dark-light@gihaume/src/lib/sys/Timezone_change_listener.ts new file mode 100644 index 00000000000..d3b3c47b0ef --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Timezone_change_listener.ts @@ -0,0 +1,60 @@ +const { Gio } = imports.gi; + +/** + * A listener for the system timezone changes. + * + * When the instance is not wanted anymore, `dispose` must be called. + */ +export class Timezone_change_listener { + private readonly _callback_on_change: (new_timezone: string) => void; + + /** @param callback_on_change - The function to be executed when the system timezone changes. */ + constructor(callback_on_change: (new_timezone: string) => void) { + this._callback_on_change = callback_on_change; + } + + enable(): void { + this._subscribe_to_changes(this._callback_on_change.bind(this)); + } + + disable(): void { + this._unsubscribe_to_changes(); + } + + /** Releases acquired resources */ + dispose(): void { + this.disable(); + } + + private _signal_id: number | undefined = undefined; + + private _subscribe_to_changes( + callback_when_changes: (new_timezone: string) => void + ): void { + if (this._signal_id) + this._unsubscribe_to_changes(); + this._signal_id = Gio.DBus.system.signal_subscribe( + 'org.freedesktop.timedate1', // sender + 'org.freedesktop.DBus.Properties', // interface_name + 'PropertiesChanged', // member + '/org/freedesktop/timedate1', // object_path + null, // arg0 + Gio.DBusSignalFlags.NONE, // flags + (_1, _2, _3, _4, _5, parameters) => { // callback + const changed_properties = parameters.deep_unpack()[1]; + if (changed_properties['Timezone']) { + const new_timezone = + changed_properties['Timezone'].deep_unpack(); + callback_when_changes(new_timezone); + } + } + ); + } + + private _unsubscribe_to_changes(): void { + if (!this._signal_id) + return; + Gio.DBus.system.signal_unsubscribe(this._signal_id); + this._signal_id = undefined; + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/launch_command.ts b/auto-dark-light@gihaume/src/lib/sys/launch_command.ts new file mode 100644 index 00000000000..e7df9e96a64 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/launch_command.ts @@ -0,0 +1,107 @@ +const { Gio, GLib } = imports.gi; +import { _, logger } from '../../globals'; + +export async function launch_command( + name: string, expiry: number, command: string +): Promise { + try { + await _launch_command(command, expiry); + } catch (error) { + const name_for_error = name !== '' ? name : command; + let msg = `${_("the command")} '${name_for_error}' ${_("has failed")}`; + if (error instanceof GLib.ShellError) + msg += ` ${_("due to a wrong format")}.\n` + + "\n" + + `${_("Detail")}${_(":")}\n` + + error.message; + else + if (error instanceof Gio.IOErrorEnum) { + if (error.code === Gio.IOErrorEnum.TIMED_OUT) + msg += ` ${_("due to timeout")}.\n` + + "\n" + + `${_("Detail")}${_(":")}\n` + + error.message; + else + if (error.code === Gio.IOErrorEnum.FAILED) + msg += ` ${_("due to an error")}.\n` + + "\n" + + `${_("Detail")}${_(":")}\n` + + error.message; + } else + msg += `${_(":")} ${error}` // last resort: full `error` object so we may see the stack trace + + logger.warn(msg); + } +} + +const TIMEOUT_EXIT_STATUS_SIGTERM = 124; +const TIMEOUT_EXIT_STATUS_SIGKILL = 137; +const SIGKILL_TIMEOUT = 10; // seconds (s) to wait after 'timeout' sends SIGTERM so it sends SIGKILL + +/** + * Executes a command with a timeout and transmits any error on failure. + * @param command - The shell command to execute. + * @param timeout - The delay in seconds before cancelling the command with a SIGTERM, then a few seconds later with a SIGKILL. `0` means infinity/never. + * @throws {GLib.ShellError} - If the command format is invalid. + * @throws {Gio.IOErrorEnum.TIMED_OUT} - If the command is cancelled due to a timeout. + * @throws {Gio.IOErrorEnum.FAILED} - If the command fails with a non-zero exit code. The error message is the `stderr` output if any, otherwise the exit status. + */ +async function _launch_command(command: string, timeout = 10): Promise { + const wrapped_command = + `timeout --kill-after=${SIGKILL_TIMEOUT} ${timeout}s sh -c ${GLib.shell_quote(command)}`; + const [_ok, argvp] = GLib.shell_parse_argv(wrapped_command); // can throw GLib.ShellError + + const process = new Gio.Subprocess({ + argv: argvp, + flags: Gio.SubprocessFlags.STDERR_PIPE + }); + + const start_time = Date.now(); // milliseconds (ms) + process.init(null); + const [_stdout, stderr] = await new Promise<[string, string]>( // Promisifies + (resolve, reject) => { + process.communicate_utf8_async( + null, + null, + (source: imports.gi.Gio.Subprocess, result) => { + try { + const [_ok, stdout, stderr] = + source.communicate_utf8_finish(result); + resolve([stdout, stderr]); + } catch (error) { + reject(error); + } + } + ); + } + ); + const elapsed_time = (Date.now() - start_time) / 1000; // seconds (s) + + const exit_status = process.get_exit_status(); + switch (exit_status) { + case 0: + break; + case TIMEOUT_EXIT_STATUS_SIGTERM: + throw new Gio.IOErrorEnum({ + code: Gio.IOErrorEnum.TIMED_OUT, + message: `may have been timed out by SIGTERM (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGTERM})` + }); + case TIMEOUT_EXIT_STATUS_SIGKILL: + throw new Gio.IOErrorEnum({ + code: Gio.IOErrorEnum.TIMED_OUT, + message: `probably killed by an external SIGKILL (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGKILL})` + }); + case 1: // workaround for 'timeout' sending SIGKILL not reported with the intended 137 exit status + if (timeout > 0 && elapsed_time >= timeout + SIGKILL_TIMEOUT) + throw new Gio.IOErrorEnum({ + code: Gio.IOErrorEnum.TIMED_OUT, + message: `probably timed out by SIGKILL` + }); + // no break, needs to stay directly above the default case + default: + throw new Gio.IOErrorEnum({ + code: Gio.IOErrorEnum.FAILED, + message: stderr ? stderr.trim() : "exit status: " + exit_status + }); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/system_time.ts b/auto-dark-light@gihaume/src/lib/sys/system_time.ts new file mode 100644 index 00000000000..646b1a4d316 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/system_time.ts @@ -0,0 +1,37 @@ +const { DateTime } = imports.gi.GLib; // Preferred over JS's `Date` to take into account timezone changes during runtime. + +import { Time_of_day } from "../core/Time_of_day"; +import type { Time_hms } from '../../types'; + +/** @returns seconds (s) */ +export function get_now_as_unix(): number { + return DateTime.new_now_local().to_unix(); +} + +export function get_now_as_hms(): Time_hms { + const datetime = DateTime.new_now_local(); + return _datetime_to_hms(datetime); +} + +export function get_now_as_time_of_day(): Time_of_day { + const datetime = DateTime.new_now_local(); + const hms = _datetime_to_hms(datetime); + return new Time_of_day(hms); +} + +/** @param unix_time - seconds (s) */ +export function new_local_time_of_day_from_unix( + unix_time: number +): Time_of_day { + const datetime = DateTime.new_from_unix_local(unix_time); + const hms = _datetime_to_hms(datetime); + return new Time_of_day(hms); +} + +function _datetime_to_hms(datetime: imports.gi.GLib.DateTime): Time_hms { + return { + h: datetime.get_hour(), + m: datetime.get_minute(), + s: datetime.get_second() + }; +} diff --git a/auto-dark-light@gihaume/src/lib/utils.ts b/auto-dark-light@gihaume/src/lib/utils.ts new file mode 100644 index 00000000000..84716c93ec0 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/utils.ts @@ -0,0 +1,4 @@ +/** @param duration - The duration to sleep for, in milliseconds (ms) */ +export async function sleep(duration: number): Promise { + return new Promise(resolve => setTimeout(resolve, duration)); +} diff --git a/auto-dark-light@gihaume/src/main.ts b/auto-dark-light@gihaume/src/main.ts new file mode 100644 index 00000000000..73267b4e007 --- /dev/null +++ b/auto-dark-light@gihaume/src/main.ts @@ -0,0 +1,37 @@ +const { IconApplet } = imports.ui.applet; + +import type { Applet } from './app/ui/Applet'; +import { initialize_globals, logger } from './globals'; +import { initialize_handlers } from './app/handlers/initialize_handlers'; +import { initialize_applet_settings } from './app/initialize_applet_settings'; + +//! @preserve +function main( + metadata: imports.ui.applet.AppletMetadata, + orientation: imports.gi.St.Side, + panel_height: number, + instance_id: number +): imports.ui.applet.Applet { + initialize_globals(metadata); // Must be called before anything else + + const applet = new IconApplet( + orientation, panel_height, instance_id + ) as Applet; + + const settings = initialize_applet_settings(metadata.uuid, instance_id); + + try { + initialize_handlers(applet, settings); + } catch (error) { + applet.set_applet_icon_symbolic_name('on-error-symbolic'); + if (error instanceof Error) + logger.error(error.message); + else + logger.error(String(error)); + settings.finalize(); // somewhat crash // TODO: find a better way? + } + + return applet; +} + +(globalThis as any)[import.meta.env.VITE_KEEP_MAIN_FUNCTION_SENTINEL] = main; // Prevents transpilation tree-shaking diff --git a/auto-dark-light@gihaume/src/types.ts b/auto-dark-light@gihaume/src/types.ts new file mode 100644 index 00000000000..b3aa2cf6187 --- /dev/null +++ b/auto-dark-light@gihaume/src/types.ts @@ -0,0 +1,28 @@ +import type { Time_of_day } from "./lib/core/Time_of_day"; + +export type Time_hms = { + h: number; + m: number; + s: number; +}; + +export type Location = { + latitude: number; + longitude: number; +}; + +export type Twilights = { + sunrise: Time_of_day; + sunset: Time_of_day; +}; + +export type Color_scheme = 'default' | 'prefer-dark' | 'prefer-light'; + +export type Command = { + name: string; + active: boolean; + expiry: number; + command: string; +}; + +export type Keybinding = `${string}::${'' | `${string}`}`; diff --git a/auto-dark-light@gihaume/src/vite-env.d.ts b/auto-dark-light@gihaume/src/vite-env.d.ts new file mode 100644 index 00000000000..bb894d499cf --- /dev/null +++ b/auto-dark-light@gihaume/src/vite-env.d.ts @@ -0,0 +1,15 @@ +/** + * Typing for workspace root's `.env`. + * + * Doc: https://vite.dev/guide/env-and-mode.html#intellisense-for-typescript + */ + +interface ViteTypeOptions {} // Makes the type of ImportMetaEnv strict to disallow unknown keys. + +interface ImportMetaEnv { + readonly VITE_KEEP_MAIN_FUNCTION_SENTINEL: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/auto-dark-light@gihaume/tests/Time_of_day.test.ts b/auto-dark-light@gihaume/tests/Time_of_day.test.ts new file mode 100644 index 00000000000..c5fe3f9a3b5 --- /dev/null +++ b/auto-dark-light@gihaume/tests/Time_of_day.test.ts @@ -0,0 +1,117 @@ +import { test, expect } from 'vitest'; + +import { Time_of_day } from '../src/lib/core/Time_of_day'; + +const hms = { h: 12, m: 34, s: 56 }; +const time = new Time_of_day(hms); + +test('get_as_hms', () => { + expect(time.get_as_hms()).toEqual(hms); +}); + +test('get_as_string_hmmss', () => { + expect(time.get_as_string_hmmss()).toBe('12:34:56'); +}); + +test('add_minutes', () => { + { + const new_time = time.add_minutes(30); + expect(new_time.get_as_string_hmmss()).toBe('13:04:56'); + } + { + const new_time = time.add_minutes(-60); + expect(new_time.get_as_string_hmmss()).toBe('11:34:56'); + } + { + const new_time = time.add_minutes(60 * 24 + 20); + expect(new_time.get_as_string_hmmss()).toBe('12:54:56'); + } +}); + +test('is_between', () => { + { + const start = new Time_of_day({ h: 6, m: 0, s: 0 }); + const end = new Time_of_day({ h: 18, m: 0, s: 0 }); + for (let h = 0; h < 6; h++) { + const time = new Time_of_day({ h, m: 0, s: 0 }); + expect(time.is_between(start, end)).toBe(false); + } + for (let h = 6; h < 18; h++) { + const time = new Time_of_day({ h, m: 0, s: 0 }); + expect(time.is_between(start, end)).toBe(true); + } + for (let h = 18; h < 24; h++) { + const time = new Time_of_day({ h, m: 0, s: 0 }); + expect(time.is_between(start, end)).toBe(false); + } + } + { + const start = new Time_of_day({ h: 0, m: 20, s: 0 }); + const end = new Time_of_day({ h: 0, m: 40, s: 0 }); + for (let m = 0; m < 20; m++) { + const time = new Time_of_day({ h: 0, m, s: 0 }); + expect(time.is_between(start, end)).toBe(false); + expect(time.is_between(end, start)).toBe(true); + } + for (let m = 20; m < 40; m++) { + const time = new Time_of_day({ h: 0, m, s: 0 }); + expect(time.is_between(start, end)).toBe(true); + expect(time.is_between(end, start)).toBe(false); + } + for (let m = 40; m < 60; m++) { + const time = new Time_of_day({ h: 0, m, s: 0 }); + expect(time.is_between(start, end)).toBe(false); + expect(time.is_between(end, start)).toBe(true); + } + } + { + const start = new Time_of_day({ h: 0, m: 0, s: 20 }); + const end = new Time_of_day({ h: 0, m: 0, s: 40 }); + for (let s = 0; s < 20; s++) { + const time = new Time_of_day({ h: 0, m: 0, s }); + expect(time.is_between(start, end)).toBe(false); + expect(time.is_between(end, start)).toBe(true); + } + for (let s = 20; s < 40; s++) { + const time = new Time_of_day({ h: 0, m: 0, s }); + expect(time.is_between(start, end)).toBe(true); + expect(time.is_between(end, start)).toBe(false); + } + for (let s = 40; s < 60; s++) { + const time = new Time_of_day({ h: 0, m: 0, s }); + expect(time.is_between(start, end)).toBe(false); + expect(time.is_between(end, start)).toBe(true); + } + } + { + const start = new Time_of_day({ h: 0, m: 0, s: 0 }); + const end = new Time_of_day({ h: 0, m: 0, s: 0 }); + const time = new Time_of_day({ h: 0, m: 0, s: 0 }); + expect(time.is_between(start, end)).toBe(true); // edge case + } + const time1 = new Time_of_day({ h: 12, m: 0, s: 0 }); + const time2 = new Time_of_day({ h: 13, m: 0, s: 0 }); + const time3 = new Time_of_day({ h: 11, m: 59, s: 59 }); + expect(time1.is_between(time3, time2)).toBe(true); + expect(time2.is_between(time1, time3)).toBe(true); + expect(time3.is_between(time1, time2)).toBe(false); +}); + +test('get_seconds_until_next_target', () => { + const time1 = new Time_of_day({ h: 12, m: 0, s: 0 }); + const time2 = new Time_of_day({ h: 13, m: 0, s: 0 }); + const time3 = new Time_of_day({ h: 11, m: 59, s: 59 }); + + expect(time1.get_seconds_until_next_target(time2)).toBe(3600); + expect(time2.get_seconds_until_next_target(time1)).toBe(23 * 3600); + expect(time3.get_seconds_until_next_target(time1)).toBe(1); + expect(time3.get_seconds_until_next_target(time2)).toBe(1 + 3600); +}); + +test('create_from_js_date', () => { + const date = new Date(0, 0, 1, 15, 30, 45); + const time = Time_of_day.create_from_js_date(date); + + expect(time.get_as_hms()).toEqual({ h: 15, m: 30, s: 45 }); + expect(time.get_as_string_hmmss()).toBe('15:30:45'); +}); diff --git a/auto-dark-light@gihaume/tsconfig.json b/auto-dark-light@gihaume/tsconfig.json new file mode 100644 index 00000000000..03ccc508560 --- /dev/null +++ b/auto-dark-light@gihaume/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "es2022", + "lib": ["ES2022"], + "module": "es2022", + "moduleResolution": "bundler", + "strict": true, + "types": [ + "@ci-types/cjs" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/auto-dark-light@gihaume/vite.config.mts b/auto-dark-light@gihaume/vite.config.mts new file mode 100644 index 00000000000..d2657d3416a --- /dev/null +++ b/auto-dark-light@gihaume/vite.config.mts @@ -0,0 +1,64 @@ +/// + +import * as child_process from 'child_process'; +import * as vite from 'vite'; + +export default vite.defineConfig(({ command, mode }) => { + const env = vite.loadEnv(mode, process.cwd(), 'VITE_'); + const out_dir_path = './files/auto-dark-light@gihaume/5.8'; + const out_file_name = 'applet.js'; + + const config: vite.UserConfig = { + build: { + minify: false, + rollupOptions: { + input: 'src/main.ts', + output: { + dir: out_dir_path, + entryFileNames: out_file_name + } + }, + emptyOutDir: false, + }, + plugins: [], // To be filled below + test: {}, // To be filled with Vitest options when needed + }; + if (mode === 'final') { + config.build!.minify = 'terser'; + config.build!.terserOptions = { + keep_fnames: /^main$|^_$/ + }; + config.plugins!.push({ + name: 'remove-globalThis-injection', + generateBundle(_, bundle) { + for (const output of Object.values(bundle)) { + if (output.type !== 'chunk') + continue; + const sentinel = env.VITE_KEEP_MAIN_FUNCTION_SENTINEL; + const pattern = new RegExp( + `globalThis\.${sentinel}=(.*);`, 's' + ); + output.code = output.code.replace(pattern, '$1'); + } + } + }); + config.plugins!.push({ + name: 'add-checksum-on-build', + writeBundle() { + child_process.execSync( + `cd ${out_dir_path} && sha256sum ${out_file_name} > ${out_file_name}.sha256sum` + ); + } + }); + } + else + config.plugins!.push({ + name: 'remove-checksum-on-dev-build', + writeBundle() { + child_process.execSync( + `rm -f ${out_dir_path}/${out_file_name}.sha256sum` + ); + } + }); + return config; +}); From c0bd3fda6b0ca001e50e8e22c23506f117c0ff87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Sun, 2 Nov 2025 21:45:43 +0100 Subject: [PATCH 02/13] Add PR id in `CHANGELOG.md` --- auto-dark-light@gihaume/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto-dark-light@gihaume/CHANGELOG.md b/auto-dark-light@gihaume/CHANGELOG.md index 9721f77a53c..27071b677d0 100644 --- a/auto-dark-light@gihaume/CHANGELOG.md +++ b/auto-dark-light@gihaume/CHANGELOG.md @@ -2,7 +2,7 @@ The format adheres to [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) and [SemVer 2.0.0](https://semver.org/spec/v2.0.0.html) -## [2.0.0] - 2025-11-02 - [#?](https://github.com/linuxmint/cinnamon-spices-applets/pull/?) +## [2.0.0] - 2025-11-02 - [#7939](https://github.com/linuxmint/cinnamon-spices-applets/pull/7939) Extensive rewrite to enable new features – some bugs may have been introduced. From d15e3c5b9616f86d9bec196c519b97bf6ca44c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Sun, 2 Nov 2025 22:28:15 +0100 Subject: [PATCH 03/13] Fix forgotten to copy new timezone location database to runtime files --- .../Timezone_location_finder/database.json | 837 +++++++++--------- .../Timezone_location_finder/database.json | 420 --------- .../generate_database.ipynb | 12 +- 3 files changed, 429 insertions(+), 840 deletions(-) delete mode 100644 auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/database.json diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Timezone_location_finder/database.json b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Timezone_location_finder/database.json index e96f43c9999..d4277ec89ef 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Timezone_location_finder/database.json +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Timezone_location_finder/database.json @@ -1,421 +1,420 @@ { - "Africa/Abidjan": [5.30966, -4.01266], - "Africa/Accra": [5.55602, -0.1969], - "Africa/Addis_Ababa": [9.02497, 38.74689], - "Africa/Algiers": [36.7525, 3.04197], - "Africa/Asmara": [15.33805, 38.93184], - "Africa/Bamako": [12.65, -8.0], - "Africa/Bangui": [4.36122, 18.55496], - "Africa/Banjul": [13.45274, -16.57803], - "Africa/Bissau": [11.86357, -15.59767], - "Africa/Blantyre": [-15.78499, 35.00854], - "Africa/Brazzaville": [-4.26613, 15.28318], - "Africa/Bujumbura": [-3.3822, 29.3644], - "Africa/Cairo": [30.06263, 31.24967], - "Africa/Casablanca": [33.58831, -7.61138], - "Africa/Ceuta": [35.88933, -5.31979], - "Africa/Conakry": [9.53795, -13.67729], - "Africa/Dakar": [14.6937, -17.44406], - "Africa/Dar_es_Salaam": [-6.82349, 39.26951], - "Africa/Djibouti": [11.58901, 43.14503], - "Africa/Douala": [4.04827, 9.70428], - "Africa/El_Aaiun": [27.15451, -13.19539], - "Africa/Freetown": [8.484, -13.22994], - "Africa/Gaborone": [-24.65451, 25.90859], - "Africa/Harare": [-17.82772, 31.05337], - "Africa/Johannesburg": [-26.20227, 28.04363], - "Africa/Juba": [4.85165, 31.58247], - "Africa/Kampala": [0.31628, 32.58219], - "Africa/Khartoum": [15.55177, 32.53241], - "Africa/Kigali": [-1.94995, 30.05885], - "Africa/Kinshasa": [-4.32758, 15.31357], - "Africa/Lagos": [6.45407, 3.39467], - "Africa/Libreville": [0.39241, 9.45356], - "Africa/Lome": [6.13748, 1.21227], - "Africa/Luanda": [-8.83682, 13.23432], - "Africa/Lubumbashi": [-11.66089, 27.47938], - "Africa/Lusaka": [-15.40669, 28.28713], - "Africa/Malabo": [3.75, 8.78333], - "Africa/Maputo": [-25.96553, 32.58322], - "Africa/Maseru": [-29.31667, 27.48333], - "Africa/Mbabane": [-26.31667, 31.13333], - "Africa/Mogadishu": [2.03711, 45.34375], - "Africa/Monrovia": [6.30054, -10.7969], - "Africa/Nairobi": [-1.28333, 36.81667], - "Africa/Ndjamena": [12.11915, 15.05028], - "Africa/Niamey": [13.51366, 2.1098], - "Africa/Nouakchott": [18.08581, -15.9785], - "Africa/Ouagadougou": [12.36566, -1.53388], - "Africa/Porto-Novo": [6.49646, 2.60359], - "Africa/Sao_Tome": [0.33654, 6.72732], - "Africa/Tripoli": [32.87519, 13.18746], - "Africa/Tunis": [36.81897, 10.16579], - "Africa/Windhoek": [-22.55941, 17.08323], - "America/Adak": [51.87361, -176.63903], - "America/Anchorage": [61.21806, -149.90028], - "America/Anguilla": [18.21704, -63.05783], - "America/Antigua": [17.11717, -61.84573], - "America/Araguaina": [-7.19111, -48.20722], - "America/Argentina/Buenos_Aires": [-34.61315, -58.37723], - "America/Argentina/Catamarca": [-27.19108, -67.10537], - "America/Argentina/Cordoba": [-31.4135, -64.18105], - "America/Argentina/Jujuy": [-23.31615, -65.75953], - "America/Argentina/La_Rioja": [-29.41105, -66.85067], - "America/Argentina/Mendoza": [-32.89084, -68.82717], - "America/Argentina/Rio_Gallegos": [-51.62261, -69.21813], - "America/Argentina/Salta": [-24.7859, -65.41166], - "America/Argentina/San_Juan": [-31.5375, -68.53639], - "America/Argentina/San_Luis": [-33.29501, -66.33563], - "America/Argentina/Tucuman": [-26.56436, -64.8824], - "America/Argentina/Ushuaia": [-54.8, -68.3], - "America/Aruba": [12.51757, -69.98186], - "America/Asuncion": [-25.30066, -57.63591], - "America/Atikokan": [48.76253, -91.6246], - "America/Bahia": [-12.28525, -41.92948], - "America/Bahia_Banderas": [19.66626, -99.06745], - "America/Barbados": [13.1, -59.61667], - "America/Belem": [-1.45583, -48.50444], - "America/Belize": [17.12049, -88.6859], - "America/Blanc-Sablon": [51.41216, -57.20185], - "America/Boa_Vista": [2.81972, -60.67333], - "America/Bogota": [4.60971, -74.08175], - "America/Boise": [43.6135, -116.20345], - "America/Cambridge_Bay": [69.11784, -105.06039], - "America/Campo_Grande": [-20.44278, -54.64639], - "America/Cancun": [21.17429, -86.84656], - "America/Caracas": [10.48801, -66.87919], - "America/Cayenne": [4.93333, -52.33333], - "America/Cayman": [19.2866, -81.37436], - "America/Chicago": [41.85003, -87.65005], - "America/Chihuahua": [28.63528, -106.08889], - "America/Ciudad_Juarez": [31.73726, -106.48565], - "America/Costa_Rica": [10.27356, -84.07391], - "America/Creston": [49.09715, -116.51298], - "America/Cuiaba": [-15.59611, -56.09667], - "America/Curacao": [12.1084, -68.93354], - "America/Danmarkshavn": [76.76952, -18.67368], - "America/Dawson": [64.06066, -139.43169], - "America/Dawson_Creek": [56.24988, -120.85292], - "America/Denver": [39.73915, -104.9847], - "America/Detroit": [42.33143, -83.04575], - "America/Dominica": [15.30174, -61.38808], - "America/Edmonton": [53.55014, -113.46871], - "America/Eirunepe": [-6.66028, -69.87361], - "America/El_Salvador": [13.80004, -88.91407], - "America/Fort_Nelson": [58.80621, -122.69427], - "America/Fortaleza": [-3.71722, -38.54306], - "America/Glace_Bay": [46.19695, -59.95698], - "America/Godthab": [64.18347, -51.72157], - "America/Goose_Bay": [53.33333, -60.41667], - "America/Grand_Turk": [21.46122, -71.14188], - "America/Grenada": [12.05644, -61.74849], - "America/Guadeloupe": [16.25288, -61.56869], - "America/Guatemala": [15.58555, -90.34576], - "America/Guayaquil": [-2.20584, -79.90795], - "America/Guyana": [4.84171, -58.64169], - "America/Halifax": [44.64533, -63.57239], - "America/Havana": [23.13302, -82.38304], - "America/Hermosillo": [29.1026, -110.97732], - "America/Indiana/Indianapolis": [39.76838, -86.15804], - "America/Indiana/Knox": [38.68701, -87.38115], - "America/Indiana/Marengo": [38.36923, -86.34359], - "America/Indiana/Petersburg": [38.49199, -87.27862], - "America/Indiana/Tell_City": [37.95085, -86.7697], - "America/Indiana/Vevay": [38.74784, -85.06717], - "America/Indiana/Vincennes": [38.67727, -87.52863], - "America/Indiana/Winamac": [41.05143, -86.60306], - "America/Inuvik": [68.36026, -133.72039], - "America/Iqaluit": [63.74927, -68.52138], - "America/Jamaica": [18.18505, -77.39477], - "America/Juneau": [58.30194, -134.41972], - "America/Kentucky/Louisville": [38.25424, -85.75941], - "America/Kentucky/Monticello": [36.82979, -84.84911], - "America/Kralendijk": [12.15, -68.26667], - "America/La_Paz": [-16.5, -68.15], - "America/Lima": [-12.04318, -77.02824], - "America/Los_Angeles": [34.05223, -118.24368], - "America/Lower_Princes": [18.026, -63.04582], - "America/Maceio": [-9.66583, -35.73528], - "America/Managua": [12.13282, -86.2504], - "America/Manaus": [-3.10194, -60.025], - "America/Marigot": [18.06667, -63.08333], - "America/Martinique": [14.61137, -60.96208], - "America/Matamoros": [25.88102, -97.50649], - "America/Mazatlan": [23.2329, -106.4062], - "America/Menominee": [46.09273, -88.64235], - "America/Merida": [20.97537, -89.61696], - "America/Metlakatla": [55.11936, -131.57474], - "America/Mexico_City": [19.42847, -99.12766], - "America/Miquelon": [46.77914, -56.1773], - "America/Moncton": [46.11594, -64.80186], - "America/Monterrey": [25.67507, -100.31847], - "America/Montevideo": [-34.90328, -56.18816], - "America/Montserrat": [16.7417, -62.19168], - "America/Nassau": [25.05823, -77.34306], - "America/New_York": [40.71273, -74.00602], - "America/Nome": [64.49751, -165.40617], - "America/Noronha": [-22.06778, -45.26389], - "America/North_Dakota/Beulah": [47.26334, -101.77795], - "America/North_Dakota/Center": [47.11639, -101.29959], - "America/North_Dakota/New_Salem": [46.82666, -100.88958], - "America/Nuuk": [64.17668, -51.73594], - "America/Ojinaga": [29.56689, -104.54487], - "America/Panama": [8.9936, -79.51973], - "America/Paramaribo": [5.86638, -55.16682], - "America/Phoenix": [33.44838, -112.07404], - "America/Port-au-Prince": [18.53917, -72.335], - "America/Port_of_Spain": [10.65727, -61.51802], - "America/Porto_Velho": [-8.76194, -63.90389], - "America/Puerto_Rico": [18.22477, -66.48583], - "America/Punta_Arenas": [-53.16257, -70.90782], - "America/Rankin_Inlet": [62.80303, -92.0868], - "America/Recife": [-8.05389, -34.88111], - "America/Regina": [50.45008, -104.6178], - "America/Resolute": [74.69703, -94.84085], - "America/Rio_Branco": [-9.97472, -67.81], - "America/Santarem": [-2.44306, -54.70833], - "America/Santiago": [-33.45694, -70.64827], - "America/Santo_Domingo": [18.50012, -69.98857], - "America/Sao_Paulo": [-23.5475, -46.63611], - "America/Scoresbysund": [70.48506, -21.9642], - "America/Sitka": [57.0525, -135.33761], - "America/St_Barthelemy": [17.89618, -62.84978], - "America/St_Johns": [56.69228, -60.93732], - "America/St_Kitts": [17.29484, -62.7261], - "America/St_Lucia": [13.9957, -61.00614], - "America/St_Thomas": [18.34291, -64.9189], - "America/St_Vincent": [12.90447, -61.27656], - "America/Swift_Current": [50.28491, -107.79845], - "America/Tegucigalpa": [14.0818, -87.20681], - "America/Thule": [77.46864, -69.22227], - "America/Thunder_Bay": [48.38202, -89.25018], - "America/Tijuana": [32.5027, -117.00371], - "America/Toronto": [43.70011, -79.4163], - "America/Tortola": [18.43882, -64.60382], - "America/Vancouver": [49.24966, -123.11934], - "America/Whitehorse": [60.71611, -135.05375], - "America/Winnipeg": [49.8844, -97.14704], - "America/Yakutat": [59.63918, -139.34294], - "America/Yellowknife": [62.456, -114.35255], - "Antarctica/Casey": [-66.28209, 110.52408], - "Antarctica/Davis": [-68.57691, 77.96837], - "Antarctica/DumontDUrville": [-66.66328, 140.0011], - "Antarctica/Macquarie": [-54.63181, 158.86176], - "Antarctica/Mawson": [-67.6029, 62.87375], - "Antarctica/McMurdo": [-77.84833, 166.66833], - "Antarctica/Palmer": [61.59957, -149.11109], - "Antarctica/Rothera": [-67.56918, -68.12217], - "Antarctica/Syowa": [-69.00424, 39.58203], - "Antarctica/Troll": [-72.01198, 2.53443], - "Antarctica/Vostok": [-78.46523, 106.83794], - "Arctic/Longyearbyen": [78.22334, 15.64689], - "Asia/Aden": [12.77944, 45.03667], - "Asia/Almaty": [43.25654, 76.92848], - "Asia/Amman": [31.95522, 35.94503], - "Asia/Anadyr": [64.73169, 177.50609], - "Asia/Aqtau": [43.63534, 51.16822], - "Asia/Aqtobe": [50.27969, 57.20718], - "Asia/Ashgabat": [37.95, 58.38333], - "Asia/Atyrau": [47.66058, 50.8062], - "Asia/Baghdad": [33.34058, 44.40088], - "Asia/Bahrain": [26.15512, 50.53446], - "Asia/Baku": [40.37767, 49.89201], - "Asia/Bangkok": [13.75398, 100.50144], - "Asia/Barnaul": [53.34755, 83.77884], - "Asia/Beirut": [33.88894, 35.49442], - "Asia/Bishkek": [42.87, 74.59], - "Asia/Chita": [52.03341, 113.50089], - "Asia/Colombo": [6.93194, 79.84778], - "Asia/Damascus": [33.5102, 36.29128], - "Asia/Dhaka": [23.7104, 90.40744], - "Asia/Dili": [-8.55861, 125.57361], - "Asia/Dubai": [25.0657, 55.17128], - "Asia/Dushanbe": [38.53575, 68.77905], - "Asia/Famagusta": [35.12053, 33.93879], - "Asia/Gaza": [31.5, 34.46667], - "Asia/Hebron": [31.52935, 35.0938], - "Asia/Ho_Chi_Minh": [10.77639, 106.70114], - "Asia/Hong_Kong": [22.28552, 114.15769], - "Asia/Hovd": [46.8998, 92.29597], - "Asia/Irkutsk": [52.29778, 104.29639], - "Asia/Jakarta": [-6.21462, 106.84513], - "Asia/Jayapura": [-2.53371, 140.71813], - "Asia/Jerusalem": [31.76904, 35.21633], - "Asia/Kabul": [34.52813, 69.17233], - "Asia/Kamchatka": [57.19149, 160.03838], - "Asia/Karachi": [24.9056, 67.0822], - "Asia/Kathmandu": [27.70169, 85.3206], - "Asia/Khandyga": [62.64779, 135.57509], - "Asia/Kolkata": [22.56263, 88.36304], - "Asia/Krasnoyarsk": [56.01839, 92.86717], - "Asia/Kuala_Lumpur": [3.1412, 101.68653], - "Asia/Kuching": [1.55, 110.33333], - "Asia/Kuwait": [29.37965, 47.97342], - "Asia/Macau": [22.20056, 113.54611], - "Asia/Magadan": [59.5638, 150.80347], - "Asia/Makassar": [-5.14, 119.4221], - "Asia/Manila": [14.6042, 120.9822], - "Asia/Muscat": [23.61387, 58.5922], - "Asia/Nicosia": [35.17531, 33.3642], - "Asia/Novokuznetsk": [53.7557, 87.1099], - "Asia/Novosibirsk": [55.0415, 82.9346], - "Asia/Omsk": [54.99244, 73.36859], - "Asia/Oral": [51.23333, 51.36667], - "Asia/Phnom_Penh": [11.56245, 104.91601], - "Asia/Pontianak": [-0.03109, 109.32199], - "Asia/Pyongyang": [39.03385, 125.75432], - "Asia/Qatar": [25.3337, 51.22953], - "Asia/Qostanay": [52.06156, 62.93727], - "Asia/Qyzylorda": [45.20589, 63.91552], - "Asia/Riyadh": [24.68773, 46.72185], - "Asia/Sakhalin": [50.15948, 143.02644], - "Asia/Samarkand": [39.655, 66.9757], - "Asia/Seoul": [37.566, 126.9784], - "Asia/Shanghai": [31.22222, 121.45806], - "Asia/Singapore": [1.28967, 103.85007], - "Asia/Srednekolymsk": [67.4555, 153.70715], - "Asia/Taipei": [25.04776, 121.53185], - "Asia/Tashkent": [41.26465, 69.21627], - "Asia/Tbilisi": [41.69411, 44.83368], - "Asia/Tehran": [35.69439, 51.42151], - "Asia/Thimphu": [27.46609, 89.64191], - "Asia/Tokyo": [35.6895, 139.69171], - "Asia/Tomsk": [58.61243, 82.04753], - "Asia/Ulaanbaatar": [47.90771, 106.88324], - "Asia/Urumqi": [43.41975, 87.31946], - "Asia/Ust-Nera": [64.56638, 143.23784], - "Asia/Vientiane": [17.96667, 102.6], - "Asia/Vladivostok": [43.10562, 131.87353], - "Asia/Yakutsk": [62.03389, 129.73306], - "Asia/Yangon": [16.79671, 96.16099], - "Asia/Yekaterinburg": [56.8519, 60.6122], - "Asia/Yerevan": [40.18111, 44.51361], - "Atlantic/Azores": [37.73333, -25.66667], - "Atlantic/Bermuda": [32.2949, -64.78303], - "Atlantic/Canary": [28.2864, -16.79601], - "Atlantic/Cape_Verde": [16.00006, -24.00839], - "Atlantic/Faroe": [62.00973, -6.77164], - "Atlantic/Madeira": [32.75175, -16.98175], - "Atlantic/Reykjavik": [64.13548, -21.89541], - "Atlantic/South_Georgia": [-54.28111, -36.5092], - "Atlantic/St_Helena": [-15.93872, -5.71675], - "Atlantic/Stanley": [-51.7, -57.85], - "Australia/Adelaide": [-34.92866, 138.59863], - "Australia/Brisbane": [-27.46794, 153.02809], - "Australia/Broken_Hill": [-31.96173, 141.45998], - "Australia/Darwin": [-12.46113, 130.84185], - "Australia/Eucla": [-31.67684, 128.88652], - "Australia/Hobart": [-42.87936, 147.32941], - "Australia/Lindeman": [-20.44473, 149.04321], - "Australia/Lord_Howe": [-31.55402, 159.08563], - "Australia/Melbourne": [-37.814, 144.96332], - "Australia/Perth": [-31.95224, 115.8614], - "Australia/Sydney": [-33.86785, 151.20732], - "Europe/Amsterdam": [52.37403, 4.88969], - "Europe/Andorra": [42.54072, 1.5732], - "Europe/Astrakhan": [46.34983, 48.03262], - "Europe/Athens": [37.97945, 23.71622], - "Europe/Belgrade": [44.80401, 20.46513], - "Europe/Berlin": [52.52437, 13.41053], - "Europe/Bratislava": [48.14816, 17.10674], - "Europe/Brussels": [50.85045, 4.34878], - "Europe/Bucharest": [44.43225, 26.10626], - "Europe/Budapest": [47.49801, 19.03991], - "Europe/Busingen": [47.6975, 8.69071], - "Europe/Chisinau": [47.00556, 28.8575], - "Europe/Copenhagen": [55.67594, 12.56553], - "Europe/Dublin": [53.33306, -6.24889], - "Europe/Gibraltar": [36.14474, -5.35257], - "Europe/Guernsey": [49.45981, -2.53527], - "Europe/Helsinki": [60.16952, 24.93545], - "Europe/Isle_of_Man": [54.15, -4.48333], - "Europe/Istanbul": [41.01384, 28.94966], - "Europe/Jersey": [49.18804, -2.10491], - "Europe/Kaliningrad": [54.70649, 20.51095], - "Europe/Kirov": [58.60357, 49.66662], - "Europe/Kyiv": [50.45003, 30.52414], - "Europe/Lisbon": [38.71667, -9.13333], - "Europe/Ljubljana": [46.05108, 14.50513], - "Europe/London": [51.50853, -0.12574], - "Europe/Luxembourg": [49.61167, 6.13], - "Europe/Madrid": [40.4165, -3.70256], - "Europe/Malta": [35.8886, 14.44769], - "Europe/Mariehamn": [60.09726, 19.93481], - "Europe/Minsk": [53.9, 27.56667], - "Europe/Monaco": [43.73333, 7.41667], - "Europe/Moscow": [55.75222, 37.61556], - "Europe/Oslo": [59.91273, 10.74609], - "Europe/Paris": [48.85341, 2.3488], - "Europe/Podgorica": [42.44111, 19.26361], - "Europe/Prague": [50.08804, 14.42076], - "Europe/Riga": [56.946, 24.10589], - "Europe/Rome": [41.89193, 12.51133], - "Europe/Samara": [53.20007, 50.15], - "Europe/San_Marino": [43.93667, 12.44639], - "Europe/Sarajevo": [43.84864, 18.35644], - "Europe/Saratov": [51.53002, 46.03468], - "Europe/Simferopol": [44.95719, 34.11079], - "Europe/Skopje": [41.99646, 21.43141], - "Europe/Sofia": [42.69751, 23.32415], - "Europe/Stockholm": [59.33258, 18.0649], - "Europe/Tallinn": [59.43696, 24.75353], - "Europe/Tirane": [41.32815, 19.81844], - "Europe/Ulyanovsk": [54.31503, 48.40337], - "Europe/Vaduz": [47.14151, 9.52154], - "Europe/Vatican": [41.90236, 12.45332], - "Europe/Vienna": [48.20849, 16.37208], - "Europe/Vilnius": [54.68916, 25.2798], - "Europe/Volgograd": [48.71939, 44.50183], - "Europe/Warsaw": [52.22977, 21.01178], - "Europe/Zagreb": [45.81444, 15.97798], - "Europe/Zurich": [47.36667, 8.55], - "Indian/Antananarivo": [-18.91368, 47.53613], - "Indian/Chagos": [-6.68476, 71.38325], - "Indian/Christmas": [-10.42172, 105.67912], - "Indian/Cocos": [-12.15681, 96.82251], - "Indian/Comoro": [-12.22657, 44.4107], - "Indian/Kerguelen": [-49.35, 70.21667], - "Indian/Mahe": [-4.61667, 55.45], - "Indian/Maldives": [4.1748, 73.50888], - "Indian/Mauritius": [-20.27595, 57.57036], - "Indian/Mayotte": [-12.82305, 45.15208], - "Indian/Reunion": [-21.13093, 55.52658], - "Pacific/Apia": [-13.83333, -171.76666], - "Pacific/Auckland": [-36.86667, 174.76667], - "Pacific/Bougainville": [-6.22977, 155.56598], - "Pacific/Chatham": [-43.9127, -176.47503], - "Pacific/Chuuk": [7.43938, 151.85155], - "Pacific/Easter": [-27.12593, -109.34959], - "Pacific/Efate": [-17.73381, 168.32188], - "Pacific/Fakaofo": [-9.37356, -171.24148], - "Pacific/Fiji": [-18.12397, 179.01227], - "Pacific/Funafuti": [-8.52425, 179.19417], - "Pacific/Galapagos": [-0.62882, -90.36388], - "Pacific/Gambier": [-23.15716, -134.95409], - "Pacific/Guadalcanal": [-9.43333, 159.95], - "Pacific/Guam": [13.44999, 144.76517], - "Pacific/Honolulu": [21.30694, -157.85833], - "Pacific/Kanton": [-2.81676, -171.6741], - "Pacific/Kiritimati": [1.872, -157.38421], - "Pacific/Kosrae": [5.31426, 162.98112], - "Pacific/Kwajalein": [9.12579, 167.57405], - "Pacific/Majuro": [7.08971, 171.38027], - "Pacific/Marquesas": [-9.77941, -139.00678], - "Pacific/Midway": [28.24175, -177.37543], - "Pacific/Nauru": [-0.52523, 166.93244], - "Pacific/Niue": [-19.05952, -169.91867], - "Pacific/Norfolk": [-29.05459, 167.96628], - "Pacific/Noumea": [-22.27631, 166.4572], - "Pacific/Pago_Pago": [-14.27806, -170.7025], - "Pacific/Palau": [7.50043, 134.62355], - "Pacific/Pitcairn": [-25.06597, -130.10147], - "Pacific/Pohnpei": [6.92477, 158.16109], - "Pacific/Port_Moresby": [-9.44314, 147.17972], - "Pacific/Rarotonga": [-21.20778, -159.775], - "Pacific/Saipan": [15.21233, 145.7545], - "Pacific/Tahiti": [-17.68734, -149.44517], - "Pacific/Tarawa": [1.3278, 172.97696], - "Pacific/Tongatapu": [-21.13938, -175.2018], - "Pacific/Wake": [16.72882, -169.53338], - "Pacific/Wallis": [-13.28163, -176.17453] + "Africa/Abidjan": [5.317, -3.967], + "Africa/Accra": [5.550, 0.217], + "Africa/Addis_Ababa": [9.033, 38.700], + "Africa/Algiers": [36.783, 3.050], + "Africa/Asmara": [15.333, 38.883], + "Africa/Bamako": [12.650, -8.000], + "Africa/Bangui": [4.367, 18.583], + "Africa/Banjul": [13.467, -15.350], + "Africa/Bissau": [11.850, -14.417], + "Africa/Blantyre": [-14.217, 35.000], + "Africa/Brazzaville": [-3.733, 15.283], + "Africa/Bujumbura": [-2.617, 29.367], + "Africa/Cairo": [30.050, 31.250], + "Africa/Casablanca": [33.650, -6.417], + "Africa/Ceuta": [35.883, -4.683], + "Africa/Conakry": [9.517, -12.283], + "Africa/Dakar": [14.667, -16.567], + "Africa/Dar_es_Salaam": [-5.200, 39.283], + "Africa/Djibouti": [11.600, 43.150], + "Africa/Douala": [4.050, 9.700], + "Africa/El_Aaiun": [27.150, -12.800], + "Africa/Freetown": [8.500, -12.750], + "Africa/Gaborone": [-23.350, 25.917], + "Africa/Harare": [-16.167, 31.050], + "Africa/Johannesburg": [-25.750, 28.000], + "Africa/Juba": [4.850, 31.617], + "Africa/Kampala": [0.317, 32.417], + "Africa/Khartoum": [15.600, 32.533], + "Africa/Kigali": [-0.050, 30.067], + "Africa/Kinshasa": [-3.700, 15.300], + "Africa/Lagos": [6.450, 3.400], + "Africa/Libreville": [0.383, 9.450], + "Africa/Lome": [6.133, 1.217], + "Africa/Luanda": [-7.200, 13.233], + "Africa/Lubumbashi": [-10.333, 27.467], + "Africa/Lusaka": [-14.583, 28.283], + "Africa/Malabo": [3.750, 8.783], + "Africa/Maputo": [-24.033, 32.583], + "Africa/Maseru": [-28.533, 27.500], + "Africa/Mbabane": [-25.700, 31.100], + "Africa/Mogadishu": [2.067, 45.367], + "Africa/Monrovia": [6.300, -9.217], + "Africa/Nairobi": [-0.717, 36.817], + "Africa/Ndjamena": [12.117, 15.050], + "Africa/Niamey": [13.517, 2.117], + "Africa/Nouakchott": [18.100, -14.050], + "Africa/Ouagadougou": [12.367, -0.483], + "Africa/Porto-Novo": [6.483, 2.617], + "Africa/Sao_Tome": [0.333, 6.733], + "Africa/Tripoli": [32.900, 13.183], + "Africa/Tunis": [36.800, 10.183], + "Africa/Windhoek": [-21.433, 17.100], + "America/Adak": [51.880, -175.342], + "America/Anchorage": [61.218, -148.100], + "America/Anguilla": [18.200, -62.933], + "America/Antigua": [17.050, -60.200], + "America/Araguaina": [-6.800, -47.800], + "America/Argentina/Buenos_Aires": [-33.400, -57.550], + "America/Argentina/Catamarca": [-27.533, -64.217], + "America/Argentina/Cordoba": [-30.600, -63.817], + "America/Argentina/Jujuy": [-23.817, -64.700], + "America/Argentina/La_Rioja": [-28.567, -65.150], + "America/Argentina/Mendoza": [-31.117, -67.183], + "America/Argentina/Rio_Gallegos": [-50.367, -68.783], + "America/Argentina/Salta": [-23.217, -64.583], + "America/Argentina/San_Juan": [-30.467, -67.483], + "America/Argentina/San_Luis": [-32.683, -65.650], + "America/Argentina/Tucuman": [-25.183, -64.783], + "America/Argentina/Ushuaia": [-53.200, -67.700], + "America/Aruba": [12.500, -68.033], + "America/Asuncion": [-24.733, -56.333], + "America/Atikokan": [48.759, -90.378], + "America/Bahia": [-11.017, -37.483], + "America/Bahia_Banderas": [20.800, -104.750], + "America/Barbados": [13.100, -58.383], + "America/Belem": [-0.550, -47.517], + "America/Belize": [17.500, -87.800], + "America/Blanc-Sablon": [51.417, -56.883], + "America/Boa_Vista": [2.817, -59.333], + "America/Bogota": [4.600, -73.917], + "America/Boise": [43.614, -115.797], + "America/Cambridge_Bay": [69.114, -104.947], + "America/Campo_Grande": [-19.550, -53.383], + "America/Cancun": [21.083, -85.233], + "America/Caracas": [10.500, -65.067], + "America/Cayenne": [4.933, -51.667], + "America/Cayman": [19.300, -80.617], + "America/Chicago": [41.850, -86.350], + "America/Chihuahua": [28.633, -105.917], + "America/Ciudad_Juarez": [31.733, -105.517], + "America/Costa_Rica": [9.933, -83.917], + "America/Coyhaique": [-44.433, -71.933], + "America/Creston": [49.100, -115.483], + "America/Cuiaba": [-14.417, -55.917], + "America/Curacao": [12.183, -69.000], + "America/Danmarkshavn": [76.767, -17.333], + "America/Dawson": [64.067, -138.583], + "America/Dawson_Creek": [55.767, -119.767], + "America/Denver": [39.739, -103.016], + "America/Detroit": [42.331, -82.954], + "America/Dominica": [15.300, -60.600], + "America/Edmonton": [53.550, -112.533], + "America/Eirunepe": [-5.333, -68.133], + "America/El_Salvador": [13.700, -88.800], + "America/Fort_Nelson": [58.800, -121.300], + "America/Fortaleza": [-2.283, -37.500], + "America/Glace_Bay": [46.200, -58.050], + "America/Goose_Bay": [53.333, -59.583], + "America/Grand_Turk": [21.467, -70.867], + "America/Grenada": [12.050, -60.250], + "America/Guadeloupe": [16.233, -60.467], + "America/Guatemala": [14.633, -89.483], + "America/Guayaquil": [-1.833, -78.167], + "America/Guyana": [6.800, -57.833], + "America/Halifax": [44.650, -62.400], + "America/Havana": [23.133, -81.633], + "America/Hermosillo": [29.067, -109.033], + "America/Indiana/Indianapolis": [39.768, -85.842], + "America/Indiana/Knox": [41.296, -85.375], + "America/Indiana/Marengo": [38.376, -85.655], + "America/Indiana/Petersburg": [38.492, -86.721], + "America/Indiana/Tell_City": [37.953, -85.239], + "America/Indiana/Vevay": [38.748, -84.933], + "America/Indiana/Vincennes": [38.677, -86.471], + "America/Indiana/Winamac": [41.051, -85.397], + "America/Inuvik": [68.350, -132.283], + "America/Iqaluit": [63.733, -67.533], + "America/Jamaica": [17.968, -75.207], + "America/Juneau": [58.302, -133.580], + "America/Kentucky/Louisville": [38.254, -84.241], + "America/Kentucky/Monticello": [36.830, -83.151], + "America/Kralendijk": [12.151, -67.723], + "America/La_Paz": [-15.500, -67.850], + "America/Lima": [-11.950, -76.950], + "America/Los_Angeles": [34.052, -117.757], + "America/Lower_Princes": [18.051, -62.953], + "America/Maceio": [-8.333, -34.283], + "America/Managua": [12.150, -85.717], + "America/Manaus": [-2.867, -59.983], + "America/Marigot": [18.067, -62.917], + "America/Martinique": [14.600, -60.917], + "America/Matamoros": [25.833, -96.500], + "America/Mazatlan": [23.217, -105.583], + "America/Menominee": [45.108, -86.386], + "America/Merida": [20.967, -88.383], + "America/Metlakatla": [55.127, -130.424], + "America/Mexico_City": [19.400, -98.850], + "America/Miquelon": [47.050, -55.667], + "America/Moncton": [46.100, -63.217], + "America/Monterrey": [25.667, -99.683], + "America/Montevideo": [-33.091, -55.787], + "America/Montserrat": [16.717, -61.783], + "America/Nassau": [25.083, -76.650], + "America/New_York": [40.714, -73.994], + "America/Nome": [64.501, -164.594], + "America/Noronha": [-2.150, -31.583], + "America/North_Dakota/Beulah": [47.264, -100.222], + "America/North_Dakota/Center": [47.116, -100.701], + "America/North_Dakota/New_Salem": [46.845, -100.589], + "America/Nuuk": [64.183, -50.267], + "America/Ojinaga": [29.567, -103.583], + "America/Panama": [8.967, -78.467], + "America/Paramaribo": [5.833, -54.833], + "America/Phoenix": [33.448, -111.927], + "America/Port-au-Prince": [18.533, -71.667], + "America/Port_of_Spain": [10.650, -60.483], + "America/Porto_Velho": [-7.233, -62.100], + "America/Puerto_Rico": [18.468, -65.894], + "America/Punta_Arenas": [-52.850, -69.083], + "America/Rankin_Inlet": [62.817, -91.917], + "America/Recife": [-7.950, -33.100], + "America/Regina": [50.400, -103.350], + "America/Resolute": [74.696, -93.171], + "America/Rio_Branco": [-8.033, -66.200], + "America/Santarem": [-1.567, -53.133], + "America/Santiago": [-32.550, -69.333], + "America/Santo_Domingo": [18.467, -68.100], + "America/Sao_Paulo": [-22.467, -45.383], + "America/Scoresbysund": [70.483, -20.033], + "America/Sitka": [57.176, -134.698], + "America/St_Barthelemy": [17.883, -61.150], + "America/St_Johns": [47.567, -51.283], + "America/St_Kitts": [17.300, -61.283], + "America/St_Lucia": [14.017, -61.000], + "America/St_Thomas": [18.350, -63.067], + "America/St_Vincent": [13.150, -60.767], + "America/Swift_Current": [50.283, -106.167], + "America/Tegucigalpa": [14.100, -86.783], + "America/Thule": [76.567, -67.217], + "America/Tijuana": [32.533, -116.983], + "America/Toronto": [43.650, -78.617], + "America/Tortola": [18.450, -63.383], + "America/Vancouver": [49.267, -122.883], + "America/Whitehorse": [60.717, -134.950], + "America/Winnipeg": [49.883, -96.850], + "America/Yakutat": [59.547, -138.273], + "Antarctica/Casey": [-65.717, 110.517], + "Antarctica/Davis": [-67.417, 77.967], + "Antarctica/DumontDUrville": [-65.333, 140.017], + "Antarctica/Macquarie": [-53.500, 158.950], + "Antarctica/Mawson": [-66.400, 62.883], + "Antarctica/McMurdo": [-76.167, 166.600], + "Antarctica/Palmer": [-63.200, -63.900], + "Antarctica/Rothera": [-66.433, -67.867], + "Antarctica/Syowa": [-68.994, 39.590], + "Antarctica/Troll": [-71.989, 2.535], + "Antarctica/Vostok": [-77.600, 106.900], + "Arctic/Longyearbyen": [78.000, 16.000], + "Asia/Aden": [12.750, 45.200], + "Asia/Almaty": [43.250, 76.950], + "Asia/Amman": [31.950, 35.933], + "Asia/Anadyr": [64.750, 177.483], + "Asia/Aqtau": [44.517, 50.267], + "Asia/Aqtobe": [50.283, 57.167], + "Asia/Ashgabat": [37.950, 58.383], + "Asia/Atyrau": [47.117, 51.933], + "Asia/Baghdad": [33.350, 44.417], + "Asia/Bahrain": [26.383, 50.583], + "Asia/Baku": [40.383, 49.850], + "Asia/Bangkok": [13.750, 100.517], + "Asia/Barnaul": [53.367, 83.750], + "Asia/Beirut": [33.883, 35.500], + "Asia/Bishkek": [42.900, 74.600], + "Asia/Brunei": [4.933, 114.917], + "Asia/Chita": [52.050, 113.467], + "Asia/Colombo": [6.933, 79.850], + "Asia/Damascus": [33.500, 36.300], + "Asia/Dhaka": [23.717, 90.417], + "Asia/Dili": [-7.450, 125.583], + "Asia/Dubai": [25.300, 55.300], + "Asia/Dushanbe": [38.583, 68.800], + "Asia/Famagusta": [35.117, 33.950], + "Asia/Gaza": [31.500, 34.467], + "Asia/Hebron": [31.533, 35.095], + "Asia/Ho_Chi_Minh": [10.750, 106.667], + "Asia/Hong_Kong": [22.283, 114.150], + "Asia/Hovd": [48.017, 91.650], + "Asia/Irkutsk": [52.267, 104.333], + "Asia/Jakarta": [-5.833, 106.800], + "Asia/Jayapura": [-1.467, 140.700], + "Asia/Jerusalem": [31.781, 35.224], + "Asia/Kabul": [34.517, 69.200], + "Asia/Kamchatka": [53.017, 158.650], + "Asia/Karachi": [24.867, 67.050], + "Asia/Kathmandu": [27.717, 85.317], + "Asia/Khandyga": [62.656, 135.554], + "Asia/Kolkata": [22.533, 88.367], + "Asia/Krasnoyarsk": [56.017, 92.833], + "Asia/Kuala_Lumpur": [3.167, 101.700], + "Asia/Kuching": [1.550, 110.333], + "Asia/Kuwait": [29.333, 47.983], + "Asia/Macau": [22.197, 113.542], + "Asia/Magadan": [59.567, 150.800], + "Asia/Makassar": [-4.883, 119.400], + "Asia/Manila": [14.587, 120.968], + "Asia/Muscat": [23.600, 58.583], + "Asia/Nicosia": [35.167, 33.367], + "Asia/Novokuznetsk": [53.750, 87.117], + "Asia/Novosibirsk": [55.033, 82.917], + "Asia/Omsk": [55.000, 73.400], + "Asia/Oral": [51.217, 51.350], + "Asia/Phnom_Penh": [11.550, 104.917], + "Asia/Pontianak": [0.033, 109.333], + "Asia/Pyongyang": [39.017, 125.750], + "Asia/Qatar": [25.283, 51.533], + "Asia/Qostanay": [53.200, 63.617], + "Asia/Qyzylorda": [44.800, 65.467], + "Asia/Riyadh": [24.633, 46.717], + "Asia/Sakhalin": [46.967, 142.700], + "Asia/Samarkand": [39.667, 66.800], + "Asia/Seoul": [37.550, 126.967], + "Asia/Shanghai": [31.233, 121.467], + "Asia/Singapore": [1.283, 103.850], + "Asia/Srednekolymsk": [67.467, 153.717], + "Asia/Taipei": [25.050, 121.500], + "Asia/Tashkent": [41.333, 69.300], + "Asia/Tbilisi": [41.717, 44.817], + "Asia/Tehran": [35.667, 51.433], + "Asia/Thimphu": [27.467, 89.650], + "Asia/Tokyo": [35.654, 139.745], + "Asia/Tomsk": [56.500, 84.967], + "Asia/Ulaanbaatar": [47.917, 106.883], + "Asia/Urumqi": [43.800, 87.583], + "Asia/Ust-Nera": [64.560, 143.227], + "Asia/Vientiane": [17.967, 102.600], + "Asia/Vladivostok": [43.167, 131.933], + "Asia/Yakutsk": [62.000, 129.667], + "Asia/Yangon": [16.783, 96.167], + "Asia/Yekaterinburg": [56.850, 60.600], + "Asia/Yerevan": [40.183, 44.500], + "Atlantic/Azores": [37.733, -24.333], + "Atlantic/Bermuda": [32.283, -63.233], + "Atlantic/Canary": [28.100, -14.600], + "Atlantic/Cape_Verde": [14.917, -22.483], + "Atlantic/Faroe": [62.017, -5.233], + "Atlantic/Madeira": [32.633, -15.100], + "Atlantic/Reykjavik": [64.150, -20.150], + "Atlantic/South_Georgia": [-53.733, -35.467], + "Atlantic/St_Helena": [-14.083, -4.300], + "Atlantic/Stanley": [-50.300, -56.150], + "Australia/Adelaide": [-33.083, 138.583], + "Australia/Brisbane": [-26.533, 153.033], + "Australia/Broken_Hill": [-30.050, 141.450], + "Australia/Darwin": [-11.533, 130.833], + "Australia/Eucla": [-30.283, 128.867], + "Australia/Hobart": [-41.117, 147.317], + "Australia/Lindeman": [-19.733, 149.000], + "Australia/Lord_Howe": [-30.450, 159.083], + "Australia/Melbourne": [-36.183, 144.967], + "Australia/Perth": [-30.050, 115.850], + "Australia/Sydney": [-32.133, 151.217], + "Europe/Amsterdam": [52.367, 4.900], + "Europe/Andorra": [42.500, 1.517], + "Europe/Astrakhan": [46.350, 48.050], + "Europe/Athens": [37.967, 23.717], + "Europe/Belgrade": [44.833, 20.500], + "Europe/Berlin": [52.500, 13.367], + "Europe/Bratislava": [48.150, 17.117], + "Europe/Brussels": [50.833, 4.333], + "Europe/Bucharest": [44.433, 26.100], + "Europe/Budapest": [47.500, 19.083], + "Europe/Busingen": [47.700, 8.683], + "Europe/Chisinau": [47.000, 28.833], + "Europe/Copenhagen": [55.667, 12.583], + "Europe/Dublin": [53.333, -5.750], + "Europe/Gibraltar": [36.133, -4.650], + "Europe/Guernsey": [49.455, -1.464], + "Europe/Helsinki": [60.167, 24.967], + "Europe/Isle_of_Man": [54.150, -3.533], + "Europe/Istanbul": [41.017, 28.967], + "Europe/Jersey": [49.184, -1.893], + "Europe/Kaliningrad": [54.717, 20.500], + "Europe/Kirov": [58.600, 49.650], + "Europe/Kyiv": [50.433, 30.517], + "Europe/Lisbon": [38.717, -8.867], + "Europe/Ljubljana": [46.050, 14.517], + "Europe/London": [51.508, 0.125], + "Europe/Luxembourg": [49.600, 6.150], + "Europe/Madrid": [40.400, -2.317], + "Europe/Malta": [35.900, 14.517], + "Europe/Mariehamn": [60.100, 19.950], + "Europe/Minsk": [53.900, 27.567], + "Europe/Monaco": [43.700, 7.383], + "Europe/Moscow": [55.756, 37.618], + "Europe/Oslo": [59.917, 10.750], + "Europe/Paris": [48.867, 2.333], + "Europe/Podgorica": [42.433, 19.267], + "Europe/Prague": [50.083, 14.433], + "Europe/Riga": [56.950, 24.100], + "Europe/Rome": [41.900, 12.483], + "Europe/Samara": [53.200, 50.150], + "Europe/San_Marino": [43.917, 12.467], + "Europe/Sarajevo": [43.867, 18.417], + "Europe/Saratov": [51.567, 46.033], + "Europe/Simferopol": [44.950, 34.100], + "Europe/Skopje": [41.983, 21.433], + "Europe/Sofia": [42.683, 23.317], + "Europe/Stockholm": [59.333, 18.050], + "Europe/Tallinn": [59.417, 24.750], + "Europe/Tirane": [41.333, 19.833], + "Europe/Ulyanovsk": [54.333, 48.400], + "Europe/Vaduz": [47.150, 9.517], + "Europe/Vatican": [41.902, 12.453], + "Europe/Vienna": [48.217, 16.333], + "Europe/Vilnius": [54.683, 25.317], + "Europe/Volgograd": [48.733, 44.417], + "Europe/Warsaw": [52.250, 21.000], + "Europe/Zagreb": [45.800, 15.967], + "Europe/Zurich": [47.383, 8.533], + "Indian/Antananarivo": [-17.083, 47.517], + "Indian/Chagos": [-6.667, 72.417], + "Indian/Christmas": [-9.583, 105.717], + "Indian/Cocos": [-11.833, 96.917], + "Indian/Comoro": [-10.317, 43.267], + "Indian/Kerguelen": [-48.647, 70.218], + "Indian/Mahe": [-3.333, 55.467], + "Indian/Maldives": [4.167, 73.500], + "Indian/Mauritius": [-19.833, 57.500], + "Indian/Mayotte": [-11.217, 45.233], + "Indian/Reunion": [-19.133, 55.467], + "Pacific/Apia": [-12.167, -170.267], + "Pacific/Auckland": [-35.133, 174.767], + "Pacific/Bougainville": [-5.783, 155.567], + "Pacific/Chatham": [-42.050, -175.450], + "Pacific/Chuuk": [7.417, 151.783], + "Pacific/Easter": [-26.850, -108.567], + "Pacific/Efate": [-16.333, 168.417], + "Pacific/Fakaofo": [-8.633, -170.767], + "Pacific/Fiji": [-17.867, 178.417], + "Pacific/Funafuti": [-7.483, 179.217], + "Pacific/Galapagos": [0.900, -88.400], + "Pacific/Gambier": [-22.867, -133.050], + "Pacific/Guadalcanal": [-8.467, 160.200], + "Pacific/Guam": [13.467, 144.750], + "Pacific/Honolulu": [21.307, -156.142], + "Pacific/Kanton": [-1.217, -170.283], + "Pacific/Kiritimati": [1.867, -156.667], + "Pacific/Kosrae": [5.317, 162.983], + "Pacific/Kwajalein": [9.083, 167.333], + "Pacific/Majuro": [7.150, 171.200], + "Pacific/Marquesas": [-9.000, -138.500], + "Pacific/Midway": [28.217, -176.633], + "Pacific/Nauru": [0.517, 166.917], + "Pacific/Niue": [-18.983, -168.083], + "Pacific/Norfolk": [-28.950, 167.967], + "Pacific/Noumea": [-21.733, 166.450], + "Pacific/Pago_Pago": [-13.733, -169.300], + "Pacific/Palau": [7.333, 134.483], + "Pacific/Pitcairn": [-24.933, -129.917], + "Pacific/Pohnpei": [6.967, 158.217], + "Pacific/Port_Moresby": [-8.500, 147.167], + "Pacific/Rarotonga": [-20.767, -158.233], + "Pacific/Saipan": [15.200, 145.750], + "Pacific/Tahiti": [-16.467, -148.433], + "Pacific/Tarawa": [1.417, 173.000], + "Pacific/Tongatapu": [-20.867, -174.800], + "Pacific/Wake": [19.283, 166.617], + "Pacific/Wallis": [-12.700, -175.833] } diff --git a/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/database.json b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/database.json deleted file mode 100644 index d4277ec89ef..00000000000 --- a/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/database.json +++ /dev/null @@ -1,420 +0,0 @@ -{ - "Africa/Abidjan": [5.317, -3.967], - "Africa/Accra": [5.550, 0.217], - "Africa/Addis_Ababa": [9.033, 38.700], - "Africa/Algiers": [36.783, 3.050], - "Africa/Asmara": [15.333, 38.883], - "Africa/Bamako": [12.650, -8.000], - "Africa/Bangui": [4.367, 18.583], - "Africa/Banjul": [13.467, -15.350], - "Africa/Bissau": [11.850, -14.417], - "Africa/Blantyre": [-14.217, 35.000], - "Africa/Brazzaville": [-3.733, 15.283], - "Africa/Bujumbura": [-2.617, 29.367], - "Africa/Cairo": [30.050, 31.250], - "Africa/Casablanca": [33.650, -6.417], - "Africa/Ceuta": [35.883, -4.683], - "Africa/Conakry": [9.517, -12.283], - "Africa/Dakar": [14.667, -16.567], - "Africa/Dar_es_Salaam": [-5.200, 39.283], - "Africa/Djibouti": [11.600, 43.150], - "Africa/Douala": [4.050, 9.700], - "Africa/El_Aaiun": [27.150, -12.800], - "Africa/Freetown": [8.500, -12.750], - "Africa/Gaborone": [-23.350, 25.917], - "Africa/Harare": [-16.167, 31.050], - "Africa/Johannesburg": [-25.750, 28.000], - "Africa/Juba": [4.850, 31.617], - "Africa/Kampala": [0.317, 32.417], - "Africa/Khartoum": [15.600, 32.533], - "Africa/Kigali": [-0.050, 30.067], - "Africa/Kinshasa": [-3.700, 15.300], - "Africa/Lagos": [6.450, 3.400], - "Africa/Libreville": [0.383, 9.450], - "Africa/Lome": [6.133, 1.217], - "Africa/Luanda": [-7.200, 13.233], - "Africa/Lubumbashi": [-10.333, 27.467], - "Africa/Lusaka": [-14.583, 28.283], - "Africa/Malabo": [3.750, 8.783], - "Africa/Maputo": [-24.033, 32.583], - "Africa/Maseru": [-28.533, 27.500], - "Africa/Mbabane": [-25.700, 31.100], - "Africa/Mogadishu": [2.067, 45.367], - "Africa/Monrovia": [6.300, -9.217], - "Africa/Nairobi": [-0.717, 36.817], - "Africa/Ndjamena": [12.117, 15.050], - "Africa/Niamey": [13.517, 2.117], - "Africa/Nouakchott": [18.100, -14.050], - "Africa/Ouagadougou": [12.367, -0.483], - "Africa/Porto-Novo": [6.483, 2.617], - "Africa/Sao_Tome": [0.333, 6.733], - "Africa/Tripoli": [32.900, 13.183], - "Africa/Tunis": [36.800, 10.183], - "Africa/Windhoek": [-21.433, 17.100], - "America/Adak": [51.880, -175.342], - "America/Anchorage": [61.218, -148.100], - "America/Anguilla": [18.200, -62.933], - "America/Antigua": [17.050, -60.200], - "America/Araguaina": [-6.800, -47.800], - "America/Argentina/Buenos_Aires": [-33.400, -57.550], - "America/Argentina/Catamarca": [-27.533, -64.217], - "America/Argentina/Cordoba": [-30.600, -63.817], - "America/Argentina/Jujuy": [-23.817, -64.700], - "America/Argentina/La_Rioja": [-28.567, -65.150], - "America/Argentina/Mendoza": [-31.117, -67.183], - "America/Argentina/Rio_Gallegos": [-50.367, -68.783], - "America/Argentina/Salta": [-23.217, -64.583], - "America/Argentina/San_Juan": [-30.467, -67.483], - "America/Argentina/San_Luis": [-32.683, -65.650], - "America/Argentina/Tucuman": [-25.183, -64.783], - "America/Argentina/Ushuaia": [-53.200, -67.700], - "America/Aruba": [12.500, -68.033], - "America/Asuncion": [-24.733, -56.333], - "America/Atikokan": [48.759, -90.378], - "America/Bahia": [-11.017, -37.483], - "America/Bahia_Banderas": [20.800, -104.750], - "America/Barbados": [13.100, -58.383], - "America/Belem": [-0.550, -47.517], - "America/Belize": [17.500, -87.800], - "America/Blanc-Sablon": [51.417, -56.883], - "America/Boa_Vista": [2.817, -59.333], - "America/Bogota": [4.600, -73.917], - "America/Boise": [43.614, -115.797], - "America/Cambridge_Bay": [69.114, -104.947], - "America/Campo_Grande": [-19.550, -53.383], - "America/Cancun": [21.083, -85.233], - "America/Caracas": [10.500, -65.067], - "America/Cayenne": [4.933, -51.667], - "America/Cayman": [19.300, -80.617], - "America/Chicago": [41.850, -86.350], - "America/Chihuahua": [28.633, -105.917], - "America/Ciudad_Juarez": [31.733, -105.517], - "America/Costa_Rica": [9.933, -83.917], - "America/Coyhaique": [-44.433, -71.933], - "America/Creston": [49.100, -115.483], - "America/Cuiaba": [-14.417, -55.917], - "America/Curacao": [12.183, -69.000], - "America/Danmarkshavn": [76.767, -17.333], - "America/Dawson": [64.067, -138.583], - "America/Dawson_Creek": [55.767, -119.767], - "America/Denver": [39.739, -103.016], - "America/Detroit": [42.331, -82.954], - "America/Dominica": [15.300, -60.600], - "America/Edmonton": [53.550, -112.533], - "America/Eirunepe": [-5.333, -68.133], - "America/El_Salvador": [13.700, -88.800], - "America/Fort_Nelson": [58.800, -121.300], - "America/Fortaleza": [-2.283, -37.500], - "America/Glace_Bay": [46.200, -58.050], - "America/Goose_Bay": [53.333, -59.583], - "America/Grand_Turk": [21.467, -70.867], - "America/Grenada": [12.050, -60.250], - "America/Guadeloupe": [16.233, -60.467], - "America/Guatemala": [14.633, -89.483], - "America/Guayaquil": [-1.833, -78.167], - "America/Guyana": [6.800, -57.833], - "America/Halifax": [44.650, -62.400], - "America/Havana": [23.133, -81.633], - "America/Hermosillo": [29.067, -109.033], - "America/Indiana/Indianapolis": [39.768, -85.842], - "America/Indiana/Knox": [41.296, -85.375], - "America/Indiana/Marengo": [38.376, -85.655], - "America/Indiana/Petersburg": [38.492, -86.721], - "America/Indiana/Tell_City": [37.953, -85.239], - "America/Indiana/Vevay": [38.748, -84.933], - "America/Indiana/Vincennes": [38.677, -86.471], - "America/Indiana/Winamac": [41.051, -85.397], - "America/Inuvik": [68.350, -132.283], - "America/Iqaluit": [63.733, -67.533], - "America/Jamaica": [17.968, -75.207], - "America/Juneau": [58.302, -133.580], - "America/Kentucky/Louisville": [38.254, -84.241], - "America/Kentucky/Monticello": [36.830, -83.151], - "America/Kralendijk": [12.151, -67.723], - "America/La_Paz": [-15.500, -67.850], - "America/Lima": [-11.950, -76.950], - "America/Los_Angeles": [34.052, -117.757], - "America/Lower_Princes": [18.051, -62.953], - "America/Maceio": [-8.333, -34.283], - "America/Managua": [12.150, -85.717], - "America/Manaus": [-2.867, -59.983], - "America/Marigot": [18.067, -62.917], - "America/Martinique": [14.600, -60.917], - "America/Matamoros": [25.833, -96.500], - "America/Mazatlan": [23.217, -105.583], - "America/Menominee": [45.108, -86.386], - "America/Merida": [20.967, -88.383], - "America/Metlakatla": [55.127, -130.424], - "America/Mexico_City": [19.400, -98.850], - "America/Miquelon": [47.050, -55.667], - "America/Moncton": [46.100, -63.217], - "America/Monterrey": [25.667, -99.683], - "America/Montevideo": [-33.091, -55.787], - "America/Montserrat": [16.717, -61.783], - "America/Nassau": [25.083, -76.650], - "America/New_York": [40.714, -73.994], - "America/Nome": [64.501, -164.594], - "America/Noronha": [-2.150, -31.583], - "America/North_Dakota/Beulah": [47.264, -100.222], - "America/North_Dakota/Center": [47.116, -100.701], - "America/North_Dakota/New_Salem": [46.845, -100.589], - "America/Nuuk": [64.183, -50.267], - "America/Ojinaga": [29.567, -103.583], - "America/Panama": [8.967, -78.467], - "America/Paramaribo": [5.833, -54.833], - "America/Phoenix": [33.448, -111.927], - "America/Port-au-Prince": [18.533, -71.667], - "America/Port_of_Spain": [10.650, -60.483], - "America/Porto_Velho": [-7.233, -62.100], - "America/Puerto_Rico": [18.468, -65.894], - "America/Punta_Arenas": [-52.850, -69.083], - "America/Rankin_Inlet": [62.817, -91.917], - "America/Recife": [-7.950, -33.100], - "America/Regina": [50.400, -103.350], - "America/Resolute": [74.696, -93.171], - "America/Rio_Branco": [-8.033, -66.200], - "America/Santarem": [-1.567, -53.133], - "America/Santiago": [-32.550, -69.333], - "America/Santo_Domingo": [18.467, -68.100], - "America/Sao_Paulo": [-22.467, -45.383], - "America/Scoresbysund": [70.483, -20.033], - "America/Sitka": [57.176, -134.698], - "America/St_Barthelemy": [17.883, -61.150], - "America/St_Johns": [47.567, -51.283], - "America/St_Kitts": [17.300, -61.283], - "America/St_Lucia": [14.017, -61.000], - "America/St_Thomas": [18.350, -63.067], - "America/St_Vincent": [13.150, -60.767], - "America/Swift_Current": [50.283, -106.167], - "America/Tegucigalpa": [14.100, -86.783], - "America/Thule": [76.567, -67.217], - "America/Tijuana": [32.533, -116.983], - "America/Toronto": [43.650, -78.617], - "America/Tortola": [18.450, -63.383], - "America/Vancouver": [49.267, -122.883], - "America/Whitehorse": [60.717, -134.950], - "America/Winnipeg": [49.883, -96.850], - "America/Yakutat": [59.547, -138.273], - "Antarctica/Casey": [-65.717, 110.517], - "Antarctica/Davis": [-67.417, 77.967], - "Antarctica/DumontDUrville": [-65.333, 140.017], - "Antarctica/Macquarie": [-53.500, 158.950], - "Antarctica/Mawson": [-66.400, 62.883], - "Antarctica/McMurdo": [-76.167, 166.600], - "Antarctica/Palmer": [-63.200, -63.900], - "Antarctica/Rothera": [-66.433, -67.867], - "Antarctica/Syowa": [-68.994, 39.590], - "Antarctica/Troll": [-71.989, 2.535], - "Antarctica/Vostok": [-77.600, 106.900], - "Arctic/Longyearbyen": [78.000, 16.000], - "Asia/Aden": [12.750, 45.200], - "Asia/Almaty": [43.250, 76.950], - "Asia/Amman": [31.950, 35.933], - "Asia/Anadyr": [64.750, 177.483], - "Asia/Aqtau": [44.517, 50.267], - "Asia/Aqtobe": [50.283, 57.167], - "Asia/Ashgabat": [37.950, 58.383], - "Asia/Atyrau": [47.117, 51.933], - "Asia/Baghdad": [33.350, 44.417], - "Asia/Bahrain": [26.383, 50.583], - "Asia/Baku": [40.383, 49.850], - "Asia/Bangkok": [13.750, 100.517], - "Asia/Barnaul": [53.367, 83.750], - "Asia/Beirut": [33.883, 35.500], - "Asia/Bishkek": [42.900, 74.600], - "Asia/Brunei": [4.933, 114.917], - "Asia/Chita": [52.050, 113.467], - "Asia/Colombo": [6.933, 79.850], - "Asia/Damascus": [33.500, 36.300], - "Asia/Dhaka": [23.717, 90.417], - "Asia/Dili": [-7.450, 125.583], - "Asia/Dubai": [25.300, 55.300], - "Asia/Dushanbe": [38.583, 68.800], - "Asia/Famagusta": [35.117, 33.950], - "Asia/Gaza": [31.500, 34.467], - "Asia/Hebron": [31.533, 35.095], - "Asia/Ho_Chi_Minh": [10.750, 106.667], - "Asia/Hong_Kong": [22.283, 114.150], - "Asia/Hovd": [48.017, 91.650], - "Asia/Irkutsk": [52.267, 104.333], - "Asia/Jakarta": [-5.833, 106.800], - "Asia/Jayapura": [-1.467, 140.700], - "Asia/Jerusalem": [31.781, 35.224], - "Asia/Kabul": [34.517, 69.200], - "Asia/Kamchatka": [53.017, 158.650], - "Asia/Karachi": [24.867, 67.050], - "Asia/Kathmandu": [27.717, 85.317], - "Asia/Khandyga": [62.656, 135.554], - "Asia/Kolkata": [22.533, 88.367], - "Asia/Krasnoyarsk": [56.017, 92.833], - "Asia/Kuala_Lumpur": [3.167, 101.700], - "Asia/Kuching": [1.550, 110.333], - "Asia/Kuwait": [29.333, 47.983], - "Asia/Macau": [22.197, 113.542], - "Asia/Magadan": [59.567, 150.800], - "Asia/Makassar": [-4.883, 119.400], - "Asia/Manila": [14.587, 120.968], - "Asia/Muscat": [23.600, 58.583], - "Asia/Nicosia": [35.167, 33.367], - "Asia/Novokuznetsk": [53.750, 87.117], - "Asia/Novosibirsk": [55.033, 82.917], - "Asia/Omsk": [55.000, 73.400], - "Asia/Oral": [51.217, 51.350], - "Asia/Phnom_Penh": [11.550, 104.917], - "Asia/Pontianak": [0.033, 109.333], - "Asia/Pyongyang": [39.017, 125.750], - "Asia/Qatar": [25.283, 51.533], - "Asia/Qostanay": [53.200, 63.617], - "Asia/Qyzylorda": [44.800, 65.467], - "Asia/Riyadh": [24.633, 46.717], - "Asia/Sakhalin": [46.967, 142.700], - "Asia/Samarkand": [39.667, 66.800], - "Asia/Seoul": [37.550, 126.967], - "Asia/Shanghai": [31.233, 121.467], - "Asia/Singapore": [1.283, 103.850], - "Asia/Srednekolymsk": [67.467, 153.717], - "Asia/Taipei": [25.050, 121.500], - "Asia/Tashkent": [41.333, 69.300], - "Asia/Tbilisi": [41.717, 44.817], - "Asia/Tehran": [35.667, 51.433], - "Asia/Thimphu": [27.467, 89.650], - "Asia/Tokyo": [35.654, 139.745], - "Asia/Tomsk": [56.500, 84.967], - "Asia/Ulaanbaatar": [47.917, 106.883], - "Asia/Urumqi": [43.800, 87.583], - "Asia/Ust-Nera": [64.560, 143.227], - "Asia/Vientiane": [17.967, 102.600], - "Asia/Vladivostok": [43.167, 131.933], - "Asia/Yakutsk": [62.000, 129.667], - "Asia/Yangon": [16.783, 96.167], - "Asia/Yekaterinburg": [56.850, 60.600], - "Asia/Yerevan": [40.183, 44.500], - "Atlantic/Azores": [37.733, -24.333], - "Atlantic/Bermuda": [32.283, -63.233], - "Atlantic/Canary": [28.100, -14.600], - "Atlantic/Cape_Verde": [14.917, -22.483], - "Atlantic/Faroe": [62.017, -5.233], - "Atlantic/Madeira": [32.633, -15.100], - "Atlantic/Reykjavik": [64.150, -20.150], - "Atlantic/South_Georgia": [-53.733, -35.467], - "Atlantic/St_Helena": [-14.083, -4.300], - "Atlantic/Stanley": [-50.300, -56.150], - "Australia/Adelaide": [-33.083, 138.583], - "Australia/Brisbane": [-26.533, 153.033], - "Australia/Broken_Hill": [-30.050, 141.450], - "Australia/Darwin": [-11.533, 130.833], - "Australia/Eucla": [-30.283, 128.867], - "Australia/Hobart": [-41.117, 147.317], - "Australia/Lindeman": [-19.733, 149.000], - "Australia/Lord_Howe": [-30.450, 159.083], - "Australia/Melbourne": [-36.183, 144.967], - "Australia/Perth": [-30.050, 115.850], - "Australia/Sydney": [-32.133, 151.217], - "Europe/Amsterdam": [52.367, 4.900], - "Europe/Andorra": [42.500, 1.517], - "Europe/Astrakhan": [46.350, 48.050], - "Europe/Athens": [37.967, 23.717], - "Europe/Belgrade": [44.833, 20.500], - "Europe/Berlin": [52.500, 13.367], - "Europe/Bratislava": [48.150, 17.117], - "Europe/Brussels": [50.833, 4.333], - "Europe/Bucharest": [44.433, 26.100], - "Europe/Budapest": [47.500, 19.083], - "Europe/Busingen": [47.700, 8.683], - "Europe/Chisinau": [47.000, 28.833], - "Europe/Copenhagen": [55.667, 12.583], - "Europe/Dublin": [53.333, -5.750], - "Europe/Gibraltar": [36.133, -4.650], - "Europe/Guernsey": [49.455, -1.464], - "Europe/Helsinki": [60.167, 24.967], - "Europe/Isle_of_Man": [54.150, -3.533], - "Europe/Istanbul": [41.017, 28.967], - "Europe/Jersey": [49.184, -1.893], - "Europe/Kaliningrad": [54.717, 20.500], - "Europe/Kirov": [58.600, 49.650], - "Europe/Kyiv": [50.433, 30.517], - "Europe/Lisbon": [38.717, -8.867], - "Europe/Ljubljana": [46.050, 14.517], - "Europe/London": [51.508, 0.125], - "Europe/Luxembourg": [49.600, 6.150], - "Europe/Madrid": [40.400, -2.317], - "Europe/Malta": [35.900, 14.517], - "Europe/Mariehamn": [60.100, 19.950], - "Europe/Minsk": [53.900, 27.567], - "Europe/Monaco": [43.700, 7.383], - "Europe/Moscow": [55.756, 37.618], - "Europe/Oslo": [59.917, 10.750], - "Europe/Paris": [48.867, 2.333], - "Europe/Podgorica": [42.433, 19.267], - "Europe/Prague": [50.083, 14.433], - "Europe/Riga": [56.950, 24.100], - "Europe/Rome": [41.900, 12.483], - "Europe/Samara": [53.200, 50.150], - "Europe/San_Marino": [43.917, 12.467], - "Europe/Sarajevo": [43.867, 18.417], - "Europe/Saratov": [51.567, 46.033], - "Europe/Simferopol": [44.950, 34.100], - "Europe/Skopje": [41.983, 21.433], - "Europe/Sofia": [42.683, 23.317], - "Europe/Stockholm": [59.333, 18.050], - "Europe/Tallinn": [59.417, 24.750], - "Europe/Tirane": [41.333, 19.833], - "Europe/Ulyanovsk": [54.333, 48.400], - "Europe/Vaduz": [47.150, 9.517], - "Europe/Vatican": [41.902, 12.453], - "Europe/Vienna": [48.217, 16.333], - "Europe/Vilnius": [54.683, 25.317], - "Europe/Volgograd": [48.733, 44.417], - "Europe/Warsaw": [52.250, 21.000], - "Europe/Zagreb": [45.800, 15.967], - "Europe/Zurich": [47.383, 8.533], - "Indian/Antananarivo": [-17.083, 47.517], - "Indian/Chagos": [-6.667, 72.417], - "Indian/Christmas": [-9.583, 105.717], - "Indian/Cocos": [-11.833, 96.917], - "Indian/Comoro": [-10.317, 43.267], - "Indian/Kerguelen": [-48.647, 70.218], - "Indian/Mahe": [-3.333, 55.467], - "Indian/Maldives": [4.167, 73.500], - "Indian/Mauritius": [-19.833, 57.500], - "Indian/Mayotte": [-11.217, 45.233], - "Indian/Reunion": [-19.133, 55.467], - "Pacific/Apia": [-12.167, -170.267], - "Pacific/Auckland": [-35.133, 174.767], - "Pacific/Bougainville": [-5.783, 155.567], - "Pacific/Chatham": [-42.050, -175.450], - "Pacific/Chuuk": [7.417, 151.783], - "Pacific/Easter": [-26.850, -108.567], - "Pacific/Efate": [-16.333, 168.417], - "Pacific/Fakaofo": [-8.633, -170.767], - "Pacific/Fiji": [-17.867, 178.417], - "Pacific/Funafuti": [-7.483, 179.217], - "Pacific/Galapagos": [0.900, -88.400], - "Pacific/Gambier": [-22.867, -133.050], - "Pacific/Guadalcanal": [-8.467, 160.200], - "Pacific/Guam": [13.467, 144.750], - "Pacific/Honolulu": [21.307, -156.142], - "Pacific/Kanton": [-1.217, -170.283], - "Pacific/Kiritimati": [1.867, -156.667], - "Pacific/Kosrae": [5.317, 162.983], - "Pacific/Kwajalein": [9.083, 167.333], - "Pacific/Majuro": [7.150, 171.200], - "Pacific/Marquesas": [-9.000, -138.500], - "Pacific/Midway": [28.217, -176.633], - "Pacific/Nauru": [0.517, 166.917], - "Pacific/Niue": [-18.983, -168.083], - "Pacific/Norfolk": [-28.950, 167.967], - "Pacific/Noumea": [-21.733, 166.450], - "Pacific/Pago_Pago": [-13.733, -169.300], - "Pacific/Palau": [7.333, 134.483], - "Pacific/Pitcairn": [-24.933, -129.917], - "Pacific/Pohnpei": [6.967, 158.217], - "Pacific/Port_Moresby": [-8.500, 147.167], - "Pacific/Rarotonga": [-20.767, -158.233], - "Pacific/Saipan": [15.200, 145.750], - "Pacific/Tahiti": [-16.467, -148.433], - "Pacific/Tarawa": [1.417, 173.000], - "Pacific/Tongatapu": [-20.867, -174.800], - "Pacific/Wake": [19.283, 166.617], - "Pacific/Wallis": [-12.700, -175.833] -} diff --git a/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/generate_database.ipynb b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/generate_database.ipynb index 116a76acb81..550f60d9d24 100644 --- a/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/generate_database.ipynb +++ b/auto-dark-light@gihaume/src/lib/core/Timezone_location_finder/generate_database.ipynb @@ -50,7 +50,17 @@ "output = output[:-2] # Removes last comma\n", "output += \"\\n}\\n\"\n", "\n", - "Path('./database.json').write_text(output)" + "Path('database.json').write_text(output)" + ] + }, + { + "cell_type": "markdown", + "id": "81895541", + "metadata": {}, + "source": [ + "The generated file must be copied to the runtime files so that the Timezone_location_finder can use it.\n", + "\n", + "Currently: `files/auto-dark-light@gihaume/5.8/Timezone_location_finder/database.json`" ] } ], From 70b3c900e5a1206a8cc523ffae8a626932e5622f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Sun, 2 Nov 2025 23:28:16 +0100 Subject: [PATCH 04/13] Remove minification --- auto-dark-light@gihaume/.env | 3 - auto-dark-light@gihaume/CONTRIBUTING.md | 11 +- .../auto-dark-light@gihaume/5.8/applet.js | 5437 ++++++++++++++++- .../5.8/applet.js.sha256sum | 1 - auto-dark-light@gihaume/package.json | 2 +- auto-dark-light@gihaume/src/main.ts | 2 +- auto-dark-light@gihaume/src/vite-env.d.ts | 15 - auto-dark-light@gihaume/vite.config.mts | 80 +- 8 files changed, 5465 insertions(+), 86 deletions(-) delete mode 100644 auto-dark-light@gihaume/.env delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js.sha256sum delete mode 100644 auto-dark-light@gihaume/src/vite-env.d.ts diff --git a/auto-dark-light@gihaume/.env b/auto-dark-light@gihaume/.env deleted file mode 100644 index 5c9a8af42cc..00000000000 --- a/auto-dark-light@gihaume/.env +++ /dev/null @@ -1,3 +0,0 @@ -# Every of theses keys to be used in `src` must be typed in `src/vite-env.d.ts` - -VITE_KEEP_MAIN_FUNCTION_SENTINEL=__auto_dark_light__ diff --git a/auto-dark-light@gihaume/CONTRIBUTING.md b/auto-dark-light@gihaume/CONTRIBUTING.md index d91428a8847..b83f2806e38 100644 --- a/auto-dark-light@gihaume/CONTRIBUTING.md +++ b/auto-dark-light@gihaume/CONTRIBUTING.md @@ -25,7 +25,7 @@ ## Development -- Create a symbolic link pointing to this repository and add it in your user applets folder: +- Create a symbolic link pointing to this folder and add it in your user applets folder: ```bash ln -s \ /files/auto-dark-light@gihaume \ @@ -55,22 +55,21 @@ Before any commit: -- The `applet.js` has to be built via a minification single run with: +- It is advisable to build `applet.js` in a single run with: ```bash pnpm build ``` - - Then it is advisable to E2E test the change again. - - Note that it produces an `applet.js.sha256sum` file using GNU's `sha256sum` command for reproducible integrity verification by a reviewer. + - then E2E test again. - The change has to be documented as an incremented version in `CHANGELOG.md` accordingly. - The version number has to be modified in `files/metadata.json` accordingly. -- If some call to gettext `_("…")` has been added or modified, the following command must be run from the root of the repository to update the `.pot` translation template file: +- If some call to gettext `_("…")` has been added or modified, the following command must be run from the root of the cinnamon spices repository to update the `.pot` translation template file: ```bash ./cinnamon-spices-makepot auto-dark-light@gihaume ``` ## Documentation -Check the [`doc/README.md`](./doc/README.md) file. +Check [`doc/README.md`](./doc/README.md). ## Linting for Python widgets (experimental) diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index 70a3a4ae4f3..a4a47d117aa 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -1,3 +1,5436 @@ -const e=imports.gettext,{GLib:t}=imports.gi,n=imports.ui.main,{St:i}=imports.gi,s={uuid:"",name:"",description:"",path:"",force_loaded:!1};function _(t){return e.dgettext(s.uuid,t)}let r="";const a=new i.Icon({icon_name:"dialog-warning",icon_type:i.IconType.SYMBOLIC,icon_size:24}),o=new i.Icon({icon_name:"dialog-error",icon_type:i.IconType.SYMBOLIC,icon_size:24}),u={info(e){global.log(r+`${_(":")} `+e),n.notify(r,e)},warn(e){global.logWarning(r+`${_(":")} `+e),n.warningNotify(r,e,a)},error(e){global.logError(r+`${_(":")} `+e),n.criticalNotify(r,e,o)}};function l(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;ie.length)&&(t=e.length);for(var n=0,i=Array(t);n=e.length?{done:!0}:{done:!1,value:e[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function z(){return z=Object.assign?Object.assign.bind():function(e){for(var t=1;ti&&(i=o.dependenciesState_)}n.length=s,e.newObserving_=null,r=t.length;for(;r--;){var u=t[r];0===u.diffValue&&wt(u,e),u.diffValue=0}for(;s--;){var l=n[s];1===l.diffValue&&(l.diffValue=0,kt(l,e))}i!==nt.UP_TO_DATE_&&(e.dependenciesState_=i,e.onBecomeStale_())}(e),pt(i),s}function ct(e){var t=e.observing_;e.observing_=[];for(var n=t.length;n--;)wt(t[n],e);e.dependenciesState_=nt.NOT_TRACKING_}function ht(e){var t=dt();try{return e()}finally{ft(t)}}function dt(){var e=yt.trackingDerivation;return yt.trackingDerivation=null,e}function ft(e){yt.trackingDerivation=e}function gt(e){var t=yt.allowStateReads;return yt.allowStateReads=e,t}function pt(e){yt.allowStateReads=e}function vt(e){if(e.dependenciesState_!==nt.UP_TO_DATE_){e.dependenciesState_=nt.UP_TO_DATE_;for(var t=e.observing_,n=t.length;n--;)t[n].lowestObserverState_=nt.UP_TO_DATE_}}var bt=function(){this.version=6,this.UNCHANGED={},this.trackingDerivation=null,this.trackingContext=null,this.runId=0,this.mobxGuid=0,this.inBatch=0,this.pendingUnobservations=[],this.pendingReactions=[],this.isRunningReactions=!1,this.allowStateChanges=!1,this.allowStateReads=!0,this.enforceActions=!0,this.spyListeners=[],this.globalReactionErrorHandlers=[],this.computedRequiresReaction=!1,this.reactionRequiresObservable=!1,this.observableRequiresReaction=!1,this.disableErrorBoundaries=!1,this.suppressReactionErrors=!1,this.useProxies=!0,this.verifyProxies=!1,this.safeDescriptors=!0},mt=!0,yt=function(){var e=h();return e.__mobxInstanceCount>0&&!e.__mobxGlobals&&(mt=!1),e.__mobxGlobals&&e.__mobxGlobals.version!==(new bt).version&&(mt=!1),mt?e.__mobxGlobals?(e.__mobxInstanceCount+=1,e.__mobxGlobals.UNCHANGED||(e.__mobxGlobals.UNCHANGED={}),e.__mobxGlobals):(e.__mobxInstanceCount=1,e.__mobxGlobals=new bt):(setTimeout(function(){l(35)},1),new bt)}();function kt(e,t){e.observers_.add(t),e.lowestObserverState_>t.dependenciesState_&&(e.lowestObserverState_=t.dependenciesState_)}function wt(e,t){e.observers_.delete(t),0===e.observers_.size&&Ot(e)}function Ot(e){!1===e.isPendingUnobservation&&(e.isPendingUnobservation=!0,yt.pendingUnobservations.push(e))}function St(){yt.inBatch++}function At(){if(0===--yt.inBatch){Vt();for(var e=yt.pendingUnobservations,t=0;t0&&Ot(e),!1)}function Et(e){e.lowestObserverState_!==nt.STALE_&&(e.lowestObserverState_=nt.STALE_,e.observers_.forEach(function(e){e.dependenciesState_===nt.UP_TO_DATE_&&e.onBecomeStale_(),e.dependenciesState_=nt.STALE_}))}var jt=function(){function e(e,t,n,i){void 0===e&&(e="Reaction"),this.name_=void 0,this.onInvalidate_=void 0,this.errorHandler_=void 0,this.requiresObservable_=void 0,this.observing_=[],this.newObserving_=[],this.dependenciesState_=nt.NOT_TRACKING_,this.runId_=0,this.unboundDepsCount_=0,this.flags_=0,this.isTracing_=st.NONE,this.name_=e,this.onInvalidate_=t,this.errorHandler_=n,this.requiresObservable_=i}var t=e.prototype;return t.onBecomeStale_=function(){this.schedule_()},t.schedule_=function(){this.isScheduled||(this.isScheduled=!0,yt.pendingReactions.push(this),Vt())},t.runReaction_=function(){if(!this.isDisposed){St(),this.isScheduled=!1;var e=yt.trackingContext;if(yt.trackingContext=this,_t(this)){this.isTrackPending=!0;try{this.onInvalidate_()}catch(t){this.reportExceptionInDerivation_(t)}}yt.trackingContext=e,At()}},t.track=function(e){if(!this.isDisposed){St(),this.isRunning=!0;var t=yt.trackingContext;yt.trackingContext=this;var n=lt(this,e,void 0);yt.trackingContext=t,this.isRunning=!1,this.isTrackPending=!1,this.isDisposed&&ct(this),ut(n)&&this.reportExceptionInDerivation_(n.cause),At()}},t.reportExceptionInDerivation_=function(e){var t=this;if(this.errorHandler_)this.errorHandler_(e,this);else{if(yt.disableErrorBoundaries)throw e;var n="[mobx] uncaught error in '"+this+"'";yt.suppressReactionErrors||console.error(n,e),yt.globalReactionErrorHandlers.forEach(function(n){return n(e,t)})}},t.dispose=function(){this.isDisposed||(this.isDisposed=!0,this.isRunning||(St(),ct(this),At()))},t.getDisposer_=function(e){var t=this,n=function n(){t.dispose(),null==e||null==e.removeEventListener||e.removeEventListener("abort",n)};return null==e||null==e.addEventListener||e.addEventListener("abort",n),n[Z]=this,"dispose"in Symbol&&"symbol"==typeof Symbol.dispose&&(n[Symbol.dispose]=n),n},t.toString=function(){return"Reaction["+this.name_+"]"},t.trace=function(e){},$(e,[{key:"isDisposed",get:function(){return B(this.flags_,e.isDisposedMask_)},set:function(t){this.flags_=U(this.flags_,e.isDisposedMask_,t)}},{key:"isScheduled",get:function(){return B(this.flags_,e.isScheduledMask_)},set:function(t){this.flags_=U(this.flags_,e.isScheduledMask_,t)}},{key:"isTrackPending",get:function(){return B(this.flags_,e.isTrackPendingMask_)},set:function(t){this.flags_=U(this.flags_,e.isTrackPendingMask_,t)}},{key:"isRunning",get:function(){return B(this.flags_,e.isRunningMask_)},set:function(t){this.flags_=U(this.flags_,e.isRunningMask_,t)}},{key:"diffValue",get:function(){return B(this.flags_,e.diffValueMask_)?1:0},set:function(t){this.flags_=U(this.flags_,e.diffValueMask_,1===t)}}])}();jt.isDisposedMask_=1,jt.isScheduledMask_=2,jt.isTrackPendingMask_=4,jt.isRunningMask_=8,jt.diffValueMask_=16;var Pt=100,Tt=function(e){return e()};function Vt(){yt.inBatch>0||yt.isRunningReactions||Tt(Dt)}function Dt(){yt.isRunningReactions=!0;for(var e=yt.pendingReactions,t=0;e.length>0;){++t===Pt&&(console.error("[mobx] cycle in reaction: "+e[0]),e.splice(0));for(var n=e.splice(0),i=0,s=n.length;i",s=function(){var e,t=arguments,s=++tn,r=$t(i+" - runid: "+s+" - init",n).apply(this,t),a=void 0,o=new Promise(function(t,n){var o=0;function u(e){var t;a=void 0;try{t=$t(i+" - runid: "+s+" - yield "+o++,r.next).call(r,e)}catch(u){return n(u)}c(t)}function l(e){var t;a=void 0;try{t=$t(i+" - runid: "+s+" - yield "+o++,r.throw).call(r,e)}catch(u){return n(u)}c(t)}function c(e){if(!S(null==e?void 0:e.then))return e.done?t(e.value):(a=Promise.resolve(e.value)).then(u,l);e.then(c,n)}e=n,u(void 0)});return o.cancel=$t(i+" - runid: "+s+" - cancel",function(){try{a&&on(a);var t=r.return(void 0),n=Promise.resolve(t.value);n.then(O,O),on(n),e(new nn)}catch(i){e(i)}}),o};return s.isMobXFlow=!0,s},sn);function on(e){S(e.cancel)&&e.cancel()}function un(e){return!0===(null==e?void 0:e.isMobXFlow)}function _n(e){return function(e){return!!e&&(Xn(e)||!!e[Z]||ee(e)||It(e)||at(e))}(e)}function ln(e,t){void 0===t&&(t=void 0),St();try{return e.apply(t)}finally{At()}}function cn(e){return e[Z]}an.bound=X(rn);var hn={has:function(e,t){return cn(e).has_(t)},get:function(e,t){return cn(e).get_(t)},set:function(e,t,n){var i;return!!A(t)&&(null==(i=cn(e).set_(t,n,!0))||i)},deleteProperty:function(e,t){var n;return!!A(t)&&(null==(n=cn(e).delete_(t,!0))||n)},defineProperty:function(e,t,n){var i;return null==(i=cn(e).defineProperty_(t,n))||i},ownKeys:function(e){return cn(e).ownKeys_()},preventExtensions:function(e){l(13)}};function dn(e){return void 0!==e.interceptors_&&e.interceptors_.length>0}function fn(e,t){var n=e.interceptors_||(e.interceptors_=[]);return n.push(t),w(function(){var e=n.indexOf(t);-1!==e&&n.splice(e,1)})}function gn(e,t){var n=dt();try{for(var i=[].concat(e.interceptors_||[]),s=0,r=i.length;s0}function vn(e,t){var n=e.changeListeners_||(e.changeListeners_=[]);return n.push(t),w(function(){var e=n.indexOf(t);-1!==e&&n.splice(e,1)})}function bn(e,t){var n=dt(),i=e.changeListeners_;if(i){for(var s=0,r=(i=i.slice()).length;s0?e.map(this.dehancer):e},t.intercept_=function(e){return fn(this,e)},t.observe_=function(e,t){return void 0===t&&(t=!1),t&&e({observableKind:"array",object:this.proxy_,debugObjectName:this.atom_.name_,type:"splice",index:0,added:this.values_.slice(),addedCount:this.values_.length,removed:[],removedCount:0}),vn(this,e)},t.getArrayLength_=function(){return this.atom_.reportObserved(),this.values_.length},t.setArrayLength_=function(e){("number"!=typeof e||isNaN(e)||e<0)&&l("Out of range: "+e);var t=this.values_.length;if(e!==t)if(e>t){for(var n=new Array(e-t),i=0;i0&&ai(e+t+1)},t.spliceWithArray_=function(e,t,n){var i=this;this.atom_;var s=this.values_.length;if(void 0===e?e=0:e>s?e=s:e<0&&(e=Math.max(0,s+e)),t=1===arguments.length?s-e:null==t?0:Math.max(0,Math.min(t,s-e)),void 0===n&&(n=v),dn(this)){var r=gn(this,{object:this.proxy_,type:kn,index:e,removedCount:t,added:n});if(!r)return v;t=r.removedCount,n=r.added}if(n=0===n.length?n:n.map(function(e){return i.enhancer_(e,void 0)}),this.legacyMode_){var a=n.length-t;this.updateArrayLength_(s,a)}var o=this.spliceItemsIntoValues_(e,t,n);return 0===t&&0===n.length||this.notifyArraySplice_(e,n,o),this.dehanceValues_(o)},t.spliceItemsIntoValues_=function(e,t,n){var i;if(n.length<1e4)return(i=this.values_).splice.apply(i,[e,t].concat(n));var s=this.values_.slice(e,e+t),r=this.values_.slice(e+t);this.values_.length+=n.length-t;for(var a=0;a=this.values_.length))return this.atom_.reportObserved(),this.dehanceValue_(this.values_[e]);console.warn("[mobx] Out of bounds read: "+e)},t.set_=function(e,t){var n=this.values_;if(this.legacyMode_&&e>n.length&&l(17,e,n.length),e2?n-2:0),s=2;s-1&&(this.splice(n,1),!0)}};function En(e,t){"function"==typeof Array.prototype[e]&&(xn[e]=t(e))}function jn(e){return function(){var t=this[Z];t.atom_.reportObserved();var n=t.dehanceValues_(t.values_);return n[e].apply(n,arguments)}}function Pn(e){return function(t,n){var i=this,s=this[Z];return s.atom_.reportObserved(),s.dehanceValues_(s.values_)[e](function(e,s){return t.call(n,e,s,i)})}}function Tn(e){return function(){var t=this,n=this[Z];n.atom_.reportObserved();var i=n.dehanceValues_(n.values_),s=arguments[0];return arguments[0]=function(e,n,i){return s(e,n,i,t)},i[e].apply(i,arguments)}}En("at",jn),En("concat",jn),En("flat",jn),En("includes",jn),En("indexOf",jn),En("join",jn),En("lastIndexOf",jn),En("slice",jn),En("toString",jn),En("toLocaleString",jn),En("toSorted",jn),En("toSpliced",jn),En("with",jn),En("every",Pn),En("filter",Pn),En("find",Pn),En("findIndex",Pn),En("findLast",Pn),En("findLastIndex",Pn),En("flatMap",Pn),En("forEach",Pn),En("map",Pn),En("some",Pn),En("toReversed",Pn),En("reduce",Tn),En("reduceRight",Tn);var Vn=V("ObservableArrayAdministration",Sn);function Dn(e){return x(e)&&Vn(e[Z])}var In={},Mn="add",Cn="delete",Nn=function(){function e(e,t,n){var i=this;void 0===t&&(t=ie),void 0===n&&(n="ObservableMap"),this.enhancer_=void 0,this.name_=void 0,this[Z]=In,this.data_=void 0,this.hasMap_=void 0,this.keysAtom_=void 0,this.interceptors_=void 0,this.changeListeners_=void 0,this.dehancer=void 0,this.enhancer_=t,this.name_=n,S(Map)||l(18),li(function(){i.keysAtom_=te("ObservableMap.keys()"),i.data_=new Map,i.hasMap_=new Map,e&&i.merge(e)})}var t=e.prototype;return t.has_=function(e){return this.data_.has(e)},t.has=function(e){var t=this;if(!yt.trackingDerivation)return this.has_(e);var n=this.hasMap_.get(e);if(!n){var i=n=new et(this.has_(e),se,"ObservableMap.key?",!1);this.hasMap_.set(e,i),Zt(i,function(){return t.hasMap_.delete(e)})}return n.get()},t.set=function(e,t){var n=this.has_(e);if(dn(this)){var i=gn(this,{type:n?wn:Mn,object:this,newValue:t,name:e});if(!i)return this;t=i.newValue}return n?this.updateValue_(e,t):this.addValue_(e,t),this},t.delete=function(e){var t=this;if((this.keysAtom_,dn(this))&&!gn(this,{type:Cn,object:this,name:e}))return!1;if(this.has_(e)){var n=pn(this),i=n?{observableKind:"map",debugObjectName:this.name_,type:Cn,object:this,oldValue:this.data_.get(e).value_,name:e}:null;return ln(function(){var n;t.keysAtom_.reportChanged(),null==(n=t.hasMap_.get(e))||n.setNewValue_(!1),t.data_.get(e).setNewValue_(void 0),t.data_.delete(e)}),n&&bn(this,i),!0}return!1},t.updateValue_=function(e,t){var n=this.data_.get(e);if((t=n.prepareNewValue_(t))!==yt.UNCHANGED){var i=pn(this),s=i?{observableKind:"map",debugObjectName:this.name_,type:wn,object:this,oldValue:n.value_,name:e,newValue:t}:null;n.setNewValue_(t),i&&bn(this,s)}},t.addValue_=function(e,t){var n=this;this.keysAtom_,ln(function(){var i,s=new et(t,n.enhancer_,"ObservableMap.key",!1);n.data_.set(e,s),t=s.value_,null==(i=n.hasMap_.get(e))||i.setNewValue_(!0),n.keysAtom_.reportChanged()});var i=pn(this),s=i?{observableKind:"map",debugObjectName:this.name_,type:Mn,object:this,name:e,newValue:t}:null;i&&bn(this,s)},t.get=function(e){return this.has(e)?this.dehanceValue_(this.data_.get(e).get()):this.dehanceValue_(void 0)},t.dehanceValue_=function(e){return void 0!==this.dehancer?this.dehancer(e):e},t.keys=function(){return this.keysAtom_.reportObserved(),this.data_.keys()},t.values=function(){var e=this,t=this.keys();return Rn({next:function(){var n=t.next(),i=n.done,s=n.value;return{done:i,value:i?void 0:e.get(s)}}})},t.entries=function(){var e=this,t=this.keys();return Rn({next:function(){var n=t.next(),i=n.done,s=n.value;return{done:i,value:i?void 0:[s,e.get(s)]}}})},t[Symbol.iterator]=function(){return this.entries()},t.forEach=function(e,t){for(var n,i=K(this);!(n=i()).done;){var s=n.value,r=s[0],a=s[1];e.call(t,a,r,this)}},t.merge=function(e){var t=this;return Ln(e)&&(e=new Map(e)),ln(function(){var n,i,s;E(e)?function(e){var t=Object.keys(e);if(!M)return t;var n=Object.getOwnPropertySymbols(e);return n.length?[].concat(t,n.filter(function(t){return p.propertyIsEnumerable.call(e,t)})):t}(e).forEach(function(n){return t.set(n,e[n])}):Array.isArray(e)?e.forEach(function(e){var n=e[0],i=e[1];return t.set(n,i)}):D(e)?(n=e,i=Object.getPrototypeOf(n),s=Object.getPrototypeOf(i),null!==Object.getPrototypeOf(s)&&l(19,e),e.forEach(function(e,n){return t.set(n,e)})):null!=e&&l(20,e)}),this},t.clear=function(){var e=this;ln(function(){ht(function(){for(var t,n=K(e.keys());!(t=n()).done;){var i=t.value;e.delete(i)}})})},t.replace=function(e){var t=this;return ln(function(){for(var n,i=function(e){if(D(e)||Ln(e))return e;if(Array.isArray(e))return new Map(e);if(E(e)){var t=new Map;for(var n in e)t.set(n,e[n]);return t}return l(21,e)}(e),s=new Map,r=!1,a=K(t.data_.keys());!(n=a()).done;){var o=n.value;if(!i.has(o))if(t.delete(o))r=!0;else{var u=t.data_.get(o);s.set(o,u)}}for(var c,h=K(i.entries());!(c=h()).done;){var d=c.value,f=d[0],g=d[1],p=t.data_.has(f);if(t.set(f,g),t.data_.has(f)){var v=t.data_.get(f);s.set(f,v),p||(r=!0)}}if(!r)if(t.data_.size!==s.size)t.keysAtom_.reportChanged();else for(var b=t.data_.keys(),m=s.keys(),y=b.next(),k=m.next();!y.done;){if(y.value!==k.value){t.keysAtom_.reportChanged();break}y=b.next(),k=m.next()}t.data_=s}),this},t.toString=function(){return"[object ObservableMap]"},t.toJSON=function(){return Array.from(this)},t.observe_=function(e,t){return vn(this,e)},t.intercept_=function(e){return fn(this,e)},$(e,[{key:"size",get:function(){return this.keysAtom_.reportObserved(),this.data_.size}},{key:Symbol.toStringTag,get:function(){return"Map"}}])}(),Ln=V("ObservableMap",Nn);function Rn(e){return e[Symbol.toStringTag]="MapIterator",vi(e)}var Bn={},Un=function(){function e(e,t,n){var i=this;void 0===t&&(t=ie),void 0===n&&(n="ObservableSet"),this.name_=void 0,this[Z]=Bn,this.data_=new Set,this.atom_=void 0,this.changeListeners_=void 0,this.interceptors_=void 0,this.dehancer=void 0,this.enhancer_=void 0,this.name_=n,S(Set)||l(22),this.enhancer_=function(e,i){return t(e,i,n)},li(function(){i.atom_=te(i.name_),e&&i.replace(e)})}var t=e.prototype;return t.dehanceValue_=function(e){return void 0!==this.dehancer?this.dehancer(e):e},t.clear=function(){var e=this;ln(function(){ht(function(){for(var t,n=K(e.data_.values());!(t=n()).done;){var i=t.value;e.delete(i)}})})},t.forEach=function(e,t){for(var n,i=K(this);!(n=i()).done;){var s=n.value;e.call(t,s,s,this)}},t.add=function(e){var t=this;if(this.atom_,dn(this)){var n=gn(this,{type:Mn,object:this,newValue:e});if(!n)return this;e=n.newValue}if(!this.has(e)){ln(function(){t.data_.add(t.enhancer_(e,void 0)),t.atom_.reportChanged()});var i=pn(this),s=i?{observableKind:"set",debugObjectName:this.name_,type:Mn,object:this,newValue:e}:null;i&&bn(this,s)}return this},t.delete=function(e){var t=this;if(dn(this)&&!gn(this,{type:Cn,object:this,oldValue:e}))return!1;if(this.has(e)){var n=pn(this),i=n?{observableKind:"set",debugObjectName:this.name_,type:Cn,object:this,oldValue:e}:null;return ln(function(){t.atom_.reportChanged(),t.data_.delete(e)}),n&&bn(this,i),!0}return!1},t.has=function(e){return this.atom_.reportObserved(),this.data_.has(this.dehanceValue_(e))},t.entries=function(){var e=this.values();return $n({next:function(){var t=e.next(),n=t.value,i=t.done;return i?{value:void 0,done:i}:{value:[n,n],done:i}}})},t.keys=function(){return this.values()},t.values=function(){this.atom_.reportObserved();var e=this,t=this.data_.values();return $n({next:function(){var n=t.next(),i=n.value,s=n.done;return s?{value:void 0,done:s}:{value:e.dehanceValue_(i),done:s}}})},t.intersection=function(e){return I(e)&&!Gn(e)?e.intersection(this):new Set(this).intersection(e)},t.union=function(e){return I(e)&&!Gn(e)?e.union(this):new Set(this).union(e)},t.difference=function(e){return new Set(this).difference(e)},t.symmetricDifference=function(e){return I(e)&&!Gn(e)?e.symmetricDifference(this):new Set(this).symmetricDifference(e)},t.isSubsetOf=function(e){return new Set(this).isSubsetOf(e)},t.isSupersetOf=function(e){return new Set(this).isSupersetOf(e)},t.isDisjointFrom=function(e){return I(e)&&!Gn(e)?e.isDisjointFrom(this):new Set(this).isDisjointFrom(e)},t.replace=function(e){var t=this;return Gn(e)&&(e=new Set(e)),ln(function(){Array.isArray(e)||I(e)?(t.clear(),e.forEach(function(e){return t.add(e)})):null!=e&&l("Cannot initialize set from "+e)}),this},t.observe_=function(e,t){return vn(this,e)},t.intercept_=function(e){return fn(this,e)},t.toJSON=function(){return Array.from(this)},t.toString=function(){return"[object ObservableSet]"},t[Symbol.iterator]=function(){return this.values()},$(e,[{key:"size",get:function(){return this.atom_.reportObserved(),this.data_.size}},{key:Symbol.toStringTag,get:function(){return"Set"}}])}(),Gn=V("ObservableSet",Un);function $n(e){return e[Symbol.toStringTag]="SetIterator",vi(e)}var Kn=Object.create(null),zn="remove",Fn=function(){function e(e,t,n,i){void 0===t&&(t=new Map),void 0===i&&(i=Ae),this.target_=void 0,this.values_=void 0,this.name_=void 0,this.defaultAnnotation_=void 0,this.keysAtom_=void 0,this.changeListeners_=void 0,this.interceptors_=void 0,this.proxy_=void 0,this.isPlainObject_=void 0,this.appliedAnnotations_=void 0,this.pendingKeys_=void 0,this.target_=e,this.values_=t,this.name_=n,this.defaultAnnotation_=i,this.keysAtom_=new Q("ObservableObject.keys"),this.isPlainObject_=E(this.target_)}var t=e.prototype;return t.getObservablePropValue_=function(e){return this.values_.get(e).get()},t.setObservablePropValue_=function(e,t){var n=this.values_.get(e);if(n instanceof tt)return n.set(t),!0;if(dn(this)){var i=gn(this,{type:wn,object:this.proxy_||this.target_,name:e,newValue:t});if(!i)return null;t=i.newValue}if((t=n.prepareNewValue_(t))!==yt.UNCHANGED){var s=pn(this),r=s?{type:wn,observableKind:"object",debugObjectName:this.name_,object:this.proxy_||this.target_,oldValue:n.value_,name:e,newValue:t}:null;n.setNewValue_(t),s&&bn(this,r)}return!0},t.get_=function(e){return yt.trackingDerivation&&!L(this.target_,e)&&this.has_(e),this.target_[e]},t.set_=function(e,t,n){return void 0===n&&(n=!1),L(this.target_,e)?this.values_.has(e)?this.setObservablePropValue_(e,t):n?Reflect.set(this.target_,e,t):(this.target_[e]=t,!0):this.extend_(e,{value:t,enumerable:!0,writable:!0,configurable:!0},this.defaultAnnotation_,n)},t.has_=function(e){if(!yt.trackingDerivation)return e in this.target_;this.pendingKeys_||(this.pendingKeys_=new Map);var t=this.pendingKeys_.get(e);return t||(t=new et(e in this.target_,se,"ObservableObject.key?",!1),this.pendingKeys_.set(e,t)),t.get()},t.make_=function(e,t){if(!0===t&&(t=this.defaultAnnotation_),!1!==t){if(!(e in this.target_)){var n;if(null!=(n=this.target_[W])&&n[e])return;l(1,t.annotationType_,this.name_+"."+e.toString())}for(var i=this.target_;i&&i!==p;){var s=f(i,e);if(s){var r=t.make_(this,e,s,i);if(0===r)return;if(1===r)break}i=Object.getPrototypeOf(i)}Yn(this,t,e)}},t.extend_=function(e,t,n,i){if(void 0===i&&(i=!1),!0===n&&(n=this.defaultAnnotation_),!1===n)return this.defineProperty_(e,t,i);var s=n.extend_(this,e,t,i);return s&&Yn(this,n,e),s},t.defineProperty_=function(e,t,n){void 0===n&&(n=!1),this.keysAtom_;try{St();var i=this.delete_(e);if(!i)return i;if(dn(this)){var s=gn(this,{object:this.proxy_||this.target_,name:e,type:Mn,newValue:t.value});if(!s)return null;var r=s.newValue;t.value!==r&&(t=z({},t,{value:r}))}if(n){if(!Reflect.defineProperty(this.target_,e,t))return!1}else g(this.target_,e,t);this.notifyPropertyAddition_(e,t.value)}finally{At()}return!0},t.defineObservableProperty_=function(e,t,n,i){void 0===i&&(i=!1),this.keysAtom_;try{St();var s=this.delete_(e);if(!s)return s;if(dn(this)){var r=gn(this,{object:this.proxy_||this.target_,name:e,type:Mn,newValue:t});if(!r)return null;t=r.newValue}var a=Wn(e),o={configurable:!yt.safeDescriptors||this.isPlainObject_,enumerable:!0,get:a.get,set:a.set};if(i){if(!Reflect.defineProperty(this.target_,e,o))return!1}else g(this.target_,e,o);var u=new et(t,n,"ObservableObject.key",!1);this.values_.set(e,u),this.notifyPropertyAddition_(e,u.value_)}finally{At()}return!0},t.defineComputedProperty_=function(e,t,n){void 0===n&&(n=!1),this.keysAtom_;try{St();var i=this.delete_(e);if(!i)return i;if(dn(this))if(!gn(this,{object:this.proxy_||this.target_,name:e,type:Mn,newValue:void 0}))return null;t.name||(t.name="ObservableObject.key"),t.context=this.proxy_||this.target_;var s=Wn(e),r={configurable:!yt.safeDescriptors||this.isPlainObject_,enumerable:!1,get:s.get,set:s.set};if(n){if(!Reflect.defineProperty(this.target_,e,r))return!1}else g(this.target_,e,r);this.values_.set(e,new tt(t)),this.notifyPropertyAddition_(e,void 0)}finally{At()}return!0},t.delete_=function(e,t){if(void 0===t&&(t=!1),this.keysAtom_,!L(this.target_,e))return!0;if(dn(this)&&!gn(this,{object:this.proxy_||this.target_,name:e,type:zn}))return null;try{var n;St();var i,s=pn(this),r=this.values_.get(e),a=void 0;if(!r&&s)a=null==(i=f(this.target_,e))?void 0:i.value;if(t){if(!Reflect.deleteProperty(this.target_,e))return!1}else delete this.target_[e];if(r&&(this.values_.delete(e),r instanceof et&&(a=r.value_),Et(r)),this.keysAtom_.reportChanged(),null==(n=this.pendingKeys_)||null==(n=n.get(e))||n.set(e in this.target_),s){var o={type:zn,observableKind:"object",object:this.proxy_||this.target_,debugObjectName:this.name_,oldValue:a,name:e};0,s&&bn(this,o)}}finally{At()}return!0},t.observe_=function(e,t){return vn(this,e)},t.intercept_=function(e){return fn(this,e)},t.notifyPropertyAddition_=function(e,t){var n,i=pn(this);if(i){var s=i?{type:Mn,observableKind:"object",debugObjectName:this.name_,object:this.proxy_||this.target_,name:e,newValue:t}:null;i&&bn(this,s)}null==(n=this.pendingKeys_)||null==(n=n.get(e))||n.set(!0),this.keysAtom_.reportChanged()},t.ownKeys_=function(){return this.keysAtom_.reportObserved(),C(this.target_)},t.keys_=function(){return this.keysAtom_.reportObserved(),Object.keys(this.target_)},e}();function qn(e,t){var n;if(L(e,Z))return e;var i=null!=(n=null==t?void 0:t.name)?n:"ObservableObject",s=new Fn(e,new Map,String(i),function(e){var t;return e?null!=(t=e.defaultDecorator)?t:xe(e):void 0}(t));return P(e,Z,s),e}var Hn=V("ObservableObjectAdministration",Fn);function Wn(e){return Kn[e]||(Kn[e]={get:function(){return this[Z].getObservablePropValue_(e)},set:function(t){return this[Z].setObservablePropValue_(e,t)}})}function Xn(e){return!!x(e)&&Hn(e[Z])}function Yn(e,t,n){var i;null==(i=e.target_[W])||delete i[n]}var Jn,Zn,Qn=si(0),ei=function(){var e=!1,t={};return Object.defineProperty(t,"0",{set:function(){e=!0}}),Object.create(t)[0]=1,!1===e}(),ti=0,ni=function(){};Jn=ni,Zn=Array.prototype,Object.setPrototypeOf?Object.setPrototypeOf(Jn.prototype,Zn):void 0!==Jn.prototype.__proto__?Jn.prototype.__proto__=Zn:Jn.prototype=Zn;var ii=function(e){function t(t,n,i,s){var r;return void 0===i&&(i="ObservableArray"),void 0===s&&(s=!1),r=e.call(this)||this,li(function(){var e=new Sn(i,n,s,!0);e.proxy_=r,T(r,Z,e),t&&t.length&&r.spliceWithArray(0,0,t),ei&&Object.defineProperty(r,"0",Qn)}),r}F(t,e);var n=t.prototype;return n.concat=function(){this[Z].atom_.reportObserved();for(var e=arguments.length,t=new Array(e),n=0;nti){for(var t=ti;t=0&&n++}e=gi(e),t=gi(t);var o="[object Array]"===a;if(!o){if("object"!=typeof e||"object"!=typeof t)return!1;var u=e.constructor,l=t.constructor;if(u!==l&&!(S(u)&&u instanceof u&&S(l)&&l instanceof l)&&"constructor"in e&&"constructor"in t)return!1}if(0===n)return!1;n<0&&(n=-1),s=s||[];for(var c=(i=i||[]).length;c--;)if(i[c]===e)return s[c]===t;if(i.push(e),s.push(t),o){if((c=e.length)!==t.length)return!1;for(;c--;)if(!fi(e[c],t[c],n-1,i,s))return!1}else{var h=Object.keys(e),d=h.length;if(Object.keys(t).length!==d)return!1;for(var f=0;fString(e).padStart(2,"0"));return`${this._h}:${e}:${t}`}get_as_string_hhmm(){const[e,t]=[this._h,this._m].map(e=>String(e).padStart(2,"0"));return`${e}:${t}`}add_minutes(e){const t=new Date(0,0,1,this._h,this._m,this._s);return t.setMinutes(t.getMinutes()+e),mi.create_from_js_date(t)}get_seconds_until_next_target(e){const[t,n]=[e,this].map(e=>e._seconds_since_midnight);return ne._seconds_since_midnight);return ithis.detect_light_background(),e.on_button_detect_background_dark=()=>this.detect_dark_background(),e.on_button_apply_background_light=()=>this.apply_light_background(),e.on_button_apply_background_dark=()=>this.apply_dark_background()}detect_light_background(){const e=ji.is_slideshow;this._settings.light_background_is_slideshow=e,e?this._settings.light_background_slideshow_folder=ji.slideshow_folder.replace("directory://","file://"):this._settings.light_background_file=ji.picture_file}detect_dark_background(){const e=ji.is_slideshow;this._settings.dark_background_is_slideshow=e,e?this._settings.dark_background_slideshow_folder=ji.slideshow_folder.replace("directory://","file://"):this._settings.dark_background_file=ji.picture_file}apply_light_background(){const e=this._settings.light_background_is_slideshow;ji.is_slideshow=e,e?ji.slideshow_folder=decodeURIComponent(this._settings.light_background_slideshow_folder.replace("file://","directory://")):ji.picture_file=this._settings.light_background_file}apply_dark_background(){const e=this._settings.dark_background_is_slideshow;ji.is_slideshow=e,e?ji.slideshow_folder=decodeURIComponent(this._settings.dark_background_slideshow_folder.replace("file://","directory://")):ji.picture_file=this._settings.dark_background_file}}const{Gio:Ti,GLib:Vi}=imports.gi;async function Di(e,t,n){try{await async function(e,t=10){const n=`timeout --kill-after=${Ci} ${t}s sh -c ${Vi.shell_quote(e)}`,[i,s]=Vi.shell_parse_argv(n),r=new Ti.Subprocess({argv:s,flags:Ti.SubprocessFlags.STDERR_PIPE}),a=Date.now();r.init(null);const[o,u]=await new Promise((e,t)=>{r.communicate_utf8_async(null,null,(n,i)=>{try{const[t,s,r]=n.communicate_utf8_finish(i);e([s,r])}catch(s){t(s)}})}),l=(Date.now()-a)/1e3,c=r.get_exit_status();switch(c){case 0:break;case Ii:throw new Ti.IOErrorEnum({code:Ti.IOErrorEnum.TIMED_OUT,message:`may have been timed out by SIGTERM (GNU 'timeout' exit status ${Ii})`});case Mi:throw new Ti.IOErrorEnum({code:Ti.IOErrorEnum.TIMED_OUT,message:`probably killed by an external SIGKILL (GNU 'timeout' exit status ${Mi})`});case 1:if(t>0&&l>=t+Ci)throw new Ti.IOErrorEnum({code:Ti.IOErrorEnum.TIMED_OUT,message:"probably timed out by SIGKILL"});default:throw new Ti.IOErrorEnum({code:Ti.IOErrorEnum.FAILED,message:u?u.trim():"exit status: "+c})}}(n,t)}catch(i){const t=""!==e?e:n;let s=`${_("the command")} '${t}' ${_("has failed")}`;i instanceof Vi.ShellError?s+=` ${_("due to a wrong format")}.\n\n${_("Detail")}${_(":")}\n`+i.message:i instanceof Ti.IOErrorEnum?i.code===Ti.IOErrorEnum.TIMED_OUT?s+=` ${_("due to timeout")}.\n\n${_("Detail")}${_(":")}\n`+i.message:i.code===Ti.IOErrorEnum.FAILED&&(s+=` ${_("due to an error")}.\n\n${_("Detail")}${_(":")}\n`+i.message):s+=`${_(":")} ${i}`,u.warn(s)}}const Ii=124,Mi=137,Ci=10;class Ni{_settings;constructor(e,t){this._settings=t,e.on_button_launch_commands_light=()=>this.launch_light_commands(),e.on_button_launch_commands_dark=()=>this.launch_dark_commands()}launch_dark_commands(){this._launch_commands(this._settings.dark_commands_list)}launch_light_commands(){this._launch_commands(this._settings.light_commands_list)}_launch_commands(e){for(const t of e)t.active&&Di(t.name,t.expiry,t.command)}}class Li{_expiration_time=0;set expiration_time(e){const t=wi().get_seconds_until_next_target(e);this._expiration_time=ki()+t}get_if_has_expired(){return ki()>this._expiration_time}reset(){this._expiration_time=0}}const{GLib:Ri}=imports.gi;class Bi{_event_id=void 0;_timer_absolute=new Li;get_if_should_be_expired(){return this._timer_absolute.get_if_has_expired()}set_the_event(e,t){this.unset_the_event();const n=wi().get_seconds_until_next_target(e);this._event_id=Ri.timeout_add_seconds(Ri.PRIORITY_DEFAULT,n,()=>(t(),Ri.SOURCE_REMOVE)),this._timer_absolute.expiration_time=e}get is_set(){return void 0!==this._event_id}unset_the_event(){this._event_id&&(Ri.source_remove(this._event_id),this._event_id=void 0,this._timer_absolute.reset())}dispose(){this.unset_the_event()}}const Ui=imports.ui.main;let Gi=0;class $i{_name;_callback;constructor(e){this._name=s.uuid+Gi++,this._callback=e}set keybinding(e){Ui.keybindingManager.addHotKey(this._name,e,this._callback)}dispose(){Ui.keybindingManager.removeHotKey(this._name)}}const{Gio:Ki}=imports.gi;class zi{_callback_on_change;constructor(e){this._callback_on_change=e}enable(){this._subscribe_to_changes(this._callback_on_change.bind(this))}disable(){this._unsubscribe_to_changes()}dispose(){this.disable()}_signal_id=void 0;_subscribe_to_changes(e){this._signal_id&&this._unsubscribe_to_changes(),this._signal_id=Ki.DBus.system.signal_subscribe("org.freedesktop.timedate1","org.freedesktop.DBus.Properties","PropertiesChanged","/org/freedesktop/timedate1",null,Ki.DBusSignalFlags.NONE,(t,n,i,s,r,a)=>{const o=a.deep_unpack()[1];if(o.Timezone){const t=o.Timezone.deep_unpack();e(t)}})}_unsubscribe_to_changes(){this._signal_id&&(Ki.DBus.system.signal_unsubscribe(this._signal_id),this._signal_id=void 0)}}const{Gio:Fi}=imports.gi;class qi{_database;constructor(e){const t=`${e}/database.json`,n=Fi.File.new_for_path(t),[i,s]=n.load_contents(null);if(!i)throw new Error(`failed to load file/contents of '${t}'`);this._database=JSON.parse((new TextDecoder).decode(s))}find(e){if(!e)throw new Error("timezone is required");if(!(e in this._database))throw new Error(`unknown timezone: '${e}'`);return{latitude:this._database[e][0],longitude:this._database[e][1]}}}const{GLib:Hi}=imports.gi;class Wi{_timezone_change_listener=new zi(e=>this._timezone=e);_timezone=Hi.TimeZone.new_local().get_identifier();get timezone(){return this._timezone}_timezone_location_finder=new qi(`${s.path}/Timezone_location_finder`);get auto_location(){return this._timezone_location_finder.find(this.timezone)}manual_location;is_location_auto;get location(){return this.is_location_auto?this.auto_location:this.manual_location}constructor(e){Object.assign(this,e),yn(this,{_timezone_change_listener:!1,_timezone_location_finder:!1,manual_location:Ge.deep}),this._timezone_change_listener.enable()}dispose(){this._timezone_change_listener.dispose()}}async function Xi(e){return new Promise(t=>setTimeout(t,e))}const{Gio:Yi}=imports.gi;class Ji{try_now_or_postpone_until_unlocked(e){Ji._get_state_async(t=>{t?this._subscribe_to_changes(t=>{t||(this._unsubscribe_to_changes(),e())}):e()})}cancel(){this._unsubscribe_to_changes()}dispose(){this.cancel()}_signal_id=void 0;_subscribe_to_changes(e){this._signal_id&&this._unsubscribe_to_changes(),this._signal_id=Yi.DBus.session.signal_subscribe("org.cinnamon.ScreenSaver","org.cinnamon.ScreenSaver","ActiveChanged","/org/cinnamon/ScreenSaver",null,Yi.DBusSignalFlags.NONE,(t,n,i,s,r,a)=>{const o=a.deep_unpack()[0];e(o)})}_unsubscribe_to_changes(){this._signal_id&&(Yi.DBus.session.signal_unsubscribe(this._signal_id),this._signal_id=void 0)}static _get_state_async(e){Yi.DBus.session.call("org.cinnamon.ScreenSaver","/org/cinnamon/ScreenSaver","org.cinnamon.ScreenSaver","GetActive",null,null,Yi.DBusCallFlags.NONE,-1,null,(t,n)=>{const i=t.call_finish(n).deep_unpack()[0];e(i)})}}const{Gio:Zi}=imports.gi;class Qi{_callback_when_sleep_entries;_callback_when_wakeup_unlocked;constructor(e,t){this._callback_when_sleep_entries=e,this._callback_when_wakeup_unlocked=t}_screen_lock_checker=new Ji;enable(){this._subscribe_to_changes(e=>{e?this._callback_when_sleep_entries():this._screen_lock_checker.try_now_or_postpone_until_unlocked(()=>this._callback_when_wakeup_unlocked())})}disable(){this._unsubscribe_to_changes(),this._screen_lock_checker.cancel()}dispose(){this._unsubscribe_to_changes(),this._screen_lock_checker.dispose()}_signal_id=void 0;_subscribe_to_changes(e){this._signal_id&&this._unsubscribe_to_changes(),this._signal_id=Zi.DBus.system.signal_subscribe("org.freedesktop.login1","org.freedesktop.login1.Manager","PrepareForSleep","/org/freedesktop/login1",null,Zi.DBusSignalFlags.NONE,(t,n,i,s,r,a)=>{const o=a.deep_unpack()[0];e(o)})}_unsubscribe_to_changes(){this._signal_id&&(Zi.DBus.system.signal_unsubscribe(this._signal_id),this._signal_id=void 0)}}const{Gio:es}=imports.gi,ts=es.Settings.new("org.x.apps.portal");class ns{_callback_on_change;_signal_id=void 0;constructor(e){this._callback_on_change=e}enable(){this.disable(),this._signal_id=ts.connect("changed::color-scheme",()=>{this._callback_on_change(ns.value)})}disable(){void 0!==this._signal_id&&(ts.disconnect(this._signal_id),this._signal_id=void 0)}dispose(){this.disable()}static get value(){return ts.get_string("color-scheme")}static set value(e){ts.set_string("color-scheme",e)}}const{Gio:is}=imports.gi,ss={desktop:is.Settings.new("org.cinnamon.desktop.interface"),cinnamon:is.Settings.new("org.cinnamon.theme")};class rs{static get mouse(){return ss.desktop.get_string("cursor-theme")}static set mouse(e){ss.desktop.set_string("cursor-theme",e)}static get apps(){return ss.desktop.get_string("gtk-theme")}static set apps(e){ss.desktop.set_string("gtk-theme",e)}static get icons(){return ss.desktop.get_string("icon-theme")}static set icons(e){ss.desktop.set_string("icon-theme",e)}static get desktop(){return ss.cinnamon.get_string("name")}static set desktop(e){ss.cinnamon.set_string("name",e)}}class as{_settings;constructor(e,t){this._settings=t,e.on_button_detect_themes_light=()=>this.detect_light_themes(),e.on_button_detect_themes_dark=()=>this.detect_dark_themes(),e.on_button_apply_themes_light=()=>this.apply_light_themes(),e.on_button_apply_themes_dark=()=>this.apply_dark_themes()}detect_light_themes(){this._settings.setValue("light_themes_mouse",rs.mouse),this._settings.setValue("light_themes_apps",rs.apps),this._settings.setValue("light_themes_icons",rs.icons),this._settings.setValue("light_themes_desktop",rs.desktop),this._settings.light_themes_have_been_detected=!0}detect_dark_themes(){this._settings.setValue("dark_themes_mouse",rs.mouse),this._settings.setValue("dark_themes_apps",rs.apps),this._settings.setValue("dark_themes_icons",rs.icons),this._settings.setValue("dark_themes_desktop",rs.desktop),this._settings.dark_themes_have_been_detected=!0}apply_light_themes(){rs.mouse=this._settings.getValue("light_themes_mouse"),rs.apps=this._settings.getValue("light_themes_apps"),rs.icons=this._settings.getValue("light_themes_icons"),rs.desktop=this._settings.getValue("light_themes_desktop"),ns.value="prefer-light"}apply_dark_themes(){rs.mouse=this._settings.getValue("dark_themes_mouse"),rs.apps=this._settings.getValue("dark_themes_apps"),rs.icons=this._settings.getValue("dark_themes_icons"),rs.desktop=this._settings.getValue("dark_themes_desktop"),ns.value="prefer-dark"}}const{Gio:os,GLib:us}=imports.gi,_s="auto-dark-light-time-change-listener";class ls{_callback_when_changes;constructor(e){this._callback_when_changes=e;const t=`${s.path}/Time_change_listener`,n=`${t}/${_s}`;us.file_test(n,us.FileTest.EXISTS)||ls._compile(t),this._run(n)}static _compile(e){if(!us.find_program_in_path("make")||!us.find_program_in_path("g++"))throw new Error(_("Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-based system with 'sudo apt install make g++', then restart Cinnamon (Ctrl+Alt+Esc)."));const t=new os.Subprocess({argv:["make","-C",e],flags:os.SubprocessFlags.STDERR_PIPE});t.init(null);try{const[e,n,i]=t.communicate_utf8(null,null);if(!t.get_successful())throw new Error(i||_("Unknown compilation error"))}catch(n){throw new Error(`${_("Failed compilation of")} '${_s}'.\n\n`+n.message)}finally{us.spawn_command_line_async(`make -C ${e} clean`)}}_input;_input_error;_output;_subprocess;_should_run=!0;_run(e){this._subprocess=new os.Subprocess({argv:[e],flags:os.SubprocessFlags.STDOUT_PIPE|os.SubprocessFlags.STDIN_PIPE|os.SubprocessFlags.STDERR_PIPE}),this._subprocess.init(null),this._output=this._subprocess.get_stdin_pipe(),this._input=new os.DataInputStream({base_stream:this._subprocess.get_stdout_pipe()}),this._input_error=new os.DataInputStream({base_stream:this._subprocess.get_stderr_pipe()}),this._listen_input(),this._listen_error()}async _listen_input(){do{await new Promise(e=>this._input.read_line_async(us.PRIORITY_DEFAULT,null,e)),this._callback_when_changes()}while(this._should_run)}async _listen_error(){do{const[e,t]=await new Promise(e=>this._input_error.read_line_async(us.PRIORITY_DEFAULT,null,(t,n)=>{try{e(t.read_line_finish(n))}catch(i){u.warn(i),e([null,0])}}));null!==e&&t>0&&u.warn(`${_("the subprocess")} \`${_s}\` ${_("has written on its error output")}${_(":")} ${e}`)}while(this._should_run)}enable(){this._output.write("enable\n",null)}disable(){this._output.write("disable\n",null)}dispose(){this._callback_when_changes=()=>{},this._should_run=!1,this._output.write("exit\n",null),this._subprocess.wait(null)}}const{PI:cs,sin:hs,cos:ds,asin:fs,acos:gs,round:ps}=Math,vs=2*cs,bs=cs/180,ms=9e-4,ys=2440587.5,ks=2451545;function ws(e){return 86400*(e-ys)}function Os(e,t,n){return ms+(e+t)/vs+n}function Ss(e,t,n){return ks+e+.0053*hs(t)-.0069*hs(2*n)}const As=hs(23.4397*bs),xs=102.9372*bs+cs;function Es(e,t){const[n,i]=function(e,t,n){const i=bs*-n,s=bs*t,r=ps(e/86400-10957.5-ms-i/vs),a=Os(0,i,r),o=bs*(.98560028*a+357.5291),u=o+bs*(1.9148*hs(o)+.02*hs(2*o)+3e-4*hs(3*o))+xs,l=fs(As*hs(u)),c=Ss(a,o,u),h=Ss(Os(gs((hs(-.833*bs)-hs(s)*hs(l))/(ds(s)*ds(l))),i,r),o,u);return[ws(2*c-h),ws(h)]}(e.to_unix(),t.latitude,t.longitude);return{sunrise:Oi(n),sunset:Oi(i)}}const{DateTime:js}=imports.gi.GLib;class Ps{_date=js.new_now_local();update(){this._date=js.new_now_local()}location;get _location_twilights(){return Es(this._date,this.location)}auto_sunrise_offset;auto_sunset_offset;get auto_sunrise(){return this._location_twilights.sunrise.add_minutes(this.auto_sunrise_offset)}get auto_sunset(){return this._location_twilights.sunset.add_minutes(this.auto_sunset_offset)}manual_sunrise;manual_sunset;is_sunrise_auto;is_sunset_auto;get _sunrise(){return this.is_sunrise_auto?this.auto_sunrise:this.manual_sunrise}get _sunset(){return this.is_sunset_auto?this.auto_sunset:this.manual_sunset}get twilights(){return{sunrise:this._sunrise,sunset:this._sunset}}constructor(e){Object.assign(this,e),yn(this)}}const{GLib:Ts}=imports.gi,Vs=2e3;const{AppletSettings:Ds}=imports.ui.settings;const{IconApplet:Is}=imports.ui.applet; +const Gettext = imports.gettext; +const { GLib: GLib$5 } = imports.gi; +const Main$1 = imports.ui.main; +const { St } = imports.gi; +const metadata = { + uuid: "", + name: "", + description: "", + path: "", + force_loaded: false +}; +function _(text) { + return Gettext.dgettext(metadata.uuid, text); +} +let translated_applet_name = ""; +function initialize_globals(applet_metadata) { + Object.assign(metadata, applet_metadata); + const translations_dir_path = GLib$5.get_home_dir() + "/.local/share/locale"; + Gettext.bindtextdomain(metadata.uuid, translations_dir_path); + translated_applet_name = _(metadata.name); +} +const icon_size = 24; +const warning_icon = new St.Icon({ + icon_name: "dialog-warning", + icon_type: St.IconType.SYMBOLIC, + icon_size +}); +const error_icon = new St.Icon({ + icon_name: "dialog-error", + icon_type: St.IconType.SYMBOLIC, + icon_size +}); +const logger = { + info(msg) { + global.log(translated_applet_name + `${_(":")} ` + msg); + Main$1.notify(translated_applet_name, msg); + }, + warn(msg) { + global.logWarning(translated_applet_name + `${_(":")} ` + msg); + Main$1.warningNotify(translated_applet_name, msg, warning_icon); + }, + error(msg) { + global.logError(translated_applet_name + `${_(":")} ` + msg); + Main$1.criticalNotify(translated_applet_name, msg, error_icon); + } +}; +function die(error) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + throw new Error(typeof error === "number" ? "[MobX] minified error nr: " + error + (args.length ? " " + args.map(String).join(",") : "") + ". Find the full error at: https://github.com/mobxjs/mobx/blob/main/packages/mobx/src/errors.ts" : "[MobX] " + error); +} +var mockGlobal = {}; +function getGlobal() { + if (typeof globalThis !== "undefined") { + return globalThis; + } + if (typeof window !== "undefined") { + return window; + } + if (typeof global !== "undefined") { + return global; + } + if (typeof self !== "undefined") { + return self; + } + return mockGlobal; +} +var assign = Object.assign; +var getDescriptor = Object.getOwnPropertyDescriptor; +var defineProperty = Object.defineProperty; +var objectPrototype = Object.prototype; +var EMPTY_ARRAY = []; +Object.freeze(EMPTY_ARRAY); +var EMPTY_OBJECT = {}; +Object.freeze(EMPTY_OBJECT); +var hasProxy = typeof Proxy !== "undefined"; +var plainObjectString = /* @__PURE__ */ Object.toString(); +function assertProxies() { + if (!hasProxy) { + die("Proxy not available"); + } +} +function once(func) { + var invoked = false; + return function() { + if (invoked) { + return; + } + invoked = true; + return func.apply(this, arguments); + }; +} +var noop = function noop2() { +}; +function isFunction(fn) { + return typeof fn === "function"; +} +function isStringish(value) { + var t = typeof value; + switch (t) { + case "string": + case "symbol": + case "number": + return true; + } + return false; +} +function isObject(value) { + return value !== null && typeof value === "object"; +} +function isPlainObject(value) { + if (!isObject(value)) { + return false; + } + var proto = Object.getPrototypeOf(value); + if (proto == null) { + return true; + } + var protoConstructor = Object.hasOwnProperty.call(proto, "constructor") && proto.constructor; + return typeof protoConstructor === "function" && protoConstructor.toString() === plainObjectString; +} +function isGenerator(obj) { + var constructor = obj == null ? void 0 : obj.constructor; + if (!constructor) { + return false; + } + if ("GeneratorFunction" === constructor.name || "GeneratorFunction" === constructor.displayName) { + return true; + } + return false; +} +function addHiddenProp(object2, propName, value) { + defineProperty(object2, propName, { + enumerable: false, + writable: true, + configurable: true, + value + }); +} +function addHiddenFinalProp(object2, propName, value) { + defineProperty(object2, propName, { + enumerable: false, + writable: false, + configurable: true, + value + }); +} +function createInstanceofPredicate(name, theClass) { + var propName = "isMobX" + name; + theClass.prototype[propName] = true; + return function(x) { + return isObject(x) && x[propName] === true; + }; +} +function isES6Map(thing) { + return thing != null && Object.prototype.toString.call(thing) === "[object Map]"; +} +function isPlainES6Map(thing) { + var mapProto = Object.getPrototypeOf(thing); + var objectProto = Object.getPrototypeOf(mapProto); + var nullProto = Object.getPrototypeOf(objectProto); + return nullProto === null; +} +function isES6Set(thing) { + return thing != null && Object.prototype.toString.call(thing) === "[object Set]"; +} +var hasGetOwnPropertySymbols = typeof Object.getOwnPropertySymbols !== "undefined"; +function getPlainObjectKeys(object2) { + var keys2 = Object.keys(object2); + if (!hasGetOwnPropertySymbols) { + return keys2; + } + var symbols = Object.getOwnPropertySymbols(object2); + if (!symbols.length) { + return keys2; + } + return [].concat(keys2, symbols.filter(function(s) { + return objectPrototype.propertyIsEnumerable.call(object2, s); + })); +} +var ownKeys = typeof Reflect !== "undefined" && Reflect.ownKeys ? Reflect.ownKeys : hasGetOwnPropertySymbols ? function(obj) { + return Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj)); +} : ( + /* istanbul ignore next */ + Object.getOwnPropertyNames +); +function toPrimitive(value) { + return value === null ? null : typeof value === "object" ? "" + value : value; +} +function hasProp(target, prop) { + return objectPrototype.hasOwnProperty.call(target, prop); +} +var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function getOwnPropertyDescriptors2(target) { + var res = {}; + ownKeys(target).forEach(function(key) { + res[key] = getDescriptor(target, key); + }); + return res; +}; +function getFlag(flags, mask) { + return !!(flags & mask); +} +function setFlag(flags, mask, newValue) { + if (newValue) { + flags |= mask; + } else { + flags &= ~mask; + } + return flags; +} +function _arrayLikeToArray(r, a) { + (null == a || a > r.length) && (a = r.length); + for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; + return n; +} +function _defineProperties(e, r) { + for (var t = 0; t < r.length; t++) { + var o = r[t]; + o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o); + } +} +function _createClass(e, r, t) { + return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", { + writable: false + }), e; +} +function _createForOfIteratorHelperLoose(r, e) { + var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; + if (t) return (t = t.call(r)).next.bind(t); + if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) { + t && (r = t); + var o = 0; + return function() { + return o >= r.length ? { + done: true + } : { + done: false, + value: r[o++] + }; + }; + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +function _extends() { + return _extends = Object.assign ? Object.assign.bind() : function(n) { + for (var e = 1; e < arguments.length; e++) { + var t = arguments[e]; + for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); + } + return n; + }, _extends.apply(null, arguments); +} +function _inheritsLoose(t, o) { + t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o); +} +function _setPrototypeOf(t, e) { + return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(t2, e2) { + return t2.__proto__ = e2, t2; + }, _setPrototypeOf(t, e); +} +function _toPrimitive(t, r) { + if ("object" != typeof t || !t) return t; + var e = t[Symbol.toPrimitive]; + if (void 0 !== e) { + var i = e.call(t, r); + if ("object" != typeof i) return i; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return String(t); +} +function _toPropertyKey(t) { + var i = _toPrimitive(t, "string"); + return "symbol" == typeof i ? i : i + ""; +} +function _unsupportedIterableToArray(r, a) { + if (r) { + if ("string" == typeof r) return _arrayLikeToArray(r, a); + var t = {}.toString.call(r).slice(8, -1); + return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; + } +} +var storedAnnotationsSymbol = /* @__PURE__ */ Symbol("mobx-stored-annotations"); +function createDecoratorAnnotation(annotation) { + function decorator(target, property) { + if (is20223Decorator(property)) { + return annotation.decorate_20223_(target, property); + } else { + storeAnnotation(target, property, annotation); + } + } + return Object.assign(decorator, annotation); +} +function storeAnnotation(prototype, key, annotation) { + if (!hasProp(prototype, storedAnnotationsSymbol)) { + addHiddenProp(prototype, storedAnnotationsSymbol, _extends({}, prototype[storedAnnotationsSymbol])); + } + if (!isOverride(annotation)) { + prototype[storedAnnotationsSymbol][key] = annotation; + } +} +function is20223Decorator(context) { + return typeof context == "object" && typeof context["kind"] == "string"; +} +var $mobx = /* @__PURE__ */ Symbol("mobx administration"); +var Atom = /* @__PURE__ */ (function() { + function Atom2(name_) { + if (name_ === void 0) { + name_ = "Atom"; + } + this.name_ = void 0; + this.flags_ = 0; + this.observers_ = /* @__PURE__ */ new Set(); + this.lastAccessedBy_ = 0; + this.lowestObserverState_ = IDerivationState_.NOT_TRACKING_; + this.onBOL = void 0; + this.onBUOL = void 0; + this.name_ = name_; + } + var _proto = Atom2.prototype; + _proto.onBO = function onBO() { + if (this.onBOL) { + this.onBOL.forEach(function(listener) { + return listener(); + }); + } + }; + _proto.onBUO = function onBUO() { + if (this.onBUOL) { + this.onBUOL.forEach(function(listener) { + return listener(); + }); + } + }; + _proto.reportObserved = function reportObserved$1() { + return reportObserved(this); + }; + _proto.reportChanged = function reportChanged() { + startBatch(); + propagateChanged(this); + endBatch(); + }; + _proto.toString = function toString2() { + return this.name_; + }; + return _createClass(Atom2, [{ + key: "isBeingObserved", + get: function get4() { + return getFlag(this.flags_, Atom2.isBeingObservedMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, Atom2.isBeingObservedMask_, newValue); + } + }, { + key: "isPendingUnobservation", + get: function get4() { + return getFlag(this.flags_, Atom2.isPendingUnobservationMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, Atom2.isPendingUnobservationMask_, newValue); + } + }, { + key: "diffValue", + get: function get4() { + return getFlag(this.flags_, Atom2.diffValueMask_) ? 1 : 0; + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, Atom2.diffValueMask_, newValue === 1 ? true : false); + } + }]); +})(); +Atom.isBeingObservedMask_ = 1; +Atom.isPendingUnobservationMask_ = 2; +Atom.diffValueMask_ = 4; +var isAtom = /* @__PURE__ */ createInstanceofPredicate("Atom", Atom); +function createAtom(name, onBecomeObservedHandler, onBecomeUnobservedHandler) { + if (onBecomeObservedHandler === void 0) { + onBecomeObservedHandler = noop; + } + if (onBecomeUnobservedHandler === void 0) { + onBecomeUnobservedHandler = noop; + } + var atom = new Atom(name); + if (onBecomeObservedHandler !== noop) { + onBecomeObserved(atom, onBecomeObservedHandler); + } + if (onBecomeUnobservedHandler !== noop) { + onBecomeUnobserved(atom, onBecomeUnobservedHandler); + } + return atom; +} +function structuralComparer(a, b) { + return deepEqual(a, b); +} +function defaultComparer(a, b) { + if (Object.is) { + return Object.is(a, b); + } + return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b; +} +var comparer = { + structural: structuralComparer, + "default": defaultComparer +}; +function deepEnhancer(v, _14, name) { + if (isObservable(v)) { + return v; + } + if (Array.isArray(v)) { + return observable.array(v, { + name + }); + } + if (isPlainObject(v)) { + return observable.object(v, void 0, { + name + }); + } + if (isES6Map(v)) { + return observable.map(v, { + name + }); + } + if (isES6Set(v)) { + return observable.set(v, { + name + }); + } + if (typeof v === "function" && !isAction(v) && !isFlow(v)) { + if (isGenerator(v)) { + return flow(v); + } else { + return autoAction(name, v); + } + } + return v; +} +function shallowEnhancer(v, _14, name) { + if (v === void 0 || v === null) { + return v; + } + if (isObservableObject(v) || isObservableArray(v) || isObservableMap(v) || isObservableSet(v)) { + return v; + } + if (Array.isArray(v)) { + return observable.array(v, { + name, + deep: false + }); + } + if (isPlainObject(v)) { + return observable.object(v, void 0, { + name, + deep: false + }); + } + if (isES6Map(v)) { + return observable.map(v, { + name, + deep: false + }); + } + if (isES6Set(v)) { + return observable.set(v, { + name, + deep: false + }); + } +} +function referenceEnhancer(newValue) { + return newValue; +} +function refStructEnhancer(v, oldValue) { + if (deepEqual(v, oldValue)) { + return oldValue; + } + return v; +} +var OVERRIDE = "override"; +function isOverride(annotation) { + return annotation.annotationType_ === OVERRIDE; +} +function createActionAnnotation(name, options) { + return { + annotationType_: name, + options_: options, + make_: make_$1, + extend_: extend_$1, + decorate_20223_: decorate_20223_$1 + }; +} +function make_$1(adm, key, descriptor, source) { + var _this$options_; + if ((_this$options_ = this.options_) != null && _this$options_.bound) { + return this.extend_(adm, key, descriptor, false) === null ? 0 : 1; + } + if (source === adm.target_) { + return this.extend_(adm, key, descriptor, false) === null ? 0 : 2; + } + if (isAction(descriptor.value)) { + return 1; + } + var actionDescriptor = createActionDescriptor(adm, this, key, descriptor, false); + defineProperty(source, key, actionDescriptor); + return 2; +} +function extend_$1(adm, key, descriptor, proxyTrap) { + var actionDescriptor = createActionDescriptor(adm, this, key, descriptor); + return adm.defineProperty_(key, actionDescriptor, proxyTrap); +} +function decorate_20223_$1(mthd, context) { + var kind = context.kind, name = context.name, addInitializer = context.addInitializer; + var ann = this; + var _createAction = function _createAction2(m) { + var _ann$options_$name, _ann$options_, _ann$options_$autoAct, _ann$options_2; + return createAction((_ann$options_$name = (_ann$options_ = ann.options_) == null ? void 0 : _ann$options_.name) != null ? _ann$options_$name : name.toString(), m, (_ann$options_$autoAct = (_ann$options_2 = ann.options_) == null ? void 0 : _ann$options_2.autoAction) != null ? _ann$options_$autoAct : false); + }; + if (kind == "field") { + return function(initMthd) { + var _ann$options_3; + var mthd2 = initMthd; + if (!isAction(mthd2)) { + mthd2 = _createAction(mthd2); + } + if ((_ann$options_3 = ann.options_) != null && _ann$options_3.bound) { + mthd2 = mthd2.bind(this); + mthd2.isMobxAction = true; + } + return mthd2; + }; + } + if (kind == "method") { + var _this$options_2; + if (!isAction(mthd)) { + mthd = _createAction(mthd); + } + if ((_this$options_2 = this.options_) != null && _this$options_2.bound) { + addInitializer(function() { + var self2 = this; + var bound = self2[name].bind(self2); + bound.isMobxAction = true; + self2[name] = bound; + }); + } + return mthd; + } + die("Cannot apply '" + ann.annotationType_ + "' to '" + String(name) + "' (kind: " + kind + "):" + ("\n'" + ann.annotationType_ + "' can only be used on properties with a function value.")); +} +function assertActionDescriptor(adm, _ref, key, _ref2) { + _ref.annotationType_; + _ref2.value; +} +function createActionDescriptor(adm, annotation, key, descriptor, safeDescriptors) { + var _annotation$options_, _annotation$options_$, _annotation$options_2, _annotation$options_$2, _annotation$options_3, _annotation$options_4, _adm$proxy_2; + if (safeDescriptors === void 0) { + safeDescriptors = globalState.safeDescriptors; + } + assertActionDescriptor(adm, annotation, key, descriptor); + var value = descriptor.value; + if ((_annotation$options_ = annotation.options_) != null && _annotation$options_.bound) { + var _adm$proxy_; + value = value.bind((_adm$proxy_ = adm.proxy_) != null ? _adm$proxy_ : adm.target_); + } + return { + value: createAction( + (_annotation$options_$ = (_annotation$options_2 = annotation.options_) == null ? void 0 : _annotation$options_2.name) != null ? _annotation$options_$ : key.toString(), + value, + (_annotation$options_$2 = (_annotation$options_3 = annotation.options_) == null ? void 0 : _annotation$options_3.autoAction) != null ? _annotation$options_$2 : false, + // https://github.com/mobxjs/mobx/discussions/3140 + (_annotation$options_4 = annotation.options_) != null && _annotation$options_4.bound ? (_adm$proxy_2 = adm.proxy_) != null ? _adm$proxy_2 : adm.target_ : void 0 + ), + // Non-configurable for classes + // prevents accidental field redefinition in subclass + configurable: safeDescriptors ? adm.isPlainObject_ : true, + // https://github.com/mobxjs/mobx/pull/2641#issuecomment-737292058 + enumerable: false, + // Non-obsevable, therefore non-writable + // Also prevents rewriting in subclass constructor + writable: safeDescriptors ? false : true + }; +} +function createFlowAnnotation(name, options) { + return { + annotationType_: name, + options_: options, + make_: make_$2, + extend_: extend_$2, + decorate_20223_: decorate_20223_$2 + }; +} +function make_$2(adm, key, descriptor, source) { + var _this$options_; + if (source === adm.target_) { + return this.extend_(adm, key, descriptor, false) === null ? 0 : 2; + } + if ((_this$options_ = this.options_) != null && _this$options_.bound && (!hasProp(adm.target_, key) || !isFlow(adm.target_[key]))) { + if (this.extend_(adm, key, descriptor, false) === null) { + return 0; + } + } + if (isFlow(descriptor.value)) { + return 1; + } + var flowDescriptor = createFlowDescriptor(adm, this, key, descriptor, false, false); + defineProperty(source, key, flowDescriptor); + return 2; +} +function extend_$2(adm, key, descriptor, proxyTrap) { + var _this$options_2; + var flowDescriptor = createFlowDescriptor(adm, this, key, descriptor, (_this$options_2 = this.options_) == null ? void 0 : _this$options_2.bound); + return adm.defineProperty_(key, flowDescriptor, proxyTrap); +} +function decorate_20223_$2(mthd, context) { + var _this$options_3; + var name = context.name, addInitializer = context.addInitializer; + if (!isFlow(mthd)) { + mthd = flow(mthd); + } + if ((_this$options_3 = this.options_) != null && _this$options_3.bound) { + addInitializer(function() { + var self2 = this; + var bound = self2[name].bind(self2); + bound.isMobXFlow = true; + self2[name] = bound; + }); + } + return mthd; +} +function assertFlowDescriptor(adm, _ref, key, _ref2) { + _ref.annotationType_; + _ref2.value; +} +function createFlowDescriptor(adm, annotation, key, descriptor, bound, safeDescriptors) { + if (safeDescriptors === void 0) { + safeDescriptors = globalState.safeDescriptors; + } + assertFlowDescriptor(adm, annotation, key, descriptor); + var value = descriptor.value; + if (!isFlow(value)) { + value = flow(value); + } + if (bound) { + var _adm$proxy_; + value = value.bind((_adm$proxy_ = adm.proxy_) != null ? _adm$proxy_ : adm.target_); + value.isMobXFlow = true; + } + return { + value, + // Non-configurable for classes + // prevents accidental field redefinition in subclass + configurable: safeDescriptors ? adm.isPlainObject_ : true, + // https://github.com/mobxjs/mobx/pull/2641#issuecomment-737292058 + enumerable: false, + // Non-obsevable, therefore non-writable + // Also prevents rewriting in subclass constructor + writable: safeDescriptors ? false : true + }; +} +function createComputedAnnotation(name, options) { + return { + annotationType_: name, + options_: options, + make_: make_$3, + extend_: extend_$3, + decorate_20223_: decorate_20223_$3 + }; +} +function make_$3(adm, key, descriptor) { + return this.extend_(adm, key, descriptor, false) === null ? 0 : 1; +} +function extend_$3(adm, key, descriptor, proxyTrap) { + assertComputedDescriptor(adm, this, key, descriptor); + return adm.defineComputedProperty_(key, _extends({}, this.options_, { + get: descriptor.get, + set: descriptor.set + }), proxyTrap); +} +function decorate_20223_$3(get4, context) { + var ann = this; + var key = context.name, addInitializer = context.addInitializer; + addInitializer(function() { + var adm = asObservableObject(this)[$mobx]; + var options = _extends({}, ann.options_, { + get: get4, + context: this + }); + options.name || (options.name = "ObservableObject." + key.toString()); + adm.values_.set(key, new ComputedValue(options)); + }); + return function() { + return this[$mobx].getObservablePropValue_(key); + }; +} +function assertComputedDescriptor(adm, _ref, key, _ref2) { + _ref.annotationType_; + _ref2.get; +} +function createObservableAnnotation(name, options) { + return { + annotationType_: name, + options_: options, + make_: make_$4, + extend_: extend_$4, + decorate_20223_: decorate_20223_$4 + }; +} +function make_$4(adm, key, descriptor) { + return this.extend_(adm, key, descriptor, false) === null ? 0 : 1; +} +function extend_$4(adm, key, descriptor, proxyTrap) { + var _this$options_$enhanc, _this$options_; + assertObservableDescriptor(adm, this); + return adm.defineObservableProperty_(key, descriptor.value, (_this$options_$enhanc = (_this$options_ = this.options_) == null ? void 0 : _this$options_.enhancer) != null ? _this$options_$enhanc : deepEnhancer, proxyTrap); +} +function decorate_20223_$4(desc, context) { + var ann = this; + var kind = context.kind, name = context.name; + var initializedObjects = /* @__PURE__ */ new WeakSet(); + function initializeObservable(target, value) { + var _ann$options_$enhance, _ann$options_; + var adm = asObservableObject(target)[$mobx]; + var observable2 = new ObservableValue(value, (_ann$options_$enhance = (_ann$options_ = ann.options_) == null ? void 0 : _ann$options_.enhancer) != null ? _ann$options_$enhance : deepEnhancer, "ObservableObject." + name.toString(), false); + adm.values_.set(name, observable2); + initializedObjects.add(target); + } + if (kind == "accessor") { + return { + get: function get4() { + if (!initializedObjects.has(this)) { + initializeObservable(this, desc.get.call(this)); + } + return this[$mobx].getObservablePropValue_(name); + }, + set: function set5(value) { + if (!initializedObjects.has(this)) { + initializeObservable(this, value); + } + return this[$mobx].setObservablePropValue_(name, value); + }, + init: function init(value) { + if (!initializedObjects.has(this)) { + initializeObservable(this, value); + } + return value; + } + }; + } + return; +} +function assertObservableDescriptor(adm, _ref, key, descriptor) { + _ref.annotationType_; +} +var AUTO = "true"; +var autoAnnotation = /* @__PURE__ */ createAutoAnnotation(); +function createAutoAnnotation(options) { + return { + annotationType_: AUTO, + options_: options, + make_: make_$5, + extend_: extend_$5, + decorate_20223_: decorate_20223_$5 + }; +} +function make_$5(adm, key, descriptor, source) { + var _this$options_3, _this$options_4; + if (descriptor.get) { + return computed.make_(adm, key, descriptor, source); + } + if (descriptor.set) { + var set5 = isAction(descriptor.set) ? descriptor.set : createAction(key.toString(), descriptor.set); + if (source === adm.target_) { + return adm.defineProperty_(key, { + configurable: globalState.safeDescriptors ? adm.isPlainObject_ : true, + set: set5 + }) === null ? 0 : 2; + } + defineProperty(source, key, { + configurable: true, + set: set5 + }); + return 2; + } + if (source !== adm.target_ && typeof descriptor.value === "function") { + var _this$options_2; + if (isGenerator(descriptor.value)) { + var _this$options_; + var flowAnnotation2 = (_this$options_ = this.options_) != null && _this$options_.autoBind ? flow.bound : flow; + return flowAnnotation2.make_(adm, key, descriptor, source); + } + var actionAnnotation2 = (_this$options_2 = this.options_) != null && _this$options_2.autoBind ? autoAction.bound : autoAction; + return actionAnnotation2.make_(adm, key, descriptor, source); + } + var observableAnnotation2 = ((_this$options_3 = this.options_) == null ? void 0 : _this$options_3.deep) === false ? observable.ref : observable; + if (typeof descriptor.value === "function" && (_this$options_4 = this.options_) != null && _this$options_4.autoBind) { + var _adm$proxy_; + descriptor.value = descriptor.value.bind((_adm$proxy_ = adm.proxy_) != null ? _adm$proxy_ : adm.target_); + } + return observableAnnotation2.make_(adm, key, descriptor, source); +} +function extend_$5(adm, key, descriptor, proxyTrap) { + var _this$options_5, _this$options_6; + if (descriptor.get) { + return computed.extend_(adm, key, descriptor, proxyTrap); + } + if (descriptor.set) { + return adm.defineProperty_(key, { + configurable: globalState.safeDescriptors ? adm.isPlainObject_ : true, + set: createAction(key.toString(), descriptor.set) + }, proxyTrap); + } + if (typeof descriptor.value === "function" && (_this$options_5 = this.options_) != null && _this$options_5.autoBind) { + var _adm$proxy_2; + descriptor.value = descriptor.value.bind((_adm$proxy_2 = adm.proxy_) != null ? _adm$proxy_2 : adm.target_); + } + var observableAnnotation2 = ((_this$options_6 = this.options_) == null ? void 0 : _this$options_6.deep) === false ? observable.ref : observable; + return observableAnnotation2.extend_(adm, key, descriptor, proxyTrap); +} +function decorate_20223_$5(desc, context) { + die("'" + this.annotationType_ + "' cannot be used as a decorator"); +} +var OBSERVABLE = "observable"; +var OBSERVABLE_REF = "observable.ref"; +var OBSERVABLE_SHALLOW = "observable.shallow"; +var OBSERVABLE_STRUCT = "observable.struct"; +var defaultCreateObservableOptions = { + deep: true, + name: void 0, + defaultDecorator: void 0, + proxy: true +}; +Object.freeze(defaultCreateObservableOptions); +function asCreateObservableOptions(thing) { + return thing || defaultCreateObservableOptions; +} +var observableAnnotation = /* @__PURE__ */ createObservableAnnotation(OBSERVABLE); +var observableRefAnnotation = /* @__PURE__ */ createObservableAnnotation(OBSERVABLE_REF, { + enhancer: referenceEnhancer +}); +var observableShallowAnnotation = /* @__PURE__ */ createObservableAnnotation(OBSERVABLE_SHALLOW, { + enhancer: shallowEnhancer +}); +var observableStructAnnotation = /* @__PURE__ */ createObservableAnnotation(OBSERVABLE_STRUCT, { + enhancer: refStructEnhancer +}); +var observableDecoratorAnnotation = /* @__PURE__ */ createDecoratorAnnotation(observableAnnotation); +function getEnhancerFromOptions(options) { + return options.deep === true ? deepEnhancer : options.deep === false ? referenceEnhancer : getEnhancerFromAnnotation(options.defaultDecorator); +} +function getAnnotationFromOptions(options) { + var _options$defaultDecor; + return options ? (_options$defaultDecor = options.defaultDecorator) != null ? _options$defaultDecor : createAutoAnnotation(options) : void 0; +} +function getEnhancerFromAnnotation(annotation) { + var _annotation$options_$, _annotation$options_; + return !annotation ? deepEnhancer : (_annotation$options_$ = (_annotation$options_ = annotation.options_) == null ? void 0 : _annotation$options_.enhancer) != null ? _annotation$options_$ : deepEnhancer; +} +function createObservable(v, arg2, arg3) { + if (is20223Decorator(arg2)) { + return observableAnnotation.decorate_20223_(v, arg2); + } + if (isStringish(arg2)) { + storeAnnotation(v, arg2, observableAnnotation); + return; + } + if (isObservable(v)) { + return v; + } + if (isPlainObject(v)) { + return observable.object(v, arg2, arg3); + } + if (Array.isArray(v)) { + return observable.array(v, arg2); + } + if (isES6Map(v)) { + return observable.map(v, arg2); + } + if (isES6Set(v)) { + return observable.set(v, arg2); + } + if (typeof v === "object" && v !== null) { + return v; + } + return observable.box(v, arg2); +} +assign(createObservable, observableDecoratorAnnotation); +var observableFactories = { + box: function box(value, options) { + var o = asCreateObservableOptions(options); + return new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals); + }, + array: function array(initialValues, options) { + var o = asCreateObservableOptions(options); + return (globalState.useProxies === false || o.proxy === false ? createLegacyArray : createObservableArray)(initialValues, getEnhancerFromOptions(o), o.name); + }, + map: function map(initialValues, options) { + var o = asCreateObservableOptions(options); + return new ObservableMap(initialValues, getEnhancerFromOptions(o), o.name); + }, + set: function set(initialValues, options) { + var o = asCreateObservableOptions(options); + return new ObservableSet(initialValues, getEnhancerFromOptions(o), o.name); + }, + object: function object(props, decorators, options) { + return initObservable(function() { + return extendObservable(globalState.useProxies === false || (options == null ? void 0 : options.proxy) === false ? asObservableObject({}, options) : asDynamicObservableObject({}, options), props, decorators); + }); + }, + ref: /* @__PURE__ */ createDecoratorAnnotation(observableRefAnnotation), + shallow: /* @__PURE__ */ createDecoratorAnnotation(observableShallowAnnotation), + deep: observableDecoratorAnnotation, + struct: /* @__PURE__ */ createDecoratorAnnotation(observableStructAnnotation) +}; +var observable = /* @__PURE__ */ assign(createObservable, observableFactories); +var COMPUTED = "computed"; +var COMPUTED_STRUCT = "computed.struct"; +var computedAnnotation = /* @__PURE__ */ createComputedAnnotation(COMPUTED); +var computedStructAnnotation = /* @__PURE__ */ createComputedAnnotation(COMPUTED_STRUCT, { + equals: comparer.structural +}); +var computed = function computed2(arg1, arg2) { + if (is20223Decorator(arg2)) { + return computedAnnotation.decorate_20223_(arg1, arg2); + } + if (isStringish(arg2)) { + return storeAnnotation(arg1, arg2, computedAnnotation); + } + if (isPlainObject(arg1)) { + return createDecoratorAnnotation(createComputedAnnotation(COMPUTED, arg1)); + } + var opts = isPlainObject(arg2) ? arg2 : {}; + opts.get = arg1; + opts.name || (opts.name = arg1.name || ""); + return new ComputedValue(opts); +}; +Object.assign(computed, computedAnnotation); +computed.struct = /* @__PURE__ */ createDecoratorAnnotation(computedStructAnnotation); +var _getDescriptor$config, _getDescriptor; +var currentActionId = 0; +var nextActionId = 1; +var isFunctionNameConfigurable = (_getDescriptor$config = (_getDescriptor = /* @__PURE__ */ getDescriptor(function() { +}, "name")) == null ? void 0 : _getDescriptor.configurable) != null ? _getDescriptor$config : false; +var tmpNameDescriptor = { + value: "action", + configurable: true, + writable: false, + enumerable: false +}; +function createAction(actionName, fn, autoAction2, ref) { + if (autoAction2 === void 0) { + autoAction2 = false; + } + function res() { + return executeAction(actionName, autoAction2, fn, ref || this, arguments); + } + res.isMobxAction = true; + res.toString = function() { + return fn.toString(); + }; + if (isFunctionNameConfigurable) { + tmpNameDescriptor.value = actionName; + defineProperty(res, "name", tmpNameDescriptor); + } + return res; +} +function executeAction(actionName, canRunAsDerivation, fn, scope, args) { + var runInfo = _startAction(actionName, canRunAsDerivation); + try { + return fn.apply(scope, args); + } catch (err) { + runInfo.error_ = err; + throw err; + } finally { + _endAction(runInfo); + } +} +function _startAction(actionName, canRunAsDerivation, scope, args) { + var notifySpy_ = false; + var startTime_ = 0; + var prevDerivation_ = globalState.trackingDerivation; + var runAsAction = !canRunAsDerivation || !prevDerivation_; + startBatch(); + var prevAllowStateChanges_ = globalState.allowStateChanges; + if (runAsAction) { + untrackedStart(); + prevAllowStateChanges_ = allowStateChangesStart(true); + } + var prevAllowStateReads_ = allowStateReadsStart(true); + var runInfo = { + runAsAction_: runAsAction, + prevDerivation_, + prevAllowStateChanges_, + prevAllowStateReads_, + notifySpy_, + startTime_, + actionId_: nextActionId++, + parentActionId_: currentActionId + }; + currentActionId = runInfo.actionId_; + return runInfo; +} +function _endAction(runInfo) { + if (currentActionId !== runInfo.actionId_) { + die(30); + } + currentActionId = runInfo.parentActionId_; + if (runInfo.error_ !== void 0) { + globalState.suppressReactionErrors = true; + } + allowStateChangesEnd(runInfo.prevAllowStateChanges_); + allowStateReadsEnd(runInfo.prevAllowStateReads_); + endBatch(); + if (runInfo.runAsAction_) { + untrackedEnd(runInfo.prevDerivation_); + } + globalState.suppressReactionErrors = false; +} +function allowStateChanges(allowStateChanges2, func) { + var prev = allowStateChangesStart(allowStateChanges2); + try { + return func(); + } finally { + allowStateChangesEnd(prev); + } +} +function allowStateChangesStart(allowStateChanges2) { + var prev = globalState.allowStateChanges; + globalState.allowStateChanges = allowStateChanges2; + return prev; +} +function allowStateChangesEnd(prev) { + globalState.allowStateChanges = prev; +} +var ObservableValue = /* @__PURE__ */ (function(_Atom) { + function ObservableValue2(value, enhancer, name_, notifySpy, equals) { + var _this; + if (name_ === void 0) { + name_ = "ObservableValue"; + } + if (equals === void 0) { + equals = comparer["default"]; + } + _this = _Atom.call(this, name_) || this; + _this.enhancer = void 0; + _this.name_ = void 0; + _this.equals = void 0; + _this.hasUnreportedChange_ = false; + _this.interceptors_ = void 0; + _this.changeListeners_ = void 0; + _this.value_ = void 0; + _this.dehancer = void 0; + _this.enhancer = enhancer; + _this.name_ = name_; + _this.equals = equals; + _this.value_ = enhancer(value, void 0, name_); + return _this; + } + _inheritsLoose(ObservableValue2, _Atom); + var _proto = ObservableValue2.prototype; + _proto.dehanceValue = function dehanceValue(value) { + if (this.dehancer !== void 0) { + return this.dehancer(value); + } + return value; + }; + _proto.set = function set5(newValue) { + this.value_; + newValue = this.prepareNewValue_(newValue); + if (newValue !== globalState.UNCHANGED) { + this.setNewValue_(newValue); + } + }; + _proto.prepareNewValue_ = function prepareNewValue_(newValue) { + if (hasInterceptors(this)) { + var change = interceptChange(this, { + object: this, + type: UPDATE, + newValue + }); + if (!change) { + return globalState.UNCHANGED; + } + newValue = change.newValue; + } + newValue = this.enhancer(newValue, this.value_, this.name_); + return this.equals(this.value_, newValue) ? globalState.UNCHANGED : newValue; + }; + _proto.setNewValue_ = function setNewValue_(newValue) { + var oldValue = this.value_; + this.value_ = newValue; + this.reportChanged(); + if (hasListeners(this)) { + notifyListeners(this, { + type: UPDATE, + object: this, + newValue, + oldValue + }); + } + }; + _proto.get = function get4() { + this.reportObserved(); + return this.dehanceValue(this.value_); + }; + _proto.intercept_ = function intercept_(handler) { + return registerInterceptor(this, handler); + }; + _proto.observe_ = function observe_(listener, fireImmediately) { + if (fireImmediately) { + listener({ + observableKind: "value", + debugObjectName: this.name_, + object: this, + type: UPDATE, + newValue: this.value_, + oldValue: void 0 + }); + } + return registerListener(this, listener); + }; + _proto.raw = function raw() { + return this.value_; + }; + _proto.toJSON = function toJSON2() { + return this.get(); + }; + _proto.toString = function toString2() { + return this.name_ + "[" + this.value_ + "]"; + }; + _proto.valueOf = function valueOf() { + return toPrimitive(this.get()); + }; + _proto[Symbol.toPrimitive] = function() { + return this.valueOf(); + }; + return ObservableValue2; +})(Atom); +var ComputedValue = /* @__PURE__ */ (function() { + function ComputedValue2(options) { + this.dependenciesState_ = IDerivationState_.NOT_TRACKING_; + this.observing_ = []; + this.newObserving_ = null; + this.observers_ = /* @__PURE__ */ new Set(); + this.runId_ = 0; + this.lastAccessedBy_ = 0; + this.lowestObserverState_ = IDerivationState_.UP_TO_DATE_; + this.unboundDepsCount_ = 0; + this.value_ = new CaughtException(null); + this.name_ = void 0; + this.triggeredBy_ = void 0; + this.flags_ = 0; + this.derivation = void 0; + this.setter_ = void 0; + this.isTracing_ = TraceMode.NONE; + this.scope_ = void 0; + this.equals_ = void 0; + this.requiresReaction_ = void 0; + this.keepAlive_ = void 0; + this.onBOL = void 0; + this.onBUOL = void 0; + if (!options.get) { + die(31); + } + this.derivation = options.get; + this.name_ = options.name || "ComputedValue"; + if (options.set) { + this.setter_ = createAction("ComputedValue-setter", options.set); + } + this.equals_ = options.equals || (options.compareStructural || options.struct ? comparer.structural : comparer["default"]); + this.scope_ = options.context; + this.requiresReaction_ = options.requiresReaction; + this.keepAlive_ = !!options.keepAlive; + } + var _proto = ComputedValue2.prototype; + _proto.onBecomeStale_ = function onBecomeStale_() { + propagateMaybeChanged(this); + }; + _proto.onBO = function onBO() { + if (this.onBOL) { + this.onBOL.forEach(function(listener) { + return listener(); + }); + } + }; + _proto.onBUO = function onBUO() { + if (this.onBUOL) { + this.onBUOL.forEach(function(listener) { + return listener(); + }); + } + }; + _proto.get = function get4() { + if (this.isComputing) { + die(32, this.name_, this.derivation); + } + if (globalState.inBatch === 0 && // !globalState.trackingDerivatpion && + this.observers_.size === 0 && !this.keepAlive_) { + if (shouldCompute(this)) { + this.warnAboutUntrackedRead_(); + startBatch(); + this.value_ = this.computeValue_(false); + endBatch(); + } + } else { + reportObserved(this); + if (shouldCompute(this)) { + var prevTrackingContext = globalState.trackingContext; + if (this.keepAlive_ && !prevTrackingContext) { + globalState.trackingContext = this; + } + if (this.trackAndCompute()) { + propagateChangeConfirmed(this); + } + globalState.trackingContext = prevTrackingContext; + } + } + var result = this.value_; + if (isCaughtException(result)) { + throw result.cause; + } + return result; + }; + _proto.set = function set5(value) { + if (this.setter_) { + if (this.isRunningSetter) { + die(33, this.name_); + } + this.isRunningSetter = true; + try { + this.setter_.call(this.scope_, value); + } finally { + this.isRunningSetter = false; + } + } else { + die(34, this.name_); + } + }; + _proto.trackAndCompute = function trackAndCompute() { + var oldValue = this.value_; + var wasSuspended = ( + /* see #1208 */ + this.dependenciesState_ === IDerivationState_.NOT_TRACKING_ + ); + var newValue = this.computeValue_(true); + var changed = wasSuspended || isCaughtException(oldValue) || isCaughtException(newValue) || !this.equals_(oldValue, newValue); + if (changed) { + this.value_ = newValue; + } + return changed; + }; + _proto.computeValue_ = function computeValue_(track) { + this.isComputing = true; + var prev = allowStateChangesStart(false); + var res; + if (track) { + res = trackDerivedFunction(this, this.derivation, this.scope_); + } else { + if (globalState.disableErrorBoundaries === true) { + res = this.derivation.call(this.scope_); + } else { + try { + res = this.derivation.call(this.scope_); + } catch (e) { + res = new CaughtException(e); + } + } + } + allowStateChangesEnd(prev); + this.isComputing = false; + return res; + }; + _proto.suspend_ = function suspend_() { + if (!this.keepAlive_) { + clearObserving(this); + this.value_ = void 0; + } + }; + _proto.observe_ = function observe_(listener, fireImmediately) { + var _this = this; + var firstTime = true; + var prevValue = void 0; + return autorun(function() { + var newValue = _this.get(); + if (!firstTime || fireImmediately) { + var prevU = untrackedStart(); + listener({ + observableKind: "computed", + debugObjectName: _this.name_, + type: UPDATE, + object: _this, + newValue, + oldValue: prevValue + }); + untrackedEnd(prevU); + } + firstTime = false; + prevValue = newValue; + }); + }; + _proto.warnAboutUntrackedRead_ = function warnAboutUntrackedRead_() { + { + return; + } + }; + _proto.toString = function toString2() { + return this.name_ + "[" + this.derivation.toString() + "]"; + }; + _proto.valueOf = function valueOf() { + return toPrimitive(this.get()); + }; + _proto[Symbol.toPrimitive] = function() { + return this.valueOf(); + }; + return _createClass(ComputedValue2, [{ + key: "isComputing", + get: function get4() { + return getFlag(this.flags_, ComputedValue2.isComputingMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, ComputedValue2.isComputingMask_, newValue); + } + }, { + key: "isRunningSetter", + get: function get4() { + return getFlag(this.flags_, ComputedValue2.isRunningSetterMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, ComputedValue2.isRunningSetterMask_, newValue); + } + }, { + key: "isBeingObserved", + get: function get4() { + return getFlag(this.flags_, ComputedValue2.isBeingObservedMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, ComputedValue2.isBeingObservedMask_, newValue); + } + }, { + key: "isPendingUnobservation", + get: function get4() { + return getFlag(this.flags_, ComputedValue2.isPendingUnobservationMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, ComputedValue2.isPendingUnobservationMask_, newValue); + } + }, { + key: "diffValue", + get: function get4() { + return getFlag(this.flags_, ComputedValue2.diffValueMask_) ? 1 : 0; + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, ComputedValue2.diffValueMask_, newValue === 1 ? true : false); + } + }]); +})(); +ComputedValue.isComputingMask_ = 1; +ComputedValue.isRunningSetterMask_ = 2; +ComputedValue.isBeingObservedMask_ = 4; +ComputedValue.isPendingUnobservationMask_ = 8; +ComputedValue.diffValueMask_ = 16; +var isComputedValue = /* @__PURE__ */ createInstanceofPredicate("ComputedValue", ComputedValue); +var IDerivationState_; +(function(IDerivationState_2) { + IDerivationState_2[IDerivationState_2["NOT_TRACKING_"] = -1] = "NOT_TRACKING_"; + IDerivationState_2[IDerivationState_2["UP_TO_DATE_"] = 0] = "UP_TO_DATE_"; + IDerivationState_2[IDerivationState_2["POSSIBLY_STALE_"] = 1] = "POSSIBLY_STALE_"; + IDerivationState_2[IDerivationState_2["STALE_"] = 2] = "STALE_"; +})(IDerivationState_ || (IDerivationState_ = {})); +var TraceMode; +(function(TraceMode2) { + TraceMode2[TraceMode2["NONE"] = 0] = "NONE"; + TraceMode2[TraceMode2["LOG"] = 1] = "LOG"; + TraceMode2[TraceMode2["BREAK"] = 2] = "BREAK"; +})(TraceMode || (TraceMode = {})); +var CaughtException = function CaughtException2(cause) { + this.cause = void 0; + this.cause = cause; +}; +function isCaughtException(e) { + return e instanceof CaughtException; +} +function shouldCompute(derivation) { + switch (derivation.dependenciesState_) { + case IDerivationState_.UP_TO_DATE_: + return false; + case IDerivationState_.NOT_TRACKING_: + case IDerivationState_.STALE_: + return true; + case IDerivationState_.POSSIBLY_STALE_: { + var prevAllowStateReads = allowStateReadsStart(true); + var prevUntracked = untrackedStart(); + var obs = derivation.observing_, l = obs.length; + for (var i = 0; i < l; i++) { + var obj = obs[i]; + if (isComputedValue(obj)) { + if (globalState.disableErrorBoundaries) { + obj.get(); + } else { + try { + obj.get(); + } catch (e) { + untrackedEnd(prevUntracked); + allowStateReadsEnd(prevAllowStateReads); + return true; + } + } + if (derivation.dependenciesState_ === IDerivationState_.STALE_) { + untrackedEnd(prevUntracked); + allowStateReadsEnd(prevAllowStateReads); + return true; + } + } + } + changeDependenciesStateTo0(derivation); + untrackedEnd(prevUntracked); + allowStateReadsEnd(prevAllowStateReads); + return false; + } + } +} +function checkIfStateModificationsAreAllowed(atom) { + { + return; + } +} +function trackDerivedFunction(derivation, f, context) { + var prevAllowStateReads = allowStateReadsStart(true); + changeDependenciesStateTo0(derivation); + derivation.newObserving_ = new Array( + // Reserve constant space for initial dependencies, dynamic space otherwise. + // See https://github.com/mobxjs/mobx/pull/3833 + derivation.runId_ === 0 ? 100 : derivation.observing_.length + ); + derivation.unboundDepsCount_ = 0; + derivation.runId_ = ++globalState.runId; + var prevTracking = globalState.trackingDerivation; + globalState.trackingDerivation = derivation; + globalState.inBatch++; + var result; + if (globalState.disableErrorBoundaries === true) { + result = f.call(context); + } else { + try { + result = f.call(context); + } catch (e) { + result = new CaughtException(e); + } + } + globalState.inBatch--; + globalState.trackingDerivation = prevTracking; + bindDependencies(derivation); + allowStateReadsEnd(prevAllowStateReads); + return result; +} +function bindDependencies(derivation) { + var prevObserving = derivation.observing_; + var observing = derivation.observing_ = derivation.newObserving_; + var lowestNewObservingDerivationState = IDerivationState_.UP_TO_DATE_; + var i0 = 0, l = derivation.unboundDepsCount_; + for (var i = 0; i < l; i++) { + var dep = observing[i]; + if (dep.diffValue === 0) { + dep.diffValue = 1; + if (i0 !== i) { + observing[i0] = dep; + } + i0++; + } + if (dep.dependenciesState_ > lowestNewObservingDerivationState) { + lowestNewObservingDerivationState = dep.dependenciesState_; + } + } + observing.length = i0; + derivation.newObserving_ = null; + l = prevObserving.length; + while (l--) { + var _dep = prevObserving[l]; + if (_dep.diffValue === 0) { + removeObserver(_dep, derivation); + } + _dep.diffValue = 0; + } + while (i0--) { + var _dep2 = observing[i0]; + if (_dep2.diffValue === 1) { + _dep2.diffValue = 0; + addObserver(_dep2, derivation); + } + } + if (lowestNewObservingDerivationState !== IDerivationState_.UP_TO_DATE_) { + derivation.dependenciesState_ = lowestNewObservingDerivationState; + derivation.onBecomeStale_(); + } +} +function clearObserving(derivation) { + var obs = derivation.observing_; + derivation.observing_ = []; + var i = obs.length; + while (i--) { + removeObserver(obs[i], derivation); + } + derivation.dependenciesState_ = IDerivationState_.NOT_TRACKING_; +} +function untracked(action2) { + var prev = untrackedStart(); + try { + return action2(); + } finally { + untrackedEnd(prev); + } +} +function untrackedStart() { + var prev = globalState.trackingDerivation; + globalState.trackingDerivation = null; + return prev; +} +function untrackedEnd(prev) { + globalState.trackingDerivation = prev; +} +function allowStateReadsStart(allowStateReads) { + var prev = globalState.allowStateReads; + globalState.allowStateReads = allowStateReads; + return prev; +} +function allowStateReadsEnd(prev) { + globalState.allowStateReads = prev; +} +function changeDependenciesStateTo0(derivation) { + if (derivation.dependenciesState_ === IDerivationState_.UP_TO_DATE_) { + return; + } + derivation.dependenciesState_ = IDerivationState_.UP_TO_DATE_; + var obs = derivation.observing_; + var i = obs.length; + while (i--) { + obs[i].lowestObserverState_ = IDerivationState_.UP_TO_DATE_; + } +} +var MobXGlobals = function MobXGlobals2() { + this.version = 6; + this.UNCHANGED = {}; + this.trackingDerivation = null; + this.trackingContext = null; + this.runId = 0; + this.mobxGuid = 0; + this.inBatch = 0; + this.pendingUnobservations = []; + this.pendingReactions = []; + this.isRunningReactions = false; + this.allowStateChanges = false; + this.allowStateReads = true; + this.enforceActions = true; + this.spyListeners = []; + this.globalReactionErrorHandlers = []; + this.computedRequiresReaction = false; + this.reactionRequiresObservable = false; + this.observableRequiresReaction = false; + this.disableErrorBoundaries = false; + this.suppressReactionErrors = false; + this.useProxies = true; + this.verifyProxies = false; + this.safeDescriptors = true; +}; +var canMergeGlobalState = true; +var globalState = /* @__PURE__ */ (function() { + var global2 = /* @__PURE__ */ getGlobal(); + if (global2.__mobxInstanceCount > 0 && !global2.__mobxGlobals) { + canMergeGlobalState = false; + } + if (global2.__mobxGlobals && global2.__mobxGlobals.version !== new MobXGlobals().version) { + canMergeGlobalState = false; + } + if (!canMergeGlobalState) { + setTimeout(function() { + { + die(35); + } + }, 1); + return new MobXGlobals(); + } else if (global2.__mobxGlobals) { + global2.__mobxInstanceCount += 1; + if (!global2.__mobxGlobals.UNCHANGED) { + global2.__mobxGlobals.UNCHANGED = {}; + } + return global2.__mobxGlobals; + } else { + global2.__mobxInstanceCount = 1; + return global2.__mobxGlobals = /* @__PURE__ */ new MobXGlobals(); + } +})(); +function addObserver(observable2, node) { + observable2.observers_.add(node); + if (observable2.lowestObserverState_ > node.dependenciesState_) { + observable2.lowestObserverState_ = node.dependenciesState_; + } +} +function removeObserver(observable2, node) { + observable2.observers_["delete"](node); + if (observable2.observers_.size === 0) { + queueForUnobservation(observable2); + } +} +function queueForUnobservation(observable2) { + if (observable2.isPendingUnobservation === false) { + observable2.isPendingUnobservation = true; + globalState.pendingUnobservations.push(observable2); + } +} +function startBatch() { + globalState.inBatch++; +} +function endBatch() { + if (--globalState.inBatch === 0) { + runReactions(); + var list = globalState.pendingUnobservations; + for (var i = 0; i < list.length; i++) { + var observable2 = list[i]; + observable2.isPendingUnobservation = false; + if (observable2.observers_.size === 0) { + if (observable2.isBeingObserved) { + observable2.isBeingObserved = false; + observable2.onBUO(); + } + if (observable2 instanceof ComputedValue) { + observable2.suspend_(); + } + } + } + globalState.pendingUnobservations = []; + } +} +function reportObserved(observable2) { + var derivation = globalState.trackingDerivation; + if (derivation !== null) { + if (derivation.runId_ !== observable2.lastAccessedBy_) { + observable2.lastAccessedBy_ = derivation.runId_; + derivation.newObserving_[derivation.unboundDepsCount_++] = observable2; + if (!observable2.isBeingObserved && globalState.trackingContext) { + observable2.isBeingObserved = true; + observable2.onBO(); + } + } + return observable2.isBeingObserved; + } else if (observable2.observers_.size === 0 && globalState.inBatch > 0) { + queueForUnobservation(observable2); + } + return false; +} +function propagateChanged(observable2) { + if (observable2.lowestObserverState_ === IDerivationState_.STALE_) { + return; + } + observable2.lowestObserverState_ = IDerivationState_.STALE_; + observable2.observers_.forEach(function(d) { + if (d.dependenciesState_ === IDerivationState_.UP_TO_DATE_) { + d.onBecomeStale_(); + } + d.dependenciesState_ = IDerivationState_.STALE_; + }); +} +function propagateChangeConfirmed(observable2) { + if (observable2.lowestObserverState_ === IDerivationState_.STALE_) { + return; + } + observable2.lowestObserverState_ = IDerivationState_.STALE_; + observable2.observers_.forEach(function(d) { + if (d.dependenciesState_ === IDerivationState_.POSSIBLY_STALE_) { + d.dependenciesState_ = IDerivationState_.STALE_; + } else if (d.dependenciesState_ === IDerivationState_.UP_TO_DATE_) { + observable2.lowestObserverState_ = IDerivationState_.UP_TO_DATE_; + } + }); +} +function propagateMaybeChanged(observable2) { + if (observable2.lowestObserverState_ !== IDerivationState_.UP_TO_DATE_) { + return; + } + observable2.lowestObserverState_ = IDerivationState_.POSSIBLY_STALE_; + observable2.observers_.forEach(function(d) { + if (d.dependenciesState_ === IDerivationState_.UP_TO_DATE_) { + d.dependenciesState_ = IDerivationState_.POSSIBLY_STALE_; + d.onBecomeStale_(); + } + }); +} +var Reaction = /* @__PURE__ */ (function() { + function Reaction2(name_, onInvalidate_, errorHandler_, requiresObservable_) { + if (name_ === void 0) { + name_ = "Reaction"; + } + this.name_ = void 0; + this.onInvalidate_ = void 0; + this.errorHandler_ = void 0; + this.requiresObservable_ = void 0; + this.observing_ = []; + this.newObserving_ = []; + this.dependenciesState_ = IDerivationState_.NOT_TRACKING_; + this.runId_ = 0; + this.unboundDepsCount_ = 0; + this.flags_ = 0; + this.isTracing_ = TraceMode.NONE; + this.name_ = name_; + this.onInvalidate_ = onInvalidate_; + this.errorHandler_ = errorHandler_; + this.requiresObservable_ = requiresObservable_; + } + var _proto = Reaction2.prototype; + _proto.onBecomeStale_ = function onBecomeStale_() { + this.schedule_(); + }; + _proto.schedule_ = function schedule_() { + if (!this.isScheduled) { + this.isScheduled = true; + globalState.pendingReactions.push(this); + runReactions(); + } + }; + _proto.runReaction_ = function runReaction_() { + if (!this.isDisposed) { + startBatch(); + this.isScheduled = false; + var prev = globalState.trackingContext; + globalState.trackingContext = this; + if (shouldCompute(this)) { + this.isTrackPending = true; + try { + this.onInvalidate_(); + if (false) ; + } catch (e) { + this.reportExceptionInDerivation_(e); + } + } + globalState.trackingContext = prev; + endBatch(); + } + }; + _proto.track = function track(fn) { + if (this.isDisposed) { + return; + } + startBatch(); + this.isRunning = true; + var prevReaction = globalState.trackingContext; + globalState.trackingContext = this; + var result = trackDerivedFunction(this, fn, void 0); + globalState.trackingContext = prevReaction; + this.isRunning = false; + this.isTrackPending = false; + if (this.isDisposed) { + clearObserving(this); + } + if (isCaughtException(result)) { + this.reportExceptionInDerivation_(result.cause); + } + endBatch(); + }; + _proto.reportExceptionInDerivation_ = function reportExceptionInDerivation_(error) { + var _this = this; + if (this.errorHandler_) { + this.errorHandler_(error, this); + return; + } + if (globalState.disableErrorBoundaries) { + throw error; + } + var message = "[mobx] uncaught error in '" + this + "'"; + if (!globalState.suppressReactionErrors) { + console.error(message, error); + } + globalState.globalReactionErrorHandlers.forEach(function(f) { + return f(error, _this); + }); + }; + _proto.dispose = function dispose() { + if (!this.isDisposed) { + this.isDisposed = true; + if (!this.isRunning) { + startBatch(); + clearObserving(this); + endBatch(); + } + } + }; + _proto.getDisposer_ = function getDisposer_(abortSignal) { + var _this2 = this; + var dispose = function dispose2() { + _this2.dispose(); + abortSignal == null || abortSignal.removeEventListener == null || abortSignal.removeEventListener("abort", dispose2); + }; + abortSignal == null || abortSignal.addEventListener == null || abortSignal.addEventListener("abort", dispose); + dispose[$mobx] = this; + if ("dispose" in Symbol && typeof Symbol.dispose === "symbol") { + dispose[Symbol.dispose] = dispose; + } + return dispose; + }; + _proto.toString = function toString2() { + return "Reaction[" + this.name_ + "]"; + }; + _proto.trace = function trace$1(enterBreakPoint) { + }; + return _createClass(Reaction2, [{ + key: "isDisposed", + get: function get4() { + return getFlag(this.flags_, Reaction2.isDisposedMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, Reaction2.isDisposedMask_, newValue); + } + }, { + key: "isScheduled", + get: function get4() { + return getFlag(this.flags_, Reaction2.isScheduledMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, Reaction2.isScheduledMask_, newValue); + } + }, { + key: "isTrackPending", + get: function get4() { + return getFlag(this.flags_, Reaction2.isTrackPendingMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, Reaction2.isTrackPendingMask_, newValue); + } + }, { + key: "isRunning", + get: function get4() { + return getFlag(this.flags_, Reaction2.isRunningMask_); + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, Reaction2.isRunningMask_, newValue); + } + }, { + key: "diffValue", + get: function get4() { + return getFlag(this.flags_, Reaction2.diffValueMask_) ? 1 : 0; + }, + set: function set5(newValue) { + this.flags_ = setFlag(this.flags_, Reaction2.diffValueMask_, newValue === 1 ? true : false); + } + }]); +})(); +Reaction.isDisposedMask_ = 1; +Reaction.isScheduledMask_ = 2; +Reaction.isTrackPendingMask_ = 4; +Reaction.isRunningMask_ = 8; +Reaction.diffValueMask_ = 16; +var MAX_REACTION_ITERATIONS = 100; +var reactionScheduler = function reactionScheduler2(f) { + return f(); +}; +function runReactions() { + if (globalState.inBatch > 0 || globalState.isRunningReactions) { + return; + } + reactionScheduler(runReactionsHelper); +} +function runReactionsHelper() { + globalState.isRunningReactions = true; + var allReactions = globalState.pendingReactions; + var iterations = 0; + while (allReactions.length > 0) { + if (++iterations === MAX_REACTION_ITERATIONS) { + console.error("[mobx] cycle in reaction: " + allReactions[0]); + allReactions.splice(0); + } + var remainingReactions = allReactions.splice(0); + for (var i = 0, l = remainingReactions.length; i < l; i++) { + remainingReactions[i].runReaction_(); + } + } + globalState.isRunningReactions = false; +} +var isReaction = /* @__PURE__ */ createInstanceofPredicate("Reaction", Reaction); +function isSpyEnabled() { + return false; +} +function spyReport(event) { + { + return; + } +} +function spyReportStart(event) { + { + return; + } +} +function spyReportEnd(change) { + { + return; + } +} +function spy(listener) { + { + console.warn("[mobx.spy] Is a no-op in production builds"); + return function() { + }; + } +} +var ACTION = "action"; +var ACTION_BOUND = "action.bound"; +var AUTOACTION = "autoAction"; +var AUTOACTION_BOUND = "autoAction.bound"; +var DEFAULT_ACTION_NAME = ""; +var actionAnnotation = /* @__PURE__ */ createActionAnnotation(ACTION); +var actionBoundAnnotation = /* @__PURE__ */ createActionAnnotation(ACTION_BOUND, { + bound: true +}); +var autoActionAnnotation = /* @__PURE__ */ createActionAnnotation(AUTOACTION, { + autoAction: true +}); +var autoActionBoundAnnotation = /* @__PURE__ */ createActionAnnotation(AUTOACTION_BOUND, { + autoAction: true, + bound: true +}); +function createActionFactory(autoAction2) { + var res = function action2(arg1, arg2) { + if (isFunction(arg1)) { + return createAction(arg1.name || DEFAULT_ACTION_NAME, arg1, autoAction2); + } + if (isFunction(arg2)) { + return createAction(arg1, arg2, autoAction2); + } + if (is20223Decorator(arg2)) { + return (autoAction2 ? autoActionAnnotation : actionAnnotation).decorate_20223_(arg1, arg2); + } + if (isStringish(arg2)) { + return storeAnnotation(arg1, arg2, autoAction2 ? autoActionAnnotation : actionAnnotation); + } + if (isStringish(arg1)) { + return createDecoratorAnnotation(createActionAnnotation(autoAction2 ? AUTOACTION : ACTION, { + name: arg1, + autoAction: autoAction2 + })); + } + }; + return res; +} +var action = /* @__PURE__ */ createActionFactory(false); +Object.assign(action, actionAnnotation); +var autoAction = /* @__PURE__ */ createActionFactory(true); +Object.assign(autoAction, autoActionAnnotation); +action.bound = /* @__PURE__ */ createDecoratorAnnotation(actionBoundAnnotation); +autoAction.bound = /* @__PURE__ */ createDecoratorAnnotation(autoActionBoundAnnotation); +function runInAction(fn) { + return executeAction(fn.name || DEFAULT_ACTION_NAME, false, fn, this, void 0); +} +function isAction(thing) { + return isFunction(thing) && thing.isMobxAction === true; +} +function autorun(view, opts) { + var _opts$name, _opts, _opts2, _opts3; + if (opts === void 0) { + opts = EMPTY_OBJECT; + } + var name = (_opts$name = (_opts = opts) == null ? void 0 : _opts.name) != null ? _opts$name : "Autorun"; + var runSync = !opts.scheduler && !opts.delay; + var reaction2; + if (runSync) { + reaction2 = new Reaction(name, function() { + this.track(reactionRunner); + }, opts.onError, opts.requiresObservable); + } else { + var scheduler = createSchedulerFromOptions(opts); + var isScheduled = false; + reaction2 = new Reaction(name, function() { + if (!isScheduled) { + isScheduled = true; + scheduler(function() { + isScheduled = false; + if (!reaction2.isDisposed) { + reaction2.track(reactionRunner); + } + }); + } + }, opts.onError, opts.requiresObservable); + } + function reactionRunner() { + view(reaction2); + } + if (!((_opts2 = opts) != null && (_opts2 = _opts2.signal) != null && _opts2.aborted)) { + reaction2.schedule_(); + } + return reaction2.getDisposer_((_opts3 = opts) == null ? void 0 : _opts3.signal); +} +var run = function run2(f) { + return f(); +}; +function createSchedulerFromOptions(opts) { + return opts.scheduler ? opts.scheduler : opts.delay ? function(f) { + return setTimeout(f, opts.delay); + } : run; +} +function reaction(expression, effect, opts) { + var _opts$name2, _opts4, _opts5; + if (opts === void 0) { + opts = EMPTY_OBJECT; + } + var name = (_opts$name2 = opts.name) != null ? _opts$name2 : "Reaction"; + var effectAction = action(name, opts.onError ? wrapErrorHandler(opts.onError, effect) : effect); + var runSync = !opts.scheduler && !opts.delay; + var scheduler = createSchedulerFromOptions(opts); + var firstTime = true; + var isScheduled = false; + var value; + var equals = opts.compareStructural ? comparer.structural : opts.equals || comparer["default"]; + var r = new Reaction(name, function() { + if (firstTime || runSync) { + reactionRunner(); + } else if (!isScheduled) { + isScheduled = true; + scheduler(reactionRunner); + } + }, opts.onError, opts.requiresObservable); + function reactionRunner() { + isScheduled = false; + if (r.isDisposed) { + return; + } + var changed = false; + var oldValue = value; + r.track(function() { + var nextValue = allowStateChanges(false, function() { + return expression(r); + }); + changed = firstTime || !equals(value, nextValue); + value = nextValue; + }); + if (firstTime && opts.fireImmediately) { + effectAction(value, oldValue, r); + } else if (!firstTime && changed) { + effectAction(value, oldValue, r); + } + firstTime = false; + } + if (!((_opts4 = opts) != null && (_opts4 = _opts4.signal) != null && _opts4.aborted)) { + r.schedule_(); + } + return r.getDisposer_((_opts5 = opts) == null ? void 0 : _opts5.signal); +} +function wrapErrorHandler(errorHandler, baseFn) { + return function() { + try { + return baseFn.apply(this, arguments); + } catch (e) { + errorHandler.call(this, e); + } + }; +} +var ON_BECOME_OBSERVED = "onBO"; +var ON_BECOME_UNOBSERVED = "onBUO"; +function onBecomeObserved(thing, arg2, arg3) { + return interceptHook(ON_BECOME_OBSERVED, thing, arg2, arg3); +} +function onBecomeUnobserved(thing, arg2, arg3) { + return interceptHook(ON_BECOME_UNOBSERVED, thing, arg2, arg3); +} +function interceptHook(hook, thing, arg2, arg3) { + var atom = getAtom(thing); + var cb = isFunction(arg3) ? arg3 : arg2; + var listenersKey = hook + "L"; + if (atom[listenersKey]) { + atom[listenersKey].add(cb); + } else { + atom[listenersKey] = /* @__PURE__ */ new Set([cb]); + } + return function() { + var hookListeners = atom[listenersKey]; + if (hookListeners) { + hookListeners["delete"](cb); + if (hookListeners.size === 0) { + delete atom[listenersKey]; + } + } + }; +} +function extendObservable(target, properties, annotations, options) { + var descriptors = getOwnPropertyDescriptors(properties); + initObservable(function() { + var adm = asObservableObject(target, options)[$mobx]; + ownKeys(descriptors).forEach(function(key) { + adm.extend_( + key, + descriptors[key], + // must pass "undefined" for { key: undefined } + !annotations ? true : key in annotations ? annotations[key] : true + ); + }); + }); + return target; +} +var generatorId = 0; +function FlowCancellationError() { + this.message = "FLOW_CANCELLED"; +} +FlowCancellationError.prototype = /* @__PURE__ */ Object.create(Error.prototype); +var flowAnnotation = /* @__PURE__ */ createFlowAnnotation("flow"); +var flowBoundAnnotation = /* @__PURE__ */ createFlowAnnotation("flow.bound", { + bound: true +}); +var flow = /* @__PURE__ */ Object.assign(function flow2(arg1, arg2) { + if (is20223Decorator(arg2)) { + return flowAnnotation.decorate_20223_(arg1, arg2); + } + if (isStringish(arg2)) { + return storeAnnotation(arg1, arg2, flowAnnotation); + } + var generator = arg1; + var name = generator.name || ""; + var res = function res2() { + var ctx = this; + var args = arguments; + var runId = ++generatorId; + var gen = action(name + " - runid: " + runId + " - init", generator).apply(ctx, args); + var rejector; + var pendingPromise = void 0; + var promise = new Promise(function(resolve, reject) { + var stepId = 0; + rejector = reject; + function onFulfilled(res3) { + pendingPromise = void 0; + var ret; + try { + ret = action(name + " - runid: " + runId + " - yield " + stepId++, gen.next).call(gen, res3); + } catch (e) { + return reject(e); + } + next(ret); + } + function onRejected(err) { + pendingPromise = void 0; + var ret; + try { + ret = action(name + " - runid: " + runId + " - yield " + stepId++, gen["throw"]).call(gen, err); + } catch (e) { + return reject(e); + } + next(ret); + } + function next(ret) { + if (isFunction(ret == null ? void 0 : ret.then)) { + ret.then(next, reject); + return; + } + if (ret.done) { + return resolve(ret.value); + } + pendingPromise = Promise.resolve(ret.value); + return pendingPromise.then(onFulfilled, onRejected); + } + onFulfilled(void 0); + }); + promise.cancel = action(name + " - runid: " + runId + " - cancel", function() { + try { + if (pendingPromise) { + cancelPromise(pendingPromise); + } + var _res = gen["return"](void 0); + var yieldedPromise = Promise.resolve(_res.value); + yieldedPromise.then(noop, noop); + cancelPromise(yieldedPromise); + rejector(new FlowCancellationError()); + } catch (e) { + rejector(e); + } + }); + return promise; + }; + res.isMobXFlow = true; + return res; +}, flowAnnotation); +flow.bound = /* @__PURE__ */ createDecoratorAnnotation(flowBoundAnnotation); +function cancelPromise(promise) { + if (isFunction(promise.cancel)) { + promise.cancel(); + } +} +function isFlow(fn) { + return (fn == null ? void 0 : fn.isMobXFlow) === true; +} +function _isObservable(value, property) { + if (!value) { + return false; + } + return isObservableObject(value) || !!value[$mobx] || isAtom(value) || isReaction(value) || isComputedValue(value); +} +function isObservable(value) { + return _isObservable(value); +} +function transaction(action2, thisArg) { + if (thisArg === void 0) { + thisArg = void 0; + } + startBatch(); + try { + return action2.apply(thisArg); + } finally { + endBatch(); + } +} +function getAdm(target) { + return target[$mobx]; +} +var objectProxyTraps = { + has: function has2(target, name) { + return getAdm(target).has_(name); + }, + get: function get2(target, name) { + return getAdm(target).get_(name); + }, + set: function set3(target, name, value) { + var _getAdm$set_; + if (!isStringish(name)) { + return false; + } + return (_getAdm$set_ = getAdm(target).set_(name, value, true)) != null ? _getAdm$set_ : true; + }, + deleteProperty: function deleteProperty(target, name) { + var _getAdm$delete_; + if (!isStringish(name)) { + return false; + } + return (_getAdm$delete_ = getAdm(target).delete_(name, true)) != null ? _getAdm$delete_ : true; + }, + defineProperty: function defineProperty2(target, name, descriptor) { + var _getAdm$definePropert; + return (_getAdm$definePropert = getAdm(target).defineProperty_(name, descriptor)) != null ? _getAdm$definePropert : true; + }, + ownKeys: function ownKeys2(target) { + return getAdm(target).ownKeys_(); + }, + preventExtensions: function preventExtensions(target) { + die(13); + } +}; +function asDynamicObservableObject(target, options) { + var _target$$mobx, _target$$mobx$proxy_; + assertProxies(); + target = asObservableObject(target, options); + return (_target$$mobx$proxy_ = (_target$$mobx = target[$mobx]).proxy_) != null ? _target$$mobx$proxy_ : _target$$mobx.proxy_ = new Proxy(target, objectProxyTraps); +} +function hasInterceptors(interceptable) { + return interceptable.interceptors_ !== void 0 && interceptable.interceptors_.length > 0; +} +function registerInterceptor(interceptable, handler) { + var interceptors = interceptable.interceptors_ || (interceptable.interceptors_ = []); + interceptors.push(handler); + return once(function() { + var idx = interceptors.indexOf(handler); + if (idx !== -1) { + interceptors.splice(idx, 1); + } + }); +} +function interceptChange(interceptable, change) { + var prevU = untrackedStart(); + try { + var interceptors = [].concat(interceptable.interceptors_ || []); + for (var i = 0, l = interceptors.length; i < l; i++) { + change = interceptors[i](change); + if (change && !change.type) { + die(14); + } + if (!change) { + break; + } + } + return change; + } finally { + untrackedEnd(prevU); + } +} +function hasListeners(listenable) { + return listenable.changeListeners_ !== void 0 && listenable.changeListeners_.length > 0; +} +function registerListener(listenable, handler) { + var listeners = listenable.changeListeners_ || (listenable.changeListeners_ = []); + listeners.push(handler); + return once(function() { + var idx = listeners.indexOf(handler); + if (idx !== -1) { + listeners.splice(idx, 1); + } + }); +} +function notifyListeners(listenable, change) { + var prevU = untrackedStart(); + var listeners = listenable.changeListeners_; + if (!listeners) { + return; + } + listeners = listeners.slice(); + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i](change); + } + untrackedEnd(prevU); +} +var keysSymbol = /* @__PURE__ */ Symbol("mobx-keys"); +function makeAutoObservable(target, overrides, options) { + if (isPlainObject(target)) { + return extendObservable(target, target, overrides, options); + } + initObservable(function() { + var adm = asObservableObject(target, options)[$mobx]; + if (!target[keysSymbol]) { + var proto = Object.getPrototypeOf(target); + var keys2 = new Set([].concat(ownKeys(target), ownKeys(proto))); + keys2["delete"]("constructor"); + keys2["delete"]($mobx); + addHiddenProp(proto, keysSymbol, keys2); + } + target[keysSymbol].forEach(function(key) { + return adm.make_( + key, + // must pass "undefined" for { key: undefined } + !overrides ? true : key in overrides ? overrides[key] : true + ); + }); + }); + return target; +} +var SPLICE = "splice"; +var UPDATE = "update"; +var MAX_SPLICE_SIZE = 1e4; +var arrayTraps = { + get: function get3(target, name) { + var adm = target[$mobx]; + if (name === $mobx) { + return adm; + } + if (name === "length") { + return adm.getArrayLength_(); + } + if (typeof name === "string" && !isNaN(name)) { + return adm.get_(parseInt(name)); + } + if (hasProp(arrayExtensions, name)) { + return arrayExtensions[name]; + } + return target[name]; + }, + set: function set4(target, name, value) { + var adm = target[$mobx]; + if (name === "length") { + adm.setArrayLength_(value); + } + if (typeof name === "symbol" || isNaN(name)) { + target[name] = value; + } else { + adm.set_(parseInt(name), value); + } + return true; + }, + preventExtensions: function preventExtensions2() { + die(15); + } +}; +var ObservableArrayAdministration = /* @__PURE__ */ (function() { + function ObservableArrayAdministration2(name, enhancer, owned_, legacyMode_) { + if (name === void 0) { + name = "ObservableArray"; + } + this.owned_ = void 0; + this.legacyMode_ = void 0; + this.atom_ = void 0; + this.values_ = []; + this.interceptors_ = void 0; + this.changeListeners_ = void 0; + this.enhancer_ = void 0; + this.dehancer = void 0; + this.proxy_ = void 0; + this.lastKnownLength_ = 0; + this.owned_ = owned_; + this.legacyMode_ = legacyMode_; + this.atom_ = new Atom(name); + this.enhancer_ = function(newV, oldV) { + return enhancer(newV, oldV, "ObservableArray[..]"); + }; + } + var _proto = ObservableArrayAdministration2.prototype; + _proto.dehanceValue_ = function dehanceValue_(value) { + if (this.dehancer !== void 0) { + return this.dehancer(value); + } + return value; + }; + _proto.dehanceValues_ = function dehanceValues_(values2) { + if (this.dehancer !== void 0 && values2.length > 0) { + return values2.map(this.dehancer); + } + return values2; + }; + _proto.intercept_ = function intercept_(handler) { + return registerInterceptor(this, handler); + }; + _proto.observe_ = function observe_(listener, fireImmediately) { + if (fireImmediately === void 0) { + fireImmediately = false; + } + if (fireImmediately) { + listener({ + observableKind: "array", + object: this.proxy_, + debugObjectName: this.atom_.name_, + type: "splice", + index: 0, + added: this.values_.slice(), + addedCount: this.values_.length, + removed: [], + removedCount: 0 + }); + } + return registerListener(this, listener); + }; + _proto.getArrayLength_ = function getArrayLength_() { + this.atom_.reportObserved(); + return this.values_.length; + }; + _proto.setArrayLength_ = function setArrayLength_(newLength) { + if (typeof newLength !== "number" || isNaN(newLength) || newLength < 0) { + die("Out of range: " + newLength); + } + var currentLength = this.values_.length; + if (newLength === currentLength) { + return; + } else if (newLength > currentLength) { + var newItems = new Array(newLength - currentLength); + for (var i = 0; i < newLength - currentLength; i++) { + newItems[i] = void 0; + } + this.spliceWithArray_(currentLength, 0, newItems); + } else { + this.spliceWithArray_(newLength, currentLength - newLength); + } + }; + _proto.updateArrayLength_ = function updateArrayLength_(oldLength, delta) { + if (oldLength !== this.lastKnownLength_) { + die(16); + } + this.lastKnownLength_ += delta; + if (this.legacyMode_ && delta > 0) { + reserveArrayBuffer(oldLength + delta + 1); + } + }; + _proto.spliceWithArray_ = function spliceWithArray_(index, deleteCount, newItems) { + var _this = this; + checkIfStateModificationsAreAllowed(this.atom_); + var length = this.values_.length; + if (index === void 0) { + index = 0; + } else if (index > length) { + index = length; + } else if (index < 0) { + index = Math.max(0, length + index); + } + if (arguments.length === 1) { + deleteCount = length - index; + } else if (deleteCount === void 0 || deleteCount === null) { + deleteCount = 0; + } else { + deleteCount = Math.max(0, Math.min(deleteCount, length - index)); + } + if (newItems === void 0) { + newItems = EMPTY_ARRAY; + } + if (hasInterceptors(this)) { + var change = interceptChange(this, { + object: this.proxy_, + type: SPLICE, + index, + removedCount: deleteCount, + added: newItems + }); + if (!change) { + return EMPTY_ARRAY; + } + deleteCount = change.removedCount; + newItems = change.added; + } + newItems = newItems.length === 0 ? newItems : newItems.map(function(v) { + return _this.enhancer_(v, void 0); + }); + if (this.legacyMode_ || false) { + var lengthDelta = newItems.length - deleteCount; + this.updateArrayLength_(length, lengthDelta); + } + var res = this.spliceItemsIntoValues_(index, deleteCount, newItems); + if (deleteCount !== 0 || newItems.length !== 0) { + this.notifyArraySplice_(index, newItems, res); + } + return this.dehanceValues_(res); + }; + _proto.spliceItemsIntoValues_ = function spliceItemsIntoValues_(index, deleteCount, newItems) { + if (newItems.length < MAX_SPLICE_SIZE) { + var _this$values_; + return (_this$values_ = this.values_).splice.apply(_this$values_, [index, deleteCount].concat(newItems)); + } else { + var res = this.values_.slice(index, index + deleteCount); + var oldItems = this.values_.slice(index + deleteCount); + this.values_.length += newItems.length - deleteCount; + for (var i = 0; i < newItems.length; i++) { + this.values_[index + i] = newItems[i]; + } + for (var _i = 0; _i < oldItems.length; _i++) { + this.values_[index + newItems.length + _i] = oldItems[_i]; + } + return res; + } + }; + _proto.notifyArrayChildUpdate_ = function notifyArrayChildUpdate_(index, newValue, oldValue) { + var notifySpy = !this.owned_ && isSpyEnabled(); + var notify = hasListeners(this); + var change = notify || notifySpy ? { + observableKind: "array", + object: this.proxy_, + type: UPDATE, + debugObjectName: this.atom_.name_, + index, + newValue, + oldValue + } : null; + this.atom_.reportChanged(); + if (notify) { + notifyListeners(this, change); + } + }; + _proto.notifyArraySplice_ = function notifyArraySplice_(index, added, removed) { + var notifySpy = !this.owned_ && isSpyEnabled(); + var notify = hasListeners(this); + var change = notify || notifySpy ? { + observableKind: "array", + object: this.proxy_, + debugObjectName: this.atom_.name_, + type: SPLICE, + index, + removed, + added, + removedCount: removed.length, + addedCount: added.length + } : null; + this.atom_.reportChanged(); + if (notify) { + notifyListeners(this, change); + } + }; + _proto.get_ = function get_(index) { + if (this.legacyMode_ && index >= this.values_.length) { + console.warn("[mobx] Out of bounds read: " + index); + return void 0; + } + this.atom_.reportObserved(); + return this.dehanceValue_(this.values_[index]); + }; + _proto.set_ = function set_(index, newValue) { + var values2 = this.values_; + if (this.legacyMode_ && index > values2.length) { + die(17, index, values2.length); + } + if (index < values2.length) { + checkIfStateModificationsAreAllowed(this.atom_); + var oldValue = values2[index]; + if (hasInterceptors(this)) { + var change = interceptChange(this, { + type: UPDATE, + object: this.proxy_, + // since "this" is the real array we need to pass its proxy + index, + newValue + }); + if (!change) { + return; + } + newValue = change.newValue; + } + newValue = this.enhancer_(newValue, oldValue); + var changed = newValue !== oldValue; + if (changed) { + values2[index] = newValue; + this.notifyArrayChildUpdate_(index, newValue, oldValue); + } + } else { + var newItems = new Array(index + 1 - values2.length); + for (var i = 0; i < newItems.length - 1; i++) { + newItems[i] = void 0; + } + newItems[newItems.length - 1] = newValue; + this.spliceWithArray_(values2.length, 0, newItems); + } + }; + return ObservableArrayAdministration2; +})(); +function createObservableArray(initialValues, enhancer, name, owned) { + if (name === void 0) { + name = "ObservableArray"; + } + if (owned === void 0) { + owned = false; + } + assertProxies(); + return initObservable(function() { + var adm = new ObservableArrayAdministration(name, enhancer, owned, false); + addHiddenFinalProp(adm.values_, $mobx, adm); + var proxy = new Proxy(adm.values_, arrayTraps); + adm.proxy_ = proxy; + if (initialValues && initialValues.length) { + adm.spliceWithArray_(0, 0, initialValues); + } + return proxy; + }); +} +var arrayExtensions = { + clear: function clear() { + return this.splice(0); + }, + replace: function replace(newItems) { + var adm = this[$mobx]; + return adm.spliceWithArray_(0, adm.values_.length, newItems); + }, + // Used by JSON.stringify + toJSON: function toJSON() { + return this.slice(); + }, + /* + * functions that do alter the internal structure of the array, (based on lib.es6.d.ts) + * since these functions alter the inner structure of the array, the have side effects. + * Because the have side effects, they should not be used in computed function, + * and for that reason the do not call dependencyState.notifyObserved + */ + splice: function splice(index, deleteCount) { + for (var _len = arguments.length, newItems = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + newItems[_key - 2] = arguments[_key]; + } + var adm = this[$mobx]; + switch (arguments.length) { + case 0: + return []; + case 1: + return adm.spliceWithArray_(index); + case 2: + return adm.spliceWithArray_(index, deleteCount); + } + return adm.spliceWithArray_(index, deleteCount, newItems); + }, + spliceWithArray: function spliceWithArray(index, deleteCount, newItems) { + return this[$mobx].spliceWithArray_(index, deleteCount, newItems); + }, + push: function push() { + var adm = this[$mobx]; + for (var _len2 = arguments.length, items = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + items[_key2] = arguments[_key2]; + } + adm.spliceWithArray_(adm.values_.length, 0, items); + return adm.values_.length; + }, + pop: function pop() { + return this.splice(Math.max(this[$mobx].values_.length - 1, 0), 1)[0]; + }, + shift: function shift() { + return this.splice(0, 1)[0]; + }, + unshift: function unshift() { + var adm = this[$mobx]; + for (var _len3 = arguments.length, items = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + items[_key3] = arguments[_key3]; + } + adm.spliceWithArray_(0, 0, items); + return adm.values_.length; + }, + reverse: function reverse() { + if (globalState.trackingDerivation) { + die(37, "reverse"); + } + this.replace(this.slice().reverse()); + return this; + }, + sort: function sort() { + if (globalState.trackingDerivation) { + die(37, "sort"); + } + var copy = this.slice(); + copy.sort.apply(copy, arguments); + this.replace(copy); + return this; + }, + remove: function remove2(value) { + var adm = this[$mobx]; + var idx = adm.dehanceValues_(adm.values_).indexOf(value); + if (idx > -1) { + this.splice(idx, 1); + return true; + } + return false; + } +}; +addArrayExtension("at", simpleFunc); +addArrayExtension("concat", simpleFunc); +addArrayExtension("flat", simpleFunc); +addArrayExtension("includes", simpleFunc); +addArrayExtension("indexOf", simpleFunc); +addArrayExtension("join", simpleFunc); +addArrayExtension("lastIndexOf", simpleFunc); +addArrayExtension("slice", simpleFunc); +addArrayExtension("toString", simpleFunc); +addArrayExtension("toLocaleString", simpleFunc); +addArrayExtension("toSorted", simpleFunc); +addArrayExtension("toSpliced", simpleFunc); +addArrayExtension("with", simpleFunc); +addArrayExtension("every", mapLikeFunc); +addArrayExtension("filter", mapLikeFunc); +addArrayExtension("find", mapLikeFunc); +addArrayExtension("findIndex", mapLikeFunc); +addArrayExtension("findLast", mapLikeFunc); +addArrayExtension("findLastIndex", mapLikeFunc); +addArrayExtension("flatMap", mapLikeFunc); +addArrayExtension("forEach", mapLikeFunc); +addArrayExtension("map", mapLikeFunc); +addArrayExtension("some", mapLikeFunc); +addArrayExtension("toReversed", mapLikeFunc); +addArrayExtension("reduce", reduceLikeFunc); +addArrayExtension("reduceRight", reduceLikeFunc); +function addArrayExtension(funcName, funcFactory) { + if (typeof Array.prototype[funcName] === "function") { + arrayExtensions[funcName] = funcFactory(funcName); + } +} +function simpleFunc(funcName) { + return function() { + var adm = this[$mobx]; + adm.atom_.reportObserved(); + var dehancedValues = adm.dehanceValues_(adm.values_); + return dehancedValues[funcName].apply(dehancedValues, arguments); + }; +} +function mapLikeFunc(funcName) { + return function(callback, thisArg) { + var _this2 = this; + var adm = this[$mobx]; + adm.atom_.reportObserved(); + var dehancedValues = adm.dehanceValues_(adm.values_); + return dehancedValues[funcName](function(element, index) { + return callback.call(thisArg, element, index, _this2); + }); + }; +} +function reduceLikeFunc(funcName) { + return function() { + var _this3 = this; + var adm = this[$mobx]; + adm.atom_.reportObserved(); + var dehancedValues = adm.dehanceValues_(adm.values_); + var callback = arguments[0]; + arguments[0] = function(accumulator, currentValue, index) { + return callback(accumulator, currentValue, index, _this3); + }; + return dehancedValues[funcName].apply(dehancedValues, arguments); + }; +} +var isObservableArrayAdministration = /* @__PURE__ */ createInstanceofPredicate("ObservableArrayAdministration", ObservableArrayAdministration); +function isObservableArray(thing) { + return isObject(thing) && isObservableArrayAdministration(thing[$mobx]); +} +var ObservableMapMarker = {}; +var ADD = "add"; +var DELETE = "delete"; +var ObservableMap = /* @__PURE__ */ (function() { + function ObservableMap2(initialData, enhancer_, name_) { + var _this = this; + if (enhancer_ === void 0) { + enhancer_ = deepEnhancer; + } + if (name_ === void 0) { + name_ = "ObservableMap"; + } + this.enhancer_ = void 0; + this.name_ = void 0; + this[$mobx] = ObservableMapMarker; + this.data_ = void 0; + this.hasMap_ = void 0; + this.keysAtom_ = void 0; + this.interceptors_ = void 0; + this.changeListeners_ = void 0; + this.dehancer = void 0; + this.enhancer_ = enhancer_; + this.name_ = name_; + if (!isFunction(Map)) { + die(18); + } + initObservable(function() { + _this.keysAtom_ = createAtom(false ? _this.name_ + ".keys()" : "ObservableMap.keys()"); + _this.data_ = /* @__PURE__ */ new Map(); + _this.hasMap_ = /* @__PURE__ */ new Map(); + if (initialData) { + _this.merge(initialData); + } + }); + } + var _proto = ObservableMap2.prototype; + _proto.has_ = function has_(key) { + return this.data_.has(key); + }; + _proto.has = function has3(key) { + var _this2 = this; + if (!globalState.trackingDerivation) { + return this.has_(key); + } + var entry = this.hasMap_.get(key); + if (!entry) { + var newEntry = entry = new ObservableValue(this.has_(key), referenceEnhancer, "ObservableMap.key?", false); + this.hasMap_.set(key, newEntry); + onBecomeUnobserved(newEntry, function() { + return _this2.hasMap_["delete"](key); + }); + } + return entry.get(); + }; + _proto.set = function set5(key, value) { + var hasKey = this.has_(key); + if (hasInterceptors(this)) { + var change = interceptChange(this, { + type: hasKey ? UPDATE : ADD, + object: this, + newValue: value, + name: key + }); + if (!change) { + return this; + } + value = change.newValue; + } + if (hasKey) { + this.updateValue_(key, value); + } else { + this.addValue_(key, value); + } + return this; + }; + _proto["delete"] = function _delete(key) { + var _this3 = this; + checkIfStateModificationsAreAllowed(this.keysAtom_); + if (hasInterceptors(this)) { + var change = interceptChange(this, { + type: DELETE, + object: this, + name: key + }); + if (!change) { + return false; + } + } + if (this.has_(key)) { + var notifySpy = isSpyEnabled(); + var notify = hasListeners(this); + var _change = notify || notifySpy ? { + observableKind: "map", + debugObjectName: this.name_, + type: DELETE, + object: this, + oldValue: this.data_.get(key).value_, + name: key + } : null; + transaction(function() { + var _this3$hasMap_$get; + _this3.keysAtom_.reportChanged(); + (_this3$hasMap_$get = _this3.hasMap_.get(key)) == null || _this3$hasMap_$get.setNewValue_(false); + var observable2 = _this3.data_.get(key); + observable2.setNewValue_(void 0); + _this3.data_["delete"](key); + }); + if (notify) { + notifyListeners(this, _change); + } + return true; + } + return false; + }; + _proto.updateValue_ = function updateValue_(key, newValue) { + var observable2 = this.data_.get(key); + newValue = observable2.prepareNewValue_(newValue); + if (newValue !== globalState.UNCHANGED) { + var notifySpy = isSpyEnabled(); + var notify = hasListeners(this); + var change = notify || notifySpy ? { + observableKind: "map", + debugObjectName: this.name_, + type: UPDATE, + object: this, + oldValue: observable2.value_, + name: key, + newValue + } : null; + observable2.setNewValue_(newValue); + if (notify) { + notifyListeners(this, change); + } + } + }; + _proto.addValue_ = function addValue_(key, newValue) { + var _this4 = this; + checkIfStateModificationsAreAllowed(this.keysAtom_); + transaction(function() { + var _this4$hasMap_$get; + var observable2 = new ObservableValue(newValue, _this4.enhancer_, "ObservableMap.key", false); + _this4.data_.set(key, observable2); + newValue = observable2.value_; + (_this4$hasMap_$get = _this4.hasMap_.get(key)) == null || _this4$hasMap_$get.setNewValue_(true); + _this4.keysAtom_.reportChanged(); + }); + var notifySpy = isSpyEnabled(); + var notify = hasListeners(this); + var change = notify || notifySpy ? { + observableKind: "map", + debugObjectName: this.name_, + type: ADD, + object: this, + name: key, + newValue + } : null; + if (notify) { + notifyListeners(this, change); + } + }; + _proto.get = function get4(key) { + if (this.has(key)) { + return this.dehanceValue_(this.data_.get(key).get()); + } + return this.dehanceValue_(void 0); + }; + _proto.dehanceValue_ = function dehanceValue_(value) { + if (this.dehancer !== void 0) { + return this.dehancer(value); + } + return value; + }; + _proto.keys = function keys2() { + this.keysAtom_.reportObserved(); + return this.data_.keys(); + }; + _proto.values = function values2() { + var self2 = this; + var keys2 = this.keys(); + return makeIterableForMap({ + next: function next() { + var _keys$next = keys2.next(), done = _keys$next.done, value = _keys$next.value; + return { + done, + value: done ? void 0 : self2.get(value) + }; + } + }); + }; + _proto.entries = function entries2() { + var self2 = this; + var keys2 = this.keys(); + return makeIterableForMap({ + next: function next() { + var _keys$next2 = keys2.next(), done = _keys$next2.done, value = _keys$next2.value; + return { + done, + value: done ? void 0 : [value, self2.get(value)] + }; + } + }); + }; + _proto[Symbol.iterator] = function() { + return this.entries(); + }; + _proto.forEach = function forEach(callback, thisArg) { + for (var _iterator = _createForOfIteratorHelperLoose(this), _step; !(_step = _iterator()).done; ) { + var _step$value = _step.value, key = _step$value[0], value = _step$value[1]; + callback.call(thisArg, value, key, this); + } + }; + _proto.merge = function merge(other) { + var _this5 = this; + if (isObservableMap(other)) { + other = new Map(other); + } + transaction(function() { + if (isPlainObject(other)) { + getPlainObjectKeys(other).forEach(function(key) { + return _this5.set(key, other[key]); + }); + } else if (Array.isArray(other)) { + other.forEach(function(_ref) { + var key = _ref[0], value = _ref[1]; + return _this5.set(key, value); + }); + } else if (isES6Map(other)) { + if (!isPlainES6Map(other)) { + die(19, other); + } + other.forEach(function(value, key) { + return _this5.set(key, value); + }); + } else if (other !== null && other !== void 0) { + die(20, other); + } + }); + return this; + }; + _proto.clear = function clear2() { + var _this6 = this; + transaction(function() { + untracked(function() { + for (var _iterator2 = _createForOfIteratorHelperLoose(_this6.keys()), _step2; !(_step2 = _iterator2()).done; ) { + var key = _step2.value; + _this6["delete"](key); + } + }); + }); + }; + _proto.replace = function replace2(values2) { + var _this7 = this; + transaction(function() { + var replacementMap = convertToMap(values2); + var orderedData = /* @__PURE__ */ new Map(); + var keysReportChangedCalled = false; + for (var _iterator3 = _createForOfIteratorHelperLoose(_this7.data_.keys()), _step3; !(_step3 = _iterator3()).done; ) { + var key = _step3.value; + if (!replacementMap.has(key)) { + var deleted = _this7["delete"](key); + if (deleted) { + keysReportChangedCalled = true; + } else { + var value = _this7.data_.get(key); + orderedData.set(key, value); + } + } + } + for (var _iterator4 = _createForOfIteratorHelperLoose(replacementMap.entries()), _step4; !(_step4 = _iterator4()).done; ) { + var _step4$value = _step4.value, _key = _step4$value[0], _value = _step4$value[1]; + var keyExisted = _this7.data_.has(_key); + _this7.set(_key, _value); + if (_this7.data_.has(_key)) { + var _value2 = _this7.data_.get(_key); + orderedData.set(_key, _value2); + if (!keyExisted) { + keysReportChangedCalled = true; + } + } + } + if (!keysReportChangedCalled) { + if (_this7.data_.size !== orderedData.size) { + _this7.keysAtom_.reportChanged(); + } else { + var iter1 = _this7.data_.keys(); + var iter2 = orderedData.keys(); + var next1 = iter1.next(); + var next2 = iter2.next(); + while (!next1.done) { + if (next1.value !== next2.value) { + _this7.keysAtom_.reportChanged(); + break; + } + next1 = iter1.next(); + next2 = iter2.next(); + } + } + } + _this7.data_ = orderedData; + }); + return this; + }; + _proto.toString = function toString2() { + return "[object ObservableMap]"; + }; + _proto.toJSON = function toJSON2() { + return Array.from(this); + }; + _proto.observe_ = function observe_(listener, fireImmediately) { + return registerListener(this, listener); + }; + _proto.intercept_ = function intercept_(handler) { + return registerInterceptor(this, handler); + }; + return _createClass(ObservableMap2, [{ + key: "size", + get: function get4() { + this.keysAtom_.reportObserved(); + return this.data_.size; + } + }, { + key: Symbol.toStringTag, + get: function get4() { + return "Map"; + } + }]); +})(); +var isObservableMap = /* @__PURE__ */ createInstanceofPredicate("ObservableMap", ObservableMap); +function makeIterableForMap(iterator) { + iterator[Symbol.toStringTag] = "MapIterator"; + return makeIterable(iterator); +} +function convertToMap(dataStructure) { + if (isES6Map(dataStructure) || isObservableMap(dataStructure)) { + return dataStructure; + } else if (Array.isArray(dataStructure)) { + return new Map(dataStructure); + } else if (isPlainObject(dataStructure)) { + var map2 = /* @__PURE__ */ new Map(); + for (var key in dataStructure) { + map2.set(key, dataStructure[key]); + } + return map2; + } else { + return die(21, dataStructure); + } +} +var ObservableSetMarker = {}; +var ObservableSet = /* @__PURE__ */ (function() { + function ObservableSet2(initialData, enhancer, name_) { + var _this = this; + if (enhancer === void 0) { + enhancer = deepEnhancer; + } + if (name_ === void 0) { + name_ = "ObservableSet"; + } + this.name_ = void 0; + this[$mobx] = ObservableSetMarker; + this.data_ = /* @__PURE__ */ new Set(); + this.atom_ = void 0; + this.changeListeners_ = void 0; + this.interceptors_ = void 0; + this.dehancer = void 0; + this.enhancer_ = void 0; + this.name_ = name_; + if (!isFunction(Set)) { + die(22); + } + this.enhancer_ = function(newV, oldV) { + return enhancer(newV, oldV, name_); + }; + initObservable(function() { + _this.atom_ = createAtom(_this.name_); + if (initialData) { + _this.replace(initialData); + } + }); + } + var _proto = ObservableSet2.prototype; + _proto.dehanceValue_ = function dehanceValue_(value) { + if (this.dehancer !== void 0) { + return this.dehancer(value); + } + return value; + }; + _proto.clear = function clear2() { + var _this2 = this; + transaction(function() { + untracked(function() { + for (var _iterator = _createForOfIteratorHelperLoose(_this2.data_.values()), _step; !(_step = _iterator()).done; ) { + var value = _step.value; + _this2["delete"](value); + } + }); + }); + }; + _proto.forEach = function forEach(callbackFn, thisArg) { + for (var _iterator2 = _createForOfIteratorHelperLoose(this), _step2; !(_step2 = _iterator2()).done; ) { + var value = _step2.value; + callbackFn.call(thisArg, value, value, this); + } + }; + _proto.add = function add(value) { + var _this3 = this; + checkIfStateModificationsAreAllowed(this.atom_); + if (hasInterceptors(this)) { + var change = interceptChange(this, { + type: ADD, + object: this, + newValue: value + }); + if (!change) { + return this; + } + value = change.newValue; + } + if (!this.has(value)) { + transaction(function() { + _this3.data_.add(_this3.enhancer_(value, void 0)); + _this3.atom_.reportChanged(); + }); + var notifySpy = false; + var notify = hasListeners(this); + var _change = notify || notifySpy ? { + observableKind: "set", + debugObjectName: this.name_, + type: ADD, + object: this, + newValue: value + } : null; + if (notify) { + notifyListeners(this, _change); + } + } + return this; + }; + _proto["delete"] = function _delete(value) { + var _this4 = this; + if (hasInterceptors(this)) { + var change = interceptChange(this, { + type: DELETE, + object: this, + oldValue: value + }); + if (!change) { + return false; + } + } + if (this.has(value)) { + var notifySpy = false; + var notify = hasListeners(this); + var _change2 = notify || notifySpy ? { + observableKind: "set", + debugObjectName: this.name_, + type: DELETE, + object: this, + oldValue: value + } : null; + transaction(function() { + _this4.atom_.reportChanged(); + _this4.data_["delete"](value); + }); + if (notify) { + notifyListeners(this, _change2); + } + return true; + } + return false; + }; + _proto.has = function has3(value) { + this.atom_.reportObserved(); + return this.data_.has(this.dehanceValue_(value)); + }; + _proto.entries = function entries2() { + var values2 = this.values(); + return makeIterableForSet({ + next: function next() { + var _values$next = values2.next(), value = _values$next.value, done = _values$next.done; + return !done ? { + value: [value, value], + done + } : { + value: void 0, + done + }; + } + }); + }; + _proto.keys = function keys2() { + return this.values(); + }; + _proto.values = function values2() { + this.atom_.reportObserved(); + var self2 = this; + var values3 = this.data_.values(); + return makeIterableForSet({ + next: function next() { + var _values$next2 = values3.next(), value = _values$next2.value, done = _values$next2.done; + return !done ? { + value: self2.dehanceValue_(value), + done + } : { + value: void 0, + done + }; + } + }); + }; + _proto.intersection = function intersection(otherSet) { + if (isES6Set(otherSet) && !isObservableSet(otherSet)) { + return otherSet.intersection(this); + } else { + var dehancedSet = new Set(this); + return dehancedSet.intersection(otherSet); + } + }; + _proto.union = function union(otherSet) { + if (isES6Set(otherSet) && !isObservableSet(otherSet)) { + return otherSet.union(this); + } else { + var dehancedSet = new Set(this); + return dehancedSet.union(otherSet); + } + }; + _proto.difference = function difference(otherSet) { + return new Set(this).difference(otherSet); + }; + _proto.symmetricDifference = function symmetricDifference(otherSet) { + if (isES6Set(otherSet) && !isObservableSet(otherSet)) { + return otherSet.symmetricDifference(this); + } else { + var dehancedSet = new Set(this); + return dehancedSet.symmetricDifference(otherSet); + } + }; + _proto.isSubsetOf = function isSubsetOf(otherSet) { + return new Set(this).isSubsetOf(otherSet); + }; + _proto.isSupersetOf = function isSupersetOf(otherSet) { + return new Set(this).isSupersetOf(otherSet); + }; + _proto.isDisjointFrom = function isDisjointFrom(otherSet) { + if (isES6Set(otherSet) && !isObservableSet(otherSet)) { + return otherSet.isDisjointFrom(this); + } else { + var dehancedSet = new Set(this); + return dehancedSet.isDisjointFrom(otherSet); + } + }; + _proto.replace = function replace2(other) { + var _this5 = this; + if (isObservableSet(other)) { + other = new Set(other); + } + transaction(function() { + if (Array.isArray(other)) { + _this5.clear(); + other.forEach(function(value) { + return _this5.add(value); + }); + } else if (isES6Set(other)) { + _this5.clear(); + other.forEach(function(value) { + return _this5.add(value); + }); + } else if (other !== null && other !== void 0) { + die("Cannot initialize set from " + other); + } + }); + return this; + }; + _proto.observe_ = function observe_(listener, fireImmediately) { + return registerListener(this, listener); + }; + _proto.intercept_ = function intercept_(handler) { + return registerInterceptor(this, handler); + }; + _proto.toJSON = function toJSON2() { + return Array.from(this); + }; + _proto.toString = function toString2() { + return "[object ObservableSet]"; + }; + _proto[Symbol.iterator] = function() { + return this.values(); + }; + return _createClass(ObservableSet2, [{ + key: "size", + get: function get4() { + this.atom_.reportObserved(); + return this.data_.size; + } + }, { + key: Symbol.toStringTag, + get: function get4() { + return "Set"; + } + }]); +})(); +var isObservableSet = /* @__PURE__ */ createInstanceofPredicate("ObservableSet", ObservableSet); +function makeIterableForSet(iterator) { + iterator[Symbol.toStringTag] = "SetIterator"; + return makeIterable(iterator); +} +var descriptorCache = /* @__PURE__ */ Object.create(null); +var REMOVE = "remove"; +var ObservableObjectAdministration = /* @__PURE__ */ (function() { + function ObservableObjectAdministration2(target_, values_, name_, defaultAnnotation_) { + if (values_ === void 0) { + values_ = /* @__PURE__ */ new Map(); + } + if (defaultAnnotation_ === void 0) { + defaultAnnotation_ = autoAnnotation; + } + this.target_ = void 0; + this.values_ = void 0; + this.name_ = void 0; + this.defaultAnnotation_ = void 0; + this.keysAtom_ = void 0; + this.changeListeners_ = void 0; + this.interceptors_ = void 0; + this.proxy_ = void 0; + this.isPlainObject_ = void 0; + this.appliedAnnotations_ = void 0; + this.pendingKeys_ = void 0; + this.target_ = target_; + this.values_ = values_; + this.name_ = name_; + this.defaultAnnotation_ = defaultAnnotation_; + this.keysAtom_ = new Atom("ObservableObject.keys"); + this.isPlainObject_ = isPlainObject(this.target_); + } + var _proto = ObservableObjectAdministration2.prototype; + _proto.getObservablePropValue_ = function getObservablePropValue_(key) { + return this.values_.get(key).get(); + }; + _proto.setObservablePropValue_ = function setObservablePropValue_(key, newValue) { + var observable2 = this.values_.get(key); + if (observable2 instanceof ComputedValue) { + observable2.set(newValue); + return true; + } + if (hasInterceptors(this)) { + var change = interceptChange(this, { + type: UPDATE, + object: this.proxy_ || this.target_, + name: key, + newValue + }); + if (!change) { + return null; + } + newValue = change.newValue; + } + newValue = observable2.prepareNewValue_(newValue); + if (newValue !== globalState.UNCHANGED) { + var notify = hasListeners(this); + var notifySpy = false; + var _change = notify || notifySpy ? { + type: UPDATE, + observableKind: "object", + debugObjectName: this.name_, + object: this.proxy_ || this.target_, + oldValue: observable2.value_, + name: key, + newValue + } : null; + observable2.setNewValue_(newValue); + if (notify) { + notifyListeners(this, _change); + } + } + return true; + }; + _proto.get_ = function get_(key) { + if (globalState.trackingDerivation && !hasProp(this.target_, key)) { + this.has_(key); + } + return this.target_[key]; + }; + _proto.set_ = function set_(key, value, proxyTrap) { + if (proxyTrap === void 0) { + proxyTrap = false; + } + if (hasProp(this.target_, key)) { + if (this.values_.has(key)) { + return this.setObservablePropValue_(key, value); + } else if (proxyTrap) { + return Reflect.set(this.target_, key, value); + } else { + this.target_[key] = value; + return true; + } + } else { + return this.extend_(key, { + value, + enumerable: true, + writable: true, + configurable: true + }, this.defaultAnnotation_, proxyTrap); + } + }; + _proto.has_ = function has_(key) { + if (!globalState.trackingDerivation) { + return key in this.target_; + } + this.pendingKeys_ || (this.pendingKeys_ = /* @__PURE__ */ new Map()); + var entry = this.pendingKeys_.get(key); + if (!entry) { + entry = new ObservableValue(key in this.target_, referenceEnhancer, "ObservableObject.key?", false); + this.pendingKeys_.set(key, entry); + } + return entry.get(); + }; + _proto.make_ = function make_2(key, annotation) { + if (annotation === true) { + annotation = this.defaultAnnotation_; + } + if (annotation === false) { + return; + } + if (!(key in this.target_)) { + var _this$target_$storedA; + if ((_this$target_$storedA = this.target_[storedAnnotationsSymbol]) != null && _this$target_$storedA[key]) { + return; + } else { + die(1, annotation.annotationType_, this.name_ + "." + key.toString()); + } + } + var source = this.target_; + while (source && source !== objectPrototype) { + var descriptor = getDescriptor(source, key); + if (descriptor) { + var outcome = annotation.make_(this, key, descriptor, source); + if (outcome === 0) { + return; + } + if (outcome === 1) { + break; + } + } + source = Object.getPrototypeOf(source); + } + recordAnnotationApplied(this, annotation, key); + }; + _proto.extend_ = function extend_2(key, descriptor, annotation, proxyTrap) { + if (proxyTrap === void 0) { + proxyTrap = false; + } + if (annotation === true) { + annotation = this.defaultAnnotation_; + } + if (annotation === false) { + return this.defineProperty_(key, descriptor, proxyTrap); + } + var outcome = annotation.extend_(this, key, descriptor, proxyTrap); + if (outcome) { + recordAnnotationApplied(this, annotation, key); + } + return outcome; + }; + _proto.defineProperty_ = function defineProperty_(key, descriptor, proxyTrap) { + if (proxyTrap === void 0) { + proxyTrap = false; + } + checkIfStateModificationsAreAllowed(this.keysAtom_); + try { + startBatch(); + var deleteOutcome = this.delete_(key); + if (!deleteOutcome) { + return deleteOutcome; + } + if (hasInterceptors(this)) { + var change = interceptChange(this, { + object: this.proxy_ || this.target_, + name: key, + type: ADD, + newValue: descriptor.value + }); + if (!change) { + return null; + } + var newValue = change.newValue; + if (descriptor.value !== newValue) { + descriptor = _extends({}, descriptor, { + value: newValue + }); + } + } + if (proxyTrap) { + if (!Reflect.defineProperty(this.target_, key, descriptor)) { + return false; + } + } else { + defineProperty(this.target_, key, descriptor); + } + this.notifyPropertyAddition_(key, descriptor.value); + } finally { + endBatch(); + } + return true; + }; + _proto.defineObservableProperty_ = function defineObservableProperty_(key, value, enhancer, proxyTrap) { + if (proxyTrap === void 0) { + proxyTrap = false; + } + checkIfStateModificationsAreAllowed(this.keysAtom_); + try { + startBatch(); + var deleteOutcome = this.delete_(key); + if (!deleteOutcome) { + return deleteOutcome; + } + if (hasInterceptors(this)) { + var change = interceptChange(this, { + object: this.proxy_ || this.target_, + name: key, + type: ADD, + newValue: value + }); + if (!change) { + return null; + } + value = change.newValue; + } + var cachedDescriptor = getCachedObservablePropDescriptor(key); + var descriptor = { + configurable: globalState.safeDescriptors ? this.isPlainObject_ : true, + enumerable: true, + get: cachedDescriptor.get, + set: cachedDescriptor.set + }; + if (proxyTrap) { + if (!Reflect.defineProperty(this.target_, key, descriptor)) { + return false; + } + } else { + defineProperty(this.target_, key, descriptor); + } + var observable2 = new ObservableValue(value, enhancer, false ? this.name_ + "." + key.toString() : "ObservableObject.key", false); + this.values_.set(key, observable2); + this.notifyPropertyAddition_(key, observable2.value_); + } finally { + endBatch(); + } + return true; + }; + _proto.defineComputedProperty_ = function defineComputedProperty_(key, options, proxyTrap) { + if (proxyTrap === void 0) { + proxyTrap = false; + } + checkIfStateModificationsAreAllowed(this.keysAtom_); + try { + startBatch(); + var deleteOutcome = this.delete_(key); + if (!deleteOutcome) { + return deleteOutcome; + } + if (hasInterceptors(this)) { + var change = interceptChange(this, { + object: this.proxy_ || this.target_, + name: key, + type: ADD, + newValue: void 0 + }); + if (!change) { + return null; + } + } + options.name || (options.name = false ? this.name_ + "." + key.toString() : "ObservableObject.key"); + options.context = this.proxy_ || this.target_; + var cachedDescriptor = getCachedObservablePropDescriptor(key); + var descriptor = { + configurable: globalState.safeDescriptors ? this.isPlainObject_ : true, + enumerable: false, + get: cachedDescriptor.get, + set: cachedDescriptor.set + }; + if (proxyTrap) { + if (!Reflect.defineProperty(this.target_, key, descriptor)) { + return false; + } + } else { + defineProperty(this.target_, key, descriptor); + } + this.values_.set(key, new ComputedValue(options)); + this.notifyPropertyAddition_(key, void 0); + } finally { + endBatch(); + } + return true; + }; + _proto.delete_ = function delete_(key, proxyTrap) { + if (proxyTrap === void 0) { + proxyTrap = false; + } + checkIfStateModificationsAreAllowed(this.keysAtom_); + if (!hasProp(this.target_, key)) { + return true; + } + if (hasInterceptors(this)) { + var change = interceptChange(this, { + object: this.proxy_ || this.target_, + name: key, + type: REMOVE + }); + if (!change) { + return null; + } + } + try { + var _this$pendingKeys_; + startBatch(); + var notify = hasListeners(this); + var notifySpy = false; + var observable2 = this.values_.get(key); + var value = void 0; + if (!observable2 && (notify || notifySpy)) { + var _getDescriptor2; + value = (_getDescriptor2 = getDescriptor(this.target_, key)) == null ? void 0 : _getDescriptor2.value; + } + if (proxyTrap) { + if (!Reflect.deleteProperty(this.target_, key)) { + return false; + } + } else { + delete this.target_[key]; + } + if (false) ; + if (observable2) { + this.values_["delete"](key); + if (observable2 instanceof ObservableValue) { + value = observable2.value_; + } + propagateChanged(observable2); + } + this.keysAtom_.reportChanged(); + (_this$pendingKeys_ = this.pendingKeys_) == null || (_this$pendingKeys_ = _this$pendingKeys_.get(key)) == null || _this$pendingKeys_.set(key in this.target_); + if (notify || notifySpy) { + var _change2 = { + type: REMOVE, + observableKind: "object", + object: this.proxy_ || this.target_, + debugObjectName: this.name_, + oldValue: value, + name: key + }; + if (false) ; + if (notify) { + notifyListeners(this, _change2); + } + if (false) ; + } + } finally { + endBatch(); + } + return true; + }; + _proto.observe_ = function observe_(callback, fireImmediately) { + return registerListener(this, callback); + }; + _proto.intercept_ = function intercept_(handler) { + return registerInterceptor(this, handler); + }; + _proto.notifyPropertyAddition_ = function notifyPropertyAddition_(key, value) { + var _this$pendingKeys_2; + var notify = hasListeners(this); + var notifySpy = false; + if (notify || notifySpy) { + var change = notify || notifySpy ? { + type: ADD, + observableKind: "object", + debugObjectName: this.name_, + object: this.proxy_ || this.target_, + name: key, + newValue: value + } : null; + if (notify) { + notifyListeners(this, change); + } + } + (_this$pendingKeys_2 = this.pendingKeys_) == null || (_this$pendingKeys_2 = _this$pendingKeys_2.get(key)) == null || _this$pendingKeys_2.set(true); + this.keysAtom_.reportChanged(); + }; + _proto.ownKeys_ = function ownKeys_() { + this.keysAtom_.reportObserved(); + return ownKeys(this.target_); + }; + _proto.keys_ = function keys_() { + this.keysAtom_.reportObserved(); + return Object.keys(this.target_); + }; + return ObservableObjectAdministration2; +})(); +function asObservableObject(target, options) { + var _options$name; + if (hasProp(target, $mobx)) { + return target; + } + var name = (_options$name = options == null ? void 0 : options.name) != null ? _options$name : "ObservableObject"; + var adm = new ObservableObjectAdministration(target, /* @__PURE__ */ new Map(), String(name), getAnnotationFromOptions(options)); + addHiddenProp(target, $mobx, adm); + return target; +} +var isObservableObjectAdministration = /* @__PURE__ */ createInstanceofPredicate("ObservableObjectAdministration", ObservableObjectAdministration); +function getCachedObservablePropDescriptor(key) { + return descriptorCache[key] || (descriptorCache[key] = { + get: function get4() { + return this[$mobx].getObservablePropValue_(key); + }, + set: function set5(value) { + return this[$mobx].setObservablePropValue_(key, value); + } + }); +} +function isObservableObject(thing) { + if (isObject(thing)) { + return isObservableObjectAdministration(thing[$mobx]); + } + return false; +} +function recordAnnotationApplied(adm, annotation, key) { + var _adm$target_$storedAn; + (_adm$target_$storedAn = adm.target_[storedAnnotationsSymbol]) == null || delete _adm$target_$storedAn[key]; +} +var ENTRY_0 = /* @__PURE__ */ createArrayEntryDescriptor(0); +var safariPrototypeSetterInheritanceBug = /* @__PURE__ */ (function() { + var v = false; + var p = {}; + Object.defineProperty(p, "0", { + set: function set5() { + v = true; + } + }); + Object.create(p)["0"] = 1; + return v === false; +})(); +var OBSERVABLE_ARRAY_BUFFER_SIZE = 0; +var StubArray = function StubArray2() { +}; +function inherit(ctor, proto) { + if (Object.setPrototypeOf) { + Object.setPrototypeOf(ctor.prototype, proto); + } else if (ctor.prototype.__proto__ !== void 0) { + ctor.prototype.__proto__ = proto; + } else { + ctor.prototype = proto; + } +} +inherit(StubArray, Array.prototype); +var LegacyObservableArray = /* @__PURE__ */ (function(_StubArray) { + function LegacyObservableArray2(initialValues, enhancer, name, owned) { + var _this; + if (name === void 0) { + name = "ObservableArray"; + } + if (owned === void 0) { + owned = false; + } + _this = _StubArray.call(this) || this; + initObservable(function() { + var adm = new ObservableArrayAdministration(name, enhancer, owned, true); + adm.proxy_ = _this; + addHiddenFinalProp(_this, $mobx, adm); + if (initialValues && initialValues.length) { + _this.spliceWithArray(0, 0, initialValues); + } + if (safariPrototypeSetterInheritanceBug) { + Object.defineProperty(_this, "0", ENTRY_0); + } + }); + return _this; + } + _inheritsLoose(LegacyObservableArray2, _StubArray); + var _proto = LegacyObservableArray2.prototype; + _proto.concat = function concat() { + this[$mobx].atom_.reportObserved(); + for (var _len = arguments.length, arrays = new Array(_len), _key = 0; _key < _len; _key++) { + arrays[_key] = arguments[_key]; + } + return Array.prototype.concat.apply( + this.slice(), + //@ts-ignore + arrays.map(function(a) { + return isObservableArray(a) ? a.slice() : a; + }) + ); + }; + _proto[Symbol.iterator] = function() { + var self2 = this; + var nextIndex = 0; + return makeIterable({ + next: function next() { + return nextIndex < self2.length ? { + value: self2[nextIndex++], + done: false + } : { + done: true, + value: void 0 + }; + } + }); + }; + return _createClass(LegacyObservableArray2, [{ + key: "length", + get: function get4() { + return this[$mobx].getArrayLength_(); + }, + set: function set5(newLength) { + this[$mobx].setArrayLength_(newLength); + } + }, { + key: Symbol.toStringTag, + get: function get4() { + return "Array"; + } + }]); +})(StubArray); +Object.entries(arrayExtensions).forEach(function(_ref) { + var prop = _ref[0], fn = _ref[1]; + if (prop !== "concat") { + addHiddenProp(LegacyObservableArray.prototype, prop, fn); + } +}); +function createArrayEntryDescriptor(index) { + return { + enumerable: false, + configurable: true, + get: function get4() { + return this[$mobx].get_(index); + }, + set: function set5(value) { + this[$mobx].set_(index, value); + } + }; +} +function createArrayBufferItem(index) { + defineProperty(LegacyObservableArray.prototype, "" + index, createArrayEntryDescriptor(index)); +} +function reserveArrayBuffer(max) { + if (max > OBSERVABLE_ARRAY_BUFFER_SIZE) { + for (var index = OBSERVABLE_ARRAY_BUFFER_SIZE; index < max + 100; index++) { + createArrayBufferItem(index); + } + OBSERVABLE_ARRAY_BUFFER_SIZE = max; + } +} +reserveArrayBuffer(1e3); +function createLegacyArray(initialValues, enhancer, name) { + return new LegacyObservableArray(initialValues, enhancer, name); +} +function getAtom(thing, property) { + if (typeof thing === "object" && thing !== null) { + if (isObservableArray(thing)) { + if (property !== void 0) { + die(23); + } + return thing[$mobx].atom_; + } + if (isObservableSet(thing)) { + return thing.atom_; + } + if (isObservableMap(thing)) { + if (property === void 0) { + return thing.keysAtom_; + } + var observable2 = thing.data_.get(property) || thing.hasMap_.get(property); + if (!observable2) { + die(25, property, getDebugName(thing)); + } + return observable2; + } + if (isObservableObject(thing)) { + if (!property) { + return die(26); + } + var _observable = thing[$mobx].values_.get(property); + if (!_observable) { + die(27, property, getDebugName(thing)); + } + return _observable; + } + if (isAtom(thing) || isComputedValue(thing) || isReaction(thing)) { + return thing; + } + } else if (isFunction(thing)) { + if (isReaction(thing[$mobx])) { + return thing[$mobx]; + } + } + die(28); +} +function getAdministration(thing, property) { + if (!thing) { + die(29); + } + if (isAtom(thing) || isComputedValue(thing) || isReaction(thing)) { + return thing; + } + if (isObservableMap(thing) || isObservableSet(thing)) { + return thing; + } + if (thing[$mobx]) { + return thing[$mobx]; + } + die(24, thing); +} +function getDebugName(thing, property) { + var named; + if (property !== void 0) { + named = getAtom(thing, property); + } else if (isAction(thing)) { + return thing.name; + } else if (isObservableObject(thing) || isObservableMap(thing) || isObservableSet(thing)) { + named = getAdministration(thing); + } else { + named = getAtom(thing); + } + return named.name_; +} +function initObservable(cb) { + var derivation = untrackedStart(); + var allowStateChanges2 = allowStateChangesStart(true); + startBatch(); + try { + return cb(); + } finally { + endBatch(); + allowStateChangesEnd(allowStateChanges2); + untrackedEnd(derivation); + } +} +var toString = objectPrototype.toString; +function deepEqual(a, b, depth) { + if (depth === void 0) { + depth = -1; + } + return eq(a, b, depth); +} +function eq(a, b, depth, aStack, bStack) { + if (a === b) { + return a !== 0 || 1 / a === 1 / b; + } + if (a == null || b == null) { + return false; + } + if (a !== a) { + return b !== b; + } + var type = typeof a; + if (type !== "function" && type !== "object" && typeof b != "object") { + return false; + } + var className = toString.call(a); + if (className !== toString.call(b)) { + return false; + } + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case "[object RegExp]": + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case "[object String]": + return "" + a === "" + b; + case "[object Number]": + if (+a !== +a) { + return +b !== +b; + } + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case "[object Date]": + case "[object Boolean]": + return +a === +b; + case "[object Symbol]": + return typeof Symbol !== "undefined" && Symbol.valueOf.call(a) === Symbol.valueOf.call(b); + case "[object Map]": + case "[object Set]": + if (depth >= 0) { + depth++; + } + break; + } + a = unwrap(a); + b = unwrap(b); + var areArrays = className === "[object Array]"; + if (!areArrays) { + if (typeof a != "object" || typeof b != "object") { + return false; + } + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && isFunction(bCtor) && bCtor instanceof bCtor) && "constructor" in a && "constructor" in b) { + return false; + } + } + if (depth === 0) { + return false; + } else if (depth < 0) { + depth = -1; + } + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + if (aStack[length] === a) { + return bStack[length] === b; + } + } + aStack.push(a); + bStack.push(b); + if (areArrays) { + length = a.length; + if (length !== b.length) { + return false; + } + while (length--) { + if (!eq(a[length], b[length], depth - 1, aStack, bStack)) { + return false; + } + } + } else { + var keys2 = Object.keys(a); + var _length = keys2.length; + if (Object.keys(b).length !== _length) { + return false; + } + for (var i = 0; i < _length; i++) { + var key = keys2[i]; + if (!(hasProp(b, key) && eq(a[key], b[key], depth - 1, aStack, bStack))) { + return false; + } + } + } + aStack.pop(); + bStack.pop(); + return true; +} +function unwrap(a) { + if (isObservableArray(a)) { + return a.slice(); + } + if (isES6Map(a) || isObservableMap(a)) { + return Array.from(a.entries()); + } + if (isES6Set(a) || isObservableSet(a)) { + return Array.from(a.entries()); + } + return a; +} +var _getGlobal$Iterator; +var maybeIteratorPrototype = ((_getGlobal$Iterator = getGlobal().Iterator) == null ? void 0 : _getGlobal$Iterator.prototype) || {}; +function makeIterable(iterator) { + iterator[Symbol.iterator] = getSelf; + return Object.assign(Object.create(maybeIteratorPrototype), iterator); +} +function getSelf() { + return this; +} +["Symbol", "Map", "Set"].forEach(function(m) { + var g = getGlobal(); + if (typeof g[m] === "undefined") { + die("MobX requires global '" + m + "' to be available or polyfilled"); + } +}); +if (typeof __MOBX_DEVTOOLS_GLOBAL_HOOK__ === "object") { + __MOBX_DEVTOOLS_GLOBAL_HOOK__.injectMobx({ + spy, + extras: { + getDebugName + }, + $mobx + }); +} +const SECONDS_PER_DAY$1 = 24 * 60 * 60; +class Time_of_day { + _h; + _m; + _s; + constructor(hms) { + ({ h: this._h, m: this._m, s: this._s } = hms); + } + static create_from_js_date(date) { + return new Time_of_day({ + h: date.getHours(), + m: date.getMinutes(), + s: date.getSeconds() + }); + } + /** @param hhmm - `HH:MM` */ + static create_from_hhmm_string(hhmm) { + const [h, m] = hhmm.split(":").map(Number); + return new Time_of_day({ h, m, s: 0 }); + } + get hour() { + return this._h; + } + get minute() { + return this._m; + } + get second() { + return this._s; + } + get_as_hms() { + return { h: this._h, m: this._m, s: this._s }; + } + /** @returns `(H)H:MM:SS` */ + get_as_string_hmmss() { + const [mm, ss] = [this._m, this._s].map( + (value) => String(value).padStart(2, "0") + ); + return `${this._h}:${mm}:${ss}`; + } + /** @returns `HH:MM` */ + get_as_string_hhmm() { + const [hh, mm] = [this._h, this._m].map( + (value) => String(value).padStart(2, "0") + ); + return `${hh}:${mm}`; + } + /** + * @param value - The offset to add. + * @returns A new instance with the added time. + */ + add_minutes(value) { + const date = new Date(0, 0, 1, this._h, this._m, this._s); + date.setMinutes(date.getMinutes() + value); + return Time_of_day.create_from_js_date(date); + } + /** Gets the delay from `this` until the next occurrence of `target`. */ + get_seconds_until_next_target(target) { + const [target_s, this_s] = [target, this].map( + (time) => time._seconds_since_midnight + ); + return this_s < target_s ? target_s - this_s : target_s - this_s + SECONDS_PER_DAY$1; + } + is_between(start, end) { + const [this_s, start_s, end_s] = [this, start, end].map( + (time) => time._seconds_since_midnight + ); + return start_s < end_s ? start_s <= this_s && this_s < end_s : start_s <= this_s || this_s < end_s; + } + get _seconds_since_midnight() { + return this._h * 3600 + this._m * 60 + this._s; + } +} +const { DateTime: DateTime$1 } = imports.gi.GLib; +function get_now_as_unix() { + return DateTime$1.new_now_local().to_unix(); +} +function get_now_as_time_of_day() { + const datetime = DateTime$1.new_now_local(); + const hms = _datetime_to_hms(datetime); + return new Time_of_day(hms); +} +function new_local_time_of_day_from_unix(unix_time) { + const datetime = DateTime$1.new_from_unix_local(unix_time); + const hms = _datetime_to_hms(datetime); + return new Time_of_day(hms); +} +function _datetime_to_hms(datetime) { + return { + h: datetime.get_hour(), + m: datetime.get_minute(), + s: datetime.get_second() + }; +} +class Appearance_handler { + _time = get_now_as_time_of_day(); + update_time() { + this._time = get_now_as_time_of_day(); + } + twilights; + get auto_is_dark() { + return this._time.is_between( + this.twilights.sunset, + this.twilights.sunrise + ); + } + manual_is_dark; + toggle_is_dark() { + this.manual_is_dark = !this.manual_is_dark; + } + is_auto; + toggle_is_auto() { + this.is_auto = !this.is_auto; + } + get is_dark() { + return this.is_auto ? this.auto_is_dark : this.manual_is_dark; + } + get is_unsynced() { + return this.manual_is_dark !== this.auto_is_dark; + } + sync_is_dark() { + this.manual_is_dark = this.auto_is_dark; + } + get next_twilight() { + return this.auto_is_dark ? this.twilights.sunrise : this.twilights.sunset; + } + constructor(initial_controls) { + Object.assign(this, initial_controls); + makeAutoObservable(this); + } +} +const { Gio: Gio$8 } = imports.gi; +const settings$2 = { + background: Gio$8.Settings.new("org.cinnamon.desktop.background"), + slideshow: Gio$8.Settings.new("org.cinnamon.desktop.background.slideshow") +}; +class System_background { + static get is_slideshow() { + return settings$2.slideshow.get_boolean("slideshow-enabled"); + } + static set is_slideshow(value) { + settings$2.slideshow.set_boolean("slideshow-enabled", value); + } + /** Irrelevant to get when slideshow is enabled */ + static get picture_file() { + return settings$2.background.get_string("picture-uri"); + } + /** /!\ To not set when slideshow is enabled */ + static set picture_file(value) { + settings$2.background.set_string("picture-uri", value); + } + /** Irrelevant to get when slideshow is disabled */ + static get slideshow_folder() { + return settings$2.slideshow.get_string("image-source"); + } + /** /!\ To not set when slideshow is disabled */ + static set slideshow_folder(value) { + settings$2.slideshow.set_string("image-source", value); + } +} +class Background_handler { + _settings; + constructor(applet, settings2) { + this._settings = settings2; + applet.on_button_detect_background_light = () => this.detect_light_background(); + applet.on_button_detect_background_dark = () => this.detect_dark_background(); + applet.on_button_apply_background_light = () => this.apply_light_background(); + applet.on_button_apply_background_dark = () => this.apply_dark_background(); + } + detect_light_background() { + const is_slideshow = System_background.is_slideshow; + this._settings.light_background_is_slideshow = is_slideshow; + if (is_slideshow) + this._settings.light_background_slideshow_folder = System_background.slideshow_folder.replace("directory://", "file://"); + else + this._settings.light_background_file = System_background.picture_file; + } + detect_dark_background() { + const is_slideshow = System_background.is_slideshow; + this._settings.dark_background_is_slideshow = is_slideshow; + if (is_slideshow) + this._settings.dark_background_slideshow_folder = System_background.slideshow_folder.replace("directory://", "file://"); + else + this._settings.dark_background_file = System_background.picture_file; + } + apply_light_background() { + const is_slideshow = this._settings.light_background_is_slideshow; + System_background.is_slideshow = is_slideshow; + if (is_slideshow) + System_background.slideshow_folder = decodeURIComponent( + // If the folder was chosen via a filechooser, it may contain non-ASCII characters + this._settings.light_background_slideshow_folder.replace("file://", "directory://") + // https://github.com/linuxmint/cinnamon/issues/12374 + ); + else + System_background.picture_file = this._settings.light_background_file; + } + apply_dark_background() { + const is_slideshow = this._settings.dark_background_is_slideshow; + System_background.is_slideshow = is_slideshow; + if (is_slideshow) + System_background.slideshow_folder = decodeURIComponent( + // If the folder was chosen via a filechooser, it may contain non-ASCII characters + this._settings.dark_background_slideshow_folder.replace("file://", "directory://") + // https://github.com/linuxmint/cinnamon/issues/12374 + ); + else + System_background.picture_file = this._settings.dark_background_file; + } +} +const { Gio: Gio$7, GLib: GLib$4 } = imports.gi; +async function launch_command(name, expiry, command) { + try { + await _launch_command(command, expiry); + } catch (error) { + const name_for_error = name !== "" ? name : command; + let msg = `${_("the command")} '${name_for_error}' ${_("has failed")}`; + if (error instanceof GLib$4.ShellError) + msg += ` ${_("due to a wrong format")}. + +${_("Detail")}${_(":")} +` + error.message; + else if (error instanceof Gio$7.IOErrorEnum) { + if (error.code === Gio$7.IOErrorEnum.TIMED_OUT) + msg += ` ${_("due to timeout")}. + +${_("Detail")}${_(":")} +` + error.message; + else if (error.code === Gio$7.IOErrorEnum.FAILED) + msg += ` ${_("due to an error")}. + +${_("Detail")}${_(":")} +` + error.message; + } else + msg += `${_(":")} ${error}`; + logger.warn(msg); + } +} +const TIMEOUT_EXIT_STATUS_SIGTERM = 124; +const TIMEOUT_EXIT_STATUS_SIGKILL = 137; +const SIGKILL_TIMEOUT = 10; +async function _launch_command(command, timeout = 10) { + const wrapped_command = `timeout --kill-after=${SIGKILL_TIMEOUT} ${timeout}s sh -c ${GLib$4.shell_quote(command)}`; + const [_ok, argvp] = GLib$4.shell_parse_argv(wrapped_command); + const process = new Gio$7.Subprocess({ + argv: argvp, + flags: Gio$7.SubprocessFlags.STDERR_PIPE + }); + const start_time = Date.now(); + process.init(null); + const [_stdout, stderr] = await new Promise( + // Promisifies + (resolve, reject) => { + process.communicate_utf8_async( + null, + null, + (source, result) => { + try { + const [_ok2, stdout, stderr2] = source.communicate_utf8_finish(result); + resolve([stdout, stderr2]); + } catch (error) { + reject(error); + } + } + ); + } + ); + const elapsed_time = (Date.now() - start_time) / 1e3; + const exit_status = process.get_exit_status(); + switch (exit_status) { + case 0: + break; + case TIMEOUT_EXIT_STATUS_SIGTERM: + throw new Gio$7.IOErrorEnum({ + code: Gio$7.IOErrorEnum.TIMED_OUT, + message: `may have been timed out by SIGTERM (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGTERM})` + }); + case TIMEOUT_EXIT_STATUS_SIGKILL: + throw new Gio$7.IOErrorEnum({ + code: Gio$7.IOErrorEnum.TIMED_OUT, + message: `probably killed by an external SIGKILL (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGKILL})` + }); + case 1: + if (timeout > 0 && elapsed_time >= timeout + SIGKILL_TIMEOUT) + throw new Gio$7.IOErrorEnum({ + code: Gio$7.IOErrorEnum.TIMED_OUT, + message: `probably timed out by SIGKILL` + }); + // no break, needs to stay directly above the default case + default: + throw new Gio$7.IOErrorEnum({ + code: Gio$7.IOErrorEnum.FAILED, + message: stderr ? stderr.trim() : "exit status: " + exit_status + }); + } +} +class Commands_handler { + _settings; + constructor(applet, settings2) { + this._settings = settings2; + applet.on_button_launch_commands_light = () => this.launch_light_commands(); + applet.on_button_launch_commands_dark = () => this.launch_dark_commands(); + } + launch_dark_commands() { + this._launch_commands(this._settings.dark_commands_list); + } + launch_light_commands() { + this._launch_commands(this._settings.light_commands_list); + } + _launch_commands(commands_list) { + for (const command of commands_list) { + if (!command.active) + continue; + launch_command(command.name, command.expiry, command.command); + } + } +} +class Timer_absolute { + /** Unix time in seconds (s) */ + _expiration_time = 0; + /** The next time of day the timer has to expire. */ + set expiration_time(value) { + const now = get_now_as_time_of_day(); + const due_delay = now.get_seconds_until_next_target(value); + this._expiration_time = get_now_as_unix() + due_delay; + } + get_if_has_expired() { + return get_now_as_unix() > this._expiration_time; + } + /** Ensures `get_if_has_expired` returns `true` */ + reset() { + this._expiration_time = 0; + } +} +const { GLib: GLib$3 } = imports.gi; +class Event_scheduler { + _event_id = void 0; + _timer_absolute = new Timer_absolute(); + /** @returns `true` if the scheduled event should have already occurred, `false` otherwise. If the event is not set, `false` is returned. */ + get_if_should_be_expired() { + return this._timer_absolute.get_if_has_expired(); + } + /** + * Calls a function at a specific next time of day. + * + * If the event is already scheduled, it will be replaced. + * + * @param time - When the event should occur. + * @param callback_on_event - The function to be executed when the event occurs. + */ + set_the_event(time, callback_on_event) { + this.unset_the_event(); + const now = get_now_as_time_of_day(); + const due_delay = now.get_seconds_until_next_target(time); + this._event_id = GLib$3.timeout_add_seconds( + GLib$3.PRIORITY_DEFAULT, + due_delay, + () => { + callback_on_event(); + return GLib$3.SOURCE_REMOVE; + } + ); + this._timer_absolute.expiration_time = time; + } + get is_set() { + return this._event_id !== void 0; + } + /** If the event is not already scheduled, nothing is done. */ + unset_the_event() { + if (!this._event_id) + return; + GLib$3.source_remove(this._event_id); + this._event_id = void 0; + this._timer_absolute.reset(); + } + /** Releases acquired resources */ + dispose() { + this.unset_the_event(); + } +} +const Main = imports.ui.main; +let counter = 0; +class Keybinding_handler { + _name; + _callback; + constructor(callback) { + this._name = metadata.uuid + counter++; + this._callback = callback; + } + set keybinding(value) { + Main.keybindingManager.addHotKey(this._name, value, this._callback); + } + dispose() { + Main.keybindingManager.removeHotKey(this._name); + } +} +const { Gio: Gio$6 } = imports.gi; +class Timezone_change_listener { + _callback_on_change; + /** @param callback_on_change - The function to be executed when the system timezone changes. */ + constructor(callback_on_change) { + this._callback_on_change = callback_on_change; + } + enable() { + this._subscribe_to_changes(this._callback_on_change.bind(this)); + } + disable() { + this._unsubscribe_to_changes(); + } + /** Releases acquired resources */ + dispose() { + this.disable(); + } + _signal_id = void 0; + _subscribe_to_changes(callback_when_changes) { + if (this._signal_id) + this._unsubscribe_to_changes(); + this._signal_id = Gio$6.DBus.system.signal_subscribe( + "org.freedesktop.timedate1", + // sender + "org.freedesktop.DBus.Properties", + // interface_name + "PropertiesChanged", + // member + "/org/freedesktop/timedate1", + // object_path + null, + // arg0 + Gio$6.DBusSignalFlags.NONE, + // flags + (_1, _2, _3, _4, _5, parameters) => { + const changed_properties = parameters.deep_unpack()[1]; + if (changed_properties["Timezone"]) { + const new_timezone = changed_properties["Timezone"].deep_unpack(); + callback_when_changes(new_timezone); + } + } + ); + } + _unsubscribe_to_changes() { + if (!this._signal_id) + return; + Gio$6.DBus.system.signal_unsubscribe(this._signal_id); + this._signal_id = void 0; + } +} +const { Gio: Gio$5 } = imports.gi; +class Timezone_location_finder { + _database; + /** + * @param path - The absolute path where the `database.json` file is located. + * @throws {Error} - If the file cannot be loaded or JSON-parsed + */ + constructor(path) { + const file_path = `${path}/database.json`; + const file = Gio$5.File.new_for_path(file_path); + const [ok, file_content] = file.load_contents(null); + if (!ok) + throw new Error(`failed to load file/contents of '${file_path}'`); + this._database = JSON.parse(new TextDecoder().decode(file_content)); + } + /** + * Gets the latitude and longitude of the timezone's city. + * @param timezone - The timezone to get the coordinates from. + * @returns The system timezone's city coordinates. + */ + find(timezone) { + if (!timezone) + throw new Error("timezone is required"); + if (!(timezone in this._database)) + throw new Error(`unknown timezone: '${timezone}'`); + return { + latitude: this._database[timezone][0], + longitude: this._database[timezone][1] + }; + } +} +const { GLib: GLib$2 } = imports.gi; +class Location_handler { + _timezone_change_listener = new Timezone_change_listener( + (new_timezone) => this._timezone = new_timezone + ); + _timezone = GLib$2.TimeZone.new_local().get_identifier(); + get timezone() { + return this._timezone; + } + _timezone_location_finder = new Timezone_location_finder( + `${metadata.path}/Timezone_location_finder` + ); + get auto_location() { + return this._timezone_location_finder.find(this.timezone); + } + manual_location; + is_location_auto; + get location() { + return this.is_location_auto ? this.auto_location : this.manual_location; + } + constructor(initial_values) { + Object.assign(this, initial_values); + makeAutoObservable(this, { + _timezone_change_listener: false, + _timezone_location_finder: false, + manual_location: observable.deep + }); + this._timezone_change_listener.enable(); + } + /** Releases acquired resources */ + dispose() { + this._timezone_change_listener.dispose(); + } +} +async function sleep(duration) { + return new Promise((resolve) => setTimeout(resolve, duration)); +} +const { Gio: Gio$4 } = imports.gi; +class Screen_lock_checker { + /** + * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. + * @param callback_when_unlocked - The function to be executed when the screen is unlocked. + */ + try_now_or_postpone_until_unlocked(callback_when_unlocked) { + Screen_lock_checker._get_state_async((is_locked) => { + if (!is_locked) + callback_when_unlocked(); + else + this._subscribe_to_changes((is_locked2) => { + if (is_locked2) + return; + this._unsubscribe_to_changes(); + callback_when_unlocked(); + }); + }); + } + /** Cancels the `try_now_or_postpone_until_unlocked` procedure. */ + cancel() { + this._unsubscribe_to_changes(); + } + /** Releases acquired resources */ + dispose() { + this.cancel(); + } + _signal_id = void 0; + /** @param callback_when_changes - The function to be executed when the screen lock state changes. */ + _subscribe_to_changes(callback_when_changes) { + if (this._signal_id) + this._unsubscribe_to_changes(); + this._signal_id = Gio$4.DBus.session.signal_subscribe( + "org.cinnamon.ScreenSaver", + // sender + "org.cinnamon.ScreenSaver", + // interface_name + "ActiveChanged", + // member + "/org/cinnamon/ScreenSaver", + // object_path + null, + // arg0 + Gio$4.DBusSignalFlags.NONE, + // flags + (_1, _2, _3, _4, _5, parameters) => { + const is_locked = parameters.deep_unpack()[0]; + callback_when_changes(is_locked); + } + ); + } + _unsubscribe_to_changes() { + if (!this._signal_id) + return; + Gio$4.DBus.session.signal_unsubscribe(this._signal_id); + this._signal_id = void 0; + } + /** + * Gets the current screen lock state asynchronously. + * @param callback_for_result - The callback object to handle the result. + */ + static _get_state_async(callback_for_result) { + Gio$4.DBus.session.call( + "org.cinnamon.ScreenSaver", + // bus_name + "/org/cinnamon/ScreenSaver", + // object_path + "org.cinnamon.ScreenSaver", + // interface_name + "GetActive", + // method_name + null, + // parameters + null, + // reply_type + Gio$4.DBusCallFlags.NONE, + // flags + -1, + // timeout_msec + null, + // cancellable + (connection, result) => { + const reply = connection.call_finish(result); + const is_locked = reply.deep_unpack()[0]; + callback_for_result(is_locked); + } + ); + } +} +const { Gio: Gio$3 } = imports.gi; +class Sleep_events_listener { + _callback_when_sleep_entries; + _callback_when_wakeup_unlocked; + /** + * @param callback_when_sleep_entries - The function to be executed when the system goes to sleep. Will be called again even without unlock. + * @param callback_when_wakeup_unlocked - The function to be executed when the system wakes up and the screen is unlocked. + */ + constructor(callback_when_sleep_entries, callback_when_wakeup_unlocked) { + this._callback_when_sleep_entries = callback_when_sleep_entries; + this._callback_when_wakeup_unlocked = callback_when_wakeup_unlocked; + } + _screen_lock_checker = new Screen_lock_checker(); + enable() { + this._subscribe_to_changes((is_sleeping) => { + if (is_sleeping) + this._callback_when_sleep_entries(); + else + this._screen_lock_checker.try_now_or_postpone_until_unlocked( + () => this._callback_when_wakeup_unlocked() + ); + }); + } + disable() { + this._unsubscribe_to_changes(); + this._screen_lock_checker.cancel(); + } + /** Releases acquired resources */ + dispose() { + this._unsubscribe_to_changes(); + this._screen_lock_checker.dispose(); + } + _signal_id = void 0; + /** @param callback - The function to be executed when the system sleep state changes. */ + _subscribe_to_changes(callback) { + if (this._signal_id) + this._unsubscribe_to_changes(); + this._signal_id = Gio$3.DBus.system.signal_subscribe( + "org.freedesktop.login1", + // sender + "org.freedesktop.login1.Manager", + // interface_name + "PrepareForSleep", + // member + "/org/freedesktop/login1", + // object_path + null, + // arg0 + Gio$3.DBusSignalFlags.NONE, + // flags + (_1, _2, _3, _4, _5, parameters) => { + const is_sleeping = parameters.deep_unpack()[0]; + callback(is_sleeping); + } + ); + } + _unsubscribe_to_changes() { + if (!this._signal_id) + return; + Gio$3.DBus.system.signal_unsubscribe(this._signal_id); + this._signal_id = void 0; + } +} +const { Gio: Gio$2 } = imports.gi; +const settings$1 = Gio$2.Settings.new("org.x.apps.portal"); +class System_color_scheme { + _callback_on_change; + _signal_id = void 0; + /** @param callback_on_change - The function to be executed when the color scheme changes. */ + constructor(callback_on_change) { + this._callback_on_change = callback_on_change; + } + enable() { + this.disable(); + this._signal_id = settings$1.connect("changed::color-scheme", () => { + this._callback_on_change(System_color_scheme.value); + }); + } + disable() { + if (this._signal_id === void 0) + return; + settings$1.disconnect(this._signal_id); + this._signal_id = void 0; + } + /** Releases acquired resources */ + dispose() { + this.disable(); + } + static get value() { + return settings$1.get_string("color-scheme"); + } + static set value(value) { + settings$1.set_string("color-scheme", value); + } +} +const { Gio: Gio$1 } = imports.gi; +const settings = { + desktop: Gio$1.Settings.new("org.cinnamon.desktop.interface"), + cinnamon: Gio$1.Settings.new("org.cinnamon.theme") +}; +class System_themes { + static get mouse() { + return settings.desktop.get_string("cursor-theme"); + } + static set mouse(value) { + settings.desktop.set_string("cursor-theme", value); + } + static get apps() { + return settings.desktop.get_string("gtk-theme"); + } + static set apps(value) { + settings.desktop.set_string("gtk-theme", value); + } + static get icons() { + return settings.desktop.get_string("icon-theme"); + } + static set icons(value) { + settings.desktop.set_string("icon-theme", value); + } + static get desktop() { + return settings.cinnamon.get_string("name"); + } + static set desktop(value) { + settings.cinnamon.set_string("name", value); + } +} +class Themes_handler { + _settings; + constructor(applet, settings2) { + this._settings = settings2; + applet.on_button_detect_themes_light = () => this.detect_light_themes(); + applet.on_button_detect_themes_dark = () => this.detect_dark_themes(); + applet.on_button_apply_themes_light = () => this.apply_light_themes(); + applet.on_button_apply_themes_dark = () => this.apply_dark_themes(); + } + detect_light_themes() { + this._settings.setValue("light_themes_mouse", System_themes.mouse); + this._settings.setValue("light_themes_apps", System_themes.apps); + this._settings.setValue("light_themes_icons", System_themes.icons); + this._settings.setValue("light_themes_desktop", System_themes.desktop); + this._settings.light_themes_have_been_detected = true; + } + detect_dark_themes() { + this._settings.setValue("dark_themes_mouse", System_themes.mouse); + this._settings.setValue("dark_themes_apps", System_themes.apps); + this._settings.setValue("dark_themes_icons", System_themes.icons); + this._settings.setValue("dark_themes_desktop", System_themes.desktop); + this._settings.dark_themes_have_been_detected = true; + } + apply_light_themes() { + System_themes.mouse = this._settings.getValue("light_themes_mouse"); + System_themes.apps = this._settings.getValue("light_themes_apps"); + System_themes.icons = this._settings.getValue("light_themes_icons"); + System_themes.desktop = this._settings.getValue("light_themes_desktop"); + System_color_scheme.value = "prefer-light"; + } + apply_dark_themes() { + System_themes.mouse = this._settings.getValue("dark_themes_mouse"); + System_themes.apps = this._settings.getValue("dark_themes_apps"); + System_themes.icons = this._settings.getValue("dark_themes_icons"); + System_themes.desktop = this._settings.getValue("dark_themes_desktop"); + System_color_scheme.value = "prefer-dark"; + } +} +const { Gio, GLib: GLib$1 } = imports.gi; +const EXECUTABLE_NAME = "auto-dark-light-time-change-listener"; +const EXECUTABLE_TARGET_FOLDER_PATH = "Time_change_listener"; +class Time_change_listener { + _callback_when_changes; + /** + * @param callback_when_changes - The function to be called when the system time changes. + * @throws {Error} If the `make` or `g++` command is not found in the system. + * @throws {Error} If the compilation of the C++ program fails. + */ + constructor(callback_when_changes) { + this._callback_when_changes = callback_when_changes; + const executable_folder_path = `${metadata.path}/${EXECUTABLE_TARGET_FOLDER_PATH}`; + const executable_path = `${executable_folder_path}/${EXECUTABLE_NAME}`; + if (!GLib$1.file_test(executable_path, GLib$1.FileTest.EXISTS)) + Time_change_listener._compile(executable_folder_path); + this._run(executable_path); + } + static _compile(executable_folder_path) { + if (!GLib$1.find_program_in_path("make") || !GLib$1.find_program_in_path("g++")) + throw new Error(_("Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-based system with 'sudo apt install make g++', then restart Cinnamon (Ctrl+Alt+Esc).")); + const process = new Gio.Subprocess({ + argv: ["make", "-C", executable_folder_path], + flags: Gio.SubprocessFlags.STDERR_PIPE + }); + process.init(null); + try { + const [_ok, _stdout, stderr] = process.communicate_utf8(null, null); + if (!process.get_successful()) + throw new Error(stderr || _("Unknown compilation error")); + } catch (error) { + throw new Error( + `${_("Failed compilation of")} '${EXECUTABLE_NAME}'. + +` + error.message + ); + } finally { + GLib$1.spawn_command_line_async( + `make -C ${executable_folder_path} clean` + ); + } + } + _input; + _input_error; + _output; + _subprocess; + _should_run = true; + _run(executable_path) { + this._subprocess = new Gio.Subprocess({ + argv: [executable_path], + flags: Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDERR_PIPE + }); + this._subprocess.init(null); + this._output = this._subprocess.get_stdin_pipe(); + this._input = new Gio.DataInputStream({ + base_stream: this._subprocess.get_stdout_pipe() + }); + this._input_error = new Gio.DataInputStream({ + base_stream: this._subprocess.get_stderr_pipe() + }); + this._listen_input(); + this._listen_error(); + } + async _listen_input() { + do { + await new Promise( + (resolve) => this._input.read_line_async( + GLib$1.PRIORITY_DEFAULT, + null, + resolve + ) + ); + this._callback_when_changes(); + } while (this._should_run); + } + async _listen_error() { + do { + const [line, length] = await new Promise( + (resolve) => this._input_error.read_line_async( + GLib$1.PRIORITY_DEFAULT, + null, + (source, result) => { + try { + resolve(source.read_line_finish(result)); + } catch (error) { + logger.warn(error); + resolve([null, 0]); + } + } + ) + ); + if (line !== null && length > 0) + logger.warn( + `${_("the subprocess")} \`${EXECUTABLE_NAME}\` ${_("has written on its error output")}${_(":")} ${line}` + ); + } while (this._should_run); + } + /** Enables listening for the system time changes. */ + enable() { + this._output.write("enable\n", null); + } + /** Disables listening for the system time changes. */ + disable() { + this._output.write("disable\n", null); + } + /** Releases acquired resources */ + dispose() { + this._callback_when_changes = () => { + }; + this._should_run = false; + this._output.write("exit\n", null); + this._subprocess.wait(null); + } +} +const { PI, sin, cos, asin, acos, round } = Math; +const TWO_PI = 2 * PI; +const RADIANS_PER_DEGREE = PI / 180; +const SECONDS_PER_DAY = 60 * 60 * 24; +const J0 = 9e-4; +const J1970 = 24405875e-1; +const J2000 = 2451545; +function _to_unix(julian_date) { + return (julian_date - J1970) * SECONDS_PER_DAY; +} +function _approximate_transit(Ht, lw, n) { + return J0 + (Ht + lw) / TWO_PI + n; +} +function _solar_transit(ds, M, L) { + return J2000 + ds + 53e-4 * sin(M) - 69e-4 * sin(2 * L); +} +const EARTH_OBLIQUITY = RADIANS_PER_DEGREE * 23.4397; +const SIN_OF_EARTH_OBLIQUITY = sin(EARTH_OBLIQUITY); +const EARTH_PERIHELION_PLUS_PI = RADIANS_PER_DEGREE * 102.9372 + PI; +const J1970_MINUS_J2000 = J1970 - J2000; +function compute_twilights$1(unix_time, latitude, longitude) { + const lw = RADIANS_PER_DEGREE * -longitude; + const phi = RADIANS_PER_DEGREE * latitude; + const d = unix_time / SECONDS_PER_DAY + J1970_MINUS_J2000; + const n = round(d - J0 - lw / TWO_PI); + const ds = _approximate_transit(0, lw, n); + const M = RADIANS_PER_DEGREE * (0.98560028 * ds + 357.5291); + const center = RADIANS_PER_DEGREE * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 3e-4 * sin(3 * M)); + const L = M + center + EARTH_PERIHELION_PLUS_PI; + const dec = asin(SIN_OF_EARTH_OBLIQUITY * sin(L)); + const julian_noon = _solar_transit(ds, M, L); + const h0 = -0.833 * RADIANS_PER_DEGREE; + const w = acos( + // "hour angle" + (sin(h0) - sin(phi) * sin(dec)) / (cos(phi) * cos(dec)) + ); + const a = _approximate_transit(w, lw, n); + const julian_sunset = _solar_transit(a, M, L); + const julian_sunrise = 2 * julian_noon - julian_sunset; + return [ + _to_unix(julian_sunrise), + _to_unix(julian_sunset) + ]; +} +function compute_twilights(date, location) { + const [sunrise, sunset] = compute_twilights$1( + date.to_unix(), + location.latitude, + location.longitude + ); + return { + sunrise: new_local_time_of_day_from_unix(sunrise), + sunset: new_local_time_of_day_from_unix(sunset) + }; +} +const { DateTime } = imports.gi.GLib; +class Twilights_handler { + _date = DateTime.new_now_local(); + // TODO: could be `null` if timezone is bad or missing? + update() { + this._date = DateTime.new_now_local(); + } + location; + get _location_twilights() { + return compute_twilights(this._date, this.location); + } + auto_sunrise_offset; + auto_sunset_offset; + get auto_sunrise() { + return this._location_twilights.sunrise.add_minutes( + this.auto_sunrise_offset + ); + } + get auto_sunset() { + return this._location_twilights.sunset.add_minutes( + this.auto_sunset_offset + ); + } + manual_sunrise; + manual_sunset; + is_sunrise_auto; + is_sunset_auto; + get _sunrise() { + return this.is_sunrise_auto ? this.auto_sunrise : this.manual_sunrise; + } + get _sunset() { + return this.is_sunset_auto ? this.auto_sunset : this.manual_sunset; + } + get twilights() { + return { sunrise: this._sunrise, sunset: this._sunset }; + } + constructor(initial_values) { + Object.assign(this, initial_values); + makeAutoObservable(this); + } +} +const { GLib } = imports.gi; +const DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING = 2e3; +function initialize_handlers(applet, settings2) { + const location_handler = new Location_handler({ + manual_location: { + latitude: settings2.manual_latitude, + longitude: settings2.manual_longitude + }, + is_location_auto: settings2.is_location_auto + }); + settings2.bind("manual_latitude", null, (value) => { + location_handler.manual_location.latitude = value; + }); + settings2.bind("manual_longitude", null, (value) => { + location_handler.manual_location.longitude = value; + }); + settings2.bind("is_location_auto", null, (value) => { + location_handler.is_location_auto = value; + }); + autorun(() => { + settings2.setValue("system_timezone", location_handler.timezone); + }); + autorun(() => { + settings2.setValue( + // https://github.com/linuxmint/cinnamon/issues/9336 + "auto_latitude", + location_handler.auto_location.latitude + ); + settings2.setValue( + // https://github.com/linuxmint/cinnamon/issues/9336 + "auto_longitude", + location_handler.auto_location.longitude + ); + }); + const twilights_handler = new Twilights_handler({ + location: location_handler.location, + auto_sunrise_offset: settings2.auto_sunrise_offset, + auto_sunset_offset: settings2.auto_sunset_offset, + manual_sunrise: new Time_of_day(settings2.manual_sunrise), + manual_sunset: new Time_of_day(settings2.manual_sunset), + is_sunrise_auto: settings2.is_sunrise_auto, + is_sunset_auto: settings2.is_sunset_auto + }); + autorun(() => { + twilights_handler.location = location_handler.location; + }); + settings2.bind("auto_sunrise_offset", null, (value) => { + twilights_handler.auto_sunrise_offset = value; + }); + settings2.bind("auto_sunset_offset", null, (value) => { + twilights_handler.auto_sunset_offset = value; + }); + settings2.bind("manual_sunrise", null, (value) => { + twilights_handler.manual_sunrise = new Time_of_day(value); + }); + settings2.bind("manual_sunset", null, (value) => { + twilights_handler.manual_sunset = new Time_of_day(value); + }); + settings2.bind("is_sunrise_auto", null, (value) => { + twilights_handler.is_sunrise_auto = value; + }); + settings2.bind("is_sunset_auto", null, (value) => { + twilights_handler.is_sunset_auto = value; + }); + reaction(() => twilights_handler.auto_sunrise, async () => { + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); + settings2.setValue( + // https://github.com/linuxmint/cinnamon/issues/9336 + "auto_sunrise", + twilights_handler.auto_sunrise.get_as_string_hhmm() + ); + }, { fireImmediately: true }); + reaction(() => twilights_handler.auto_sunset, async () => { + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); + settings2.setValue( + // https://github.com/linuxmint/cinnamon/issues/9336 + "auto_sunset", + twilights_handler.auto_sunset.get_as_string_hhmm() + ); + }, { fireImmediately: true }); + const appearance_handler = new Appearance_handler({ + twilights: twilights_handler.twilights, + manual_is_dark: System_color_scheme.value === "prefer-dark", + is_auto: settings2.is_appearance_auto + }); + autorun(() => { + appearance_handler.twilights = twilights_handler.twilights; + }); + applet.on_applet_clicked = () => { + appearance_handler.toggle_is_dark(); + }; + applet.on_applet_middle_clicked = () => { + appearance_handler.toggle_is_auto(); + }; + settings2.bind("is_appearance_dark", null, (value) => { + appearance_handler.manual_is_dark = value; + }); + settings2.bind("is_appearance_auto", null, (value) => { + appearance_handler.is_auto = value; + }); + reaction(() => appearance_handler.manual_is_dark, async () => { + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); + settings2.is_appearance_dark = appearance_handler.manual_is_dark; + }, { fireImmediately: true }); + reaction(() => appearance_handler.is_auto, () => { + settings2.is_appearance_auto = appearance_handler.is_auto; + }); + reaction(() => appearance_handler.is_unsynced, async () => { + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); + settings2.setValue( + // https://github.com/linuxmint/cinnamon/issues/9336 + "is_appearance_unsynced", + appearance_handler.is_unsynced + ); + }, { fireImmediately: true }); + reaction(() => appearance_handler.next_twilight, async () => { + await sleep(DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING); + settings2.setValue( + // https://github.com/linuxmint/cinnamon/issues/9336 + "next_update", + appearance_handler.next_twilight.get_as_string_hhmm() + ); + }, { fireImmediately: true }); + autorun(() => { + applet.set_applet_icon_symbolic_name( + appearance_handler.is_auto ? appearance_handler.is_unsynced ? "auto-inverted-symbolic" : "auto-symbolic" : appearance_handler.manual_is_dark ? "dark-symbolic" : "light-symbolic" + ); + }); + const keybinding_handler = new Keybinding_handler(() => { + appearance_handler.toggle_is_dark(); + }); + keybinding_handler.keybinding = settings2.appearance_keybinding; + settings2.bind("appearance_keybinding", null, (value) => { + keybinding_handler.keybinding = value; + }); + const themes_handler = new Themes_handler(applet, settings2); + if (System_color_scheme.value === "prefer-dark") { + if (settings2.dark_themes_have_been_detected) + themes_handler.detect_dark_themes(); + } else { + if (settings2.light_themes_have_been_detected) + themes_handler.detect_light_themes(); + } + const color_scheme = makeAutoObservable({ + value: System_color_scheme.value + }); + const system_color_scheme = new System_color_scheme((new_color_scheme) => { + color_scheme.value = new_color_scheme; + }); + let is_update_from_system = false; + autorun(() => { + appearance_handler.manual_is_dark = color_scheme.value === "prefer-dark"; + is_update_from_system = true; + }); + const background_handler = new Background_handler(applet, settings2); + const commands_handler = new Commands_handler(applet, settings2); + reaction(() => appearance_handler.manual_is_dark, () => { + if (is_update_from_system === true) { + is_update_from_system = false; + return; + } + if (appearance_handler.manual_is_dark) { + system_color_scheme.disable(); + themes_handler.apply_dark_themes(); + system_color_scheme.enable(); + if (settings2.enable_background) + background_handler.apply_dark_background(); + if (settings2.dark_commands_is_enabled) + commands_handler.launch_dark_commands(); + } else { + system_color_scheme.disable(); + themes_handler.apply_light_themes(); + system_color_scheme.enable(); + if (settings2.enable_background) + background_handler.apply_light_background(); + if (settings2.light_commands_is_enabled) + commands_handler.launch_light_commands(); + } + }, { fireImmediately: true }); + autorun(() => { + if (!appearance_handler.is_auto) + return; + appearance_handler.manual_is_dark = appearance_handler.is_dark; + }); + const time_change_listener = new Time_change_listener( + // Throws + () => runInAction(() => { + twilights_handler.update(); + appearance_handler.update_time(); + if (scheduler.is_set && scheduler.get_if_should_be_expired()) + appearance_handler.sync_is_dark(); + }) + ); + const sleep_events_listener = new Sleep_events_listener( + // on sleep entries: + () => { + time_change_listener.disable(); + }, + // on wake-up unlocked: + () => runInAction(() => { + twilights_handler.update(); + appearance_handler.update_time(); + if (scheduler.is_set && scheduler.get_if_should_be_expired()) + appearance_handler.sync_is_dark(); + time_change_listener.enable(); + }) + ); + const scheduler = new Event_scheduler(); + const schedule_the_event = () => { + scheduler.set_the_event(appearance_handler.next_twilight, () => { + twilights_handler.update(); + appearance_handler.update_time(); + appearance_handler.sync_is_dark(); + }); + }; + reaction(() => appearance_handler.is_auto, () => { + if (appearance_handler.is_auto) { + appearance_handler.update_time(); + appearance_handler.sync_is_dark(); + schedule_the_event(); + time_change_listener.enable(); + sleep_events_listener.enable(); + } else { + scheduler.unset_the_event(); + time_change_listener.disable(); + sleep_events_listener.disable(); + } + }); + reaction(() => appearance_handler.next_twilight, () => { + if (appearance_handler.is_auto) + schedule_the_event(); + }, { fireImmediately: true }); + applet.set_applet_tooltip( + `${_("Click")}${_(":")} ${_("toggle dark/light appearance")} +${_("Middle-click")}${_(":")} ${_("toggle automatic switch")}`, + true + // use_markup + ); + applet.on_button_open_os_timezone_settings = () => GLib.spawn_command_line_async("cinnamon-settings calendar"); + applet.on_button_open_os_themes_settings = () => GLib.spawn_command_line_async("cinnamon-settings themes"); + applet.on_button_open_os_background_settings = () => GLib.spawn_command_line_async("cinnamon-settings background"); + applet.on_applet_removed_from_panel = () => { + keybinding_handler.dispose(); + location_handler.dispose(); + scheduler.dispose(); + sleep_events_listener.dispose(); + system_color_scheme.dispose(); + time_change_listener.dispose(); + settings2.finalize(); + }; + system_color_scheme.enable(); + time_change_listener.enable(); + sleep_events_listener.enable(); +} +const { AppletSettings } = imports.ui.settings; +function initialize_applet_settings(uuid, instance_id) { + const settings2 = new AppletSettings( + {}, + uuid, + instance_id + ); + [ + "is_appearance_dark", + "appearance_keybinding", + "is_appearance_auto", + // 'is_appearance_unsynced', + // 'next_update', + "auto_sunrise_offset", + "auto_sunset_offset", + // 'auto_sunrise', 'auto_sunset', + "manual_sunrise", + "manual_sunset", + "is_sunrise_auto", + "is_sunset_auto", + "manual_latitude", + "manual_longitude", + "is_location_auto", + // 'system_timezone', + // 'auto_latitude', 'auto_longitude', + // 'light_themes_mouse', + // 'light_themes_apps', + // 'light_themes_icons', + // 'light_themes_desktop', + // 'dark_themes_mouse', + // 'dark_themes_apps', + // 'dark_themes_icons', + // 'dark_themes_desktop', + "enable_background", + "light_background_is_slideshow", + "light_background_file", + "light_background_slideshow_folder", + "dark_background_is_slideshow", + "dark_background_file", + "dark_background_slideshow_folder", + "light_commands_is_enabled", + "light_commands_list", + "dark_commands_is_enabled", + "dark_commands_list", + "scheduler_timer_absolute_time", + // TODO: use to get the unsynced appearance state properly restored? + "light_themes_have_been_detected", + "dark_themes_have_been_detected" + // Commented entries because: https://github.com/linuxmint/cinnamon/issues/9336 + ].forEach((key) => settings2.bindWithObject(settings2, key, key)); + return settings2; +} +const { IconApplet } = imports.ui.applet; //! @preserve -function main(n,i,a,o){!function(n){Object.assign(s,n);const i=t.get_home_dir()+"/.local/share/locale";e.bindtextdomain(s.uuid,i),r=_(s.name)}(n);const l=new Is(i,a,o),c=function(e,t){const n=new Ds({},e,t);return["is_appearance_dark","appearance_keybinding","is_appearance_auto","auto_sunrise_offset","auto_sunset_offset","manual_sunrise","manual_sunset","is_sunrise_auto","is_sunset_auto","manual_latitude","manual_longitude","is_location_auto","enable_background","light_background_is_slideshow","light_background_file","light_background_slideshow_folder","dark_background_is_slideshow","dark_background_file","dark_background_slideshow_folder","light_commands_is_enabled","light_commands_list","dark_commands_is_enabled","dark_commands_list","scheduler_timer_absolute_time","light_themes_have_been_detected","dark_themes_have_been_detected"].forEach(e=>n.bindWithObject(n,e,e)),n}(n.uuid,o);try{!function(e,t){const n=new Wi({manual_location:{latitude:t.manual_latitude,longitude:t.manual_longitude},is_location_auto:t.is_location_auto});t.bind("manual_latitude",null,e=>{n.manual_location.latitude=e}),t.bind("manual_longitude",null,e=>{n.manual_location.longitude=e}),t.bind("is_location_auto",null,e=>{n.is_location_auto=e}),qt(()=>{t.setValue("system_timezone",n.timezone)}),qt(()=>{t.setValue("auto_latitude",n.auto_location.latitude),t.setValue("auto_longitude",n.auto_location.longitude)});const i=new Ps({location:n.location,auto_sunrise_offset:t.auto_sunrise_offset,auto_sunset_offset:t.auto_sunset_offset,manual_sunrise:new mi(t.manual_sunrise),manual_sunset:new mi(t.manual_sunset),is_sunrise_auto:t.is_sunrise_auto,is_sunset_auto:t.is_sunset_auto});qt(()=>{i.location=n.location}),t.bind("auto_sunrise_offset",null,e=>{i.auto_sunrise_offset=e}),t.bind("auto_sunset_offset",null,e=>{i.auto_sunset_offset=e}),t.bind("manual_sunrise",null,e=>{i.manual_sunrise=new mi(e)}),t.bind("manual_sunset",null,e=>{i.manual_sunset=new mi(e)}),t.bind("is_sunrise_auto",null,e=>{i.is_sunrise_auto=e}),t.bind("is_sunset_auto",null,e=>{i.is_sunset_auto=e}),Xt(()=>i.auto_sunrise,async()=>{await Xi(Vs),t.setValue("auto_sunrise",i.auto_sunrise.get_as_string_hhmm())},{fireImmediately:!0}),Xt(()=>i.auto_sunset,async()=>{await Xi(Vs),t.setValue("auto_sunset",i.auto_sunset.get_as_string_hhmm())},{fireImmediately:!0});const s=new Ai({twilights:i.twilights,manual_is_dark:"prefer-dark"===ns.value,is_auto:t.is_appearance_auto});qt(()=>{s.twilights=i.twilights}),e.on_applet_clicked=()=>{s.toggle_is_dark()},e.on_applet_middle_clicked=()=>{s.toggle_is_auto()},t.bind("is_appearance_dark",null,e=>{s.manual_is_dark=e}),t.bind("is_appearance_auto",null,e=>{s.is_auto=e}),Xt(()=>s.manual_is_dark,async()=>{await Xi(Vs),t.is_appearance_dark=s.manual_is_dark},{fireImmediately:!0}),Xt(()=>s.is_auto,()=>{t.is_appearance_auto=s.is_auto}),Xt(()=>s.is_unsynced,async()=>{await Xi(Vs),t.setValue("is_appearance_unsynced",s.is_unsynced)},{fireImmediately:!0}),Xt(()=>s.next_twilight,async()=>{await Xi(Vs),t.setValue("next_update",s.next_twilight.get_as_string_hhmm())},{fireImmediately:!0}),qt(()=>{e.set_applet_icon_symbolic_name(s.is_auto?s.is_unsynced?"auto-inverted-symbolic":"auto-symbolic":s.manual_is_dark?"dark-symbolic":"light-symbolic")});const r=new $i(()=>{s.toggle_is_dark()});r.keybinding=t.appearance_keybinding,t.bind("appearance_keybinding",null,e=>{r.keybinding=e});const a=new as(e,t);"prefer-dark"===ns.value?t.dark_themes_have_been_detected&&a.detect_dark_themes():t.light_themes_have_been_detected&&a.detect_light_themes();const o=yn({value:ns.value}),u=new ns(e=>{o.value=e});let l=!1;qt(()=>{s.manual_is_dark="prefer-dark"===o.value,l=!0});const c=new Pi(e,t),h=new Ni(e,t);Xt(()=>s.manual_is_dark,()=>{!0!==l?s.manual_is_dark?(u.disable(),a.apply_dark_themes(),u.enable(),t.enable_background&&c.apply_dark_background(),t.dark_commands_is_enabled&&h.launch_dark_commands()):(u.disable(),a.apply_light_themes(),u.enable(),t.enable_background&&c.apply_light_background(),t.light_commands_is_enabled&&h.launch_light_commands()):l=!1},{fireImmediately:!0}),qt(()=>{s.is_auto&&(s.manual_is_dark=s.is_dark)});const d=new ls(()=>zt(()=>{i.update(),s.update_time(),g.is_set&&g.get_if_should_be_expired()&&s.sync_is_dark()})),f=new Qi(()=>{d.disable()},()=>zt(()=>{i.update(),s.update_time(),g.is_set&&g.get_if_should_be_expired()&&s.sync_is_dark(),d.enable()})),g=new Bi,p=()=>{g.set_the_event(s.next_twilight,()=>{i.update(),s.update_time(),s.sync_is_dark()})};Xt(()=>s.is_auto,()=>{s.is_auto?(s.update_time(),s.sync_is_dark(),p(),d.enable(),f.enable()):(g.unset_the_event(),d.disable(),f.disable())}),Xt(()=>s.next_twilight,()=>{s.is_auto&&p()},{fireImmediately:!0}),e.set_applet_tooltip(`${_("Click")}${_(":")} ${_("toggle dark/light appearance")}\n${_("Middle-click")}${_(":")} ${_("toggle automatic switch")}`,!0),e.on_button_open_os_timezone_settings=()=>Ts.spawn_command_line_async("cinnamon-settings calendar"),e.on_button_open_os_themes_settings=()=>Ts.spawn_command_line_async("cinnamon-settings themes"),e.on_button_open_os_background_settings=()=>Ts.spawn_command_line_async("cinnamon-settings background"),e.on_applet_removed_from_panel=()=>{r.dispose(),n.dispose(),g.dispose(),f.dispose(),u.dispose(),d.dispose(),t.finalize()},u.enable(),d.enable(),f.enable()}(l,c)}catch(h){l.set_applet_icon_symbolic_name("on-error-symbolic"),h instanceof Error?u.error(h.message):u.error(String(h)),c.finalize()}return l} +function main(metadata2, orientation, panel_height, instance_id) { + initialize_globals(metadata2); + const applet = new IconApplet( + orientation, + panel_height, + instance_id + ); + const settings2 = initialize_applet_settings(metadata2.uuid, instance_id); + try { + initialize_handlers(applet, settings2); + } catch (error) { + applet.set_applet_icon_symbolic_name("on-error-symbolic"); + if (error instanceof Error) + logger.error(error.message); + else + logger.error(String(error)); + settings2.finalize(); + } + return applet; +} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js.sha256sum b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js.sha256sum deleted file mode 100644 index 58f0429636c..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js.sha256sum +++ /dev/null @@ -1 +0,0 @@ -122d3313587ab5ab3543c309c5eca6a3dace69cb27e3d6dd96e031982978d4b7 applet.js diff --git a/auto-dark-light@gihaume/package.json b/auto-dark-light@gihaume/package.json index a99541cb2f7..ec8a5c7dd07 100644 --- a/auto-dark-light@gihaume/package.json +++ b/auto-dark-light@gihaume/package.json @@ -1,7 +1,7 @@ { "scripts": { "dev": "vite build --watch", - "build": "vite build --mode=final", + "build": "vite build", "test": "vitest" }, "dependencies": { diff --git a/auto-dark-light@gihaume/src/main.ts b/auto-dark-light@gihaume/src/main.ts index 73267b4e007..6fbabb3d54c 100644 --- a/auto-dark-light@gihaume/src/main.ts +++ b/auto-dark-light@gihaume/src/main.ts @@ -34,4 +34,4 @@ function main( return applet; } -(globalThis as any)[import.meta.env.VITE_KEEP_MAIN_FUNCTION_SENTINEL] = main; // Prevents transpilation tree-shaking +(globalThis as any).__auto_dark_light__ = main; // Prevents transpilation tree-shaking diff --git a/auto-dark-light@gihaume/src/vite-env.d.ts b/auto-dark-light@gihaume/src/vite-env.d.ts deleted file mode 100644 index bb894d499cf..00000000000 --- a/auto-dark-light@gihaume/src/vite-env.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Typing for workspace root's `.env`. - * - * Doc: https://vite.dev/guide/env-and-mode.html#intellisense-for-typescript - */ - -interface ViteTypeOptions {} // Makes the type of ImportMetaEnv strict to disallow unknown keys. - -interface ImportMetaEnv { - readonly VITE_KEEP_MAIN_FUNCTION_SENTINEL: string -} - -interface ImportMeta { - readonly env: ImportMetaEnv -} diff --git a/auto-dark-light@gihaume/vite.config.mts b/auto-dark-light@gihaume/vite.config.mts index d2657d3416a..99c6c023cab 100644 --- a/auto-dark-light@gihaume/vite.config.mts +++ b/auto-dark-light@gihaume/vite.config.mts @@ -1,64 +1,30 @@ /// -import * as child_process from 'child_process'; import * as vite from 'vite'; -export default vite.defineConfig(({ command, mode }) => { - const env = vite.loadEnv(mode, process.cwd(), 'VITE_'); - const out_dir_path = './files/auto-dark-light@gihaume/5.8'; - const out_file_name = 'applet.js'; - - const config: vite.UserConfig = { - build: { - minify: false, - rollupOptions: { - input: 'src/main.ts', - output: { - dir: out_dir_path, - entryFileNames: out_file_name - } - }, - emptyOutDir: false, - }, - plugins: [], // To be filled below - test: {}, // To be filled with Vitest options when needed - }; - if (mode === 'final') { - config.build!.minify = 'terser'; - config.build!.terserOptions = { - keep_fnames: /^main$|^_$/ - }; - config.plugins!.push({ - name: 'remove-globalThis-injection', - generateBundle(_, bundle) { - for (const output of Object.values(bundle)) { - if (output.type !== 'chunk') - continue; - const sentinel = env.VITE_KEEP_MAIN_FUNCTION_SENTINEL; - const pattern = new RegExp( - `globalThis\.${sentinel}=(.*);`, 's' - ); - output.code = output.code.replace(pattern, '$1'); - } +export default vite.defineConfig({ + build: { + minify: false, + rollupOptions: { + input: 'src/main.ts', + output: { + dir: './files/auto-dark-light@gihaume/5.8', + entryFileNames: 'applet.js' } - }); - config.plugins!.push({ - name: 'add-checksum-on-build', - writeBundle() { - child_process.execSync( - `cd ${out_dir_path} && sha256sum ${out_file_name} > ${out_file_name}.sha256sum` - ); - } - }); - } - else - config.plugins!.push({ - name: 'remove-checksum-on-dev-build', - writeBundle() { - child_process.execSync( - `rm -f ${out_dir_path}/${out_file_name}.sha256sum` - ); + }, + emptyOutDir: false, + }, + plugins: [{ + name: 'remove-globalThis-injection-line', + generateBundle(_, bundle) { + for (const output of Object.values(bundle)) { + if (output.type !== 'chunk') + continue; + const lines = output.code.split('\n'); + lines.splice(lines.length - 2, 1); // Removes the second-to-last line + output.code = lines.join('\n') } - }); - return config; + } + }], + test: {}, // To be filled with Vitest options when needed }); From cba97996623a5b23b40d431b158762c0691790df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Sun, 2 Nov 2025 23:32:05 +0100 Subject: [PATCH 05/13] Remove slight relicat of Terser use for minification --- .../files/auto-dark-light@gihaume/5.8/applet.js | 1 - auto-dark-light@gihaume/src/main.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index a4a47d117aa..6421f6f9068 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -5413,7 +5413,6 @@ function initialize_applet_settings(uuid, instance_id) { return settings2; } const { IconApplet } = imports.ui.applet; -//! @preserve function main(metadata2, orientation, panel_height, instance_id) { initialize_globals(metadata2); const applet = new IconApplet( diff --git a/auto-dark-light@gihaume/src/main.ts b/auto-dark-light@gihaume/src/main.ts index 6fbabb3d54c..180de9e9fe5 100644 --- a/auto-dark-light@gihaume/src/main.ts +++ b/auto-dark-light@gihaume/src/main.ts @@ -5,7 +5,6 @@ import { initialize_globals, logger } from './globals'; import { initialize_handlers } from './app/handlers/initialize_handlers'; import { initialize_applet_settings } from './app/initialize_applet_settings'; -//! @preserve function main( metadata: imports.ui.applet.AppletMetadata, orientation: imports.gi.St.Side, From b21aea63fb358ef28c4d5b05f65557bc1f8128f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Sat, 22 Nov 2025 13:26:39 +0100 Subject: [PATCH 06/13] Replace C++ passive `Time_change_listener` by JS active `Wall_clock_adjustment_monitor` --- auto-dark-light@gihaume/.vscode/settings.json | 3 +- auto-dark-light@gihaume/CHANGELOG.md | 5 +- auto-dark-light@gihaume/README.md | 6 +- .../5.8/Time_change_listener/.gitignore | 2 - .../5.8/Time_change_listener/Makefile | 28 -- .../Time_change_listener.cpp | 83 ----- .../Time_change_listener.hpp | 42 --- .../5.8/Time_change_listener/main.cpp | 50 --- .../auto-dark-light@gihaume/5.8/applet.js | 296 ++++++++---------- .../src/app/handlers/initialize_handlers.ts | 31 +- .../src/lib/sys/Time_change_listener.ts | 147 --------- .../lib/sys/Wall_clock_adjustment_monitor.js | 95 ++++++ .../test Wall_clock_adjustment_monitor.js | 15 + auto-dark-light@gihaume/src/types.ts | 15 + auto-dark-light@gihaume/tsconfig.json | 6 +- 15 files changed, 276 insertions(+), 548 deletions(-) delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/.gitignore delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Makefile delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.cpp delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.hpp delete mode 100644 auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/main.cpp delete mode 100644 auto-dark-light@gihaume/src/lib/sys/Time_change_listener.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/Wall_clock_adjustment_monitor.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/tests/test Wall_clock_adjustment_monitor.js diff --git a/auto-dark-light@gihaume/.vscode/settings.json b/auto-dark-light@gihaume/.vscode/settings.json index 7d955dffb7d..c981030bccd 100644 --- a/auto-dark-light@gihaume/.vscode/settings.json +++ b/auto-dark-light@gihaume/.vscode/settings.json @@ -2,6 +2,5 @@ "typescript.tsdk": "node_modules/typescript/lib", "python.analysis.extraPaths": [ "/usr/share/cinnamon/cinnamon-settings/bin" - ], - "C_Cpp.default.cppStandard": "c++20" + ] } diff --git a/auto-dark-light@gihaume/CHANGELOG.md b/auto-dark-light@gihaume/CHANGELOG.md index 27071b677d0..11177555486 100644 --- a/auto-dark-light@gihaume/CHANGELOG.md +++ b/auto-dark-light@gihaume/CHANGELOG.md @@ -23,14 +23,15 @@ Extensive rewrite to enable new features – some bugs may have been introduced. - Themes fields to be read-only. - Timezone coordinates local database to be the same as the ones used by Cinnamon Settings Daemon's Night Light. - Note that there can still be a difference in the twilight times as their calculation is done differently. -- Improved logging and notifications types for better look and clarity. +- Improvement of logging and notifications types for better look and clarity. ### Changed (internal) - Use of MobX for scalable reactive state management. - Use of Vite transpilation for better imports handling, use of external libraries and bundling. -- Use of TypeScript for better typing expressivity. +- Use of TypeScript for more concise typing. - Use of Vitest for unit testing. +- Replacement of the C++ wall-clock adjustment (passive) listener for a simpler JavaScript monitor counterpart (active polling). ## [1.2.6] - 2025-05-18 - [#7257](https://github.com/linuxmint/cinnamon-spices-applets/pull/7257) diff --git a/auto-dark-light@gihaume/README.md b/auto-dark-light@gihaume/README.md index 15162272518..44f89b7fb4d 100644 --- a/auto-dark-light@gihaume/README.md +++ b/auto-dark-light@gihaume/README.md @@ -16,7 +16,7 @@ The appearance consists of: - Always sync instantaneously with system changes of color scheme (appearance), region/city and time (useful in e.g. after a sleep wake up). - Automatic appearance switch can be disabled. - Dark/light appearance can always be switched manually. -- Everything is fully event-listening and scheduling based (no active polling). +- Almost everything is fully event-listening and scheduling based (no active monitoring, except for wall-clock adjustment). ## Applet icons legend @@ -41,10 +41,6 @@ The appearance consists of: The applet is in an error state and is not functional. A notification should have been shown giving more details about the error. If it has disappeared, it is possible to find it in the Looking Glass logs: press Alt+F2 and enter 'lg'. -## Dependencies - -`make` and `g++`, which can be installed on Debian-based system with `sudo apt install make g++`. - ## Feedback - Add a `⭐ Score` on the [Cinnamon spices page](https://cinnamon-spices.linuxmint.com/applets/view/397)'s top if you like this applet. diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/.gitignore b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/.gitignore deleted file mode 100644 index 1dc1265edc6..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build -auto-dark-light-time-change-listener diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Makefile b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Makefile deleted file mode 100644 index b1202004ce1..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -BUILD_FOLDER := build -SOURCE_FILES := $(wildcard *.cpp) -OBJECT_FILES := $(patsubst %.cpp, $(BUILD_FOLDER)/%.o, $(SOURCE_FILES)) -EXECUTABLE := auto-dark-light-time-change-listener -COMPILER := g++ -COMPILER_FLAGS := -std=c++20 -LINKER_FLAGS := - - -all: build - - -build: $(EXECUTABLE) - --include $(OBJECT_FILES:.o=.d) - -$(EXECUTABLE): $(OBJECT_FILES) - $(COMPILER) -o $@ $^ $(LINKER_FLAGS) - -$(BUILD_FOLDER)/%.o: %.cpp - @mkdir -p $(@D) - $(COMPILER) -c $(COMPILER_FLAGS) -o $@ $< -MMD -MF $(@:.o=.d) - - -clean: - $(RM) -rf $(BUILD_FOLDER) - -.PHONY: all build clean diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.cpp b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.cpp deleted file mode 100644 index 89525a785ae..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "Time_change_listener.hpp" - -#include -#include - -#include -#include -#include -#include -#include - -namespace { - -std::system_error system_error(const char* what) { - return std::system_error{errno, std::system_category(), what}; -} - -// To inject instructions in the constructor's `fd` initializer -int new_timerfd() { - int fd = ::timerfd_create(CLOCK_REALTIME, 0); - if (fd == -1) - throw system_error( - "Time_change_listener::new_timer_fd: timerfd_create failed" - ); - return fd; -} - -} // namespace - -Time_change_listener::Time_change_listener(std::function callback) : - fd{new_timerfd()}, - callback{callback}, - listener_thread{&This::listener_thread_function, this} -{} - -void Time_change_listener::listener_thread_function() const { - do { - static uint64_t dull_buffer; - if (-1 == ::read(this->fd, &dull_buffer, sizeof(dull_buffer))) { - if (errno == ECANCELED) { // system time changed - this->callback(); - continue; - } else { - std::cerr << "Time_change_listener::listener_thread_function: " - "read failed: " << std::strerror(errno) - << std::endl; - return; - } - } - } while (this->should_listener_thread_run); -} - -static constexpr struct itimerspec SETTIME_NEVER = {{0, 0}, {0, 0}}; - -void Time_change_listener::enable() const { - static constexpr auto FLAGS = TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET; - if (-1 == ::timerfd_settime(this->fd, FLAGS, &SETTIME_NEVER, NULL)) - throw system_error( - "Time_change_listener::enable: timerfd_settime failed" - ); -} - -void Time_change_listener::disable() const { - if (-1 == ::timerfd_settime(this->fd, 0, &SETTIME_NEVER, nullptr)) - throw system_error( - "Time_change_listener::disable: timerfd_settime failed" - ); -} - -Time_change_listener::~Time_change_listener() { - this->should_listener_thread_run = false; - - static constexpr struct itimerspec VIRTUALLY_NOW = {{0, 0}, {0, 1}}; // "Once, in 1 ns" - - if (-1 == ::timerfd_settime(this->fd, 0, &VIRTUALLY_NOW, nullptr)) // Unblocks the blocked `read` call in the `listener_thread_function` method - std::cerr << "Time_change_listener::~Time_change_listener: " - "timerfd_settime failed: " - << std::strerror(errno) << std::endl; - - if (-1 == ::close(this->fd)) - std::cerr << "Time_change_listener::~Time_change_listener: " - "close failed: " << std::strerror(errno) << std::endl; -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.hpp b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.hpp deleted file mode 100644 index c6b094f8a7b..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/Time_change_listener.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include -#include - -/** - * @brief A passive listener for system time changes implementing the kernel's `TFD_TIMER_CANCEL_ON_SET` flag feature. - */ -class Time_change_listener { - using This = Time_change_listener; - - // Owned ressource (mustn't be copied) - Time_change_listener(const This&) = delete; - This& operator=(const This&) = delete; - - public: - /** - * @param callback The function to be called to notify when the system time changes. - * @throw `std::system_error` if the internal timer file descriptor failed to be created due to any operating system restriction. - */ - Time_change_listener(std::function callback); - - /** - * @brief Enable listening for the system time changes. - */ - void enable() const; - - /** - * @brief Disable listening for the system time changes. - */ - void disable() const; - - ~Time_change_listener(); - - private: - const int fd; // Linux file descriptor - const std::function callback; - const std::jthread listener_thread; - std::atomic_bool should_listener_thread_run = true; - void listener_thread_function() const; -}; diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/main.cpp b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/main.cpp deleted file mode 100644 index 6dda301c45e..00000000000 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/Time_change_listener/main.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "Time_change_listener.hpp" - -int main(int argc, char* argv[]) { - if ( - std::any_of(argv, argv + argc, [](char* arg) { - return std::string_view(arg) == "--help"; - }) - ) { - std::cout - << "Listens for system time changes and prints 'changed' to `stdout` each time it occurs.\n" - << '\n' - << "Commands via `stdin`:\n" - << " 'enable': Enable listening for the system time changes.\n" - << " 'disable': Disable listening for the system time changes.\n" - << " 'exit': Exit the program.\n" - << '\n' - << "Options:\n" - << " --help: Display this help message.\n" - << std::endl; - return 0; - } - - try { - Time_change_listener listener([]() { - std::cout << "changed" << std::endl; - }); - - std::string input; - while (std::getline(std::cin, input)) { - if (input == "enable") - listener.enable(); - else - if (input == "disable") - listener.disable(); - else - if (input == "exit") - break; - } - } catch (const std::exception& e) { - std::cerr << e.what() << std::endl; - return 1; - } -} diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index 6421f6f9068..53e2d991541 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -4260,10 +4260,10 @@ class Appearance_handler { makeAutoObservable(this); } } -const { Gio: Gio$8 } = imports.gi; +const { Gio: Gio$7 } = imports.gi; const settings$2 = { - background: Gio$8.Settings.new("org.cinnamon.desktop.background"), - slideshow: Gio$8.Settings.new("org.cinnamon.desktop.background.slideshow") + background: Gio$7.Settings.new("org.cinnamon.desktop.background"), + slideshow: Gio$7.Settings.new("org.cinnamon.desktop.background.slideshow") }; class System_background { static get is_slideshow() { @@ -4339,7 +4339,7 @@ class Background_handler { System_background.picture_file = this._settings.dark_background_file; } } -const { Gio: Gio$7, GLib: GLib$4 } = imports.gi; +const { Gio: Gio$6, GLib: GLib$4 } = imports.gi; async function launch_command(name, expiry, command) { try { await _launch_command(command, expiry); @@ -4351,13 +4351,13 @@ async function launch_command(name, expiry, command) { ${_("Detail")}${_(":")} ` + error.message; - else if (error instanceof Gio$7.IOErrorEnum) { - if (error.code === Gio$7.IOErrorEnum.TIMED_OUT) + else if (error instanceof Gio$6.IOErrorEnum) { + if (error.code === Gio$6.IOErrorEnum.TIMED_OUT) msg += ` ${_("due to timeout")}. ${_("Detail")}${_(":")} ` + error.message; - else if (error.code === Gio$7.IOErrorEnum.FAILED) + else if (error.code === Gio$6.IOErrorEnum.FAILED) msg += ` ${_("due to an error")}. ${_("Detail")}${_(":")} @@ -4373,9 +4373,9 @@ const SIGKILL_TIMEOUT = 10; async function _launch_command(command, timeout = 10) { const wrapped_command = `timeout --kill-after=${SIGKILL_TIMEOUT} ${timeout}s sh -c ${GLib$4.shell_quote(command)}`; const [_ok, argvp] = GLib$4.shell_parse_argv(wrapped_command); - const process = new Gio$7.Subprocess({ + const process = new Gio$6.Subprocess({ argv: argvp, - flags: Gio$7.SubprocessFlags.STDERR_PIPE + flags: Gio$6.SubprocessFlags.STDERR_PIPE }); const start_time = Date.now(); process.init(null); @@ -4402,25 +4402,25 @@ async function _launch_command(command, timeout = 10) { case 0: break; case TIMEOUT_EXIT_STATUS_SIGTERM: - throw new Gio$7.IOErrorEnum({ - code: Gio$7.IOErrorEnum.TIMED_OUT, + throw new Gio$6.IOErrorEnum({ + code: Gio$6.IOErrorEnum.TIMED_OUT, message: `may have been timed out by SIGTERM (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGTERM})` }); case TIMEOUT_EXIT_STATUS_SIGKILL: - throw new Gio$7.IOErrorEnum({ - code: Gio$7.IOErrorEnum.TIMED_OUT, + throw new Gio$6.IOErrorEnum({ + code: Gio$6.IOErrorEnum.TIMED_OUT, message: `probably killed by an external SIGKILL (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGKILL})` }); case 1: if (timeout > 0 && elapsed_time >= timeout + SIGKILL_TIMEOUT) - throw new Gio$7.IOErrorEnum({ - code: Gio$7.IOErrorEnum.TIMED_OUT, + throw new Gio$6.IOErrorEnum({ + code: Gio$6.IOErrorEnum.TIMED_OUT, message: `probably timed out by SIGKILL` }); // no break, needs to stay directly above the default case default: - throw new Gio$7.IOErrorEnum({ - code: Gio$7.IOErrorEnum.FAILED, + throw new Gio$6.IOErrorEnum({ + code: Gio$6.IOErrorEnum.FAILED, message: stderr ? stderr.trim() : "exit status: " + exit_status }); } @@ -4525,7 +4525,7 @@ class Keybinding_handler { Main.keybindingManager.removeHotKey(this._name); } } -const { Gio: Gio$6 } = imports.gi; +const { Gio: Gio$5 } = imports.gi; class Timezone_change_listener { _callback_on_change; /** @param callback_on_change - The function to be executed when the system timezone changes. */ @@ -4546,7 +4546,7 @@ class Timezone_change_listener { _subscribe_to_changes(callback_when_changes) { if (this._signal_id) this._unsubscribe_to_changes(); - this._signal_id = Gio$6.DBus.system.signal_subscribe( + this._signal_id = Gio$5.DBus.system.signal_subscribe( "org.freedesktop.timedate1", // sender "org.freedesktop.DBus.Properties", @@ -4557,7 +4557,7 @@ class Timezone_change_listener { // object_path null, // arg0 - Gio$6.DBusSignalFlags.NONE, + Gio$5.DBusSignalFlags.NONE, // flags (_1, _2, _3, _4, _5, parameters) => { const changed_properties = parameters.deep_unpack()[1]; @@ -4571,11 +4571,11 @@ class Timezone_change_listener { _unsubscribe_to_changes() { if (!this._signal_id) return; - Gio$6.DBus.system.signal_unsubscribe(this._signal_id); + Gio$5.DBus.system.signal_unsubscribe(this._signal_id); this._signal_id = void 0; } } -const { Gio: Gio$5 } = imports.gi; +const { Gio: Gio$4 } = imports.gi; class Timezone_location_finder { _database; /** @@ -4584,7 +4584,7 @@ class Timezone_location_finder { */ constructor(path) { const file_path = `${path}/database.json`; - const file = Gio$5.File.new_for_path(file_path); + const file = Gio$4.File.new_for_path(file_path); const [ok, file_content] = file.load_contents(null); if (!ok) throw new Error(`failed to load file/contents of '${file_path}'`); @@ -4643,7 +4643,7 @@ class Location_handler { async function sleep(duration) { return new Promise((resolve) => setTimeout(resolve, duration)); } -const { Gio: Gio$4 } = imports.gi; +const { Gio: Gio$3 } = imports.gi; class Screen_lock_checker { /** * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. @@ -4675,7 +4675,7 @@ class Screen_lock_checker { _subscribe_to_changes(callback_when_changes) { if (this._signal_id) this._unsubscribe_to_changes(); - this._signal_id = Gio$4.DBus.session.signal_subscribe( + this._signal_id = Gio$3.DBus.session.signal_subscribe( "org.cinnamon.ScreenSaver", // sender "org.cinnamon.ScreenSaver", @@ -4686,7 +4686,7 @@ class Screen_lock_checker { // object_path null, // arg0 - Gio$4.DBusSignalFlags.NONE, + Gio$3.DBusSignalFlags.NONE, // flags (_1, _2, _3, _4, _5, parameters) => { const is_locked = parameters.deep_unpack()[0]; @@ -4697,7 +4697,7 @@ class Screen_lock_checker { _unsubscribe_to_changes() { if (!this._signal_id) return; - Gio$4.DBus.session.signal_unsubscribe(this._signal_id); + Gio$3.DBus.session.signal_unsubscribe(this._signal_id); this._signal_id = void 0; } /** @@ -4705,7 +4705,7 @@ class Screen_lock_checker { * @param callback_for_result - The callback object to handle the result. */ static _get_state_async(callback_for_result) { - Gio$4.DBus.session.call( + Gio$3.DBus.session.call( "org.cinnamon.ScreenSaver", // bus_name "/org/cinnamon/ScreenSaver", @@ -4718,7 +4718,7 @@ class Screen_lock_checker { // parameters null, // reply_type - Gio$4.DBusCallFlags.NONE, + Gio$3.DBusCallFlags.NONE, // flags -1, // timeout_msec @@ -4732,7 +4732,7 @@ class Screen_lock_checker { ); } } -const { Gio: Gio$3 } = imports.gi; +const { Gio: Gio$2 } = imports.gi; class Sleep_events_listener { _callback_when_sleep_entries; _callback_when_wakeup_unlocked; @@ -4769,7 +4769,7 @@ class Sleep_events_listener { _subscribe_to_changes(callback) { if (this._signal_id) this._unsubscribe_to_changes(); - this._signal_id = Gio$3.DBus.system.signal_subscribe( + this._signal_id = Gio$2.DBus.system.signal_subscribe( "org.freedesktop.login1", // sender "org.freedesktop.login1.Manager", @@ -4780,7 +4780,7 @@ class Sleep_events_listener { // object_path null, // arg0 - Gio$3.DBusSignalFlags.NONE, + Gio$2.DBusSignalFlags.NONE, // flags (_1, _2, _3, _4, _5, parameters) => { const is_sleeping = parameters.deep_unpack()[0]; @@ -4791,12 +4791,12 @@ class Sleep_events_listener { _unsubscribe_to_changes() { if (!this._signal_id) return; - Gio$3.DBus.system.signal_unsubscribe(this._signal_id); + Gio$2.DBus.system.signal_unsubscribe(this._signal_id); this._signal_id = void 0; } } -const { Gio: Gio$2 } = imports.gi; -const settings$1 = Gio$2.Settings.new("org.x.apps.portal"); +const { Gio: Gio$1 } = imports.gi; +const settings$1 = Gio$1.Settings.new("org.x.apps.portal"); class System_color_scheme { _callback_on_change; _signal_id = void 0; @@ -4827,10 +4827,10 @@ class System_color_scheme { settings$1.set_string("color-scheme", value); } } -const { Gio: Gio$1 } = imports.gi; +const { Gio } = imports.gi; const settings = { - desktop: Gio$1.Settings.new("org.cinnamon.desktop.interface"), - cinnamon: Gio$1.Settings.new("org.cinnamon.theme") + desktop: Gio.Settings.new("org.cinnamon.desktop.interface"), + cinnamon: Gio.Settings.new("org.cinnamon.theme") }; class System_themes { static get mouse() { @@ -4896,120 +4896,6 @@ class Themes_handler { System_color_scheme.value = "prefer-dark"; } } -const { Gio, GLib: GLib$1 } = imports.gi; -const EXECUTABLE_NAME = "auto-dark-light-time-change-listener"; -const EXECUTABLE_TARGET_FOLDER_PATH = "Time_change_listener"; -class Time_change_listener { - _callback_when_changes; - /** - * @param callback_when_changes - The function to be called when the system time changes. - * @throws {Error} If the `make` or `g++` command is not found in the system. - * @throws {Error} If the compilation of the C++ program fails. - */ - constructor(callback_when_changes) { - this._callback_when_changes = callback_when_changes; - const executable_folder_path = `${metadata.path}/${EXECUTABLE_TARGET_FOLDER_PATH}`; - const executable_path = `${executable_folder_path}/${EXECUTABLE_NAME}`; - if (!GLib$1.file_test(executable_path, GLib$1.FileTest.EXISTS)) - Time_change_listener._compile(executable_folder_path); - this._run(executable_path); - } - static _compile(executable_folder_path) { - if (!GLib$1.find_program_in_path("make") || !GLib$1.find_program_in_path("g++")) - throw new Error(_("Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-based system with 'sudo apt install make g++', then restart Cinnamon (Ctrl+Alt+Esc).")); - const process = new Gio.Subprocess({ - argv: ["make", "-C", executable_folder_path], - flags: Gio.SubprocessFlags.STDERR_PIPE - }); - process.init(null); - try { - const [_ok, _stdout, stderr] = process.communicate_utf8(null, null); - if (!process.get_successful()) - throw new Error(stderr || _("Unknown compilation error")); - } catch (error) { - throw new Error( - `${_("Failed compilation of")} '${EXECUTABLE_NAME}'. - -` + error.message - ); - } finally { - GLib$1.spawn_command_line_async( - `make -C ${executable_folder_path} clean` - ); - } - } - _input; - _input_error; - _output; - _subprocess; - _should_run = true; - _run(executable_path) { - this._subprocess = new Gio.Subprocess({ - argv: [executable_path], - flags: Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDERR_PIPE - }); - this._subprocess.init(null); - this._output = this._subprocess.get_stdin_pipe(); - this._input = new Gio.DataInputStream({ - base_stream: this._subprocess.get_stdout_pipe() - }); - this._input_error = new Gio.DataInputStream({ - base_stream: this._subprocess.get_stderr_pipe() - }); - this._listen_input(); - this._listen_error(); - } - async _listen_input() { - do { - await new Promise( - (resolve) => this._input.read_line_async( - GLib$1.PRIORITY_DEFAULT, - null, - resolve - ) - ); - this._callback_when_changes(); - } while (this._should_run); - } - async _listen_error() { - do { - const [line, length] = await new Promise( - (resolve) => this._input_error.read_line_async( - GLib$1.PRIORITY_DEFAULT, - null, - (source, result) => { - try { - resolve(source.read_line_finish(result)); - } catch (error) { - logger.warn(error); - resolve([null, 0]); - } - } - ) - ); - if (line !== null && length > 0) - logger.warn( - `${_("the subprocess")} \`${EXECUTABLE_NAME}\` ${_("has written on its error output")}${_(":")} ${line}` - ); - } while (this._should_run); - } - /** Enables listening for the system time changes. */ - enable() { - this._output.write("enable\n", null); - } - /** Disables listening for the system time changes. */ - disable() { - this._output.write("disable\n", null); - } - /** Releases acquired resources */ - dispose() { - this._callback_when_changes = () => { - }; - this._should_run = false; - this._output.write("exit\n", null); - this._subprocess.wait(null); - } -} const { PI, sin, cos, asin, acos, round } = Math; const TWO_PI = 2 * PI; const RADIANS_PER_DEGREE = PI / 180; @@ -5106,6 +4992,82 @@ class Twilights_handler { makeAutoObservable(this); } } +const { GLib: GLib$1 } = imports.gi; +class Wall_clock_adjustment_monitor { + /** In seconds (s) + * @private */ + _monitoring_interval = 10; + /** Check interval, in integer seconds (s) greater or equal to 1, defaults to 10 + * @returns {number} */ + get monitoring_interval() { + return this._monitoring_interval; + } + set monitoring_interval(value) { + value = Math.max(1, value); + value = Math.round(value); + this._monitoring_interval = value; + if (this._timeout_id) { + this.disable(); + this.enable(); + } + } + /** Function to call when the wall clock has been modified, defaults to null + * @type {(() => void) | null} */ + callback = null; + /** @private @type {ReturnType | null} */ + _timeout_id = null; + /** In microseconds (µs) + * @private */ + _last_wall_clock_time = Number(); + /** In microseconds (µs) + * @private */ + _last_monotonic_time = Number(); + enable() { + if (this._timeout_id) + return; + this._last_wall_clock_time = GLib$1.get_real_time(); + this._last_monotonic_time = GLib$1.get_monotonic_time(); + this._timeout_id = GLib$1.timeout_add_seconds( + GLib$1.PRIORITY_DEFAULT, + this._monitoring_interval, + this._timeout_function + ); + } + /** In microseconds (µs) + * @private */ + _time_difference_tolerance = 2e6; + /** Maximum for time difference between wall clock and monotonic times to not trigger the callback, in seconds (s) greater or equal to 1, defaults to 2 + * @returns {number} */ + get time_difference_tolerance() { + return this._time_difference_tolerance / 1e6; + } + set time_difference_tolerance(value) { + value *= 1e6; + value = Math.max(1, value); + this._time_difference_tolerance = value; + } + /** @private @type {Parameters[2]} */ + _timeout_function = () => { + const wall_clock_time = GLib$1.get_real_time(), monotonic_time = GLib$1.get_monotonic_time(); + const delta_wall_clock = wall_clock_time - this._last_wall_clock_time; + const delta_monotonic = monotonic_time - this._last_monotonic_time; + const difference = Math.abs(delta_wall_clock - delta_monotonic); + if (difference > this._time_difference_tolerance) + this.callback?.(); + this._last_wall_clock_time = wall_clock_time; + this._last_monotonic_time = monotonic_time; + return GLib$1.SOURCE_CONTINUE; + }; + disable() { + if (!this._timeout_id) + return; + GLib$1.source_remove(this._timeout_id); + this._timeout_id = null; + } + dispose() { + this.disable(); + } +} const { GLib } = imports.gi; const DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING = 2e3; function initialize_handlers(applet, settings2) { @@ -5290,27 +5252,23 @@ function initialize_handlers(applet, settings2) { return; appearance_handler.manual_is_dark = appearance_handler.is_dark; }); - const time_change_listener = new Time_change_listener( - // Throws - () => runInAction(() => { - twilights_handler.update(); - appearance_handler.update_time(); - if (scheduler.is_set && scheduler.get_if_should_be_expired()) - appearance_handler.sync_is_dark(); - }) - ); + const wall_clock_monitor = new Wall_clock_adjustment_monitor(); + wall_clock_monitor.callback = () => runInAction(() => { + twilights_handler.update(); + appearance_handler.update_time(); + if (scheduler.is_set && scheduler.get_if_should_be_expired()) + appearance_handler.sync_is_dark(); + }); const sleep_events_listener = new Sleep_events_listener( // on sleep entries: - () => { - time_change_listener.disable(); - }, + () => wall_clock_monitor.disable(), // on wake-up unlocked: () => runInAction(() => { twilights_handler.update(); appearance_handler.update_time(); if (scheduler.is_set && scheduler.get_if_should_be_expired()) appearance_handler.sync_is_dark(); - time_change_listener.enable(); + wall_clock_monitor.enable(); }) ); const scheduler = new Event_scheduler(); @@ -5326,11 +5284,11 @@ function initialize_handlers(applet, settings2) { appearance_handler.update_time(); appearance_handler.sync_is_dark(); schedule_the_event(); - time_change_listener.enable(); + wall_clock_monitor.enable(); sleep_events_listener.enable(); } else { scheduler.unset_the_event(); - time_change_listener.disable(); + wall_clock_monitor.disable(); sleep_events_listener.disable(); } }); @@ -5353,11 +5311,11 @@ function initialize_handlers(applet, settings2) { scheduler.dispose(); sleep_events_listener.dispose(); system_color_scheme.dispose(); - time_change_listener.dispose(); + wall_clock_monitor.dispose(); settings2.finalize(); }; system_color_scheme.enable(); - time_change_listener.enable(); + wall_clock_monitor.enable(); sleep_events_listener.enable(); } const { AppletSettings } = imports.ui.settings; diff --git a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts index 505a768c891..fff73677d0b 100644 --- a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts +++ b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts @@ -16,9 +16,9 @@ import { sleep } from '../../lib/utils'; import { Sleep_events_listener } from '../../lib/sys/Sleep_events_listener/Sleep_events_listener'; import { System_color_scheme } from '../../lib/sys/System_color_scheme'; import { Themes_handler } from './Themes_handler'; -import { Time_change_listener } from '../../lib/sys/Time_change_listener'; import { Time_of_day } from '../../lib/core/Time_of_day'; import { Twilights_handler } from './Twilights_handler'; +import { Wall_clock_adjustment_monitor } from '../../lib/sys/Wall_clock_adjustment_monitor'; const DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING = 2000; // milliseconds (ms) @@ -221,27 +221,24 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { appearance_handler.manual_is_dark = appearance_handler.is_dark; }); - const time_change_listener = new Time_change_listener( // Throws - () => mobx.runInAction(() => { - twilights_handler.update(); - appearance_handler.update_time(); - if (scheduler.is_set && scheduler.get_if_should_be_expired()) // TODO: need of the same logic at startup ? - appearance_handler.sync_is_dark(); - }) - ); + const wall_clock_monitor = new Wall_clock_adjustment_monitor(); + wall_clock_monitor.callback = () => mobx.runInAction(() => { + twilights_handler.update(); + appearance_handler.update_time(); + if (scheduler.is_set && scheduler.get_if_should_be_expired()) // TODO: need of the same logic at startup ? + appearance_handler.sync_is_dark(); + }); const sleep_events_listener = new Sleep_events_listener( // on sleep entries: - () => { - time_change_listener.disable(); - }, + () => wall_clock_monitor.disable(), // on wake-up unlocked: () => mobx.runInAction(() => { twilights_handler.update(); appearance_handler.update_time(); if (scheduler.is_set && scheduler.get_if_should_be_expired()) // TODO: need of the same logic at startup ? appearance_handler.sync_is_dark(); - time_change_listener.enable(); + wall_clock_monitor.enable(); }) ); @@ -259,11 +256,11 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { appearance_handler.update_time(); appearance_handler.sync_is_dark(); schedule_the_event(); - time_change_listener.enable(); + wall_clock_monitor.enable(); sleep_events_listener.enable(); } else { scheduler.unset_the_event(); - time_change_listener.disable(); + wall_clock_monitor.disable(); sleep_events_listener.disable(); } }); @@ -298,11 +295,11 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { scheduler.dispose(); sleep_events_listener.dispose(); system_color_scheme.dispose(); - time_change_listener.dispose(); + wall_clock_monitor.dispose(); settings.finalize(); }; system_color_scheme.enable(); - time_change_listener.enable(); + wall_clock_monitor.enable(); sleep_events_listener.enable(); } diff --git a/auto-dark-light@gihaume/src/lib/sys/Time_change_listener.ts b/auto-dark-light@gihaume/src/lib/sys/Time_change_listener.ts deleted file mode 100644 index 91c73983af1..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/Time_change_listener.ts +++ /dev/null @@ -1,147 +0,0 @@ -const { Gio, GLib } = imports.gi; - -import { _, logger, metadata } from '../../globals'; - -const EXECUTABLE_NAME = 'auto-dark-light-time-change-listener'; // From the Makefile -const EXECUTABLE_TARGET_FOLDER_PATH = 'Time_change_listener'; // Relative to transpiled `applet.js` // TODO: find a cleaner way? - -/** - * A passive listener for system time changes. - * - * It interfaces the C++ program whose API is in `backend/Time_change_listener.hpp`. - */ -export class Time_change_listener { - private _callback_when_changes: () => void; - - /** - * @param callback_when_changes - The function to be called when the system time changes. - * @throws {Error} If the `make` or `g++` command is not found in the system. - * @throws {Error} If the compilation of the C++ program fails. - */ - constructor(callback_when_changes: () => void) { - this._callback_when_changes = callback_when_changes; - - const executable_folder_path = - `${metadata.path}/${EXECUTABLE_TARGET_FOLDER_PATH}`; - const executable_path = `${executable_folder_path}/${EXECUTABLE_NAME}`; - - if (!GLib.file_test(executable_path, GLib.FileTest.EXISTS)) - Time_change_listener._compile(executable_folder_path); - - this._run(executable_path); - } - - private static _compile(executable_folder_path: string) { - if ( - !GLib.find_program_in_path('make') || - !GLib.find_program_in_path('g++') - ) - throw new Error(_("Missing dependencies 'make' and/or 'g++'. Install them, in e.g. on Debian-based system with 'sudo apt install make g++', then restart Cinnamon (Ctrl+Alt+Esc).")); - - const process = new Gio.Subprocess({ - argv: ['make', '-C', executable_folder_path], - flags: Gio.SubprocessFlags.STDERR_PIPE - }); - process.init(null); - - try { - const [_ok, _stdout, stderr] = - process.communicate_utf8(null, null); - if (!process.get_successful()) - throw new Error(stderr || _("Unknown compilation error")); - } catch (error) { - throw new Error( - `${_("Failed compilation of")} '${EXECUTABLE_NAME}'.\n` - + "\n" - + error.message - ); - } finally { - GLib.spawn_command_line_async( - `make -C ${executable_folder_path} clean` - ); - } - } - - private _input: imports.gi.Gio.DataInputStream; - private _input_error: imports.gi.Gio.DataInputStream; - private _output: imports.gi.Gio.OutputStream; - private _subprocess: imports.gi.Gio.Subprocess; - private _should_run = true; - - private _run(executable_path: string) { - this._subprocess = new Gio.Subprocess({ - argv: [executable_path], - flags: - Gio.SubprocessFlags.STDOUT_PIPE | - Gio.SubprocessFlags.STDIN_PIPE | - Gio.SubprocessFlags.STDERR_PIPE - }); - this._subprocess.init(null); - - this._output = this._subprocess.get_stdin_pipe(); - this._input = new Gio.DataInputStream({ - base_stream: this._subprocess.get_stdout_pipe() - }); - this._input_error = new Gio.DataInputStream({ - base_stream: this._subprocess.get_stderr_pipe() - }); - - this._listen_input(); - this._listen_error(); - } - - private async _listen_input() { // thread-like - do { - await new Promise( - resolve => this._input.read_line_async( - GLib.PRIORITY_DEFAULT, null, resolve - ) - ); - this._callback_when_changes(); - } while (this._should_run); - } - - private async _listen_error() { // thread-like - do { - const [line, length] = await new Promise(resolve => - this._input_error.read_line_async( - GLib.PRIORITY_DEFAULT, - null, - ( - source: imports.gi.Gio.DataInputStream, - result: imports.gi.Gio.AsyncResult - ) => { - try { - resolve(source.read_line_finish(result)); - } catch (error) { - logger.warn(error); - resolve([null, 0]); - } - } - ) - ); - if (line !== null && length > 0) - logger.warn( - `${_("the subprocess")} \`${EXECUTABLE_NAME}\` ${_("has written on its error output")}${_(":")} ${line}` - ); - } while (this._should_run); - } - - /** Enables listening for the system time changes. */ - enable() { - this._output.write('enable\n', null); - } - - /** Disables listening for the system time changes. */ - disable() { - this._output.write('disable\n', null); - } - - /** Releases acquired resources */ - dispose() { - this._callback_when_changes = () => {}; - this._should_run = false; - this._output.write('exit\n', null); - this._subprocess.wait(null); - } -} diff --git a/auto-dark-light@gihaume/src/lib/sys/Wall_clock_adjustment_monitor.js b/auto-dark-light@gihaume/src/lib/sys/Wall_clock_adjustment_monitor.js new file mode 100644 index 00000000000..f3b320be1e0 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Wall_clock_adjustment_monitor.js @@ -0,0 +1,95 @@ +const { GLib } = imports.gi; + +/** @typedef {import('../../types').Observer} Observer */ + +/** @implements {Observer} */ +export class Wall_clock_adjustment_monitor { + /** In seconds (s) + * @private */ + _monitoring_interval = 10; + + /** Check interval, in integer seconds (s) greater or equal to 1, defaults to 10 + * @returns {number} */ + get monitoring_interval() { + return this._monitoring_interval; + } + + set monitoring_interval(/** @type {number} */ value) { + value = Math.max(1, value); + value = Math.round(value); + this._monitoring_interval = value; + if (this._timeout_id) { + this.disable(); + this.enable(); + } + } + + /** Function to call when the wall clock has been modified, defaults to null + * @type {(() => void) | null} */ + callback = null; + + /** @private @type {ReturnType | null} */ + _timeout_id = null; + + /** In microseconds (µs) + * @private */ + _last_wall_clock_time = Number(); + + /** In microseconds (µs) + * @private */ + _last_monotonic_time = Number(); + + enable() { + if (this._timeout_id) + return; + this._last_wall_clock_time = GLib.get_real_time(); + this._last_monotonic_time = GLib.get_monotonic_time(); + this._timeout_id = GLib.timeout_add_seconds( + GLib.PRIORITY_DEFAULT, + this._monitoring_interval, + this._timeout_function + ); + } + + /** In microseconds (µs) + * @private */ + _time_difference_tolerance = 2e6; + + /** Maximum for time difference between wall clock and monotonic times to not trigger the callback, in seconds (s) greater or equal to 1, defaults to 2 + * @returns {number} */ + get time_difference_tolerance() { + return this._time_difference_tolerance / 1e6; + } + + set time_difference_tolerance(/** @type {number} */ value) { + value *= 1e6; + value = Math.max(1, value); + this._time_difference_tolerance = value; + } + + /** @private @type {Parameters[2]} */ + _timeout_function = () => { + const wall_clock_time = GLib.get_real_time(), + monotonic_time = GLib.get_monotonic_time(); + const delta_wall_clock = + wall_clock_time - this._last_wall_clock_time; + const delta_monotonic = monotonic_time - this._last_monotonic_time; + const difference = Math.abs(delta_wall_clock - delta_monotonic); + if (difference > this._time_difference_tolerance) + this.callback?.(); + this._last_wall_clock_time = wall_clock_time; + this._last_monotonic_time = monotonic_time; + return GLib.SOURCE_CONTINUE; + }; + + disable() { + if (!this._timeout_id) + return; + GLib.source_remove(this._timeout_id); + this._timeout_id = null; + } + + dispose() { + this.disable(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/tests/test Wall_clock_adjustment_monitor.js b/auto-dark-light@gihaume/src/lib/sys/tests/test Wall_clock_adjustment_monitor.js new file mode 100644 index 00000000000..659cf815d3b --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/tests/test Wall_clock_adjustment_monitor.js @@ -0,0 +1,15 @@ +/** + * To be tested manually with `cjs -m `. + * + * Criteria: changing the system wall clock time for more than `time_difference_tolerance` seconds must trigger the console log within `monitoring_interval` seconds. + */ + +import { Wall_clock_adjustment_monitor } from '../Wall_clock_adjustment_monitor.js'; + +const monitor = new Wall_clock_adjustment_monitor(); +monitor.callback = () => console.log('Wall-clock has been adjusted'); +monitor.time_difference_tolerance = 2; +monitor.monitoring_interval = 1; +monitor.enable(); + +new imports.gi.GLib.MainLoop(null, false).run(); diff --git a/auto-dark-light@gihaume/src/types.ts b/auto-dark-light@gihaume/src/types.ts index b3aa2cf6187..ec338a8d1e2 100644 --- a/auto-dark-light@gihaume/src/types.ts +++ b/auto-dark-light@gihaume/src/types.ts @@ -26,3 +26,18 @@ export type Command = { }; export type Keybinding = `${string}::${'' | `${string}`}`; + +export interface Disposable { + /** Releases acquired resources */ + dispose(): void; +} + +export interface Observer extends Disposable { + callback: ((value: any) => void) | null; + + /** Note: it doesn't do anything if already enabled. */ + enable(): void; + + /** Note: it doesn't do anything if already disabled. */ + disable(): void; +} diff --git a/auto-dark-light@gihaume/tsconfig.json b/auto-dark-light@gihaume/tsconfig.json index 03ccc508560..d2f99d557dd 100644 --- a/auto-dark-light@gihaume/tsconfig.json +++ b/auto-dark-light@gihaume/tsconfig.json @@ -4,12 +4,16 @@ "lib": ["ES2022"], "module": "es2022", "moduleResolution": "bundler", + "moduleDetection": "force", + "allowJs": true, + "checkJs":true, "strict": true, "types": [ "@ci-types/cjs" ] }, "include": [ - "src/**/*.ts" + "src/**/*.ts", + "src/**/*.js" ] } From 3233fb974970a98280631267ed35c362d652151d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Wed, 26 Nov 2025 20:55:27 +0100 Subject: [PATCH 07/13] Change `Sleep_events_listener`: - Change `Screen_lock_checker` class direct use of DBus for `imports.misc.screenSaver` instead and rename it `Screen_lock_change_listener` - Wrap `Screen_lock_change_listener` class in an awaitable `Screen_unlock_waiter` - Make `Sleep_events_listener` class only be the DBus wrapper then compose the whole wanted logic in a `Sleep_and_lock_handler` - Add unit tests in CinnamonJS context, so go back to JS with TS via JSDoc for this - Add a class diagram --- .../auto-dark-light@gihaume/5.8/applet.js | 312 +++++++++--------- .../src/app/handlers/initialize_handlers.ts | 37 ++- .../Screen_lock_change_listener.js | 67 ++++ .../Screen_unlock_waiter.js | 49 +++ .../Sleep_and_lock_handler.js | 41 +++ .../Sleep_events_listener.js | 45 +++ .../doc/Sleep_and_lock_handler.drawio.svg | 4 + .../tests/test Screen_lock_change_listener.js | 19 ++ .../tests/test Screen_unlock_waiter.js | 20 ++ .../tests/test Sleep_and_lock_handler.js | 19 ++ .../tests/test Sleep_events_listener.js | 19 ++ .../Screen_lock_checker.ts | 91 ----- .../Sleep_events_listener.ts | 76 ----- 13 files changed, 461 insertions(+), 338 deletions(-) create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_lock_change_listener.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_unlock_waiter.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_events_listener.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_events_listener.js delete mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Screen_lock_checker.ts delete mode 100644 auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Sleep_events_listener.ts diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index 53e2d991541..7ecd447ce70 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -4260,10 +4260,10 @@ class Appearance_handler { makeAutoObservable(this); } } -const { Gio: Gio$7 } = imports.gi; +const { Gio: Gio$6 } = imports.gi; const settings$2 = { - background: Gio$7.Settings.new("org.cinnamon.desktop.background"), - slideshow: Gio$7.Settings.new("org.cinnamon.desktop.background.slideshow") + background: Gio$6.Settings.new("org.cinnamon.desktop.background"), + slideshow: Gio$6.Settings.new("org.cinnamon.desktop.background.slideshow") }; class System_background { static get is_slideshow() { @@ -4339,7 +4339,7 @@ class Background_handler { System_background.picture_file = this._settings.dark_background_file; } } -const { Gio: Gio$6, GLib: GLib$4 } = imports.gi; +const { Gio: Gio$5, GLib: GLib$4 } = imports.gi; async function launch_command(name, expiry, command) { try { await _launch_command(command, expiry); @@ -4351,13 +4351,13 @@ async function launch_command(name, expiry, command) { ${_("Detail")}${_(":")} ` + error.message; - else if (error instanceof Gio$6.IOErrorEnum) { - if (error.code === Gio$6.IOErrorEnum.TIMED_OUT) + else if (error instanceof Gio$5.IOErrorEnum) { + if (error.code === Gio$5.IOErrorEnum.TIMED_OUT) msg += ` ${_("due to timeout")}. ${_("Detail")}${_(":")} ` + error.message; - else if (error.code === Gio$6.IOErrorEnum.FAILED) + else if (error.code === Gio$5.IOErrorEnum.FAILED) msg += ` ${_("due to an error")}. ${_("Detail")}${_(":")} @@ -4373,9 +4373,9 @@ const SIGKILL_TIMEOUT = 10; async function _launch_command(command, timeout = 10) { const wrapped_command = `timeout --kill-after=${SIGKILL_TIMEOUT} ${timeout}s sh -c ${GLib$4.shell_quote(command)}`; const [_ok, argvp] = GLib$4.shell_parse_argv(wrapped_command); - const process = new Gio$6.Subprocess({ + const process = new Gio$5.Subprocess({ argv: argvp, - flags: Gio$6.SubprocessFlags.STDERR_PIPE + flags: Gio$5.SubprocessFlags.STDERR_PIPE }); const start_time = Date.now(); process.init(null); @@ -4402,25 +4402,25 @@ async function _launch_command(command, timeout = 10) { case 0: break; case TIMEOUT_EXIT_STATUS_SIGTERM: - throw new Gio$6.IOErrorEnum({ - code: Gio$6.IOErrorEnum.TIMED_OUT, + throw new Gio$5.IOErrorEnum({ + code: Gio$5.IOErrorEnum.TIMED_OUT, message: `may have been timed out by SIGTERM (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGTERM})` }); case TIMEOUT_EXIT_STATUS_SIGKILL: - throw new Gio$6.IOErrorEnum({ - code: Gio$6.IOErrorEnum.TIMED_OUT, + throw new Gio$5.IOErrorEnum({ + code: Gio$5.IOErrorEnum.TIMED_OUT, message: `probably killed by an external SIGKILL (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGKILL})` }); case 1: if (timeout > 0 && elapsed_time >= timeout + SIGKILL_TIMEOUT) - throw new Gio$6.IOErrorEnum({ - code: Gio$6.IOErrorEnum.TIMED_OUT, + throw new Gio$5.IOErrorEnum({ + code: Gio$5.IOErrorEnum.TIMED_OUT, message: `probably timed out by SIGKILL` }); // no break, needs to stay directly above the default case default: - throw new Gio$6.IOErrorEnum({ - code: Gio$6.IOErrorEnum.FAILED, + throw new Gio$5.IOErrorEnum({ + code: Gio$5.IOErrorEnum.FAILED, message: stderr ? stderr.trim() : "exit status: " + exit_status }); } @@ -4525,7 +4525,7 @@ class Keybinding_handler { Main.keybindingManager.removeHotKey(this._name); } } -const { Gio: Gio$5 } = imports.gi; +const { Gio: Gio$4 } = imports.gi; class Timezone_change_listener { _callback_on_change; /** @param callback_on_change - The function to be executed when the system timezone changes. */ @@ -4546,7 +4546,7 @@ class Timezone_change_listener { _subscribe_to_changes(callback_when_changes) { if (this._signal_id) this._unsubscribe_to_changes(); - this._signal_id = Gio$5.DBus.system.signal_subscribe( + this._signal_id = Gio$4.DBus.system.signal_subscribe( "org.freedesktop.timedate1", // sender "org.freedesktop.DBus.Properties", @@ -4557,7 +4557,7 @@ class Timezone_change_listener { // object_path null, // arg0 - Gio$5.DBusSignalFlags.NONE, + Gio$4.DBusSignalFlags.NONE, // flags (_1, _2, _3, _4, _5, parameters) => { const changed_properties = parameters.deep_unpack()[1]; @@ -4571,11 +4571,11 @@ class Timezone_change_listener { _unsubscribe_to_changes() { if (!this._signal_id) return; - Gio$5.DBus.system.signal_unsubscribe(this._signal_id); + Gio$4.DBus.system.signal_unsubscribe(this._signal_id); this._signal_id = void 0; } } -const { Gio: Gio$4 } = imports.gi; +const { Gio: Gio$3 } = imports.gi; class Timezone_location_finder { _database; /** @@ -4584,7 +4584,7 @@ class Timezone_location_finder { */ constructor(path) { const file_path = `${path}/database.json`; - const file = Gio$4.File.new_for_path(file_path); + const file = Gio$3.File.new_for_path(file_path); const [ok, file_content] = file.load_contents(null); if (!ok) throw new Error(`failed to load file/contents of '${file_path}'`); @@ -4643,132 +4643,107 @@ class Location_handler { async function sleep(duration) { return new Promise((resolve) => setTimeout(resolve, duration)); } -const { Gio: Gio$3 } = imports.gi; -class Screen_lock_checker { - /** - * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. - * @param callback_when_unlocked - The function to be executed when the screen is unlocked. - */ - try_now_or_postpone_until_unlocked(callback_when_unlocked) { - Screen_lock_checker._get_state_async((is_locked) => { - if (!is_locked) - callback_when_unlocked(); - else - this._subscribe_to_changes((is_locked2) => { - if (is_locked2) - return; - this._unsubscribe_to_changes(); - callback_when_unlocked(); - }); - }); - } - /** Cancels the `try_now_or_postpone_until_unlocked` procedure. */ - cancel() { - this._unsubscribe_to_changes(); - } - /** Releases acquired resources */ - dispose() { - this.cancel(); - } - _signal_id = void 0; - /** @param callback_when_changes - The function to be executed when the screen lock state changes. */ - _subscribe_to_changes(callback_when_changes) { +const { ScreenSaverProxy } = imports.misc.screenSaver; +class Screen_lock_change_listener { + /** @private @type {number | null} */ + _signal_id = null; + /** @private @readonly @type {imports.gi.Gio.DBusProxy} */ + _screen_saver_proxy = ScreenSaverProxy(); + // /** + // * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. + // * @param {() => void} callback_when_unlocked - The function to be executed when the screen is unlocked. + // */ + // try_now_or_postpone_until_unlocked(callback_when_unlocked) { + // if (!this.is_locked) { + // callback_when_unlocked(); + // } else { + // this._subscribe_to_changes(is_locked => { + // if (is_locked) + // return; + // this._unsubscribe_to_changes(); + // callback_when_unlocked(); + // }); + // } + // } + /** @returns {boolean} */ + get is_locked() { + return this._screen_saver_proxy.screenSaverActive; + } + /** @type {((is_locked: boolean) => void) | null} */ + callback = null; + enable() { if (this._signal_id) - this._unsubscribe_to_changes(); - this._signal_id = Gio$3.DBus.session.signal_subscribe( - "org.cinnamon.ScreenSaver", - // sender - "org.cinnamon.ScreenSaver", - // interface_name + return; + this._signal_id = this._screen_saver_proxy.connectSignal( "ActiveChanged", - // member - "/org/cinnamon/ScreenSaver", - // object_path - null, - // arg0 - Gio$3.DBusSignalFlags.NONE, - // flags - (_1, _2, _3, _4, _5, parameters) => { - const is_locked = parameters.deep_unpack()[0]; - callback_when_changes(is_locked); + /** + * @param {any} _0 + * @param {any} _1 + * @param {[boolean]} params + */ + (_0, _1, [screenSaverActive]) => { + this.callback?.(screenSaverActive); } ); } - _unsubscribe_to_changes() { + disable() { if (!this._signal_id) return; - Gio$3.DBus.session.signal_unsubscribe(this._signal_id); - this._signal_id = void 0; + this._screen_saver_proxy.disconnectSignal(this._signal_id); + this._signal_id = null; } - /** - * Gets the current screen lock state asynchronously. - * @param callback_for_result - The callback object to handle the result. - */ - static _get_state_async(callback_for_result) { - Gio$3.DBus.session.call( - "org.cinnamon.ScreenSaver", - // bus_name - "/org/cinnamon/ScreenSaver", - // object_path - "org.cinnamon.ScreenSaver", - // interface_name - "GetActive", - // method_name - null, - // parameters - null, - // reply_type - Gio$3.DBusCallFlags.NONE, - // flags - -1, - // timeout_msec - null, - // cancellable - (connection, result) => { - const reply = connection.call_finish(result); - const is_locked = reply.deep_unpack()[0]; - callback_for_result(is_locked); - } - ); + dispose() { + this.disable(); } } -const { Gio: Gio$2 } = imports.gi; -class Sleep_events_listener { - _callback_when_sleep_entries; - _callback_when_wakeup_unlocked; - /** - * @param callback_when_sleep_entries - The function to be executed when the system goes to sleep. Will be called again even without unlock. - * @param callback_when_wakeup_unlocked - The function to be executed when the system wakes up and the screen is unlocked. - */ - constructor(callback_when_sleep_entries, callback_when_wakeup_unlocked) { - this._callback_when_sleep_entries = callback_when_sleep_entries; - this._callback_when_wakeup_unlocked = callback_when_wakeup_unlocked; - } - _screen_lock_checker = new Screen_lock_checker(); - enable() { - this._subscribe_to_changes((is_sleeping) => { - if (is_sleeping) - this._callback_when_sleep_entries(); - else - this._screen_lock_checker.try_now_or_postpone_until_unlocked( - () => this._callback_when_wakeup_unlocked() - ); +class Screen_unlock_waiter { + /** @private @readonly */ + _screen_lock = new Screen_lock_change_listener(); + /** @private @type {(() => void) | null} */ + _unblock_wait_if_locked = null; + /** Waits until the screen is unlocked or returns immediately if it is already unlocked. + * @returns {Promise} */ + wait_if_locked() { + return new Promise((resolve) => { + if (!this._screen_lock.is_locked) { + resolve(); + return; + } + this._unblock_wait_if_locked = resolve; + this._screen_lock.callback = (is_locked) => { + if (is_locked) + return; + this._screen_lock.disable(); + this._screen_lock.callback = null; + this._unblock_wait_if_locked = null; + resolve(); + }; + this._screen_lock.enable(); }); } - disable() { - this._unsubscribe_to_changes(); - this._screen_lock_checker.cancel(); + /** Note: it doesn't do anything if not currently waiting. + * @returns {void} */ + unblock_wait_if_locked() { + if (!this._unblock_wait_if_locked) + return; + this._unblock_wait_if_locked(); + this._unblock_wait_if_locked = null; } - /** Releases acquired resources */ dispose() { - this._unsubscribe_to_changes(); - this._screen_lock_checker.dispose(); + this.unblock_wait_if_locked(); + this._screen_lock.dispose(); } - _signal_id = void 0; - /** @param callback - The function to be executed when the system sleep state changes. */ - _subscribe_to_changes(callback) { +} +const { Gio: Gio$2 } = imports.gi; +class Sleep_events_listener { + /** @private @type {number | null} */ + _signal_id = null; + /** The function to call when the system is entering sleep or has just wake up (`is_entering_sleep` at `false`). + * @type {((is_entering_sleep: boolean) => void) | null} */ + callback = null; + enable() { if (this._signal_id) - this._unsubscribe_to_changes(); + return; this._signal_id = Gio$2.DBus.system.signal_subscribe( "org.freedesktop.login1", // sender @@ -4783,16 +4758,46 @@ class Sleep_events_listener { Gio$2.DBusSignalFlags.NONE, // flags (_1, _2, _3, _4, _5, parameters) => { - const is_sleeping = parameters.deep_unpack()[0]; - callback(is_sleeping); + const is_entering_sleep = parameters.deep_unpack()[0]; + this.callback?.(is_entering_sleep); } ); } - _unsubscribe_to_changes() { + disable() { if (!this._signal_id) return; Gio$2.DBus.system.signal_unsubscribe(this._signal_id); - this._signal_id = void 0; + this._signal_id = null; + } + dispose() { + this.disable(); + } +} +class Sleep_and_lock_handler { + /** @private @readonly */ + _unlock_waiter = new Screen_unlock_waiter(); + /** @private @readonly */ + _sleep_events = new Sleep_events_listener(); + /** The function to call when the system is entering sleep or has just wake up and is unlocked (`is_entering_sleep` at `false`). + * @type {((is_entering_sleep: boolean) => void) | null} */ + callback = null; + constructor() { + this._sleep_events.callback = async (is_entering_sleep) => { + if (!is_entering_sleep) + await this._unlock_waiter.wait_if_locked(); + this.callback?.(is_entering_sleep); + }; + } + enable() { + this._sleep_events.enable(); + } + disable() { + this._unlock_waiter.unblock_wait_if_locked(); + this._sleep_events.disable(); + } + dispose() { + this._unlock_waiter.dispose(); + this._sleep_events.dispose(); } } const { Gio: Gio$1 } = imports.gi; @@ -5259,18 +5264,19 @@ function initialize_handlers(applet, settings2) { if (scheduler.is_set && scheduler.get_if_should_be_expired()) appearance_handler.sync_is_dark(); }); - const sleep_events_listener = new Sleep_events_listener( - // on sleep entries: - () => wall_clock_monitor.disable(), - // on wake-up unlocked: - () => runInAction(() => { - twilights_handler.update(); - appearance_handler.update_time(); - if (scheduler.is_set && scheduler.get_if_should_be_expired()) - appearance_handler.sync_is_dark(); - wall_clock_monitor.enable(); - }) - ); + const sleep_and_lock_handler = new Sleep_and_lock_handler(); + sleep_and_lock_handler.callback = (is_sleeping) => { + if (is_sleeping) + wall_clock_monitor.disable(); + else + runInAction(() => { + twilights_handler.update(); + appearance_handler.update_time(); + if (scheduler.is_set && scheduler.get_if_should_be_expired()) + appearance_handler.sync_is_dark(); + wall_clock_monitor.enable(); + }); + }; const scheduler = new Event_scheduler(); const schedule_the_event = () => { scheduler.set_the_event(appearance_handler.next_twilight, () => { @@ -5285,11 +5291,11 @@ function initialize_handlers(applet, settings2) { appearance_handler.sync_is_dark(); schedule_the_event(); wall_clock_monitor.enable(); - sleep_events_listener.enable(); + sleep_and_lock_handler.enable(); } else { scheduler.unset_the_event(); wall_clock_monitor.disable(); - sleep_events_listener.disable(); + sleep_and_lock_handler.disable(); } }); reaction(() => appearance_handler.next_twilight, () => { @@ -5309,14 +5315,14 @@ function initialize_handlers(applet, settings2) { keybinding_handler.dispose(); location_handler.dispose(); scheduler.dispose(); - sleep_events_listener.dispose(); + sleep_and_lock_handler.dispose(); system_color_scheme.dispose(); wall_clock_monitor.dispose(); settings2.finalize(); }; system_color_scheme.enable(); wall_clock_monitor.enable(); - sleep_events_listener.enable(); + sleep_and_lock_handler.enable(); } const { AppletSettings } = imports.ui.settings; function initialize_applet_settings(uuid, instance_id) { diff --git a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts index fff73677d0b..23ce8dfe06f 100644 --- a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts +++ b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts @@ -13,7 +13,7 @@ import { Location_handler } from './Location_handler'; import { logger } from '../../globals'; import type { Settings } from '../ui/Settings'; import { sleep } from '../../lib/utils'; -import { Sleep_events_listener } from '../../lib/sys/Sleep_events_listener/Sleep_events_listener'; +import { Sleep_and_lock_handler } from '../../lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler'; import { System_color_scheme } from '../../lib/sys/System_color_scheme'; import { Themes_handler } from './Themes_handler'; import { Time_of_day } from '../../lib/core/Time_of_day'; @@ -169,7 +169,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { const themes_handler = new Themes_handler(applet, settings); - if (System_color_scheme.value === 'prefer-dark') { // TODO: clear this idea so the user if not confused + if (System_color_scheme.value === 'prefer-dark') { // TODO: clear this idea so the user is not confused if (settings.dark_themes_have_been_detected) themes_handler.detect_dark_themes(); } else { @@ -229,18 +229,19 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { appearance_handler.sync_is_dark(); }); - const sleep_events_listener = new Sleep_events_listener( - // on sleep entries: - () => wall_clock_monitor.disable(), - // on wake-up unlocked: - () => mobx.runInAction(() => { - twilights_handler.update(); - appearance_handler.update_time(); - if (scheduler.is_set && scheduler.get_if_should_be_expired()) // TODO: need of the same logic at startup ? - appearance_handler.sync_is_dark(); - wall_clock_monitor.enable(); - }) - ); + const sleep_and_lock_handler = new Sleep_and_lock_handler(); + sleep_and_lock_handler.callback = (is_sleeping: boolean) => { + if (is_sleeping) + wall_clock_monitor.disable(); + else + mobx.runInAction(() => { + twilights_handler.update(); + appearance_handler.update_time(); + if (scheduler.is_set && scheduler.get_if_should_be_expired()) // TODO: need of the same logic at startup ? + appearance_handler.sync_is_dark(); + wall_clock_monitor.enable(); + }); + }; const scheduler = new Event_scheduler(); const schedule_the_event = () => { @@ -257,11 +258,11 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { appearance_handler.sync_is_dark(); schedule_the_event(); wall_clock_monitor.enable(); - sleep_events_listener.enable(); + sleep_and_lock_handler.enable(); } else { scheduler.unset_the_event(); wall_clock_monitor.disable(); - sleep_events_listener.disable(); + sleep_and_lock_handler.disable(); } }); mobx.reaction(() => appearance_handler.next_twilight, () => { @@ -293,7 +294,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { keybinding_handler.dispose(); location_handler.dispose(); scheduler.dispose(); - sleep_events_listener.dispose(); + sleep_and_lock_handler.dispose(); system_color_scheme.dispose(); wall_clock_monitor.dispose(); settings.finalize(); @@ -301,5 +302,5 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { system_color_scheme.enable(); wall_clock_monitor.enable(); - sleep_events_listener.enable(); + sleep_and_lock_handler.enable(); } diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_lock_change_listener.js b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_lock_change_listener.js new file mode 100644 index 00000000000..b52bb12d807 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_lock_change_listener.js @@ -0,0 +1,67 @@ +const { ScreenSaverProxy } = imports.misc.screenSaver; + +/** @typedef {import('../../../types').Observer} Observer */ + +/** + * An interface to read and listen to the screen locked state. + * + * @implements {Observer} + */ +export class Screen_lock_change_listener { + /** @private @type {number | null} */ + _signal_id = null; + + /** @private @readonly @type {imports.gi.Gio.DBusProxy} */ + _screen_saver_proxy = ScreenSaverProxy(); + + // /** + // * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. + // * @param {() => void} callback_when_unlocked - The function to be executed when the screen is unlocked. + // */ + // try_now_or_postpone_until_unlocked(callback_when_unlocked) { + // if (!this.is_locked) { + // callback_when_unlocked(); + // } else { + // this._subscribe_to_changes(is_locked => { + // if (is_locked) + // return; + // this._unsubscribe_to_changes(); + // callback_when_unlocked(); + // }); + // } + // } + + /** @returns {boolean} */ + get is_locked() { + return this._screen_saver_proxy.screenSaverActive; + } + + /** @type {((is_locked: boolean) => void) | null} */ + callback = null; + + enable() { + if (this._signal_id) + return; + this._signal_id = this._screen_saver_proxy.connectSignal('ActiveChanged', + /** + * @param {any} _0 + * @param {any} _1 + * @param {[boolean]} params + */ + (_0, _1, [screenSaverActive]) => { + this.callback?.(screenSaverActive); + } + ); + } + + disable() { + if (!this._signal_id) + return; + this._screen_saver_proxy.disconnectSignal(this._signal_id); + this._signal_id = null; + } + + dispose() { + this.disable(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_unlock_waiter.js b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_unlock_waiter.js new file mode 100644 index 00000000000..73e1ab5a2b2 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_unlock_waiter.js @@ -0,0 +1,49 @@ +/** @typedef {import('../../../types').Disposable} Disposable */ +import { Screen_lock_change_listener } from './Screen_lock_change_listener.js'; + +/** + * A handler to wait until the screen is unlocked. + * @implements {Disposable} + */ +export class Screen_unlock_waiter { + /** @private @readonly */ + _screen_lock = new Screen_lock_change_listener(); + + /** @private @type {(() => void) | null} */ + _unblock_wait_if_locked = null; + + /** Waits until the screen is unlocked or returns immediately if it is already unlocked. + * @returns {Promise} */ + wait_if_locked() { + return new Promise(resolve => { + if (!this._screen_lock.is_locked) { + resolve(); + return; + } + this._unblock_wait_if_locked = resolve; + this._screen_lock.callback = (/**@type {boolean} */ is_locked) => { + if (is_locked) + return; + this._screen_lock.disable(); + this._screen_lock.callback = null; + this._unblock_wait_if_locked = null; + resolve(); + }; + this._screen_lock.enable(); + }); + } + + /** Note: it doesn't do anything if not currently waiting. + * @returns {void} */ + unblock_wait_if_locked() { + if (!this._unblock_wait_if_locked) + return; + this._unblock_wait_if_locked(); + this._unblock_wait_if_locked = null; + } + + dispose() { + this.unblock_wait_if_locked(); + this._screen_lock.dispose(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler.js b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler.js new file mode 100644 index 00000000000..6a506afc7a8 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler.js @@ -0,0 +1,41 @@ +/** @typedef {import('../../../types').Observer} Observer */ +import { Screen_unlock_waiter } from './Screen_unlock_waiter.js'; +import { Sleep_events_listener } from './Sleep_events_listener.js'; + +/** + * A handler to wait until the screen is unlocked. + * @implements {Observer} + */ +export class Sleep_and_lock_handler { + /** @private @readonly */ + _unlock_waiter = new Screen_unlock_waiter(); + + /** @private @readonly */ + _sleep_events = new Sleep_events_listener(); + + /** The function to call when the system is entering sleep or has just wake up and is unlocked (`is_entering_sleep` at `false`). + * @type {((is_entering_sleep: boolean) => void) | null} */ + callback = null; + + constructor() { + this._sleep_events.callback = async is_entering_sleep => { + if (!is_entering_sleep) + await this._unlock_waiter.wait_if_locked(); + this.callback?.(is_entering_sleep); + }; + } + + enable() { + this._sleep_events.enable(); + } + + disable() { + this._unlock_waiter.unblock_wait_if_locked(); + this._sleep_events.disable(); + } + + dispose() { + this._unlock_waiter.dispose(); + this._sleep_events.dispose(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_events_listener.js new file mode 100644 index 00000000000..2b74d3cea51 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_events_listener.js @@ -0,0 +1,45 @@ +const { Gio } = imports.gi; + +/** @typedef {import('../../../types').Observer} Observer */ + +/** + * An interface to listen to the sleep entering and waking events. + * + * @implements {Observer} + */ +export class Sleep_events_listener { + /** @private @type {number | null} */ + _signal_id = null; + + /** The function to call when the system is entering sleep or has just wake up (`is_entering_sleep` at `false`). + * @type {((is_entering_sleep: boolean) => void) | null} */ + callback = null; + + enable() { + if (this._signal_id) + return; + this._signal_id = Gio.DBus.system.signal_subscribe( + 'org.freedesktop.login1', // sender + 'org.freedesktop.login1.Manager', // interface_name + 'PrepareForSleep', // member + '/org/freedesktop/login1', // object_path + null, // arg0 + Gio.DBusSignalFlags.NONE, // flags + (_1, _2, _3, _4, _5, parameters) => { // callback + const is_entering_sleep = parameters.deep_unpack()[0]; + this.callback?.(is_entering_sleep); + } + ); + } + + disable() { + if (!this._signal_id) + return; + Gio.DBus.system.signal_unsubscribe(this._signal_id); + this._signal_id = null; + } + + dispose() { + this.disable(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg new file mode 100644 index 00000000000..54e075fbbe9 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg @@ -0,0 +1,4 @@ + + + +
     «use»
    Gio.DBus

    «TypeScript interface»

    Observer<T>
    callback: (T => void) | null
    enable(): void
    disable(): void

    «TypeScript interface»

    Disposable
    dispose(): void

    «JavaScript class»

    Sleep_events_listener

    «JavaScript class»

    Screen_lock_change_listener
    is_locked: bool {read-only}
     «use»
    imports.misc.screenSaver

    «JavaScript class»

    Screen_unlock_waiter
    wait_if_locked(): Promise<void>

    «JavaScript class»

    Sleep_and_lock_handler
    _unlock_waiter
     _screen_lock
    _sleep_events
    \ No newline at end of file diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js new file mode 100644 index 00000000000..7bf13ce2051 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js @@ -0,0 +1,19 @@ +/** + * To be tested manually with `cjs -m `. + * + * Criteria: changing the screen lock state must trigger the console log at either the locking and unlocking events. + */ + +imports.searchPath.push('/usr/share/cinnamon/js'); + +const { Screen_lock_change_listener } = await import('../Screen_lock_change_listener.js'); + +const screen_lock = new Screen_lock_change_listener(); +screen_lock.callback = (/** @type {boolean} */ is_locked) => { + console.log( + `Screen lock state changed: ${is_locked ? 'locked' : 'unlocked'}` + ); +}; +screen_lock.enable(); + +new imports.gi.GLib.MainLoop(null, false).run(); diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js new file mode 100644 index 00000000000..f8fb485e8a3 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js @@ -0,0 +1,20 @@ +/** + * To be tested manually with `cjs -m `. + * + * Criteria: the second message must be logged only once the screen is unlocked. + */ + +imports.searchPath.push('/usr/share/cinnamon/js'); + +const { Screen_unlock_waiter } = await import('../Screen_unlock_waiter.js'); + +const screen_unlock_waiter = new Screen_unlock_waiter(); + +const duration = 5; // seconds +console.log(`You must lock the screen now. You have ${duration} seconds to do it.`); +await new Promise(resolve => setTimeout(resolve, duration * 1e3)); + +console.log('Waiting for the screen to be unlocked...'); +await screen_unlock_waiter.wait_if_locked(); + +console.log('The screen is now unlocked.'); diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js new file mode 100644 index 00000000000..9dcd7f5ef03 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js @@ -0,0 +1,19 @@ +/** + * To be tested manually with `cjs -m `. + * + * Criteria: changing the sleeping state must trigger the console log at either the entering sleep and woke up unlocked events. + */ + +imports.searchPath.push('/usr/share/cinnamon/js'); + +const { Sleep_and_lock_handler } = await import('../Sleep_and_lock_handler.js'); + +const sleep_events = new Sleep_and_lock_handler(); +sleep_events.callback = (/** @type {boolean} */ is_entering_sleep) => { + console.log( + `Sleep state changed: ${is_entering_sleep ? 'entering sleep' : 'woke up unlocked'}` + ); +}; +sleep_events.enable(); + +await new imports.gi.GLib.MainLoop(null, false).runAsync(); diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_events_listener.js new file mode 100644 index 00000000000..fa3eda90083 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_events_listener.js @@ -0,0 +1,19 @@ +/** + * To be tested manually with `cjs -m `. + * + * Criteria: changing the sleeping state must trigger the console log at either the sleeping and waking events. + */ + +imports.searchPath.push('/usr/share/cinnamon/js'); + +const { Sleep_events_listener } = await import('../Sleep_events_listener.js'); + +const sleep_events = new Sleep_events_listener(); +sleep_events.callback = (/** @type {boolean} */ is_entering_sleep) => { + console.log( + `Sleep state changed: ${is_entering_sleep ? 'entering sleep' : 'woke up'}` + ); +}; +sleep_events.enable(); + +new imports.gi.GLib.MainLoop(null, false).run(); diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Screen_lock_checker.ts b/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Screen_lock_checker.ts deleted file mode 100644 index 5a673871495..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Screen_lock_checker.ts +++ /dev/null @@ -1,91 +0,0 @@ -const { Gio } = imports.gi; - -/** - * A gatekeeper for the screen locked state. - * - * When the instance is not wanted anymore, `dispose` must be called. - */ -export class Screen_lock_checker { - /** - * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. - * @param callback_when_unlocked - The function to be executed when the screen is unlocked. - */ - try_now_or_postpone_until_unlocked( - callback_when_unlocked: () => void): void { - Screen_lock_checker._get_state_async(is_locked => { - if (!is_locked) - callback_when_unlocked(); - else - this._subscribe_to_changes(is_locked => { - if (is_locked) - return; - this._unsubscribe_to_changes(); - callback_when_unlocked(); - }); - }); - } - - /** Cancels the `try_now_or_postpone_until_unlocked` procedure. */ - cancel(): void { - this._unsubscribe_to_changes(); - } - - /** Releases acquired resources */ - dispose(): void { - this.cancel(); - } - - private _signal_id: number | undefined = undefined; - - /** @param callback_when_changes - The function to be executed when the screen lock state changes. */ - _subscribe_to_changes( - callback_when_changes: (is_locked: boolean) => void - ): void { - if (this._signal_id) - this._unsubscribe_to_changes(); - this._signal_id = Gio.DBus.session.signal_subscribe( - 'org.cinnamon.ScreenSaver', // sender - 'org.cinnamon.ScreenSaver', // interface_name - 'ActiveChanged', // member - '/org/cinnamon/ScreenSaver', // object_path - null, // arg0 - Gio.DBusSignalFlags.NONE, // flags - (_1, _2, _3, _4, _5, parameters) => { // callback - const is_locked = parameters.deep_unpack()[0]; - callback_when_changes(is_locked); - } - ); - } - - _unsubscribe_to_changes(): void { - if (!this._signal_id) - return; - Gio.DBus.session.signal_unsubscribe(this._signal_id); - this._signal_id = undefined; - } - - /** - * Gets the current screen lock state asynchronously. - * @param callback_for_result - The callback object to handle the result. - */ - static _get_state_async( - callback_for_result: (is_locked: boolean) => void - ): void { - Gio.DBus.session.call( - 'org.cinnamon.ScreenSaver', // bus_name - '/org/cinnamon/ScreenSaver', // object_path - 'org.cinnamon.ScreenSaver', // interface_name - 'GetActive', // method_name - null, // parameters - null, // reply_type - Gio.DBusCallFlags.NONE, // flags - -1, // timeout_msec - null, // cancellable - (connection, result) => { // callback - const reply = connection.call_finish(result); - const is_locked = reply.deep_unpack()[0]; - callback_for_result(is_locked); - } - ); - } -} diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Sleep_events_listener.ts b/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Sleep_events_listener.ts deleted file mode 100644 index d24f7b10e69..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/Sleep_events_listener/Sleep_events_listener.ts +++ /dev/null @@ -1,76 +0,0 @@ -const {Gio} = imports.gi; - -import { Screen_lock_checker } from './Screen_lock_checker'; - -/** - * A gatekeeper for the sleep combined with the screen locked on wakeup. - * - * When the instance is not wanted anymore, `dispose` must be called. - */ -export class Sleep_events_listener { - private readonly _callback_when_sleep_entries: () => void; - private readonly _callback_when_wakeup_unlocked: () => void; - - /** - * @param callback_when_sleep_entries - The function to be executed when the system goes to sleep. Will be called again even without unlock. - * @param callback_when_wakeup_unlocked - The function to be executed when the system wakes up and the screen is unlocked. - */ - constructor( - callback_when_sleep_entries: () => void, - callback_when_wakeup_unlocked: () => void - ) { - this._callback_when_sleep_entries = callback_when_sleep_entries; - this._callback_when_wakeup_unlocked = callback_when_wakeup_unlocked; - } - - private readonly _screen_lock_checker = new Screen_lock_checker(); - - enable(): void { - this._subscribe_to_changes(is_sleeping => { - if (is_sleeping) - this._callback_when_sleep_entries(); - else - this._screen_lock_checker.try_now_or_postpone_until_unlocked( - () => this._callback_when_wakeup_unlocked() - ); - }); - } - - disable(): void { - this._unsubscribe_to_changes(); - this._screen_lock_checker.cancel(); - } - - /** Releases acquired resources */ - dispose(): void { - this._unsubscribe_to_changes(); - this._screen_lock_checker.dispose(); - } - - private _signal_id: number | undefined = undefined; - - /** @param callback - The function to be executed when the system sleep state changes. */ - _subscribe_to_changes(callback: (is_sleeping: boolean) => void): void { - if (this._signal_id) - this._unsubscribe_to_changes(); - this._signal_id = Gio.DBus.system.signal_subscribe( - 'org.freedesktop.login1', // sender - 'org.freedesktop.login1.Manager', // interface_name - 'PrepareForSleep', // member - '/org/freedesktop/login1', // object_path - null, // arg0 - Gio.DBusSignalFlags.NONE, // flags - (_1, _2, _3, _4, _5, parameters) => { // callback - const is_sleeping = parameters.deep_unpack()[0]; - callback(is_sleeping); - } - ); - } - - _unsubscribe_to_changes(): void { - if (!this._signal_id) - return; - Gio.DBus.system.signal_unsubscribe(this._signal_id); - this._signal_id = undefined; - } -} From 42ef1d4f58fa42a3173b672360aa0dcdb1f9980c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Thu, 27 Nov 2025 19:04:19 +0100 Subject: [PATCH 08/13] Bump dependencies --- auto-dark-light@gihaume/package.json | 7 +- auto-dark-light@gihaume/pnpm-lock.yaml | 173 ++++++++++---------- auto-dark-light@gihaume/pnpm-workspace.yaml | 2 +- 3 files changed, 87 insertions(+), 95 deletions(-) diff --git a/auto-dark-light@gihaume/package.json b/auto-dark-light@gihaume/package.json index ec8a5c7dd07..1bca131c660 100644 --- a/auto-dark-light@gihaume/package.json +++ b/auto-dark-light@gihaume/package.json @@ -9,12 +9,11 @@ }, "devDependencies": { "@ci-types/cjs": "6.0.2-5", - "@types/luxon": "^3.7.1", + "@types/luxon": "3.7.1", "luxon": "3.7.2", - "terser": "5.44.0", "typescript": "5.9.3", - "vite": "7.1.12", - "vitest": "^4.0.6" + "vite": "7.2.4", + "vitest": "4.0.14" }, "pnpm": { "onlyBuiltDependencies": [ diff --git a/auto-dark-light@gihaume/pnpm-lock.yaml b/auto-dark-light@gihaume/pnpm-lock.yaml index 6c76a106815..e83ed5ef453 100644 --- a/auto-dark-light@gihaume/pnpm-lock.yaml +++ b/auto-dark-light@gihaume/pnpm-lock.yaml @@ -16,23 +16,20 @@ importers: specifier: 6.0.2-5 version: 6.0.2-5 '@types/luxon': - specifier: ^3.7.1 + specifier: 3.7.1 version: 3.7.1 luxon: specifier: 3.7.2 version: 3.7.2 - terser: - specifier: 5.44.0 - version: 5.44.0 typescript: specifier: 5.9.3 version: 5.9.3 vite: - specifier: 7.1.12 - version: 7.1.12(@types/node@24.9.2)(terser@5.44.0) + specifier: 7.2.4 + version: 7.2.4(@types/node@24.10.1)(terser@5.44.0) vitest: - specifier: ^4.0.6 - version: 4.0.6(@types/node@24.9.2)(terser@5.44.0) + specifier: 4.0.14 + version: 4.0.14(@types/node@24.10.1)(terser@5.44.0) packages: @@ -336,14 +333,14 @@ packages: '@types/luxon@3.7.1': resolution: {integrity: sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==} - '@types/node@24.9.2': - resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==} + '@types/node@24.10.1': + resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} - '@vitest/expect@4.0.6': - resolution: {integrity: sha512-5j8UUlBVhOjhj4lR2Nt9sEV8b4WtbcYh8vnfhTNA2Kn5+smtevzjNq+xlBuVhnFGXiyPPNzGrOVvmyHWkS5QGg==} + '@vitest/expect@4.0.14': + resolution: {integrity: sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==} - '@vitest/mocker@4.0.6': - resolution: {integrity: sha512-3COEIew5HqdzBFEYN9+u0dT3i/NCwppLnO1HkjGfAP1Vs3vti1Hxm/MvcbC4DAn3Szo1M7M3otiAaT83jvqIjA==} + '@vitest/mocker@4.0.14': + resolution: {integrity: sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -353,20 +350,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.6': - resolution: {integrity: sha512-4vptgNkLIA1W1Nn5X4x8rLJBzPiJwnPc+awKtfBE5hNMVsoAl/JCCPPzNrbf+L4NKgklsis5Yp2gYa+XAS442g==} + '@vitest/pretty-format@4.0.14': + resolution: {integrity: sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==} - '@vitest/runner@4.0.6': - resolution: {integrity: sha512-trPk5qpd7Jj+AiLZbV/e+KiiaGXZ8ECsRxtnPnCrJr9OW2mLB72Cb824IXgxVz/mVU3Aj4VebY+tDTPn++j1Og==} + '@vitest/runner@4.0.14': + resolution: {integrity: sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==} - '@vitest/snapshot@4.0.6': - resolution: {integrity: sha512-PaYLt7n2YzuvxhulDDu6c9EosiRuIE+FI2ECKs6yvHyhoga+2TBWI8dwBjs+IeuQaMtZTfioa9tj3uZb7nev1g==} + '@vitest/snapshot@4.0.14': + resolution: {integrity: sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==} - '@vitest/spy@4.0.6': - resolution: {integrity: sha512-g9jTUYPV1LtRPRCQfhbMintW7BTQz1n6WXYQYRQ25qkyffA4bjVXjkROokZnv7t07OqfaFKw1lPzqKGk1hmNuQ==} + '@vitest/spy@4.0.14': + resolution: {integrity: sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==} - '@vitest/utils@4.0.6': - resolution: {integrity: sha512-bG43VS3iYKrMIZXBo+y8Pti0O7uNju3KvNn6DrQWhQQKcLavMB+0NZfO1/QBAEbq0MaQ3QjNsnnXlGQvsh0Z6A==} + '@vitest/utils@4.0.14': + resolution: {integrity: sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==} acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} @@ -380,22 +377,13 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - chai@6.2.0: - resolution: {integrity: sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==} + chai@6.2.1: + resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} engines: {node: '>=18'} commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -435,14 +423,14 @@ packages: mobx@6.15.0: resolution: {integrity: sha512-UczzB+0nnwGotYSgllfARAqWCJ5e/skuV2K/l+Zyck/H6pJIhLXuBnz+6vn2i211o7DtbE78HQtsYEKICHGI+g==} - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -509,8 +497,8 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - vite@7.1.12: - resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} + vite@7.2.4: + resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -549,24 +537,24 @@ packages: yaml: optional: true - vitest@4.0.6: - resolution: {integrity: sha512-gR7INfiVRwnEOkCk47faros/9McCZMp5LM+OMNWGLaDBSvJxIzwjgNFufkuePBNaesGRnLmNfW+ddbUJRZn0nQ==} + vitest@4.0.14: + resolution: {integrity: sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 + '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.6 - '@vitest/browser-preview': 4.0.6 - '@vitest/browser-webdriverio': 4.0.6 - '@vitest/ui': 4.0.6 + '@vitest/browser-playwright': 4.0.14 + '@vitest/browser-preview': 4.0.14 + '@vitest/browser-webdriverio': 4.0.14 + '@vitest/ui': 4.0.14 happy-dom: '*' jsdom: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true - '@types/debug': + '@opentelemetry/api': optional: true '@types/node': optional: true @@ -674,13 +662,16 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 + optional: true - '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/resolve-uri@3.1.2': + optional: true '@jridgewell/source-map@0.3.11': dependencies: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 + optional: true '@jridgewell/sourcemap-codec@1.5.5': {} @@ -688,6 +679,7 @@ snapshots: dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + optional: true '@rollup/rollup-android-arm-eabi@4.52.5': optional: true @@ -768,63 +760,62 @@ snapshots: '@types/luxon@3.7.1': {} - '@types/node@24.9.2': + '@types/node@24.10.1': dependencies: undici-types: 7.16.0 optional: true - '@vitest/expect@4.0.6': + '@vitest/expect@4.0.14': dependencies: '@standard-schema/spec': 1.0.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.6 - '@vitest/utils': 4.0.6 - chai: 6.2.0 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 + chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.6(vite@7.1.12(@types/node@24.9.2)(terser@5.44.0))': + '@vitest/mocker@4.0.14(vite@7.2.4(@types/node@24.10.1)(terser@5.44.0))': dependencies: - '@vitest/spy': 4.0.6 + '@vitest/spy': 4.0.14 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.1.12(@types/node@24.9.2)(terser@5.44.0) + vite: 7.2.4(@types/node@24.10.1)(terser@5.44.0) - '@vitest/pretty-format@4.0.6': + '@vitest/pretty-format@4.0.14': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.6': + '@vitest/runner@4.0.14': dependencies: - '@vitest/utils': 4.0.6 + '@vitest/utils': 4.0.14 pathe: 2.0.3 - '@vitest/snapshot@4.0.6': + '@vitest/snapshot@4.0.14': dependencies: - '@vitest/pretty-format': 4.0.6 + '@vitest/pretty-format': 4.0.14 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.6': {} + '@vitest/spy@4.0.14': {} - '@vitest/utils@4.0.6': + '@vitest/utils@4.0.14': dependencies: - '@vitest/pretty-format': 4.0.6 + '@vitest/pretty-format': 4.0.14 tinyrainbow: 3.0.3 - acorn@8.15.0: {} + acorn@8.15.0: + optional: true assertion-error@2.0.1: {} - buffer-from@1.1.2: {} - - chai@6.2.0: {} + buffer-from@1.1.2: + optional: true - commander@2.20.3: {} + chai@6.2.1: {} - debug@4.4.3: - dependencies: - ms: 2.1.3 + commander@2.20.3: + optional: true es-module-lexer@1.7.0: {} @@ -878,10 +869,10 @@ snapshots: mobx@6.15.0: {} - ms@2.1.3: {} - nanoid@3.3.11: {} + obug@2.1.1: {} + pathe@2.0.3: {} picocolors@1.1.1: {} @@ -930,8 +921,10 @@ snapshots: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + optional: true - source-map@0.6.1: {} + source-map@0.6.1: + optional: true stackback@0.0.2: {} @@ -943,6 +936,7 @@ snapshots: acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 + optional: true tinybench@2.9.0: {} @@ -960,7 +954,7 @@ snapshots: undici-types@7.16.0: optional: true - vite@7.1.12(@types/node@24.9.2)(terser@5.44.0): + vite@7.2.4(@types/node@24.10.1)(terser@5.44.0): dependencies: esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) @@ -969,23 +963,23 @@ snapshots: rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.1 fsevents: 2.3.3 terser: 5.44.0 - vitest@4.0.6(@types/node@24.9.2)(terser@5.44.0): + vitest@4.0.14(@types/node@24.10.1)(terser@5.44.0): dependencies: - '@vitest/expect': 4.0.6 - '@vitest/mocker': 4.0.6(vite@7.1.12(@types/node@24.9.2)(terser@5.44.0)) - '@vitest/pretty-format': 4.0.6 - '@vitest/runner': 4.0.6 - '@vitest/snapshot': 4.0.6 - '@vitest/spy': 4.0.6 - '@vitest/utils': 4.0.6 - debug: 4.4.3 + '@vitest/expect': 4.0.14 + '@vitest/mocker': 4.0.14(vite@7.2.4(@types/node@24.10.1)(terser@5.44.0)) + '@vitest/pretty-format': 4.0.14 + '@vitest/runner': 4.0.14 + '@vitest/snapshot': 4.0.14 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 es-module-lexer: 1.7.0 expect-type: 1.2.2 magic-string: 0.30.21 + obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.10.0 @@ -993,10 +987,10 @@ snapshots: tinyexec: 0.3.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.1.12(@types/node@24.9.2)(terser@5.44.0) + vite: 7.2.4(@types/node@24.10.1)(terser@5.44.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.1 transitivePeerDependencies: - jiti - less @@ -1006,7 +1000,6 @@ snapshots: - sass-embedded - stylus - sugarss - - supports-color - terser - tsx - yaml diff --git a/auto-dark-light@gihaume/pnpm-workspace.yaml b/auto-dark-light@gihaume/pnpm-workspace.yaml index 483f12ea4b1..a3272d11f55 100644 --- a/auto-dark-light@gihaume/pnpm-workspace.yaml +++ b/auto-dark-light@gihaume/pnpm-workspace.yaml @@ -1 +1 @@ -useNodeVersion: 24.11.0 +useNodeVersion: 24.11.1 From 1f9c29898d9df0593d0df8f7e1c8b175f38bfc72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Thu, 27 Nov 2025 19:39:48 +0100 Subject: [PATCH 09/13] Refactor `Keybinding_handler` --- .../auto-dark-light@gihaume/5.8/applet.js | 51 ++++++++++++------- .../src/app/handlers/initialize_handlers.ts | 14 ++--- .../src/lib/sys/Keybinding_handler.ts | 33 ++++++++---- 3 files changed, 62 insertions(+), 36 deletions(-) diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index 7ecd447ce70..b2ea783fc60 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -1,6 +1,6 @@ const Gettext = imports.gettext; const { GLib: GLib$5 } = imports.gi; -const Main$1 = imports.ui.main; +const Main = imports.ui.main; const { St } = imports.gi; const metadata = { uuid: "", @@ -33,15 +33,15 @@ const error_icon = new St.Icon({ const logger = { info(msg) { global.log(translated_applet_name + `${_(":")} ` + msg); - Main$1.notify(translated_applet_name, msg); + Main.notify(translated_applet_name, msg); }, warn(msg) { global.logWarning(translated_applet_name + `${_(":")} ` + msg); - Main$1.warningNotify(translated_applet_name, msg, warning_icon); + Main.warningNotify(translated_applet_name, msg, warning_icon); }, error(msg) { global.logError(translated_applet_name + `${_(":")} ` + msg); - Main$1.criticalNotify(translated_applet_name, msg, error_icon); + Main.criticalNotify(translated_applet_name, msg, error_icon); } }; function die(error) { @@ -4509,20 +4509,32 @@ class Event_scheduler { this.unset_the_event(); } } -const Main = imports.ui.main; -let counter = 0; +const { keybindingManager } = imports.ui.main; class Keybinding_handler { - _name; + _uuid; + static _unicity_count = 0; _callback; - constructor(callback) { - this._name = metadata.uuid + counter++; + /** + * @param unique_namespace - a specific enough id to avoid name collisions with any other system keybinding name, typically the application name + * @param callback - the function to be called when the keybinding has been pressed + */ + constructor(unique_namespace, callback) { + this._uuid = unique_namespace + Keybinding_handler._unicity_count++; this._callback = callback; } - set keybinding(value) { - Main.keybindingManager.addHotKey(this._name, value, this._callback); + /** @param keybinding - the keybinding to set, in the format accepted by Cinnamon (e.g. 'F1') */ + set(keybinding) { + return keybindingManager.addHotKey( + this._uuid, + keybinding, + this._callback + ); + } + unset() { + keybindingManager.removeHotKey(this._uuid); } dispose() { - Main.keybindingManager.removeHotKey(this._name); + this.unset(); } } const { Gio: Gio$4 } = imports.gi; @@ -5201,12 +5213,15 @@ function initialize_handlers(applet, settings2) { appearance_handler.is_auto ? appearance_handler.is_unsynced ? "auto-inverted-symbolic" : "auto-symbolic" : appearance_handler.manual_is_dark ? "dark-symbolic" : "light-symbolic" ); }); - const keybinding_handler = new Keybinding_handler(() => { - appearance_handler.toggle_is_dark(); - }); - keybinding_handler.keybinding = settings2.appearance_keybinding; + const keybinding = new Keybinding_handler( + metadata.uuid, + () => { + appearance_handler.toggle_is_dark(); + } + ); + keybinding.set(settings2.appearance_keybinding); settings2.bind("appearance_keybinding", null, (value) => { - keybinding_handler.keybinding = value; + keybinding.set(value); }); const themes_handler = new Themes_handler(applet, settings2); if (System_color_scheme.value === "prefer-dark") { @@ -5312,7 +5327,7 @@ function initialize_handlers(applet, settings2) { applet.on_button_open_os_themes_settings = () => GLib.spawn_command_line_async("cinnamon-settings themes"); applet.on_button_open_os_background_settings = () => GLib.spawn_command_line_async("cinnamon-settings background"); applet.on_applet_removed_from_panel = () => { - keybinding_handler.dispose(); + keybinding.dispose(); location_handler.dispose(); scheduler.dispose(); sleep_and_lock_handler.dispose(); diff --git a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts index 23ce8dfe06f..e7084c0c330 100644 --- a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts +++ b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts @@ -2,7 +2,7 @@ const { GLib } = imports.gi; import * as mobx from 'mobx'; -import { _ } from '../../globals'; +import { _, metadata } from '../../globals'; import { Appearance_handler } from './Appearance_handler'; import type { Applet } from '../ui/Applet'; import { Background_handler } from './Background_handler'; @@ -159,12 +159,12 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { ); }); - const keybinding_handler = new Keybinding_handler(() => { - appearance_handler.toggle_is_dark(); - }); - keybinding_handler.keybinding = settings.appearance_keybinding; + const keybinding = new Keybinding_handler( + metadata.uuid, () => { appearance_handler.toggle_is_dark(); } + ); + keybinding.set(settings.appearance_keybinding); settings.bind('appearance_keybinding', null, value => { - keybinding_handler.keybinding = value; + keybinding.set(value); }); const themes_handler = new Themes_handler(applet, settings); @@ -291,7 +291,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { // applet.on_panel_icon_size_changed = () => {}; applet.on_applet_removed_from_panel = () => { - keybinding_handler.dispose(); + keybinding.dispose(); location_handler.dispose(); scheduler.dispose(); sleep_and_lock_handler.dispose(); diff --git a/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts b/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts index c954ecaa63c..00985863cba 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts +++ b/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts @@ -1,23 +1,34 @@ -const Main = imports.ui.main; +const { keybindingManager } = imports.ui.main; -import { metadata } from "../../globals"; +import { Disposable } from '../../types'; -let counter = 0; - -export class Keybinding_handler { - private readonly _name: string; +/** A responsible handler to set a Cinnamon keybinding. */ +export class Keybinding_handler implements Disposable { + private readonly _uuid: string; + private static _unicity_count: number = 0; private readonly _callback: () => void; - constructor(callback: () => void) { - this._name = metadata.uuid + counter++; + /** + * @param unique_namespace - a specific enough id to avoid name collisions with any other system keybinding name, typically the application name + * @param callback - the function to be called when the keybinding has been pressed + */ + constructor(unique_namespace: string, callback: () => void) { + this._uuid = unique_namespace + Keybinding_handler._unicity_count++; this._callback = callback; } - set keybinding(value: string) { - Main.keybindingManager.addHotKey(this._name, value, this._callback); + /** @param keybinding - the keybinding to set, in the format accepted by Cinnamon (e.g. 'F1') */ + set(keybinding: string): boolean { + return keybindingManager.addHotKey( + this._uuid, keybinding, this._callback + ); + } + + unset(): void { + keybindingManager.removeHotKey(this._uuid); } dispose() { - Main.keybindingManager.removeHotKey(this._name); + this.unset(); } } From 84d44ba3416df647b4c434cc638dca6f711b6aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Thu, 27 Nov 2025 20:20:01 +0100 Subject: [PATCH 10/13] Reorganize et rename classes in `src/lib/sys` folder --- .../auto-dark-light@gihaume/5.8/applet.js | 104 ++++++++---------- .../src/app/handlers/Appearance_handler.ts | 2 +- .../src/app/handlers/Background_handler.ts | 26 ++--- .../src/app/handlers/Commands_handler.ts | 2 +- .../src/app/handlers/Location_handler.ts | 2 +- .../src/app/handlers/Themes_handler.ts | 40 +++---- .../src/app/handlers/initialize_handlers.ts | 32 +++--- .../compute_twilights/compute_twilights.ts | 2 +- .../src/lib/{ => core}/utils.ts | 0 .../Background_accessor.ts} | 2 +- .../Color_scheme_handler.ts} | 6 +- .../sys/{ => cinnamon}/Keybinding_handler.ts | 2 +- .../Screen_lock_change_listener.js | 19 +--- .../Screen_unlock_waiter.js | 2 +- .../Sleep_and_lock_handler.js | 2 +- .../Sleep_events_listener.js | 2 +- .../doc/Sleep_and_lock_handler.drawio.svg | 0 .../cinnamon/Sleep_and_lock_handler/index.js | 3 + .../tests/test Screen_lock_change_listener.js | 0 .../tests/test Screen_unlock_waiter.js | 0 .../tests/test Sleep_and_lock_handler.js | 0 .../tests/test Sleep_events_listener.js | 0 .../Themes_accessor.ts} | 2 +- .../Event_scheduler/Event_scheduler.ts | 2 +- .../Event_scheduler/Timer_absolute.ts | 2 +- .../lib/sys/gnome/Event_scheduler/index.js | 3 + .../{ => gnome}/Timezone_change_listener.ts | 0 .../Wall_clock_adjustment_monitor.js | 2 +- .../src/lib/sys/{ => gnome}/launch_command.ts | 2 +- .../src/lib/sys/{ => gnome}/system_time.ts | 4 +- .../test Wall_clock_adjustment_monitor.js | 0 31 files changed, 119 insertions(+), 146 deletions(-) rename auto-dark-light@gihaume/src/lib/{ => core}/utils.ts (100%) rename auto-dark-light@gihaume/src/lib/sys/{System_background.ts => cinnamon/Background_accessor.ts} (97%) rename auto-dark-light@gihaume/src/lib/sys/{System_color_scheme.ts => cinnamon/Color_scheme_handler.ts} (88%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Keybinding_handler.ts (96%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/Screen_lock_change_listener.js (62%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/Screen_unlock_waiter.js (95%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/Sleep_and_lock_handler.js (94%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/Sleep_events_listener.js (95%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg (100%) create mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/index.js rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js (100%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js (100%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js (100%) rename auto-dark-light@gihaume/src/lib/sys/{ => cinnamon}/Sleep_and_lock_handler/tests/test Sleep_events_listener.js (100%) rename auto-dark-light@gihaume/src/lib/sys/{System_themes.ts => cinnamon/Themes_accessor.ts} (97%) rename auto-dark-light@gihaume/src/lib/sys/{ => gnome}/Event_scheduler/Event_scheduler.ts (97%) rename auto-dark-light@gihaume/src/lib/sys/{ => gnome}/Event_scheduler/Timer_absolute.ts (92%) create mode 100644 auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/index.js rename auto-dark-light@gihaume/src/lib/sys/{ => gnome}/Timezone_change_listener.ts (100%) rename auto-dark-light@gihaume/src/lib/sys/{ => gnome}/Wall_clock_adjustment_monitor.js (97%) rename auto-dark-light@gihaume/src/lib/sys/{ => gnome}/launch_command.ts (98%) rename auto-dark-light@gihaume/src/lib/sys/{ => gnome}/system_time.ts (90%) rename auto-dark-light@gihaume/src/lib/sys/{ => gnome}/tests/test Wall_clock_adjustment_monitor.js (100%) diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index b2ea783fc60..9c99afbd30f 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -4265,7 +4265,7 @@ const settings$2 = { background: Gio$6.Settings.new("org.cinnamon.desktop.background"), slideshow: Gio$6.Settings.new("org.cinnamon.desktop.background.slideshow") }; -class System_background { +class Background_accessor { static get is_slideshow() { return settings$2.slideshow.get_boolean("slideshow-enabled"); } @@ -4299,44 +4299,44 @@ class Background_handler { applet.on_button_apply_background_dark = () => this.apply_dark_background(); } detect_light_background() { - const is_slideshow = System_background.is_slideshow; + const is_slideshow = Background_accessor.is_slideshow; this._settings.light_background_is_slideshow = is_slideshow; if (is_slideshow) - this._settings.light_background_slideshow_folder = System_background.slideshow_folder.replace("directory://", "file://"); + this._settings.light_background_slideshow_folder = Background_accessor.slideshow_folder.replace("directory://", "file://"); else - this._settings.light_background_file = System_background.picture_file; + this._settings.light_background_file = Background_accessor.picture_file; } detect_dark_background() { - const is_slideshow = System_background.is_slideshow; + const is_slideshow = Background_accessor.is_slideshow; this._settings.dark_background_is_slideshow = is_slideshow; if (is_slideshow) - this._settings.dark_background_slideshow_folder = System_background.slideshow_folder.replace("directory://", "file://"); + this._settings.dark_background_slideshow_folder = Background_accessor.slideshow_folder.replace("directory://", "file://"); else - this._settings.dark_background_file = System_background.picture_file; + this._settings.dark_background_file = Background_accessor.picture_file; } apply_light_background() { const is_slideshow = this._settings.light_background_is_slideshow; - System_background.is_slideshow = is_slideshow; + Background_accessor.is_slideshow = is_slideshow; if (is_slideshow) - System_background.slideshow_folder = decodeURIComponent( + Background_accessor.slideshow_folder = decodeURIComponent( // If the folder was chosen via a filechooser, it may contain non-ASCII characters this._settings.light_background_slideshow_folder.replace("file://", "directory://") // https://github.com/linuxmint/cinnamon/issues/12374 ); else - System_background.picture_file = this._settings.light_background_file; + Background_accessor.picture_file = this._settings.light_background_file; } apply_dark_background() { const is_slideshow = this._settings.dark_background_is_slideshow; - System_background.is_slideshow = is_slideshow; + Background_accessor.is_slideshow = is_slideshow; if (is_slideshow) - System_background.slideshow_folder = decodeURIComponent( + Background_accessor.slideshow_folder = decodeURIComponent( // If the folder was chosen via a filechooser, it may contain non-ASCII characters this._settings.dark_background_slideshow_folder.replace("file://", "directory://") // https://github.com/linuxmint/cinnamon/issues/12374 ); else - System_background.picture_file = this._settings.dark_background_file; + Background_accessor.picture_file = this._settings.dark_background_file; } } const { Gio: Gio$5, GLib: GLib$4 } = imports.gi; @@ -4661,22 +4661,6 @@ class Screen_lock_change_listener { _signal_id = null; /** @private @readonly @type {imports.gi.Gio.DBusProxy} */ _screen_saver_proxy = ScreenSaverProxy(); - // /** - // * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. - // * @param {() => void} callback_when_unlocked - The function to be executed when the screen is unlocked. - // */ - // try_now_or_postpone_until_unlocked(callback_when_unlocked) { - // if (!this.is_locked) { - // callback_when_unlocked(); - // } else { - // this._subscribe_to_changes(is_locked => { - // if (is_locked) - // return; - // this._unsubscribe_to_changes(); - // callback_when_unlocked(); - // }); - // } - // } /** @returns {boolean} */ get is_locked() { return this._screen_saver_proxy.screenSaverActive; @@ -4814,7 +4798,7 @@ class Sleep_and_lock_handler { } const { Gio: Gio$1 } = imports.gi; const settings$1 = Gio$1.Settings.new("org.x.apps.portal"); -class System_color_scheme { +class Color_scheme_handler { _callback_on_change; _signal_id = void 0; /** @param callback_on_change - The function to be executed when the color scheme changes. */ @@ -4824,7 +4808,7 @@ class System_color_scheme { enable() { this.disable(); this._signal_id = settings$1.connect("changed::color-scheme", () => { - this._callback_on_change(System_color_scheme.value); + this._callback_on_change(Color_scheme_handler.value); }); } disable() { @@ -4849,7 +4833,7 @@ const settings = { desktop: Gio.Settings.new("org.cinnamon.desktop.interface"), cinnamon: Gio.Settings.new("org.cinnamon.theme") }; -class System_themes { +class Themes_accessor { static get mouse() { return settings.desktop.get_string("cursor-theme"); } @@ -4885,32 +4869,32 @@ class Themes_handler { applet.on_button_apply_themes_dark = () => this.apply_dark_themes(); } detect_light_themes() { - this._settings.setValue("light_themes_mouse", System_themes.mouse); - this._settings.setValue("light_themes_apps", System_themes.apps); - this._settings.setValue("light_themes_icons", System_themes.icons); - this._settings.setValue("light_themes_desktop", System_themes.desktop); + this._settings.setValue("light_themes_mouse", Themes_accessor.mouse); + this._settings.setValue("light_themes_apps", Themes_accessor.apps); + this._settings.setValue("light_themes_icons", Themes_accessor.icons); + this._settings.setValue("light_themes_desktop", Themes_accessor.desktop); this._settings.light_themes_have_been_detected = true; } detect_dark_themes() { - this._settings.setValue("dark_themes_mouse", System_themes.mouse); - this._settings.setValue("dark_themes_apps", System_themes.apps); - this._settings.setValue("dark_themes_icons", System_themes.icons); - this._settings.setValue("dark_themes_desktop", System_themes.desktop); + this._settings.setValue("dark_themes_mouse", Themes_accessor.mouse); + this._settings.setValue("dark_themes_apps", Themes_accessor.apps); + this._settings.setValue("dark_themes_icons", Themes_accessor.icons); + this._settings.setValue("dark_themes_desktop", Themes_accessor.desktop); this._settings.dark_themes_have_been_detected = true; } apply_light_themes() { - System_themes.mouse = this._settings.getValue("light_themes_mouse"); - System_themes.apps = this._settings.getValue("light_themes_apps"); - System_themes.icons = this._settings.getValue("light_themes_icons"); - System_themes.desktop = this._settings.getValue("light_themes_desktop"); - System_color_scheme.value = "prefer-light"; + Themes_accessor.mouse = this._settings.getValue("light_themes_mouse"); + Themes_accessor.apps = this._settings.getValue("light_themes_apps"); + Themes_accessor.icons = this._settings.getValue("light_themes_icons"); + Themes_accessor.desktop = this._settings.getValue("light_themes_desktop"); + Color_scheme_handler.value = "prefer-light"; } apply_dark_themes() { - System_themes.mouse = this._settings.getValue("dark_themes_mouse"); - System_themes.apps = this._settings.getValue("dark_themes_apps"); - System_themes.icons = this._settings.getValue("dark_themes_icons"); - System_themes.desktop = this._settings.getValue("dark_themes_desktop"); - System_color_scheme.value = "prefer-dark"; + Themes_accessor.mouse = this._settings.getValue("dark_themes_mouse"); + Themes_accessor.apps = this._settings.getValue("dark_themes_apps"); + Themes_accessor.icons = this._settings.getValue("dark_themes_icons"); + Themes_accessor.desktop = this._settings.getValue("dark_themes_desktop"); + Color_scheme_handler.value = "prefer-dark"; } } const { PI, sin, cos, asin, acos, round } = Math; @@ -5167,7 +5151,7 @@ function initialize_handlers(applet, settings2) { }, { fireImmediately: true }); const appearance_handler = new Appearance_handler({ twilights: twilights_handler.twilights, - manual_is_dark: System_color_scheme.value === "prefer-dark", + manual_is_dark: Color_scheme_handler.value === "prefer-dark", is_auto: settings2.is_appearance_auto }); autorun(() => { @@ -5224,7 +5208,7 @@ function initialize_handlers(applet, settings2) { keybinding.set(value); }); const themes_handler = new Themes_handler(applet, settings2); - if (System_color_scheme.value === "prefer-dark") { + if (Color_scheme_handler.value === "prefer-dark") { if (settings2.dark_themes_have_been_detected) themes_handler.detect_dark_themes(); } else { @@ -5232,9 +5216,9 @@ function initialize_handlers(applet, settings2) { themes_handler.detect_light_themes(); } const color_scheme = makeAutoObservable({ - value: System_color_scheme.value + value: Color_scheme_handler.value }); - const system_color_scheme = new System_color_scheme((new_color_scheme) => { + const color_scheme_handler = new Color_scheme_handler((new_color_scheme) => { color_scheme.value = new_color_scheme; }); let is_update_from_system = false; @@ -5250,17 +5234,17 @@ function initialize_handlers(applet, settings2) { return; } if (appearance_handler.manual_is_dark) { - system_color_scheme.disable(); + color_scheme_handler.disable(); themes_handler.apply_dark_themes(); - system_color_scheme.enable(); + color_scheme_handler.enable(); if (settings2.enable_background) background_handler.apply_dark_background(); if (settings2.dark_commands_is_enabled) commands_handler.launch_dark_commands(); } else { - system_color_scheme.disable(); + color_scheme_handler.disable(); themes_handler.apply_light_themes(); - system_color_scheme.enable(); + color_scheme_handler.enable(); if (settings2.enable_background) background_handler.apply_light_background(); if (settings2.light_commands_is_enabled) @@ -5331,11 +5315,11 @@ function initialize_handlers(applet, settings2) { location_handler.dispose(); scheduler.dispose(); sleep_and_lock_handler.dispose(); - system_color_scheme.dispose(); + color_scheme_handler.dispose(); wall_clock_monitor.dispose(); settings2.finalize(); }; - system_color_scheme.enable(); + color_scheme_handler.enable(); wall_clock_monitor.enable(); sleep_and_lock_handler.enable(); } diff --git a/auto-dark-light@gihaume/src/app/handlers/Appearance_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Appearance_handler.ts index 03c293245f8..fe521a41db3 100644 --- a/auto-dark-light@gihaume/src/app/handlers/Appearance_handler.ts +++ b/auto-dark-light@gihaume/src/app/handlers/Appearance_handler.ts @@ -1,7 +1,7 @@ import * as mobx from "mobx"; import type { Twilights } from "../../types"; -import * as system_time from "../../lib/sys/system_time"; +import * as system_time from "../../lib/sys/gnome/system_time"; import type { Time_of_day } from "../../lib/core/Time_of_day"; export class Appearance_handler { diff --git a/auto-dark-light@gihaume/src/app/handlers/Background_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Background_handler.ts index 8504f922656..ea9ec936139 100644 --- a/auto-dark-light@gihaume/src/app/handlers/Background_handler.ts +++ b/auto-dark-light@gihaume/src/app/handlers/Background_handler.ts @@ -1,6 +1,6 @@ import type { Applet } from "../ui/Applet"; import type { Settings } from "../ui/Settings"; -import { System_background } from "../../lib/sys/System_background"; +import { Background_accessor as Background } from "../../lib/sys/cinnamon/Background_accessor"; export class Background_handler { private readonly _settings: Settings; @@ -19,48 +19,48 @@ export class Background_handler { } detect_light_background(): void { - const is_slideshow = System_background.is_slideshow; + const is_slideshow = Background.is_slideshow; this._settings.light_background_is_slideshow = is_slideshow; if (is_slideshow) this._settings.light_background_slideshow_folder = - System_background.slideshow_folder + Background.slideshow_folder .replace('directory://', "file://") // https://github.com/linuxmint/cinnamon/issues/12374 else - this._settings.light_background_file = System_background.picture_file; + this._settings.light_background_file = Background.picture_file; } detect_dark_background(): void { - const is_slideshow = System_background.is_slideshow; + const is_slideshow = Background.is_slideshow; this._settings.dark_background_is_slideshow = is_slideshow; if (is_slideshow) this._settings.dark_background_slideshow_folder = - System_background.slideshow_folder + Background.slideshow_folder .replace('directory://', "file://"); // https://github.com/linuxmint/cinnamon/issues/12374 else - this._settings.dark_background_file = System_background.picture_file; + this._settings.dark_background_file = Background.picture_file; } apply_light_background(): void { const is_slideshow = this._settings.light_background_is_slideshow; - System_background.is_slideshow = is_slideshow; + Background.is_slideshow = is_slideshow; if (is_slideshow) - System_background.slideshow_folder = + Background.slideshow_folder = decodeURIComponent( // If the folder was chosen via a filechooser, it may contain non-ASCII characters this._settings.light_background_slideshow_folder .replace('file://', "directory://") // https://github.com/linuxmint/cinnamon/issues/12374 ); else - System_background.picture_file = + Background.picture_file = this._settings.light_background_file; } apply_dark_background(): void { const is_slideshow = this._settings.dark_background_is_slideshow; - System_background.is_slideshow = is_slideshow; + Background.is_slideshow = is_slideshow; if (is_slideshow) - System_background.slideshow_folder = + Background.slideshow_folder = decodeURIComponent( // If the folder was chosen via a filechooser, it may contain non-ASCII characters this._settings.dark_background_slideshow_folder .replace('file://', "directory://") // https://github.com/linuxmint/cinnamon/issues/12374 ); else - System_background.picture_file = this._settings.dark_background_file; + Background.picture_file = this._settings.dark_background_file; } } diff --git a/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts index 5c4287eebd8..90557fd7ecd 100644 --- a/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts +++ b/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts @@ -1,5 +1,5 @@ import type { Applet } from "../ui/Applet"; -import { launch_command } from "../../lib/sys/launch_command"; +import { launch_command } from "../../lib/sys/gnome/launch_command"; import type { Settings } from "../ui/Settings"; export class Commands_handler { diff --git a/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts index 652a3c144e4..54c8ec4c99d 100644 --- a/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts +++ b/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts @@ -4,7 +4,7 @@ import * as mobx from "mobx"; import type { Location } from "../../types"; import { metadata } from '../../globals'; -import { Timezone_change_listener } from '../../lib/sys/Timezone_change_listener'; +import { Timezone_change_listener } from '../../lib/sys/gnome/Timezone_change_listener'; import { Timezone_location_finder } from "../../lib/core/Timezone_location_finder/Timezone_location_finder"; export class Location_handler { diff --git a/auto-dark-light@gihaume/src/app/handlers/Themes_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Themes_handler.ts index 06ad8d3f7e4..0a38cc73afe 100644 --- a/auto-dark-light@gihaume/src/app/handlers/Themes_handler.ts +++ b/auto-dark-light@gihaume/src/app/handlers/Themes_handler.ts @@ -1,7 +1,7 @@ import type { Applet } from "../ui/Applet"; +import { Color_scheme_handler as Color_scheme } from "../../lib/sys/cinnamon/Color_scheme_handler"; import type { Settings } from "../ui/Settings"; -import { System_color_scheme } from "../../lib/sys/System_color_scheme"; -import { System_themes } from "../../lib/sys/System_themes"; +import { Themes_accessor as Themes } from "../../lib/sys/cinnamon/Themes_accessor"; export class Themes_handler { private readonly _settings: Settings; @@ -16,34 +16,34 @@ export class Themes_handler { } detect_light_themes(): void { - this._settings.setValue('light_themes_mouse', System_themes.mouse); - this._settings.setValue('light_themes_apps', System_themes.apps); - this._settings.setValue('light_themes_icons', System_themes.icons); - this._settings.setValue('light_themes_desktop', System_themes.desktop); + this._settings.setValue('light_themes_mouse', Themes.mouse); + this._settings.setValue('light_themes_apps', Themes.apps); + this._settings.setValue('light_themes_icons', Themes.icons); + this._settings.setValue('light_themes_desktop', Themes.desktop); this._settings.light_themes_have_been_detected = true; } detect_dark_themes(): void { - this._settings.setValue('dark_themes_mouse', System_themes.mouse); - this._settings.setValue('dark_themes_apps', System_themes.apps); - this._settings.setValue('dark_themes_icons', System_themes.icons); - this._settings.setValue('dark_themes_desktop', System_themes.desktop); + this._settings.setValue('dark_themes_mouse', Themes.mouse); + this._settings.setValue('dark_themes_apps', Themes.apps); + this._settings.setValue('dark_themes_icons', Themes.icons); + this._settings.setValue('dark_themes_desktop', Themes.desktop); this._settings.dark_themes_have_been_detected = true; } apply_light_themes(): void { - System_themes.mouse = this._settings.getValue('light_themes_mouse'); - System_themes.apps = this._settings.getValue('light_themes_apps'); - System_themes.icons = this._settings.getValue('light_themes_icons'); - System_themes.desktop = this._settings.getValue('light_themes_desktop'); - System_color_scheme.value = 'prefer-light'; + Themes.mouse = this._settings.getValue('light_themes_mouse'); + Themes.apps = this._settings.getValue('light_themes_apps'); + Themes.icons = this._settings.getValue('light_themes_icons'); + Themes.desktop = this._settings.getValue('light_themes_desktop'); + Color_scheme.value = 'prefer-light'; } apply_dark_themes(): void { - System_themes.mouse = this._settings.getValue('dark_themes_mouse'); - System_themes.apps = this._settings.getValue('dark_themes_apps'); - System_themes.icons = this._settings.getValue('dark_themes_icons'); - System_themes.desktop = this._settings.getValue('dark_themes_desktop'); - System_color_scheme.value = 'prefer-dark'; + Themes.mouse = this._settings.getValue('dark_themes_mouse'); + Themes.apps = this._settings.getValue('dark_themes_apps'); + Themes.icons = this._settings.getValue('dark_themes_icons'); + Themes.desktop = this._settings.getValue('dark_themes_desktop'); + Color_scheme.value = 'prefer-dark'; } } diff --git a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts index e7084c0c330..d51039c9c66 100644 --- a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts +++ b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts @@ -7,18 +7,18 @@ import { Appearance_handler } from './Appearance_handler'; import type { Applet } from '../ui/Applet'; import { Background_handler } from './Background_handler'; import { Commands_handler } from './Commands_handler'; -import { Event_scheduler } from "../../lib/sys/Event_scheduler/Event_scheduler"; -import { Keybinding_handler } from '../../lib/sys/Keybinding_handler'; +import { Event_scheduler } from "../../lib/sys/gnome/Event_scheduler"; +import { Keybinding_handler } from '../../lib/sys/cinnamon/Keybinding_handler'; import { Location_handler } from './Location_handler'; import { logger } from '../../globals'; import type { Settings } from '../ui/Settings'; -import { sleep } from '../../lib/utils'; -import { Sleep_and_lock_handler } from '../../lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler'; -import { System_color_scheme } from '../../lib/sys/System_color_scheme'; +import { sleep } from '../../lib/core/utils'; +import { Sleep_and_lock_handler } from '../../lib/sys/cinnamon/Sleep_and_lock_handler'; +import { Color_scheme_handler } from '../../lib/sys/cinnamon/Color_scheme_handler'; import { Themes_handler } from './Themes_handler'; import { Time_of_day } from '../../lib/core/Time_of_day'; import { Twilights_handler } from './Twilights_handler'; -import { Wall_clock_adjustment_monitor } from '../../lib/sys/Wall_clock_adjustment_monitor'; +import { Wall_clock_adjustment_monitor } from '../../lib/sys/gnome/Wall_clock_adjustment_monitor'; const DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING = 2000; // milliseconds (ms) @@ -104,7 +104,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { const appearance_handler = new Appearance_handler({ twilights: twilights_handler.twilights, - manual_is_dark: System_color_scheme.value === 'prefer-dark', + manual_is_dark: Color_scheme_handler.value === 'prefer-dark', is_auto: settings.is_appearance_auto }); @@ -169,7 +169,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { const themes_handler = new Themes_handler(applet, settings); - if (System_color_scheme.value === 'prefer-dark') { // TODO: clear this idea so the user is not confused + if (Color_scheme_handler.value === 'prefer-dark') { // TODO: clear this idea so the user is not confused if (settings.dark_themes_have_been_detected) themes_handler.detect_dark_themes(); } else { @@ -177,9 +177,9 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { themes_handler.detect_light_themes(); } const color_scheme = mobx.makeAutoObservable({ - value: System_color_scheme.value + value: Color_scheme_handler.value }); - const system_color_scheme = new System_color_scheme(new_color_scheme => { + const color_scheme_handler = new Color_scheme_handler(new_color_scheme => { color_scheme.value = new_color_scheme; }); let is_update_from_system = false; // Temporary fix // TODO: improve the model @@ -198,17 +198,17 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { return; } if (appearance_handler.manual_is_dark) { - system_color_scheme.disable(); + color_scheme_handler.disable(); themes_handler.apply_dark_themes(); - system_color_scheme.enable(); + color_scheme_handler.enable(); if (settings.enable_background) background_handler.apply_dark_background(); if (settings.dark_commands_is_enabled) commands_handler.launch_dark_commands(); } else { - system_color_scheme.disable(); + color_scheme_handler.disable(); themes_handler.apply_light_themes(); - system_color_scheme.enable(); + color_scheme_handler.enable(); if (settings.enable_background) background_handler.apply_light_background(); if (settings.light_commands_is_enabled) @@ -295,12 +295,12 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { location_handler.dispose(); scheduler.dispose(); sleep_and_lock_handler.dispose(); - system_color_scheme.dispose(); + color_scheme_handler.dispose(); wall_clock_monitor.dispose(); settings.finalize(); }; - system_color_scheme.enable(); + color_scheme_handler.enable(); wall_clock_monitor.enable(); sleep_and_lock_handler.enable(); } diff --git a/auto-dark-light@gihaume/src/lib/core/compute_twilights/compute_twilights.ts b/auto-dark-light@gihaume/src/lib/core/compute_twilights/compute_twilights.ts index 5ec7d269fea..ef794db832a 100644 --- a/auto-dark-light@gihaume/src/lib/core/compute_twilights/compute_twilights.ts +++ b/auto-dark-light@gihaume/src/lib/core/compute_twilights/compute_twilights.ts @@ -1,5 +1,5 @@ import type { Location, Twilights } from '../../../types'; -import * as system_time from '../../sys/system_time'; +import * as system_time from '../../sys/gnome/system_time'; import * as uSunCalc from './uSunCalc'; export function compute_twilights( diff --git a/auto-dark-light@gihaume/src/lib/utils.ts b/auto-dark-light@gihaume/src/lib/core/utils.ts similarity index 100% rename from auto-dark-light@gihaume/src/lib/utils.ts rename to auto-dark-light@gihaume/src/lib/core/utils.ts diff --git a/auto-dark-light@gihaume/src/lib/sys/System_background.ts b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Background_accessor.ts similarity index 97% rename from auto-dark-light@gihaume/src/lib/sys/System_background.ts rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Background_accessor.ts index a91dacd5dce..cdd00ff6acd 100644 --- a/auto-dark-light@gihaume/src/lib/sys/System_background.ts +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Background_accessor.ts @@ -6,7 +6,7 @@ const settings = { } as const; /** An accessor to the Cinnamon system background settings. */ -export class System_background { +export class Background_accessor { static get is_slideshow(): boolean { return settings.slideshow.get_boolean('slideshow-enabled'); } diff --git a/auto-dark-light@gihaume/src/lib/sys/System_color_scheme.ts b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Color_scheme_handler.ts similarity index 88% rename from auto-dark-light@gihaume/src/lib/sys/System_color_scheme.ts rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Color_scheme_handler.ts index 7366c6fdb9a..7baeaa68e3c 100644 --- a/auto-dark-light@gihaume/src/lib/sys/System_color_scheme.ts +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Color_scheme_handler.ts @@ -1,11 +1,11 @@ const { Gio } = imports.gi; -import { Color_scheme } from "../../types"; +import { Color_scheme } from "../../../types"; const settings = Gio.Settings.new('org.x.apps.portal'); /** A listener and accessor to the Cinnamon system color scheme setting. */ -export class System_color_scheme { +export class Color_scheme_handler { private readonly _callback_on_change: (color_scheme: Color_scheme) => void; private _signal_id: number | undefined = undefined; @@ -17,7 +17,7 @@ export class System_color_scheme { enable() { this.disable(); // Ensures only one signal is connected this._signal_id = settings.connect('changed::color-scheme', () => { - this._callback_on_change(System_color_scheme.value); + this._callback_on_change(Color_scheme_handler.value); }); } diff --git a/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts similarity index 96% rename from auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts index 00985863cba..d4947b8ae57 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Keybinding_handler.ts +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts @@ -1,6 +1,6 @@ const { keybindingManager } = imports.ui.main; -import { Disposable } from '../../types'; +import { Disposable } from '../../../types'; /** A responsible handler to set a Cinnamon keybinding. */ export class Keybinding_handler implements Disposable { diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_lock_change_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js similarity index 62% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_lock_change_listener.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js index b52bb12d807..72f34e83628 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_lock_change_listener.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js @@ -1,6 +1,6 @@ const { ScreenSaverProxy } = imports.misc.screenSaver; -/** @typedef {import('../../../types').Observer} Observer */ +/** @typedef {import('../../../../types').Observer} Observer */ /** * An interface to read and listen to the screen locked state. @@ -14,23 +14,6 @@ export class Screen_lock_change_listener { /** @private @readonly @type {imports.gi.Gio.DBusProxy} */ _screen_saver_proxy = ScreenSaverProxy(); - // /** - // * Asynchronously tries now or postpones until the screen is unlocked to execute a procedure. - // * @param {() => void} callback_when_unlocked - The function to be executed when the screen is unlocked. - // */ - // try_now_or_postpone_until_unlocked(callback_when_unlocked) { - // if (!this.is_locked) { - // callback_when_unlocked(); - // } else { - // this._subscribe_to_changes(is_locked => { - // if (is_locked) - // return; - // this._unsubscribe_to_changes(); - // callback_when_unlocked(); - // }); - // } - // } - /** @returns {boolean} */ get is_locked() { return this._screen_saver_proxy.screenSaverActive; diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_unlock_waiter.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_unlock_waiter.js similarity index 95% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_unlock_waiter.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_unlock_waiter.js index 73e1ab5a2b2..8314186b97c 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Screen_unlock_waiter.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_unlock_waiter.js @@ -1,4 +1,4 @@ -/** @typedef {import('../../../types').Disposable} Disposable */ +/** @typedef {import('../../../../types.js').Disposable} Disposable */ import { Screen_lock_change_listener } from './Screen_lock_change_listener.js'; /** diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_and_lock_handler.js similarity index 94% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_and_lock_handler.js index 6a506afc7a8..4d7e5eb4e06 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_and_lock_handler.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_and_lock_handler.js @@ -1,4 +1,4 @@ -/** @typedef {import('../../../types').Observer} Observer */ +/** @typedef {import('../../../../types.js').Observer} Observer */ import { Screen_unlock_waiter } from './Screen_unlock_waiter.js'; import { Sleep_events_listener } from './Sleep_events_listener.js'; diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js similarity index 95% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_events_listener.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js index 2b74d3cea51..c6a4c5e2630 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/Sleep_events_listener.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js @@ -1,6 +1,6 @@ const { Gio } = imports.gi; -/** @typedef {import('../../../types').Observer} Observer */ +/** @typedef {import('../../../../types').Observer} Observer */ /** * An interface to listen to the sleep entering and waking events. diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/index.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/index.js new file mode 100644 index 00000000000..94126b39e7d --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/index.js @@ -0,0 +1,3 @@ +import { Sleep_and_lock_handler } from "./Sleep_and_lock_handler"; + +export { Sleep_and_lock_handler }; diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js diff --git a/auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/Sleep_and_lock_handler/tests/test Sleep_events_listener.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js diff --git a/auto-dark-light@gihaume/src/lib/sys/System_themes.ts b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Themes_accessor.ts similarity index 97% rename from auto-dark-light@gihaume/src/lib/sys/System_themes.ts rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Themes_accessor.ts index 45c798f03c2..c23b3b4921b 100644 --- a/auto-dark-light@gihaume/src/lib/sys/System_themes.ts +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Themes_accessor.ts @@ -6,7 +6,7 @@ const settings = { } as const; /** An accessor to the Cinnamon system themes settings. */ -export class System_themes { +export class Themes_accessor { static get mouse(): string { return settings.desktop.get_string('cursor-theme'); } diff --git a/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Event_scheduler.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts similarity index 97% rename from auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Event_scheduler.ts rename to auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts index ae4b3a7e409..13dd707d037 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Event_scheduler.ts +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts @@ -1,7 +1,7 @@ const { GLib } = imports.gi; import * as system_time from "../system_time"; -import type { Time_of_day } from "../../core/Time_of_day"; +import type { Time_of_day } from "../../../core/Time_of_day"; import { Timer_absolute } from "./Timer_absolute"; /** diff --git a/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Timer_absolute.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.ts similarity index 92% rename from auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Timer_absolute.ts rename to auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.ts index 98bfb5daa95..b6a2341f56b 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Event_scheduler/Timer_absolute.ts +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.ts @@ -1,5 +1,5 @@ import * as system_time from '../system_time'; -import type { Time_of_day } from '../../core/Time_of_day'; +import type { Time_of_day } from '../../../core/Time_of_day'; /** A basic request-based absolute timer to be set for a next occurring time of day. */ export class Timer_absolute { diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/index.js b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/index.js new file mode 100644 index 00000000000..fc8a7963c95 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/index.js @@ -0,0 +1,3 @@ +import { Event_scheduler } from "./Event_scheduler"; + +export { Event_scheduler }; diff --git a/auto-dark-light@gihaume/src/lib/sys/Timezone_change_listener.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/Timezone_change_listener.ts similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/Timezone_change_listener.ts rename to auto-dark-light@gihaume/src/lib/sys/gnome/Timezone_change_listener.ts diff --git a/auto-dark-light@gihaume/src/lib/sys/Wall_clock_adjustment_monitor.js b/auto-dark-light@gihaume/src/lib/sys/gnome/Wall_clock_adjustment_monitor.js similarity index 97% rename from auto-dark-light@gihaume/src/lib/sys/Wall_clock_adjustment_monitor.js rename to auto-dark-light@gihaume/src/lib/sys/gnome/Wall_clock_adjustment_monitor.js index f3b320be1e0..f4e44a5d01a 100644 --- a/auto-dark-light@gihaume/src/lib/sys/Wall_clock_adjustment_monitor.js +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/Wall_clock_adjustment_monitor.js @@ -1,6 +1,6 @@ const { GLib } = imports.gi; -/** @typedef {import('../../types').Observer} Observer */ +/** @typedef {import('../../../types').Observer} Observer */ /** @implements {Observer} */ export class Wall_clock_adjustment_monitor { diff --git a/auto-dark-light@gihaume/src/lib/sys/launch_command.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/launch_command.ts similarity index 98% rename from auto-dark-light@gihaume/src/lib/sys/launch_command.ts rename to auto-dark-light@gihaume/src/lib/sys/gnome/launch_command.ts index e7df9e96a64..4055d67ec94 100644 --- a/auto-dark-light@gihaume/src/lib/sys/launch_command.ts +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/launch_command.ts @@ -1,5 +1,5 @@ const { Gio, GLib } = imports.gi; -import { _, logger } from '../../globals'; +import { _, logger } from '../../../globals'; export async function launch_command( name: string, expiry: number, command: string diff --git a/auto-dark-light@gihaume/src/lib/sys/system_time.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/system_time.ts similarity index 90% rename from auto-dark-light@gihaume/src/lib/sys/system_time.ts rename to auto-dark-light@gihaume/src/lib/sys/gnome/system_time.ts index 646b1a4d316..d55ff68e55b 100644 --- a/auto-dark-light@gihaume/src/lib/sys/system_time.ts +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/system_time.ts @@ -1,7 +1,7 @@ const { DateTime } = imports.gi.GLib; // Preferred over JS's `Date` to take into account timezone changes during runtime. -import { Time_of_day } from "../core/Time_of_day"; -import type { Time_hms } from '../../types'; +import { Time_of_day } from "../../core/Time_of_day"; +import type { Time_hms } from '../../../types'; /** @returns seconds (s) */ export function get_now_as_unix(): number { diff --git a/auto-dark-light@gihaume/src/lib/sys/tests/test Wall_clock_adjustment_monitor.js b/auto-dark-light@gihaume/src/lib/sys/gnome/tests/test Wall_clock_adjustment_monitor.js similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/tests/test Wall_clock_adjustment_monitor.js rename to auto-dark-light@gihaume/src/lib/sys/gnome/tests/test Wall_clock_adjustment_monitor.js From 89fb8b289877657415e0ad456aa5df93d61c3a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Thu, 27 Nov 2025 21:03:42 +0100 Subject: [PATCH 11/13] Improve handling of classes which implements `Disposable` --- auto-dark-light@gihaume/CONTRIBUTING.md | 2 +- .../auto-dark-light@gihaume/5.8/applet.js | 81 +++++++++---------- .../src/app/handlers/Location_handler.ts | 7 +- .../src/app/handlers/initialize_handlers.ts | 35 ++++---- .../lib/sys/cinnamon/Color_scheme_handler.ts | 24 +++--- .../lib/sys/cinnamon/Keybinding_handler.ts | 16 ++-- .../Screen_lock_change_listener.js | 4 +- .../Sleep_events_listener.js | 4 +- .../gnome/Event_scheduler/Event_scheduler.ts | 6 +- 9 files changed, 86 insertions(+), 93 deletions(-) diff --git a/auto-dark-light@gihaume/CONTRIBUTING.md b/auto-dark-light@gihaume/CONTRIBUTING.md index b83f2806e38..47e3009dcd5 100644 --- a/auto-dark-light@gihaume/CONTRIBUTING.md +++ b/auto-dark-light@gihaume/CONTRIBUTING.md @@ -4,7 +4,7 @@ ### Global dependencies -- [pnpm](https://pnpm.io/installation#on-posix-systems) (tested v10.20.0). +- [pnpm](https://pnpm.io/installation#on-posix-systems) (tested v10.23.0). ### Local dependencies diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index 9c99afbd30f..2d2d727e6ef 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -4504,7 +4504,6 @@ class Event_scheduler { this._event_id = void 0; this._timer_absolute.reset(); } - /** Releases acquired resources */ dispose() { this.unset_the_event(); } @@ -4513,21 +4512,20 @@ const { keybindingManager } = imports.ui.main; class Keybinding_handler { _uuid; static _unicity_count = 0; - _callback; - /** - * @param unique_namespace - a specific enough id to avoid name collisions with any other system keybinding name, typically the application name - * @param callback - the function to be called when the keybinding has been pressed - */ - constructor(unique_namespace, callback) { + /** @param unique_namespace - A specific enough id to avoid name collisions with any other system keybinding name, typically the application name. */ + constructor(unique_namespace) { this._uuid = unique_namespace + Keybinding_handler._unicity_count++; - this._callback = callback; } - /** @param keybinding - the keybinding to set, in the format accepted by Cinnamon (e.g. 'F1') */ + /** The function to be called when the keybinding has been pressed */ + callback = null; + /** @param keybinding - In the format accepted by Cinnamon (e.g. 'F1'). */ set(keybinding) { return keybindingManager.addHotKey( this._uuid, keybinding, - this._callback + () => { + this.callback?.(); + } ); } unset() { @@ -4647,7 +4645,6 @@ class Location_handler { }); this._timezone_change_listener.enable(); } - /** Releases acquired resources */ dispose() { this._timezone_change_listener.dispose(); } @@ -4668,7 +4665,7 @@ class Screen_lock_change_listener { /** @type {((is_locked: boolean) => void) | null} */ callback = null; enable() { - if (this._signal_id) + if (this._signal_id !== null) return; this._signal_id = this._screen_saver_proxy.connectSignal( "ActiveChanged", @@ -4683,7 +4680,7 @@ class Screen_lock_change_listener { ); } disable() { - if (!this._signal_id) + if (this._signal_id === null) return; this._screen_saver_proxy.disconnectSignal(this._signal_id); this._signal_id = null; @@ -4738,7 +4735,7 @@ class Sleep_events_listener { * @type {((is_entering_sleep: boolean) => void) | null} */ callback = null; enable() { - if (this._signal_id) + if (this._signal_id !== null) return; this._signal_id = Gio$2.DBus.system.signal_subscribe( "org.freedesktop.login1", @@ -4760,7 +4757,7 @@ class Sleep_events_listener { ); } disable() { - if (!this._signal_id) + if (this._signal_id === null) return; Gio$2.DBus.system.signal_unsubscribe(this._signal_id); this._signal_id = null; @@ -4799,25 +4796,22 @@ class Sleep_and_lock_handler { const { Gio: Gio$1 } = imports.gi; const settings$1 = Gio$1.Settings.new("org.x.apps.portal"); class Color_scheme_handler { - _callback_on_change; - _signal_id = void 0; - /** @param callback_on_change - The function to be executed when the color scheme changes. */ - constructor(callback_on_change) { - this._callback_on_change = callback_on_change; - } + /** The function to be called when the color scheme has changed */ + callback = null; + _signal_id = null; enable() { - this.disable(); + if (this._signal_id !== null) + return; this._signal_id = settings$1.connect("changed::color-scheme", () => { - this._callback_on_change(Color_scheme_handler.value); + this.callback?.(Color_scheme_handler.value); }); } disable() { - if (this._signal_id === void 0) + if (this._signal_id === null) return; settings$1.disconnect(this._signal_id); - this._signal_id = void 0; + this._signal_id = null; } - /** Releases acquired resources */ dispose() { this.disable(); } @@ -5072,6 +5066,11 @@ class Wall_clock_adjustment_monitor { const { GLib } = imports.gi; const DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING = 2e3; function initialize_handlers(applet, settings2) { + const disposables = []; + applet.on_applet_removed_from_panel = () => { + disposables.forEach((element) => element.dispose()); + settings2.finalize(); + }; const location_handler = new Location_handler({ manual_location: { latitude: settings2.manual_latitude, @@ -5079,6 +5078,7 @@ function initialize_handlers(applet, settings2) { }, is_location_auto: settings2.is_location_auto }); + disposables.push(location_handler); settings2.bind("manual_latitude", null, (value) => { location_handler.manual_location.latitude = value; }); @@ -5197,12 +5197,11 @@ function initialize_handlers(applet, settings2) { appearance_handler.is_auto ? appearance_handler.is_unsynced ? "auto-inverted-symbolic" : "auto-symbolic" : appearance_handler.manual_is_dark ? "dark-symbolic" : "light-symbolic" ); }); - const keybinding = new Keybinding_handler( - metadata.uuid, - () => { - appearance_handler.toggle_is_dark(); - } - ); + const keybinding = new Keybinding_handler(metadata.uuid); + disposables.push(keybinding); + keybinding.callback = () => { + appearance_handler.toggle_is_dark(); + }; keybinding.set(settings2.appearance_keybinding); settings2.bind("appearance_keybinding", null, (value) => { keybinding.set(value); @@ -5218,9 +5217,11 @@ function initialize_handlers(applet, settings2) { const color_scheme = makeAutoObservable({ value: Color_scheme_handler.value }); - const color_scheme_handler = new Color_scheme_handler((new_color_scheme) => { + const color_scheme_handler = new Color_scheme_handler(); + disposables.push(color_scheme_handler); + color_scheme_handler.callback = (new_color_scheme) => { color_scheme.value = new_color_scheme; - }); + }; let is_update_from_system = false; autorun(() => { appearance_handler.manual_is_dark = color_scheme.value === "prefer-dark"; @@ -5257,6 +5258,7 @@ function initialize_handlers(applet, settings2) { appearance_handler.manual_is_dark = appearance_handler.is_dark; }); const wall_clock_monitor = new Wall_clock_adjustment_monitor(); + disposables.push(wall_clock_monitor); wall_clock_monitor.callback = () => runInAction(() => { twilights_handler.update(); appearance_handler.update_time(); @@ -5264,6 +5266,7 @@ function initialize_handlers(applet, settings2) { appearance_handler.sync_is_dark(); }); const sleep_and_lock_handler = new Sleep_and_lock_handler(); + disposables.push(sleep_and_lock_handler); sleep_and_lock_handler.callback = (is_sleeping) => { if (is_sleeping) wall_clock_monitor.disable(); @@ -5277,6 +5280,7 @@ function initialize_handlers(applet, settings2) { }); }; const scheduler = new Event_scheduler(); + disposables.push(scheduler); const schedule_the_event = () => { scheduler.set_the_event(appearance_handler.next_twilight, () => { twilights_handler.update(); @@ -5310,15 +5314,6 @@ function initialize_handlers(applet, settings2) { applet.on_button_open_os_timezone_settings = () => GLib.spawn_command_line_async("cinnamon-settings calendar"); applet.on_button_open_os_themes_settings = () => GLib.spawn_command_line_async("cinnamon-settings themes"); applet.on_button_open_os_background_settings = () => GLib.spawn_command_line_async("cinnamon-settings background"); - applet.on_applet_removed_from_panel = () => { - keybinding.dispose(); - location_handler.dispose(); - scheduler.dispose(); - sleep_and_lock_handler.dispose(); - color_scheme_handler.dispose(); - wall_clock_monitor.dispose(); - settings2.finalize(); - }; color_scheme_handler.enable(); wall_clock_monitor.enable(); sleep_and_lock_handler.enable(); diff --git a/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts index 54c8ec4c99d..438d545d606 100644 --- a/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts +++ b/auto-dark-light@gihaume/src/app/handlers/Location_handler.ts @@ -2,12 +2,12 @@ const { GLib } = imports.gi; import * as mobx from "mobx"; -import type { Location } from "../../types"; +import type { Disposable, Location } from "../../types"; import { metadata } from '../../globals'; import { Timezone_change_listener } from '../../lib/sys/gnome/Timezone_change_listener'; import { Timezone_location_finder } from "../../lib/core/Timezone_location_finder/Timezone_location_finder"; -export class Location_handler { +export class Location_handler implements Disposable { private readonly _timezone_change_listener = new Timezone_change_listener( new_timezone => this._timezone = new_timezone ); @@ -48,8 +48,7 @@ export class Location_handler { this._timezone_change_listener.enable(); } - /** Releases acquired resources */ - dispose(): void { + dispose() { this._timezone_change_listener.dispose(); } } diff --git a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts index d51039c9c66..0b52064e598 100644 --- a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts +++ b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts @@ -7,6 +7,7 @@ import { Appearance_handler } from './Appearance_handler'; import type { Applet } from '../ui/Applet'; import { Background_handler } from './Background_handler'; import { Commands_handler } from './Commands_handler'; +import type { Disposable } from '../../types'; import { Event_scheduler } from "../../lib/sys/gnome/Event_scheduler"; import { Keybinding_handler } from '../../lib/sys/cinnamon/Keybinding_handler'; import { Location_handler } from './Location_handler'; @@ -23,6 +24,12 @@ import { Wall_clock_adjustment_monitor } from '../../lib/sys/gnome/Wall_clock_ad const DURATION_TO_AWAIT_BEFORE_UPDATING_DERIVED_SETTING = 2000; // milliseconds (ms) export function initialize_handlers(applet: Applet, settings: Settings): void { + const disposables: Disposable[] = []; + applet.on_applet_removed_from_panel = () => { + disposables.forEach(element => element.dispose()); + settings.finalize(); + }; + const location_handler = new Location_handler({ manual_location: { latitude: settings.manual_latitude, @@ -30,6 +37,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { }, is_location_auto: settings.is_location_auto }); + disposables.push(location_handler); // Controls settings.bind('manual_latitude', null, value => { @@ -159,16 +167,15 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { ); }); - const keybinding = new Keybinding_handler( - metadata.uuid, () => { appearance_handler.toggle_is_dark(); } - ); + const keybinding = new Keybinding_handler(metadata.uuid); + disposables.push(keybinding); + keybinding.callback = () => { appearance_handler.toggle_is_dark(); }; keybinding.set(settings.appearance_keybinding); settings.bind('appearance_keybinding', null, value => { keybinding.set(value); }); const themes_handler = new Themes_handler(applet, settings); - if (Color_scheme_handler.value === 'prefer-dark') { // TODO: clear this idea so the user is not confused if (settings.dark_themes_have_been_detected) themes_handler.detect_dark_themes(); @@ -176,12 +183,15 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { if (settings.light_themes_have_been_detected) themes_handler.detect_light_themes(); } + const color_scheme = mobx.makeAutoObservable({ value: Color_scheme_handler.value }); - const color_scheme_handler = new Color_scheme_handler(new_color_scheme => { + const color_scheme_handler = new Color_scheme_handler() + disposables.push(color_scheme_handler); + color_scheme_handler.callback = new_color_scheme => { color_scheme.value = new_color_scheme; - }); + }; let is_update_from_system = false; // Temporary fix // TODO: improve the model mobx.autorun(() => { appearance_handler.manual_is_dark = @@ -222,6 +232,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { }); const wall_clock_monitor = new Wall_clock_adjustment_monitor(); + disposables.push(wall_clock_monitor); wall_clock_monitor.callback = () => mobx.runInAction(() => { twilights_handler.update(); appearance_handler.update_time(); @@ -230,6 +241,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { }); const sleep_and_lock_handler = new Sleep_and_lock_handler(); + disposables.push(sleep_and_lock_handler); sleep_and_lock_handler.callback = (is_sleeping: boolean) => { if (is_sleeping) wall_clock_monitor.disable(); @@ -244,6 +256,7 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { }; const scheduler = new Event_scheduler(); + disposables.push(scheduler); const schedule_the_event = () => { // logger.info(`Next change at ${appearance_handler.next_twilight.get_as_string_hmmss()}`); // Debug scheduler.set_the_event(appearance_handler.next_twilight, () => { @@ -290,16 +303,6 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { // applet.on_panel_height_changed = () => {}; // applet.on_panel_icon_size_changed = () => {}; - applet.on_applet_removed_from_panel = () => { - keybinding.dispose(); - location_handler.dispose(); - scheduler.dispose(); - sleep_and_lock_handler.dispose(); - color_scheme_handler.dispose(); - wall_clock_monitor.dispose(); - settings.finalize(); - }; - color_scheme_handler.enable(); wall_clock_monitor.enable(); sleep_and_lock_handler.enable(); diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Color_scheme_handler.ts b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Color_scheme_handler.ts index 7baeaa68e3c..011386d5683 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Color_scheme_handler.ts +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Color_scheme_handler.ts @@ -1,34 +1,32 @@ const { Gio } = imports.gi; -import { Color_scheme } from "../../../types"; +import { Color_scheme, Observer } from "../../../types"; const settings = Gio.Settings.new('org.x.apps.portal'); /** A listener and accessor to the Cinnamon system color scheme setting. */ -export class Color_scheme_handler { - private readonly _callback_on_change: (color_scheme: Color_scheme) => void; - private _signal_id: number | undefined = undefined; +export class Color_scheme_handler implements Observer { - /** @param callback_on_change - The function to be executed when the color scheme changes. */ - constructor(callback_on_change: (color_scheme: Color_scheme) => void) { - this._callback_on_change = callback_on_change; - } + /** The function to be called when the color scheme has changed */ + callback: ((color_scheme: Color_scheme) => void) | null = null; + + private _signal_id: number | null = null; enable() { - this.disable(); // Ensures only one signal is connected + if (this._signal_id !== null) + return; this._signal_id = settings.connect('changed::color-scheme', () => { - this._callback_on_change(Color_scheme_handler.value); + this.callback?.(Color_scheme_handler.value); }); } disable() { - if (this._signal_id === undefined) + if (this._signal_id === null) return; settings.disconnect(this._signal_id); - this._signal_id = undefined; + this._signal_id = null; } - /** Releases acquired resources */ dispose() { this.disable(); } diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts index d4947b8ae57..0ece76498fc 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts @@ -6,21 +6,19 @@ import { Disposable } from '../../../types'; export class Keybinding_handler implements Disposable { private readonly _uuid: string; private static _unicity_count: number = 0; - private readonly _callback: () => void; - /** - * @param unique_namespace - a specific enough id to avoid name collisions with any other system keybinding name, typically the application name - * @param callback - the function to be called when the keybinding has been pressed - */ - constructor(unique_namespace: string, callback: () => void) { + /** @param unique_namespace - A specific enough id to avoid name collisions with any other system keybinding name, typically the application name. */ + constructor(unique_namespace: string) { this._uuid = unique_namespace + Keybinding_handler._unicity_count++; - this._callback = callback; } - /** @param keybinding - the keybinding to set, in the format accepted by Cinnamon (e.g. 'F1') */ + /** The function to be called when the keybinding has been pressed */ + callback: (() => void) | null = null; + + /** @param keybinding - In the format accepted by Cinnamon (e.g. 'F1'). */ set(keybinding: string): boolean { return keybindingManager.addHotKey( - this._uuid, keybinding, this._callback + this._uuid, keybinding, () => { this.callback?.(); } ); } diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js index 72f34e83628..bd6c5060f9d 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js @@ -23,7 +23,7 @@ export class Screen_lock_change_listener { callback = null; enable() { - if (this._signal_id) + if (this._signal_id !== null) return; this._signal_id = this._screen_saver_proxy.connectSignal('ActiveChanged', /** @@ -38,7 +38,7 @@ export class Screen_lock_change_listener { } disable() { - if (!this._signal_id) + if (this._signal_id === null) return; this._screen_saver_proxy.disconnectSignal(this._signal_id); this._signal_id = null; diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js index c6a4c5e2630..f60dcd34344 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js @@ -16,7 +16,7 @@ export class Sleep_events_listener { callback = null; enable() { - if (this._signal_id) + if (this._signal_id !== null) return; this._signal_id = Gio.DBus.system.signal_subscribe( 'org.freedesktop.login1', // sender @@ -33,7 +33,7 @@ export class Sleep_events_listener { } disable() { - if (!this._signal_id) + if (this._signal_id === null) return; Gio.DBus.system.signal_unsubscribe(this._signal_id); this._signal_id = null; diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts index 13dd707d037..47842f5aa13 100644 --- a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts @@ -1,5 +1,6 @@ const { GLib } = imports.gi; +import type { Disposable } from "../../../../types"; import * as system_time from "../system_time"; import type { Time_of_day } from "../../../core/Time_of_day"; import { Timer_absolute } from "./Timer_absolute"; @@ -11,7 +12,7 @@ import { Timer_absolute } from "./Timer_absolute"; * * When the instance is not wanted anymore, `dispose` must be called. */ -export class Event_scheduler { +export class Event_scheduler implements Disposable { private _event_id: number | undefined = undefined; private readonly _timer_absolute = new Timer_absolute(); @@ -56,8 +57,7 @@ export class Event_scheduler { this._timer_absolute.reset(); } - /** Releases acquired resources */ - dispose(): void { + dispose() { this.unset_the_event(); } } From c005fb1d30fee470ea11f2e20a758d0bdd248a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Sun, 30 Nov 2025 18:50:17 +0100 Subject: [PATCH 12/13] - Convert some `sys` files back to JS - Correct command launching error handling and add tests - Improve `CONTRIBUTING.md` --- .../.vscode/extensions.json | 1 + auto-dark-light@gihaume/.vscode/settings.json | 4 +- auto-dark-light@gihaume/CONTRIBUTING.md | 65 ++++- .../auto-dark-light@gihaume/5.8/applet.js | 225 +++++++++--------- .../src/app/handlers/Commands_handler.ts | 2 +- .../src/app/launch_command.ts | 52 ++++ .../lib/sys/cinnamon/Keybinding_handler.ts | 2 +- .../Sleep_events_listener.js | 1 - .../tests/test Screen_lock_change_listener.js | 2 +- .../tests/test Screen_unlock_waiter.js | 2 +- .../tests/test Sleep_and_lock_handler.js | 2 +- .../tests/test Sleep_events_listener.js | 2 +- .../gnome/Event_scheduler/Event_scheduler.js | 73 ++++++ .../gnome/Event_scheduler/Event_scheduler.ts | 63 ----- .../gnome/Event_scheduler/Timer_absolute.js | 31 +++ .../gnome/Event_scheduler/Timer_absolute.ts | 24 -- ...istener.ts => Timezone_change_listener.js} | 50 ++-- .../src/lib/sys/gnome/command_launching.js | 75 ++++++ .../src/lib/sys/gnome/launch_command.ts | 107 --------- .../gnome/{system_time.ts => system_time.js} | 27 ++- .../test Wall_clock_adjustment_monitor.js | 2 +- .../sys/gnome/tests/test command_launching.js | 138 +++++++++++ auto-dark-light@gihaume/tsconfig.json | 5 +- 23 files changed, 596 insertions(+), 359 deletions(-) create mode 100644 auto-dark-light@gihaume/src/app/launch_command.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.js delete mode 100644 auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts create mode 100644 auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.js delete mode 100644 auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.ts rename auto-dark-light@gihaume/src/lib/sys/gnome/{Timezone_change_listener.ts => Timezone_change_listener.js} (50%) create mode 100644 auto-dark-light@gihaume/src/lib/sys/gnome/command_launching.js delete mode 100644 auto-dark-light@gihaume/src/lib/sys/gnome/launch_command.ts rename auto-dark-light@gihaume/src/lib/sys/gnome/{system_time.ts => system_time.js} (57%) create mode 100644 auto-dark-light@gihaume/src/lib/sys/gnome/tests/test command_launching.js diff --git a/auto-dark-light@gihaume/.vscode/extensions.json b/auto-dark-light@gihaume/.vscode/extensions.json index 6d1524737e1..ef6c9e6e6c9 100644 --- a/auto-dark-light@gihaume/.vscode/extensions.json +++ b/auto-dark-light@gihaume/.vscode/extensions.json @@ -2,6 +2,7 @@ "recommendations": [ "EditorConfig.EditorConfig", "ms-python.python", + "pkief.material-icon-theme", "vitest.explorer" ] } diff --git a/auto-dark-light@gihaume/.vscode/settings.json b/auto-dark-light@gihaume/.vscode/settings.json index c981030bccd..5803206bb0d 100644 --- a/auto-dark-light@gihaume/.vscode/settings.json +++ b/auto-dark-light@gihaume/.vscode/settings.json @@ -2,5 +2,7 @@ "typescript.tsdk": "node_modules/typescript/lib", "python.analysis.extraPaths": [ "/usr/share/cinnamon/cinnamon-settings/bin" - ] + ], + "javascript.preferences.quoteStyle": "single", // For imports autocompletion + "typescript.preferences.quoteStyle": "single" // For imports autocompletion } diff --git a/auto-dark-light@gihaume/CONTRIBUTING.md b/auto-dark-light@gihaume/CONTRIBUTING.md index 47e3009dcd5..c569f25b20a 100644 --- a/auto-dark-light@gihaume/CONTRIBUTING.md +++ b/auto-dark-light@gihaume/CONTRIBUTING.md @@ -1,12 +1,12 @@ # Contributing -## Prerequisites +## Dependencies -### Global dependencies +### Global -- [pnpm](https://pnpm.io/installation#on-posix-systems) (tested v10.23.0). +- [pnpm](https://pnpm.io/installation#on-posix-systems) (tested v10.24.0). -### Local dependencies +### Local - Install dependencies: ```bash @@ -23,7 +23,50 @@ pnpm i --store-dir=.pnpm-store ``` -## Development +### Optional + +- [Visual Studio Code](https://code.visualstudio.com) + - With the extensions in [`.vscode/extensions.json`](./.vscode/extensions.json). +- `poedit` for translation: + - On Debian-based systems: + ```bash + sudo apt install poedit + ``` + +## Conventions +### Files organization + +- `doc`: applet development documentation +- `src`: source files + - `app`: application specifics + - `core`: business logic + - `ui`: user interface bindings + - `lib`: reusable generic library + - `core`: business logic + - `sys`: system/OS interfacing + - `cinnamon`: Cinnamon desktop environment specifics + - `gnome`: GNOME desktop environment specifics + +Notes : +- Nothing in `lib` depends on anything in `app`. +- Some files in `sys` are not in TypeScript so they are more reusable and directly launchable by GnomeJS in order to test them. + +### Style + +- See [`.editorconfig`](./.editorconfig). +- Variables names uses `snake_case`. +- Classes names uses `Capitalized_snake_case`. +- Where both single and double quotes are possible: + - single quotes means to reference to something existing, + - double quotes means to create something new. +- Braces placement: [K&R](https://en.wikipedia.org/wiki/Indentation_style#K&R) but also for functions. +- Brackets the same as braces as soon as their content is too big for one line. +- When a list content or function arguments is too big for one line: + - A new line under can have all arguments if they fit in one line, + - As soon as they don't fit in one line: one argument per line. +- All instructions are terminated by semicolons: ASI is considered a fallback and not a feature. + +## Development workflow - Create a symbolic link pointing to this folder and add it in your user applets folder: ```bash @@ -43,18 +86,26 @@ - `~/.xsession-errors` logs file. - Press `Ctrl`+`C` (`SIGINT`) to stop the continuous build. -## Testing +## Unit testing -- Run all unit tests: +### Core logic + +- Run all core logic automatic unit tests: ```bash pnpm test ``` - The VS Code extension [Vitest](vscode:extension/vitest.explorer) can also be used. +### System/OS interfacing + +Check `test *.js` files in various `tests` folders and run them manually according to their instructions in their headers. + ## Committing Before any commit: +- All core logic automatic unit tests must pass. +- If any system/OS interfacing has been modified, related manual tests must be performed again carefully. - It is advisable to build `applet.js` in a single run with: ```bash pnpm build diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index 2d2d727e6ef..57dd4017e77 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -1,5 +1,5 @@ const Gettext = imports.gettext; -const { GLib: GLib$5 } = imports.gi; +const { GLib: GLib$6 } = imports.gi; const Main = imports.ui.main; const { St } = imports.gi; const metadata = { @@ -15,7 +15,7 @@ function _(text) { let translated_applet_name = ""; function initialize_globals(applet_metadata) { Object.assign(metadata, applet_metadata); - const translations_dir_path = GLib$5.get_home_dir() + "/.local/share/locale"; + const translations_dir_path = GLib$6.get_home_dir() + "/.local/share/locale"; Gettext.bindtextdomain(metadata.uuid, translations_dir_path); translated_applet_name = _(metadata.name); } @@ -4339,90 +4339,95 @@ class Background_handler { Background_accessor.picture_file = this._settings.dark_background_file; } } -const { Gio: Gio$5, GLib: GLib$4 } = imports.gi; -async function launch_command(name, expiry, command) { - try { - await _launch_command(command, expiry); - } catch (error) { - const name_for_error = name !== "" ? name : command; - let msg = `${_("the command")} '${name_for_error}' ${_("has failed")}`; - if (error instanceof GLib$4.ShellError) - msg += ` ${_("due to a wrong format")}. - -${_("Detail")}${_(":")} -` + error.message; - else if (error instanceof Gio$5.IOErrorEnum) { - if (error.code === Gio$5.IOErrorEnum.TIMED_OUT) - msg += ` ${_("due to timeout")}. - -${_("Detail")}${_(":")} -` + error.message; - else if (error.code === Gio$5.IOErrorEnum.FAILED) - msg += ` ${_("due to an error")}. - -${_("Detail")}${_(":")} -` + error.message; - } else - msg += `${_(":")} ${error}`; - logger.warn(msg); - } +const { Gio: Gio$5, GLib: GLib$5 } = imports.gi; +class Error_timed_out_by_sigterm extends Error { +} +class Error_timed_out_by_sigkill extends Error { } -const TIMEOUT_EXIT_STATUS_SIGTERM = 124; -const TIMEOUT_EXIT_STATUS_SIGKILL = 137; -const SIGKILL_TIMEOUT = 10; -async function _launch_command(command, timeout = 10) { - const wrapped_command = `timeout --kill-after=${SIGKILL_TIMEOUT} ${timeout}s sh -c ${GLib$4.shell_quote(command)}`; - const [_ok, argvp] = GLib$4.shell_parse_argv(wrapped_command); +class Error_failed extends Error { +} +const GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGTERM = 124; +const GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGKILL = 137; +async function launch_command$1(command, sigterm_timeout = 0, sigkill_timeout = 10) { + const wrapped_command = `timeout --kill-after=${sigkill_timeout}s ${sigterm_timeout}s sh -c ${GLib$5.shell_quote(command)}`; + const [_ok, argvp] = GLib$5.shell_parse_argv(wrapped_command); const process = new Gio$5.Subprocess({ argv: argvp, flags: Gio$5.SubprocessFlags.STDERR_PIPE }); const start_time = Date.now(); process.init(null); - const [_stdout, stderr] = await new Promise( - // Promisifies - (resolve, reject) => { - process.communicate_utf8_async( - null, - null, - (source, result) => { - try { - const [_ok2, stdout, stderr2] = source.communicate_utf8_finish(result); - resolve([stdout, stderr2]); - } catch (error) { - reject(error); - } - } - ); - } - ); + const [_stdout, stderr] = await new Promise((resolve, reject) => { + process.communicate_utf8_async(null, null, (source, result) => { + try { + const [_ok2, stdout, stderr2] = ( + /** @type {imports.gi.Gio.Subprocess} */ + source.communicate_utf8_finish(result) + ); + resolve([stdout, stderr2]); + } catch (error) { + reject(error); + } + }); + }); const elapsed_time = (Date.now() - start_time) / 1e3; const exit_status = process.get_exit_status(); switch (exit_status) { case 0: break; - case TIMEOUT_EXIT_STATUS_SIGTERM: - throw new Gio$5.IOErrorEnum({ - code: Gio$5.IOErrorEnum.TIMED_OUT, - message: `may have been timed out by SIGTERM (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGTERM})` - }); - case TIMEOUT_EXIT_STATUS_SIGKILL: - throw new Gio$5.IOErrorEnum({ - code: Gio$5.IOErrorEnum.TIMED_OUT, - message: `probably killed by an external SIGKILL (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGKILL})` - }); + case GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGTERM: + throw new Error_timed_out_by_sigterm( + "The command may have been timed out by SIGTERM" + ); + case GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGKILL: + throw new Error_timed_out_by_sigkill( + "The command was probably killed by an external SIGKILL" + ); case 1: - if (timeout > 0 && elapsed_time >= timeout + SIGKILL_TIMEOUT) - throw new Gio$5.IOErrorEnum({ - code: Gio$5.IOErrorEnum.TIMED_OUT, - message: `probably timed out by SIGKILL` - }); - // no break, needs to stay directly above the default case + if (sigterm_timeout > 0 && elapsed_time >= sigterm_timeout + sigkill_timeout) + throw new Error_timed_out_by_sigkill( + "The command was probably timed out by SIGKILL" + ); + // No break in order to fall through, and so also needs to stay directly above the default case default: - throw new Gio$5.IOErrorEnum({ - code: Gio$5.IOErrorEnum.FAILED, - message: stderr ? stderr.trim() : "exit status: " + exit_status - }); + throw new Error_failed( + stderr ? stderr.trim() : "exit status: " + exit_status + ); + } +} +const { GLib: GLib$4 } = imports.gi; +async function launch_command(name, expiry, command) { + try { + await launch_command$1(command, expiry); + } catch (error) { + const name_for_error = name !== "" ? name : command; + let msg = `${_("Failed to run command")} '${name_for_error}'. +`; + if (error instanceof Error_failed) + msg += `${_("Reason")}${_(":")} ${_("command error")}. +${_("Detail")}${_(":")} ${error.message}`; + else if (error instanceof Error_timed_out_by_sigterm) + msg += `${_("Reason")}${_(":")} ${_("command timeout")}. +${_("Detail")}${_(":")} ${error.message}`; + else if (error instanceof Error_timed_out_by_sigkill) + msg += `${_("Reason")}${_(":")} ${_("command timeout (killed)")}. +${_("Detail")}${_(":")} ${error.message}`; + else if (error instanceof GLib$4.Error) + msg += `${_("Reason")}${_(":")} GLib error. +${_("Detail")}${_(":")} +Domain: ${error.domain} +Code: ${error.code} +Message: ${error.message}`; + else if (error instanceof Error) + msg += `${_("Reason")}${_(":")} ${_("Other error")} +${_("Detail")}${_(":")} +Name: ${error.name} +Message: ${error.message} +Stack?: +${error?.stack}`; + else + msg += `${_("Unknown error type")}${_(":")} ${error}`; + logger.warn(msg); } } class Commands_handler { @@ -4447,37 +4452,47 @@ class Commands_handler { } } class Timer_absolute { - /** Unix time in seconds (s) */ + /** @private Unix time in seconds (s) */ _expiration_time = 0; - /** The next time of day the timer has to expire. */ + /** + * The next time of day the timer has to expire. + * @param {Time_of_day} value + */ set expiration_time(value) { const now = get_now_as_time_of_day(); const due_delay = now.get_seconds_until_next_target(value); this._expiration_time = get_now_as_unix() + due_delay; } + /** @returns {boolean} */ get_if_has_expired() { return get_now_as_unix() > this._expiration_time; } - /** Ensures `get_if_has_expired` returns `true` */ + /** + * Ensures `get_if_has_expired` returns `true` + * @returns {void} + */ reset() { this._expiration_time = 0; } } const { GLib: GLib$3 } = imports.gi; class Event_scheduler { - _event_id = void 0; + /** @private @type {number | null} */ + _event_id = null; + /** @private @readonly */ _timer_absolute = new Timer_absolute(); - /** @returns `true` if the scheduled event should have already occurred, `false` otherwise. If the event is not set, `false` is returned. */ + /** @returns {boolean} `true` if the scheduled event should have already occurred, `false` otherwise. If the event is not set, `false` is returned. */ get_if_should_be_expired() { return this._timer_absolute.get_if_has_expired(); } /** * Calls a function at a specific next time of day. * - * If the event is already scheduled, it will be replaced. + * Note: if the event is already scheduled, it will be replaced. * - * @param time - When the event should occur. - * @param callback_on_event - The function to be executed when the event occurs. + * @param {Time_of_day} time - When the event should occur. + * @param {() => void} callback_on_event - The function to be executed when the event occurs. + * @returns {void} */ set_the_event(time, callback_on_event) { this.unset_the_event(); @@ -4493,15 +4508,19 @@ class Event_scheduler { ); this._timer_absolute.expiration_time = time; } + /** @returns {boolean} `true` if an event is currently scheduled, `false` otherwise. */ get is_set() { - return this._event_id !== void 0; + return this._event_id !== null; } - /** If the event is not already scheduled, nothing is done. */ + /** + * Note: if the event is not already scheduled, nothing is done. + * @returns {void} + */ unset_the_event() { - if (!this._event_id) + if (this._event_id === null) return; GLib$3.source_remove(this._event_id); - this._event_id = void 0; + this._event_id = null; this._timer_absolute.reset(); } dispose() { @@ -4518,7 +4537,7 @@ class Keybinding_handler { } /** The function to be called when the keybinding has been pressed */ callback = null; - /** @param keybinding - In the format accepted by Cinnamon (e.g. 'F1'). */ + /** @param keybinding - In the format accepted by Cinnamon (e.g. 'F1'), which can be multiple ones separated with `::`. */ set(keybinding) { return keybindingManager.addHotKey( this._uuid, @@ -4537,25 +4556,14 @@ class Keybinding_handler { } const { Gio: Gio$4 } = imports.gi; class Timezone_change_listener { - _callback_on_change; - /** @param callback_on_change - The function to be executed when the system timezone changes. */ - constructor(callback_on_change) { - this._callback_on_change = callback_on_change; - } + /** @private @type {number | null} */ + _signal_id = null; + /** The function to call when the system timezone changes. + * @type {((new_timezone: string) => void) | null} */ + callback = null; enable() { - this._subscribe_to_changes(this._callback_on_change.bind(this)); - } - disable() { - this._unsubscribe_to_changes(); - } - /** Releases acquired resources */ - dispose() { - this.disable(); - } - _signal_id = void 0; - _subscribe_to_changes(callback_when_changes) { - if (this._signal_id) - this._unsubscribe_to_changes(); + if (this._signal_id !== null) + return; this._signal_id = Gio$4.DBus.system.signal_subscribe( "org.freedesktop.timedate1", // sender @@ -4573,16 +4581,19 @@ class Timezone_change_listener { const changed_properties = parameters.deep_unpack()[1]; if (changed_properties["Timezone"]) { const new_timezone = changed_properties["Timezone"].deep_unpack(); - callback_when_changes(new_timezone); + this.callback?.(new_timezone); } } ); } - _unsubscribe_to_changes() { - if (!this._signal_id) + disable() { + if (this._signal_id === null) return; Gio$4.DBus.system.signal_unsubscribe(this._signal_id); - this._signal_id = void 0; + this._signal_id = null; + } + dispose() { + this.disable(); } } const { Gio: Gio$3 } = imports.gi; diff --git a/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts b/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts index 90557fd7ecd..6f6f51ac5a2 100644 --- a/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts +++ b/auto-dark-light@gihaume/src/app/handlers/Commands_handler.ts @@ -1,5 +1,5 @@ import type { Applet } from "../ui/Applet"; -import { launch_command } from "../../lib/sys/gnome/launch_command"; +import { launch_command } from '../launch_command'; import type { Settings } from "../ui/Settings"; export class Commands_handler { diff --git a/auto-dark-light@gihaume/src/app/launch_command.ts b/auto-dark-light@gihaume/src/app/launch_command.ts new file mode 100644 index 00000000000..1ad3f331146 --- /dev/null +++ b/auto-dark-light@gihaume/src/app/launch_command.ts @@ -0,0 +1,52 @@ +const { GLib } = imports.gi; + +import { _, logger } from '../globals'; +import * as cmd_launching from '../lib/sys/gnome/command_launching'; + +/** + * Launches a command with a timeout and logs any error on failure. + * @param name - The name of the command to display in case of error. If empty, the command itself is used. + * @param expiry - The delay in seconds before cancelling the command with a SIGTERM, then 10 seconds later with a SIGKILL. `0` means infinity/never. + * @param command - The shell command to execute. + * @returns Resolves when the command has been executed or rejects if an error occurs. + */ +export async function launch_command(name: string, expiry: number, command: string): Promise { + try { + await cmd_launching.launch_command(command, expiry); + } catch (error) { + const name_for_error = name !== '' ? name : command; + let msg = `${_("Failed to run command")} '${name_for_error}'.\n`; + + if (error instanceof cmd_launching.Error_failed) + msg += `${_("Reason")}${_(":")} ${_("command error")}.\n` + + `${_("Detail")}${_(":")} ${error.message}`; + else + if (error instanceof cmd_launching.Error_timed_out_by_sigterm) + msg += `${_("Reason")}${_(":")} ${_("command timeout")}.\n` + + `${_("Detail")}${_(":")} ${error.message}`; + else + if (error instanceof cmd_launching.Error_timed_out_by_sigkill) + msg += `${_("Reason")}${_(":")} ${_("command timeout (killed)")}.\n` + + `${_("Detail")}${_(":")} ${error.message}`; + else + if (error instanceof GLib.Error) + msg += `${_("Reason")}${_(":")} GLib error.\n` + + `${_("Detail")}${_(":")}\n` + + `Domain: ${error.domain}\n` + + `Code: ${error.code}\n` + + `Message: ${error.message}`; + else + // Fallbacks + if (error instanceof Error) + msg += `${_("Reason")}${_(":")} ${_("Other error")}\n` + + `${_("Detail")}${_(":")}\n` + + `Name: ${error.name}\n` + + `Message: ${error.message}\n` + + `Stack?:\n` + + `${error?.stack}`; + else + msg += `${_("Unknown error type")}${_(":")} ${error}`; + + logger.warn(msg); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts index 0ece76498fc..65e9e1f9215 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Keybinding_handler.ts @@ -15,7 +15,7 @@ export class Keybinding_handler implements Disposable { /** The function to be called when the keybinding has been pressed */ callback: (() => void) | null = null; - /** @param keybinding - In the format accepted by Cinnamon (e.g. 'F1'). */ + /** @param keybinding - In the format accepted by Cinnamon (e.g. 'F1'), which can be multiple ones separated with `::`. */ set(keybinding: string): boolean { return keybindingManager.addHotKey( this._uuid, keybinding, () => { this.callback?.(); } diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js index f60dcd34344..46304e65a4d 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js @@ -4,7 +4,6 @@ const { Gio } = imports.gi; /** * An interface to listen to the sleep entering and waking events. - * * @implements {Observer} */ export class Sleep_events_listener { diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js index 7bf13ce2051..ff5d546d017 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js @@ -1,7 +1,7 @@ /** * To be tested manually with `cjs -m `. * - * Criteria: changing the screen lock state must trigger the console log at either the locking and unlocking events. + * Changing the screen lock state must trigger the console log at either the locking and unlocking events. */ imports.searchPath.push('/usr/share/cinnamon/js'); diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js index f8fb485e8a3..5a7cfff9159 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js @@ -1,7 +1,7 @@ /** * To be tested manually with `cjs -m `. * - * Criteria: the second message must be logged only once the screen is unlocked. + * The second message must be logged only once the screen is unlocked. */ imports.searchPath.push('/usr/share/cinnamon/js'); diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js index 9dcd7f5ef03..5764aa88126 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js @@ -1,7 +1,7 @@ /** * To be tested manually with `cjs -m `. * - * Criteria: changing the sleeping state must trigger the console log at either the entering sleep and woke up unlocked events. + * Changing the sleeping state must trigger the console log at either the entering sleep and woke up unlocked events. */ imports.searchPath.push('/usr/share/cinnamon/js'); diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js index fa3eda90083..3cd0e63986b 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js @@ -1,7 +1,7 @@ /** * To be tested manually with `cjs -m `. * - * Criteria: changing the sleeping state must trigger the console log at either the sleeping and waking events. + * Changing the sleeping state must trigger the console log at either the sleeping and waking events. */ imports.searchPath.push('/usr/share/cinnamon/js'); diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.js b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.js new file mode 100644 index 00000000000..b13b0342de3 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.js @@ -0,0 +1,73 @@ +const { GLib } = imports.gi; + +/** @typedef {import('../../../../types').Disposable} Disposable */ +import * as system_time from '../system_time.js'; +/** @typedef {import('../../../core/Time_of_day').Time_of_day} Time_of_day */ +import { Timer_absolute } from './Timer_absolute.js'; + +/** + * A single-event scheduler which call a function at a specific next time of day. + * + * Under the hood it uses a monotonic timeout delay and so doesn't take into account system sleep or time changes. So to the user can check if the event should already have occurred with `get_if_should_be_expired`. + * + * When the instance is not wanted anymore, `dispose` must be called. + * + * @implements {Disposable} + */ +export class Event_scheduler { + /** @private @type {number | null} */ + _event_id = null; + + /** @private @readonly */ + _timer_absolute = new Timer_absolute(); + + /** @returns {boolean} `true` if the scheduled event should have already occurred, `false` otherwise. If the event is not set, `false` is returned. */ + get_if_should_be_expired() { + return this._timer_absolute.get_if_has_expired(); + } + + /** + * Calls a function at a specific next time of day. + * + * Note: if the event is already scheduled, it will be replaced. + * + * @param {Time_of_day} time - When the event should occur. + * @param {() => void} callback_on_event - The function to be executed when the event occurs. + * @returns {void} + */ + set_the_event(time, callback_on_event) { + this.unset_the_event(); + const now = system_time.get_now_as_time_of_day(); + const due_delay = now.get_seconds_until_next_target(time); + this._event_id = GLib.timeout_add_seconds( + GLib.PRIORITY_DEFAULT, + due_delay, + () => { + callback_on_event(); + return GLib.SOURCE_REMOVE; + } + ); + this._timer_absolute.expiration_time = time; + } + + /** @returns {boolean} `true` if an event is currently scheduled, `false` otherwise. */ + get is_set() { + return this._event_id !== null; + } + + /** + * Note: if the event is not already scheduled, nothing is done. + * @returns {void} + */ + unset_the_event() { + if (this._event_id === null) + return; + GLib.source_remove(this._event_id); + this._event_id = null; + this._timer_absolute.reset(); + } + + dispose() { + this.unset_the_event(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts deleted file mode 100644 index 47842f5aa13..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Event_scheduler.ts +++ /dev/null @@ -1,63 +0,0 @@ -const { GLib } = imports.gi; - -import type { Disposable } from "../../../../types"; -import * as system_time from "../system_time"; -import type { Time_of_day } from "../../../core/Time_of_day"; -import { Timer_absolute } from "./Timer_absolute"; - -/** - * A single-event scheduler which call a function at a specific next time of day. - * - * Under the hood it uses a monotonic timeout delay and so doesn't take into account system sleep or time changes. So to the user can check if the event should already have occurred with `get_if_should_be_expired`. - * - * When the instance is not wanted anymore, `dispose` must be called. - */ -export class Event_scheduler implements Disposable { - private _event_id: number | undefined = undefined; - private readonly _timer_absolute = new Timer_absolute(); - - /** @returns `true` if the scheduled event should have already occurred, `false` otherwise. If the event is not set, `false` is returned. */ - get_if_should_be_expired(): boolean { - return this._timer_absolute.get_if_has_expired(); - } - - /** - * Calls a function at a specific next time of day. - * - * If the event is already scheduled, it will be replaced. - * - * @param time - When the event should occur. - * @param callback_on_event - The function to be executed when the event occurs. - */ - set_the_event(time: Time_of_day, callback_on_event: () => void): void { - this.unset_the_event(); - const now = system_time.get_now_as_time_of_day(); - const due_delay = now.get_seconds_until_next_target(time); - this._event_id = GLib.timeout_add_seconds( - GLib.PRIORITY_DEFAULT, - due_delay, - () => { - callback_on_event(); - return GLib.SOURCE_REMOVE; - } - ); - this._timer_absolute.expiration_time = time; - } - - get is_set(): boolean { - return this._event_id !== undefined; - } - - /** If the event is not already scheduled, nothing is done. */ - unset_the_event(): void { - if (!this._event_id) - return; - GLib.source_remove(this._event_id); - this._event_id = undefined; - this._timer_absolute.reset(); - } - - dispose() { - this.unset_the_event(); - } -} diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.js b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.js new file mode 100644 index 00000000000..fd46ddb6cf0 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.js @@ -0,0 +1,31 @@ +import * as system_time from '../system_time.js'; +/** @typedef {import('../../../core/Time_of_day').Time_of_day} Time_of_day */ + +/** A basic request-based absolute timer to be set for a next occurring time of day. */ +export class Timer_absolute { + /** @private Unix time in seconds (s) */ + _expiration_time = 0; + + /** + * The next time of day the timer has to expire. + * @param {Time_of_day} value + */ + set expiration_time(value) { + const now = system_time.get_now_as_time_of_day(); + const due_delay = now.get_seconds_until_next_target(value); + this._expiration_time = system_time.get_now_as_unix() + due_delay; + } + + /** @returns {boolean} */ + get_if_has_expired() { + return system_time.get_now_as_unix() > this._expiration_time; + } + + /** + * Ensures `get_if_has_expired` returns `true` + * @returns {void} + */ + reset() { + this._expiration_time = 0; + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.ts deleted file mode 100644 index b6a2341f56b..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/gnome/Event_scheduler/Timer_absolute.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as system_time from '../system_time'; -import type { Time_of_day } from '../../../core/Time_of_day'; - -/** A basic request-based absolute timer to be set for a next occurring time of day. */ -export class Timer_absolute { - /** Unix time in seconds (s) */ - private _expiration_time = 0; - - /** The next time of day the timer has to expire. */ - set expiration_time(value: Time_of_day) { - const now = system_time.get_now_as_time_of_day(); - const due_delay = now.get_seconds_until_next_target(value); - this._expiration_time = system_time.get_now_as_unix() + due_delay; - } - - get_if_has_expired(): boolean { - return system_time.get_now_as_unix() > this._expiration_time; - } - - /** Ensures `get_if_has_expired` returns `true` */ - reset(): void { - this._expiration_time = 0; - } -} diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/Timezone_change_listener.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/Timezone_change_listener.js similarity index 50% rename from auto-dark-light@gihaume/src/lib/sys/gnome/Timezone_change_listener.ts rename to auto-dark-light@gihaume/src/lib/sys/gnome/Timezone_change_listener.js index d3b3c47b0ef..7519458a068 100644 --- a/auto-dark-light@gihaume/src/lib/sys/gnome/Timezone_change_listener.ts +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/Timezone_change_listener.js @@ -1,38 +1,22 @@ const { Gio } = imports.gi; +/** @typedef {import('../../../types').Observer} Observer */ + /** * A listener for the system timezone changes. - * - * When the instance is not wanted anymore, `dispose` must be called. + * @implements {Observer} */ export class Timezone_change_listener { - private readonly _callback_on_change: (new_timezone: string) => void; - - /** @param callback_on_change - The function to be executed when the system timezone changes. */ - constructor(callback_on_change: (new_timezone: string) => void) { - this._callback_on_change = callback_on_change; - } - - enable(): void { - this._subscribe_to_changes(this._callback_on_change.bind(this)); - } - - disable(): void { - this._unsubscribe_to_changes(); - } + /** @private @type {number | null} */ + _signal_id = null; - /** Releases acquired resources */ - dispose(): void { - this.disable(); - } + /** The function to call when the system timezone changes. + * @type {((new_timezone: string) => void) | null} */ + callback = null; - private _signal_id: number | undefined = undefined; - - private _subscribe_to_changes( - callback_when_changes: (new_timezone: string) => void - ): void { - if (this._signal_id) - this._unsubscribe_to_changes(); + enable() { + if (this._signal_id !== null) + return; this._signal_id = Gio.DBus.system.signal_subscribe( 'org.freedesktop.timedate1', // sender 'org.freedesktop.DBus.Properties', // interface_name @@ -45,16 +29,20 @@ export class Timezone_change_listener { if (changed_properties['Timezone']) { const new_timezone = changed_properties['Timezone'].deep_unpack(); - callback_when_changes(new_timezone); + this.callback?.(new_timezone); } } ); } - private _unsubscribe_to_changes(): void { - if (!this._signal_id) + disable() { + if (this._signal_id === null) return; Gio.DBus.system.signal_unsubscribe(this._signal_id); - this._signal_id = undefined; + this._signal_id = null; + } + + dispose() { + this.disable(); } } diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/command_launching.js b/auto-dark-light@gihaume/src/lib/sys/gnome/command_launching.js new file mode 100644 index 00000000000..6f435e52dc8 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/command_launching.js @@ -0,0 +1,75 @@ +const { Gio, GLib } = imports.gi; + +export class Error_timed_out_by_sigterm extends Error {}; +export class Error_timed_out_by_sigkill extends Error {}; +export class Error_failed extends Error {}; + +const GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGTERM = 124; +const GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGKILL = 137; + +/** + * Executes a command with a timeout and transmits any error on failure. + * @param {string} command - The shell command to execute. + * @param {number} sigterm_timeout - The delay in seconds (s) before cancelling the command with a SIGTERM. 0 means infinity/never. Defaults to 0. + * @param {number} sigkill_timeout - The delay in seconds (s) after SIGTERM before cancelling the command with a SIGKILL. 0 means infinity/never. `sigterm_timeout` at 0 disables this. Defaults to 10. + * @returns {Promise} Resolves when the command has been executed or rejects if an error occurs. + * @throws {GLib.Error} - If an error occurs during communication with the subprocess running the command. + * @throws {Error_timed_out_by_sigterm} - If the command is cancelled due to a timeout by SIGTERM. + * @throws {Error_timed_out_by_sigkill} - If the command is cancelled due to a timeout by SIGKILL. + * @throws {Error_failed} - If the command fails with a non-zero exit code. The error message is the `stderr` output if any, otherwise the exit status. + */ +export async function launch_command( + command, sigterm_timeout = 0, sigkill_timeout = 10 +) { + const wrapped_command = + `timeout --kill-after=${sigkill_timeout}s ${sigterm_timeout}s sh -c ${GLib.shell_quote(command)}`; + const [_ok, argvp] = GLib.shell_parse_argv(wrapped_command); // Can throw `GLib.Error` with domain `GLib.ShellError` + + const process = new Gio.Subprocess({ + argv: argvp, + flags: Gio.SubprocessFlags.STDERR_PIPE + }); + + const start_time = Date.now(); // milliseconds (ms) + process.init(null); + const [_stdout, stderr] = await new Promise((resolve, reject) => { + process.communicate_utf8_async(null, null, (source, result) => { + try { + const [_ok, stdout, stderr] = + /** @type {imports.gi.Gio.Subprocess} */ (source) + .communicate_utf8_finish(result); + resolve([stdout, stderr]); + } catch (error) { + reject(error); + } + }); + }); + const elapsed_time = (Date.now() - start_time) / 1000; // seconds (s) + + const exit_status = process.get_exit_status(); + switch (exit_status) { + case 0: + break; + case GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGTERM: + throw new Error_timed_out_by_sigterm( + "The command may have been timed out by SIGTERM" + ); + case GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGKILL: + throw new Error_timed_out_by_sigkill( + "The command was probably killed by an external SIGKILL" + ); + case 1: // Workaround for 'timeout' sending SIGKILL not reported with the intended above exit status + if ( + sigterm_timeout > 0 && + elapsed_time >= sigterm_timeout + sigkill_timeout + ) + throw new Error_timed_out_by_sigkill( + "The command was probably timed out by SIGKILL" + ); + // No break in order to fall through, and so also needs to stay directly above the default case + default: + throw new Error_failed( + stderr ? stderr.trim() : "exit status: " + exit_status + ); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/launch_command.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/launch_command.ts deleted file mode 100644 index 4055d67ec94..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/gnome/launch_command.ts +++ /dev/null @@ -1,107 +0,0 @@ -const { Gio, GLib } = imports.gi; -import { _, logger } from '../../../globals'; - -export async function launch_command( - name: string, expiry: number, command: string -): Promise { - try { - await _launch_command(command, expiry); - } catch (error) { - const name_for_error = name !== '' ? name : command; - let msg = `${_("the command")} '${name_for_error}' ${_("has failed")}`; - if (error instanceof GLib.ShellError) - msg += ` ${_("due to a wrong format")}.\n` - + "\n" - + `${_("Detail")}${_(":")}\n` - + error.message; - else - if (error instanceof Gio.IOErrorEnum) { - if (error.code === Gio.IOErrorEnum.TIMED_OUT) - msg += ` ${_("due to timeout")}.\n` - + "\n" - + `${_("Detail")}${_(":")}\n` - + error.message; - else - if (error.code === Gio.IOErrorEnum.FAILED) - msg += ` ${_("due to an error")}.\n` - + "\n" - + `${_("Detail")}${_(":")}\n` - + error.message; - } else - msg += `${_(":")} ${error}` // last resort: full `error` object so we may see the stack trace - - logger.warn(msg); - } -} - -const TIMEOUT_EXIT_STATUS_SIGTERM = 124; -const TIMEOUT_EXIT_STATUS_SIGKILL = 137; -const SIGKILL_TIMEOUT = 10; // seconds (s) to wait after 'timeout' sends SIGTERM so it sends SIGKILL - -/** - * Executes a command with a timeout and transmits any error on failure. - * @param command - The shell command to execute. - * @param timeout - The delay in seconds before cancelling the command with a SIGTERM, then a few seconds later with a SIGKILL. `0` means infinity/never. - * @throws {GLib.ShellError} - If the command format is invalid. - * @throws {Gio.IOErrorEnum.TIMED_OUT} - If the command is cancelled due to a timeout. - * @throws {Gio.IOErrorEnum.FAILED} - If the command fails with a non-zero exit code. The error message is the `stderr` output if any, otherwise the exit status. - */ -async function _launch_command(command: string, timeout = 10): Promise { - const wrapped_command = - `timeout --kill-after=${SIGKILL_TIMEOUT} ${timeout}s sh -c ${GLib.shell_quote(command)}`; - const [_ok, argvp] = GLib.shell_parse_argv(wrapped_command); // can throw GLib.ShellError - - const process = new Gio.Subprocess({ - argv: argvp, - flags: Gio.SubprocessFlags.STDERR_PIPE - }); - - const start_time = Date.now(); // milliseconds (ms) - process.init(null); - const [_stdout, stderr] = await new Promise<[string, string]>( // Promisifies - (resolve, reject) => { - process.communicate_utf8_async( - null, - null, - (source: imports.gi.Gio.Subprocess, result) => { - try { - const [_ok, stdout, stderr] = - source.communicate_utf8_finish(result); - resolve([stdout, stderr]); - } catch (error) { - reject(error); - } - } - ); - } - ); - const elapsed_time = (Date.now() - start_time) / 1000; // seconds (s) - - const exit_status = process.get_exit_status(); - switch (exit_status) { - case 0: - break; - case TIMEOUT_EXIT_STATUS_SIGTERM: - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.TIMED_OUT, - message: `may have been timed out by SIGTERM (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGTERM})` - }); - case TIMEOUT_EXIT_STATUS_SIGKILL: - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.TIMED_OUT, - message: `probably killed by an external SIGKILL (GNU 'timeout' exit status ${TIMEOUT_EXIT_STATUS_SIGKILL})` - }); - case 1: // workaround for 'timeout' sending SIGKILL not reported with the intended 137 exit status - if (timeout > 0 && elapsed_time >= timeout + SIGKILL_TIMEOUT) - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.TIMED_OUT, - message: `probably timed out by SIGKILL` - }); - // no break, needs to stay directly above the default case - default: - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.FAILED, - message: stderr ? stderr.trim() : "exit status: " + exit_status - }); - } -} diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/system_time.ts b/auto-dark-light@gihaume/src/lib/sys/gnome/system_time.js similarity index 57% rename from auto-dark-light@gihaume/src/lib/sys/gnome/system_time.ts rename to auto-dark-light@gihaume/src/lib/sys/gnome/system_time.js index d55ff68e55b..52bf15d0cb7 100644 --- a/auto-dark-light@gihaume/src/lib/sys/gnome/system_time.ts +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/system_time.js @@ -1,34 +1,41 @@ const { DateTime } = imports.gi.GLib; // Preferred over JS's `Date` to take into account timezone changes during runtime. +/** @typedef {import('../../../types').Time_hms} Time_hms */ import { Time_of_day } from "../../core/Time_of_day"; -import type { Time_hms } from '../../../types'; -/** @returns seconds (s) */ -export function get_now_as_unix(): number { +/** @returns {number} seconds (s) */ +export function get_now_as_unix() { return DateTime.new_now_local().to_unix(); } -export function get_now_as_hms(): Time_hms { +/** @returns {Time_hms} */ +export function get_now_as_hms() { const datetime = DateTime.new_now_local(); return _datetime_to_hms(datetime); } -export function get_now_as_time_of_day(): Time_of_day { +/** @returns {Time_of_day} */ +export function get_now_as_time_of_day() { const datetime = DateTime.new_now_local(); const hms = _datetime_to_hms(datetime); return new Time_of_day(hms); } -/** @param unix_time - seconds (s) */ -export function new_local_time_of_day_from_unix( - unix_time: number -): Time_of_day { +/** + * @param {number} unix_time - seconds (s) + * @returns {Time_of_day} + */ +export function new_local_time_of_day_from_unix(unix_time) { const datetime = DateTime.new_from_unix_local(unix_time); const hms = _datetime_to_hms(datetime); return new Time_of_day(hms); } -function _datetime_to_hms(datetime: imports.gi.GLib.DateTime): Time_hms { +/** + * @param {imports.gi.GLib.DateTime} datetime + * @returns {Time_hms} +*/ +function _datetime_to_hms(datetime) { return { h: datetime.get_hour(), m: datetime.get_minute(), diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/tests/test Wall_clock_adjustment_monitor.js b/auto-dark-light@gihaume/src/lib/sys/gnome/tests/test Wall_clock_adjustment_monitor.js index 659cf815d3b..f27dc13c062 100644 --- a/auto-dark-light@gihaume/src/lib/sys/gnome/tests/test Wall_clock_adjustment_monitor.js +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/tests/test Wall_clock_adjustment_monitor.js @@ -1,7 +1,7 @@ /** * To be tested manually with `cjs -m `. * - * Criteria: changing the system wall clock time for more than `time_difference_tolerance` seconds must trigger the console log within `monitoring_interval` seconds. + * Changing the system wall clock time for more than `time_difference_tolerance` seconds must trigger the console log within `monitoring_interval` seconds. */ import { Wall_clock_adjustment_monitor } from '../Wall_clock_adjustment_monitor.js'; diff --git a/auto-dark-light@gihaume/src/lib/sys/gnome/tests/test command_launching.js b/auto-dark-light@gihaume/src/lib/sys/gnome/tests/test command_launching.js new file mode 100644 index 00000000000..8ddb43d1b95 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/gnome/tests/test command_launching.js @@ -0,0 +1,138 @@ +/** + * To be tested manually with `cjs -m `. + * + * Only ✅ and ⚠️ but no ❌ should be logged. The ⚠️ messages should be checked. The `GLib-GIO-CRITICAL` can be ignored. + */ + +import * as cmd from '../command_launching.js'; + +{ + const name = "Simple command completion without timeout"; + try { + await cmd.launch_command(`:`, 0, 0); + console.log(`✅ ${name}.`); + } catch (error) { + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "Simple command completion with timeout"; + try { + await cmd.launch_command(`:`, 1, 0); + console.log(`✅ ${name}.`); + } catch (error) { + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "Long-running command completion without timeout"; + try { + await cmd.launch_command(`sleep 1`, 0, 0); + console.log(`✅ ${name}.`); + } catch (error) { + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "Long-running command completion with timeout"; + try { + await cmd.launch_command(`sleep 1`, 2, 0); + console.log(`✅ ${name}.`); + } catch (error) { + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "SIGTERM timeout"; + try { + await cmd.launch_command("sleep 2", 1, 1); + console.error(`❌ ${name}.`, "No error thrown."); + } catch (error) { + error instanceof cmd.Error_timed_out_by_sigterm ? + console.log(`✅ ${name}.`) : + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "SIGKILL timeout"; + try { + await cmd.launch_command("trap '' TERM; sleep 2", 1, 1); + console.error(`❌ ${name}.`, "No error thrown."); + } catch (error) { + error instanceof cmd.Error_timed_out_by_sigkill ? + console.log(`✅ ${name}.`) : + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "SIGKILL timeout disabled when SIGTERM timeout set to 0"; + try { + await cmd.launch_command("exec sleep 2", 0, 1); + console.log(`✅ ${name}.`); + } catch (error) { + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "Non-zero exit code"; + try { + await cmd.launch_command("exit 42", 0, 0); + console.error(`❌ ${name}.`, "No error thrown."); + } catch (error) { + error instanceof cmd.Error_failed ? + console.log(`✅ ${name}.`) : + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "Non-existent command"; + try { + await cmd.launch_command("nonexistent_command_xyz", 0, 0); + console.error(`❌ ${name}.`, "No error thrown."); + } catch (error) { + error instanceof cmd.Error_failed ? + console.log(`✅ ${name}.`) : + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "Wrong format"; + try { + await cmd.launch_command("\"unclosed'", 0, 0); + console.error(`❌ ${name}.`, "No error thrown."); + } catch (error) { + error instanceof cmd.Error_failed ? + console.log(`✅ ${name}.`) : + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "Long-running aborted by SIGTERM returning waiting time"; + try { + console.log(`ℹ️ ${name}. Starting test...`); + await cmd.launch_command("sleep 5", 1, 10); + console.error(`❌ ${name}.`, "No error thrown."); + } + catch (error) { + error instanceof cmd.Error_timed_out_by_sigterm ? + console.log( + `⚠️ ${name}. Ensure that this message appears ~1 second and not 5 after the 'Starting test...' one above.` + ) : + console.error(`❌ ${name}.`, error); + } +} +{ + const name = "Long-running aborted by SIGKILL returning waiting time"; + try { + console.log(`ℹ️ ${name}. Starting test...`); + await cmd.launch_command("trap '' TERM; sleep 5", 1, 1); + console.error(`❌ ${name}.`, "No error thrown."); + } + catch (error) { + error instanceof cmd.Error_timed_out_by_sigkill ? + console.log( + `⚠️ ${name}. Ensure that this message appears ~2 seconds and not 5 after the 'Starting test...' one above.` + ) : + console.error(`❌ ${name}.`, error); + } +} diff --git a/auto-dark-light@gihaume/tsconfig.json b/auto-dark-light@gihaume/tsconfig.json index d2f99d557dd..9f8b0162838 100644 --- a/auto-dark-light@gihaume/tsconfig.json +++ b/auto-dark-light@gihaume/tsconfig.json @@ -1,7 +1,10 @@ { "compilerOptions": { "target": "es2022", - "lib": ["ES2022"], + "lib": [ + "ES2022", + "DOM" // For `console` in JS tests + ], "module": "es2022", "moduleResolution": "bundler", "moduleDetection": "force", From a45c5806cd4078071df4f0bac38bd3be9448f1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20M=C3=BCller?= Date: Sun, 30 Nov 2025 21:16:47 +0100 Subject: [PATCH 13/13] Replace DBus `login1` `PrepareForSleep` by Cinnamon `misc.gnomeSession` `Presence` proxy --- .../auto-dark-light@gihaume/5.8/applet.js | 130 +++++++++--------- .../src/app/handlers/initialize_handlers.ts | 14 +- .../Screen_lock_change_listener.js | 1 - .../Screen_presence_listener.js | 46 +++++++ .../Screen_state_handler.js | 41 ++++++ .../Screen_unlock_waiter.js | 0 .../doc/Screen_state_handler.drawio.svg | 4 + .../cinnamon/Screen_state_handler/index.js | 3 + .../tests/test Screen_lock_change_listener.js | 0 .../tests/test Screen_presence_listener.js | 19 +++ .../tests/test Screen_state_handler.js} | 10 +- .../tests/test Screen_unlock_waiter.js | 0 .../Sleep_and_lock_handler.js | 41 ------ .../Sleep_events_listener.js | 44 ------ .../doc/Sleep_and_lock_handler.drawio.svg | 4 - .../cinnamon/Sleep_and_lock_handler/index.js | 3 - .../tests/test Sleep_events_listener.js | 19 --- 17 files changed, 188 insertions(+), 191 deletions(-) rename auto-dark-light@gihaume/src/lib/sys/cinnamon/{Sleep_and_lock_handler => Screen_state_handler}/Screen_lock_change_listener.js (99%) create mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_presence_listener.js create mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_state_handler.js rename auto-dark-light@gihaume/src/lib/sys/cinnamon/{Sleep_and_lock_handler => Screen_state_handler}/Screen_unlock_waiter.js (100%) create mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/doc/Screen_state_handler.drawio.svg create mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/index.js rename auto-dark-light@gihaume/src/lib/sys/cinnamon/{Sleep_and_lock_handler => Screen_state_handler}/tests/test Screen_lock_change_listener.js (100%) create mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_presence_listener.js rename auto-dark-light@gihaume/src/lib/sys/cinnamon/{Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js => Screen_state_handler/tests/test Screen_state_handler.js} (50%) rename auto-dark-light@gihaume/src/lib/sys/cinnamon/{Sleep_and_lock_handler => Screen_state_handler}/tests/test Screen_unlock_waiter.js (100%) delete mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_and_lock_handler.js delete mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js delete mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg delete mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/index.js delete mode 100644 auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js diff --git a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js index 57dd4017e77..67f54421287 100644 --- a/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js +++ b/auto-dark-light@gihaume/files/auto-dark-light@gihaume/5.8/applet.js @@ -4260,10 +4260,10 @@ class Appearance_handler { makeAutoObservable(this); } } -const { Gio: Gio$6 } = imports.gi; +const { Gio: Gio$5 } = imports.gi; const settings$2 = { - background: Gio$6.Settings.new("org.cinnamon.desktop.background"), - slideshow: Gio$6.Settings.new("org.cinnamon.desktop.background.slideshow") + background: Gio$5.Settings.new("org.cinnamon.desktop.background"), + slideshow: Gio$5.Settings.new("org.cinnamon.desktop.background.slideshow") }; class Background_accessor { static get is_slideshow() { @@ -4339,7 +4339,7 @@ class Background_handler { Background_accessor.picture_file = this._settings.dark_background_file; } } -const { Gio: Gio$5, GLib: GLib$5 } = imports.gi; +const { Gio: Gio$4, GLib: GLib$5 } = imports.gi; class Error_timed_out_by_sigterm extends Error { } class Error_timed_out_by_sigkill extends Error { @@ -4351,9 +4351,9 @@ const GNU_TIMEOUT_EXIT_STATUS_WHEN_SIGKILL = 137; async function launch_command$1(command, sigterm_timeout = 0, sigkill_timeout = 10) { const wrapped_command = `timeout --kill-after=${sigkill_timeout}s ${sigterm_timeout}s sh -c ${GLib$5.shell_quote(command)}`; const [_ok, argvp] = GLib$5.shell_parse_argv(wrapped_command); - const process = new Gio$5.Subprocess({ + const process = new Gio$4.Subprocess({ argv: argvp, - flags: Gio$5.SubprocessFlags.STDERR_PIPE + flags: Gio$4.SubprocessFlags.STDERR_PIPE }); const start_time = Date.now(); process.init(null); @@ -4554,7 +4554,7 @@ class Keybinding_handler { this.unset(); } } -const { Gio: Gio$4 } = imports.gi; +const { Gio: Gio$3 } = imports.gi; class Timezone_change_listener { /** @private @type {number | null} */ _signal_id = null; @@ -4564,7 +4564,7 @@ class Timezone_change_listener { enable() { if (this._signal_id !== null) return; - this._signal_id = Gio$4.DBus.system.signal_subscribe( + this._signal_id = Gio$3.DBus.system.signal_subscribe( "org.freedesktop.timedate1", // sender "org.freedesktop.DBus.Properties", @@ -4575,7 +4575,7 @@ class Timezone_change_listener { // object_path null, // arg0 - Gio$4.DBusSignalFlags.NONE, + Gio$3.DBusSignalFlags.NONE, // flags (_1, _2, _3, _4, _5, parameters) => { const changed_properties = parameters.deep_unpack()[1]; @@ -4589,14 +4589,14 @@ class Timezone_change_listener { disable() { if (this._signal_id === null) return; - Gio$4.DBus.system.signal_unsubscribe(this._signal_id); + Gio$3.DBus.system.signal_unsubscribe(this._signal_id); this._signal_id = null; } dispose() { this.disable(); } } -const { Gio: Gio$3 } = imports.gi; +const { Gio: Gio$2 } = imports.gi; class Timezone_location_finder { _database; /** @@ -4605,7 +4605,7 @@ class Timezone_location_finder { */ constructor(path) { const file_path = `${path}/database.json`; - const file = Gio$3.File.new_for_path(file_path); + const file = Gio$2.File.new_for_path(file_path); const [ok, file_content] = file.load_contents(null); if (!ok) throw new Error(`failed to load file/contents of '${file_path}'`); @@ -4663,6 +4663,41 @@ class Location_handler { async function sleep(duration) { return new Promise((resolve) => setTimeout(resolve, duration)); } +const { gnomeSession } = imports.misc; +class Screen_presence_listener { + /** @private @type {number | null} */ + _signal_id = null; + /** @private @readonly @type {imports.gi.Gio.DBusProxy} */ + _presence_proxy = gnomeSession.Presence(); + /** @type {((is_present: boolean) => void) | null} */ + callback = null; + enable() { + if (this._signal_id !== null) + return; + this._signal_id = this._presence_proxy.connectSignal( + "StatusChanged", + /** + * @param {any} _0 + * @param {any} _1 + * @param {[number]} params + */ + (_0, _1, [presenceStatus]) => { + this.callback?.( + presenceStatus === gnomeSession.PresenceStatus.AVAILABLE + ); + } + ); + } + disable() { + if (this._signal_id === null) + return; + this._presence_proxy.disconnectSignal(this._signal_id); + this._signal_id = null; + } + dispose() { + this.disable(); + } +} const { ScreenSaverProxy } = imports.misc.screenSaver; class Screen_lock_change_listener { /** @private @type {number | null} */ @@ -4738,70 +4773,31 @@ class Screen_unlock_waiter { this._screen_lock.dispose(); } } -const { Gio: Gio$2 } = imports.gi; -class Sleep_events_listener { - /** @private @type {number | null} */ - _signal_id = null; - /** The function to call when the system is entering sleep or has just wake up (`is_entering_sleep` at `false`). - * @type {((is_entering_sleep: boolean) => void) | null} */ - callback = null; - enable() { - if (this._signal_id !== null) - return; - this._signal_id = Gio$2.DBus.system.signal_subscribe( - "org.freedesktop.login1", - // sender - "org.freedesktop.login1.Manager", - // interface_name - "PrepareForSleep", - // member - "/org/freedesktop/login1", - // object_path - null, - // arg0 - Gio$2.DBusSignalFlags.NONE, - // flags - (_1, _2, _3, _4, _5, parameters) => { - const is_entering_sleep = parameters.deep_unpack()[0]; - this.callback?.(is_entering_sleep); - } - ); - } - disable() { - if (this._signal_id === null) - return; - Gio$2.DBus.system.signal_unsubscribe(this._signal_id); - this._signal_id = null; - } - dispose() { - this.disable(); - } -} -class Sleep_and_lock_handler { +class Screen_state_handler { /** @private @readonly */ _unlock_waiter = new Screen_unlock_waiter(); /** @private @readonly */ - _sleep_events = new Sleep_events_listener(); - /** The function to call when the system is entering sleep or has just wake up and is unlocked (`is_entering_sleep` at `false`). - * @type {((is_entering_sleep: boolean) => void) | null} */ + _presence_listener = new Screen_presence_listener(); + /** The function to call when the system is entering sleep or has just wake up and is unlocked (`is_present` at `false`). + * @type {((is_present: boolean) => void) | null} */ callback = null; constructor() { - this._sleep_events.callback = async (is_entering_sleep) => { - if (!is_entering_sleep) + this._presence_listener.callback = async (is_present) => { + if (!is_present) await this._unlock_waiter.wait_if_locked(); - this.callback?.(is_entering_sleep); + this.callback?.(!is_present); }; } enable() { - this._sleep_events.enable(); + this._presence_listener.enable(); } disable() { this._unlock_waiter.unblock_wait_if_locked(); - this._sleep_events.disable(); + this._presence_listener.disable(); } dispose() { this._unlock_waiter.dispose(); - this._sleep_events.dispose(); + this._presence_listener.dispose(); } } const { Gio: Gio$1 } = imports.gi; @@ -5276,9 +5272,9 @@ function initialize_handlers(applet, settings2) { if (scheduler.is_set && scheduler.get_if_should_be_expired()) appearance_handler.sync_is_dark(); }); - const sleep_and_lock_handler = new Sleep_and_lock_handler(); - disposables.push(sleep_and_lock_handler); - sleep_and_lock_handler.callback = (is_sleeping) => { + const screen_state_handler = new Screen_state_handler(); + disposables.push(screen_state_handler); + screen_state_handler.callback = (is_sleeping) => { if (is_sleeping) wall_clock_monitor.disable(); else @@ -5305,11 +5301,11 @@ function initialize_handlers(applet, settings2) { appearance_handler.sync_is_dark(); schedule_the_event(); wall_clock_monitor.enable(); - sleep_and_lock_handler.enable(); + screen_state_handler.enable(); } else { scheduler.unset_the_event(); wall_clock_monitor.disable(); - sleep_and_lock_handler.disable(); + screen_state_handler.disable(); } }); reaction(() => appearance_handler.next_twilight, () => { @@ -5327,7 +5323,7 @@ function initialize_handlers(applet, settings2) { applet.on_button_open_os_background_settings = () => GLib.spawn_command_line_async("cinnamon-settings background"); color_scheme_handler.enable(); wall_clock_monitor.enable(); - sleep_and_lock_handler.enable(); + screen_state_handler.enable(); } const { AppletSettings } = imports.ui.settings; function initialize_applet_settings(uuid, instance_id) { diff --git a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts index 0b52064e598..260890de2c9 100644 --- a/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts +++ b/auto-dark-light@gihaume/src/app/handlers/initialize_handlers.ts @@ -14,7 +14,7 @@ import { Location_handler } from './Location_handler'; import { logger } from '../../globals'; import type { Settings } from '../ui/Settings'; import { sleep } from '../../lib/core/utils'; -import { Sleep_and_lock_handler } from '../../lib/sys/cinnamon/Sleep_and_lock_handler'; +import { Screen_state_handler } from '../../lib/sys/cinnamon/Screen_state_handler'; import { Color_scheme_handler } from '../../lib/sys/cinnamon/Color_scheme_handler'; import { Themes_handler } from './Themes_handler'; import { Time_of_day } from '../../lib/core/Time_of_day'; @@ -240,9 +240,9 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { appearance_handler.sync_is_dark(); }); - const sleep_and_lock_handler = new Sleep_and_lock_handler(); - disposables.push(sleep_and_lock_handler); - sleep_and_lock_handler.callback = (is_sleeping: boolean) => { + const screen_state_handler = new Screen_state_handler(); + disposables.push(screen_state_handler); + screen_state_handler.callback = (is_sleeping: boolean) => { if (is_sleeping) wall_clock_monitor.disable(); else @@ -271,11 +271,11 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { appearance_handler.sync_is_dark(); schedule_the_event(); wall_clock_monitor.enable(); - sleep_and_lock_handler.enable(); + screen_state_handler.enable(); } else { scheduler.unset_the_event(); wall_clock_monitor.disable(); - sleep_and_lock_handler.disable(); + screen_state_handler.disable(); } }); mobx.reaction(() => appearance_handler.next_twilight, () => { @@ -305,5 +305,5 @@ export function initialize_handlers(applet: Applet, settings: Settings): void { color_scheme_handler.enable(); wall_clock_monitor.enable(); - sleep_and_lock_handler.enable(); + screen_state_handler.enable(); } diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_lock_change_listener.js similarity index 99% rename from auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_lock_change_listener.js index bd6c5060f9d..370b342da10 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_lock_change_listener.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_lock_change_listener.js @@ -4,7 +4,6 @@ const { ScreenSaverProxy } = imports.misc.screenSaver; /** * An interface to read and listen to the screen locked state. - * * @implements {Observer} */ export class Screen_lock_change_listener { diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_presence_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_presence_listener.js new file mode 100644 index 00000000000..40bce89f667 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_presence_listener.js @@ -0,0 +1,46 @@ +const { gnomeSession } = imports.misc; + +/** @typedef {import('../../../../types').Observer} Observer */ + +/** + * An interface to read and listen to the screen presence state for i.e. detecting when entering and leaving sleep. + * @implements {Observer} + */ +export class Screen_presence_listener { + /** @private @type {number | null} */ + _signal_id = null; + + /** @private @readonly @type {imports.gi.Gio.DBusProxy} */ + _presence_proxy = gnomeSession.Presence(); + + /** @type {((is_present: boolean) => void) | null} */ + callback = null; + + enable() { + if (this._signal_id !== null) + return; + this._signal_id = this._presence_proxy.connectSignal('StatusChanged', + /** + * @param {any} _0 + * @param {any} _1 + * @param {[number]} params + */ + (_0, _1, [presenceStatus]) => { + this.callback?.( + presenceStatus === gnomeSession.PresenceStatus.AVAILABLE + ); + } + ); + } + + disable() { + if (this._signal_id === null) + return; + this._presence_proxy.disconnectSignal(this._signal_id); + this._signal_id = null; + } + + dispose() { + this.disable(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_state_handler.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_state_handler.js new file mode 100644 index 00000000000..067c9697d51 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_state_handler.js @@ -0,0 +1,41 @@ +/** @typedef {import('../../../../types.js').Observer} Observer */ +import { Screen_presence_listener } from './Screen_presence_listener.js'; +import { Screen_unlock_waiter } from './Screen_unlock_waiter.js'; + +/** + * A handler to react when the system is entering sleep or has just wake up and is unlocked. + * @implements {Observer} + */ +export class Screen_state_handler { + /** @private @readonly */ + _unlock_waiter = new Screen_unlock_waiter(); + + /** @private @readonly */ + _presence_listener = new Screen_presence_listener(); + + /** The function to call when the system is entering sleep or has just wake up and is unlocked (`is_present` at `false`). + * @type {((is_present: boolean) => void) | null} */ + callback = null; + + constructor() { + this._presence_listener.callback = async is_present => { + if (!is_present) + await this._unlock_waiter.wait_if_locked(); + this.callback?.(!is_present); + }; + } + + enable() { + this._presence_listener.enable(); + } + + disable() { + this._unlock_waiter.unblock_wait_if_locked(); + this._presence_listener.disable(); + } + + dispose() { + this._unlock_waiter.dispose(); + this._presence_listener.dispose(); + } +} diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_unlock_waiter.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_unlock_waiter.js similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Screen_unlock_waiter.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/Screen_unlock_waiter.js diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/doc/Screen_state_handler.drawio.svg b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/doc/Screen_state_handler.drawio.svg new file mode 100644 index 00000000000..da2aacd63c6 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/doc/Screen_state_handler.drawio.svg @@ -0,0 +1,4 @@ + + + +
     «use»
    imports.misc.gnomeSession

    «TypeScript interface»

    Observer<T>
    callback: (T => void) | null
    enable(): void
    disable(): void

    «TypeScript interface»

    Disposable
    dispose(): void

    «JavaScript class»

    Screen_presence_listener

    «JavaScript class»

    Screen_lock_change_listener
    is_locked: bool {read-only}
     «use»
    imports.misc.screenSaver

    «JavaScript class»

    Screen_unlock_waiter
    wait_if_locked(): Promise<void>

    «JavaScript class»

    Screen_state_handler
    _unlock_waiter 
     _screen_lock
    _presence_listener
    \ No newline at end of file diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/index.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/index.js new file mode 100644 index 00000000000..5abd4da9006 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/index.js @@ -0,0 +1,3 @@ +import { Screen_state_handler } from "./Screen_state_handler"; + +export { Screen_state_handler }; diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_lock_change_listener.js similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_lock_change_listener.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_lock_change_listener.js diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_presence_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_presence_listener.js new file mode 100644 index 00000000000..1b084c0c6e3 --- /dev/null +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_presence_listener.js @@ -0,0 +1,19 @@ +/** + * To be tested manually with `cjs -m `. + * + * Changing the sleeping state must trigger the console log at either the sleeping and waking events. + */ + +imports.searchPath.push('/usr/share/cinnamon/js'); + +const { Screen_presence_listener } = await import('../Screen_presence_listener.js'); + +const listener = new Screen_presence_listener(); +listener.callback = (/** @type {boolean} */ is_present) => { + console.log( + `Screen presence state changed: ${is_present ? 'present' : 'not present'}` + ); +}; +listener.enable(); + +new imports.gi.GLib.MainLoop(null, false).run(); diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_state_handler.js similarity index 50% rename from auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_state_handler.js index 5764aa88126..b3bcae37460 100644 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_and_lock_handler.js +++ b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_state_handler.js @@ -6,14 +6,14 @@ imports.searchPath.push('/usr/share/cinnamon/js'); -const { Sleep_and_lock_handler } = await import('../Sleep_and_lock_handler.js'); +const { Screen_state_handler } = await import('../Screen_state_handler.js'); -const sleep_events = new Sleep_and_lock_handler(); -sleep_events.callback = (/** @type {boolean} */ is_entering_sleep) => { +const screen_state = new Screen_state_handler(); +screen_state.callback = (/** @type {boolean} */ is_present) => { console.log( - `Sleep state changed: ${is_entering_sleep ? 'entering sleep' : 'woke up unlocked'}` + `Sleep state changed: ${is_present ? 'woke up unlocked' : 'entering sleep or locking'}` ); }; -sleep_events.enable(); +screen_state.enable(); await new imports.gi.GLib.MainLoop(null, false).runAsync(); diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_unlock_waiter.js similarity index 100% rename from auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Screen_unlock_waiter.js rename to auto-dark-light@gihaume/src/lib/sys/cinnamon/Screen_state_handler/tests/test Screen_unlock_waiter.js diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_and_lock_handler.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_and_lock_handler.js deleted file mode 100644 index 4d7e5eb4e06..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_and_lock_handler.js +++ /dev/null @@ -1,41 +0,0 @@ -/** @typedef {import('../../../../types.js').Observer} Observer */ -import { Screen_unlock_waiter } from './Screen_unlock_waiter.js'; -import { Sleep_events_listener } from './Sleep_events_listener.js'; - -/** - * A handler to wait until the screen is unlocked. - * @implements {Observer} - */ -export class Sleep_and_lock_handler { - /** @private @readonly */ - _unlock_waiter = new Screen_unlock_waiter(); - - /** @private @readonly */ - _sleep_events = new Sleep_events_listener(); - - /** The function to call when the system is entering sleep or has just wake up and is unlocked (`is_entering_sleep` at `false`). - * @type {((is_entering_sleep: boolean) => void) | null} */ - callback = null; - - constructor() { - this._sleep_events.callback = async is_entering_sleep => { - if (!is_entering_sleep) - await this._unlock_waiter.wait_if_locked(); - this.callback?.(is_entering_sleep); - }; - } - - enable() { - this._sleep_events.enable(); - } - - disable() { - this._unlock_waiter.unblock_wait_if_locked(); - this._sleep_events.disable(); - } - - dispose() { - this._unlock_waiter.dispose(); - this._sleep_events.dispose(); - } -} diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js deleted file mode 100644 index 46304e65a4d..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/Sleep_events_listener.js +++ /dev/null @@ -1,44 +0,0 @@ -const { Gio } = imports.gi; - -/** @typedef {import('../../../../types').Observer} Observer */ - -/** - * An interface to listen to the sleep entering and waking events. - * @implements {Observer} - */ -export class Sleep_events_listener { - /** @private @type {number | null} */ - _signal_id = null; - - /** The function to call when the system is entering sleep or has just wake up (`is_entering_sleep` at `false`). - * @type {((is_entering_sleep: boolean) => void) | null} */ - callback = null; - - enable() { - if (this._signal_id !== null) - return; - this._signal_id = Gio.DBus.system.signal_subscribe( - 'org.freedesktop.login1', // sender - 'org.freedesktop.login1.Manager', // interface_name - 'PrepareForSleep', // member - '/org/freedesktop/login1', // object_path - null, // arg0 - Gio.DBusSignalFlags.NONE, // flags - (_1, _2, _3, _4, _5, parameters) => { // callback - const is_entering_sleep = parameters.deep_unpack()[0]; - this.callback?.(is_entering_sleep); - } - ); - } - - disable() { - if (this._signal_id === null) - return; - Gio.DBus.system.signal_unsubscribe(this._signal_id); - this._signal_id = null; - } - - dispose() { - this.disable(); - } -} diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg deleted file mode 100644 index 54e075fbbe9..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/doc/Sleep_and_lock_handler.drawio.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
     «use»
    Gio.DBus

    «TypeScript interface»

    Observer<T>
    callback: (T => void) | null
    enable(): void
    disable(): void

    «TypeScript interface»

    Disposable
    dispose(): void

    «JavaScript class»

    Sleep_events_listener

    «JavaScript class»

    Screen_lock_change_listener
    is_locked: bool {read-only}
     «use»
    imports.misc.screenSaver

    «JavaScript class»

    Screen_unlock_waiter
    wait_if_locked(): Promise<void>

    «JavaScript class»

    Sleep_and_lock_handler
    _unlock_waiter
     _screen_lock
    _sleep_events
    \ No newline at end of file diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/index.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/index.js deleted file mode 100644 index 94126b39e7d..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import { Sleep_and_lock_handler } from "./Sleep_and_lock_handler"; - -export { Sleep_and_lock_handler }; diff --git a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js b/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js deleted file mode 100644 index 3cd0e63986b..00000000000 --- a/auto-dark-light@gihaume/src/lib/sys/cinnamon/Sleep_and_lock_handler/tests/test Sleep_events_listener.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * To be tested manually with `cjs -m `. - * - * Changing the sleeping state must trigger the console log at either the sleeping and waking events. - */ - -imports.searchPath.push('/usr/share/cinnamon/js'); - -const { Sleep_events_listener } = await import('../Sleep_events_listener.js'); - -const sleep_events = new Sleep_events_listener(); -sleep_events.callback = (/** @type {boolean} */ is_entering_sleep) => { - console.log( - `Sleep state changed: ${is_entering_sleep ? 'entering sleep' : 'woke up'}` - ); -}; -sleep_events.enable(); - -new imports.gi.GLib.MainLoop(null, false).run();