From 105f65c93a5493be9d63ea51025aee0570b359ed Mon Sep 17 00:00:00 2001 From: William Date: Wed, 20 Sep 2023 14:02:26 +0100 Subject: [PATCH] v3.0: New modular, more compatible data format, new API, better UX (#160) * Start work on v3 * More work on task scheduling * Add comment to notification display slot * Synchronise branches * Use new HuskHomes-style task system * Bump to 2.3 * Remove HuskSyncInitializationException.java * Optimise database for MariaDB * Update libraries, move some around * Tweak command registration * Remove dummyhusksync * Fixup core synchronisation logic to use new task system * Implement new event dispatch subsystem * Remove last remaining future calls * Remove `Event#fire()` * Refactor startup process * New command subsystem, more initialization improvements, locale fixes * Update docs, tweak command perms * Reduce task number during data setting * add todo * Start work on data format / serialization refactor * More work on Bukkit impl * More serialization work * Fixes to serialization, data preview system * Start legacy conversion skeleton * Handle setting empty inventories * Start on-the-fly legacy conversion work * Add advancement conversion * Rewrite advancement get / apply logic * Start work on locked map persistence * More map persistence work * More work on map serialization * Move around persistence logic * Add testing suite * Fix item synchronisation * Finalize more reliable locked map persistence * Remove deprecated method call * remove sync feature enum * Fix held item slot syncing * Make data types modular and API-extensible * Remove some excessive debugging, minor refactor * Fixup date formatting, improve menu UIs * Finish up legacy data converting * Null safety in item stack serializaiton * Fix relocation of nbtapi, update dumping docs * Add v1/MPDB Migrators back in * Fix pinning/unpinning data not working * Consumer instead of Function for editing data * Show file size in DataSnapshotOverview * Fix getIdentifier always returning empty * Re-add items and inventory GUI commands * Improve config file, fixup data restoration * Add min time between backups (more useful backups!) * More work on backups * Fixup backup rotation frequency * Remove stdout debug print in `#getEventPriority` * Improve sync complete locale logic, fix synchronization spelling * Remove `static` on exception * Use dedicated thread for Redis, properly unsubscribe * Refactor `player` package -> `user` * `PlayerDataHolder` -> `UserDataHolder` * Make `StatisticsMap` public, but `@ApiStatus.Internal` * Suppress unused warnings on `Data` * Add option to disable Plan hook * Decompress legacy data before converting * Decompress bytes in fromBytes * Check permission node before serving TAB suggestions * Actually convert legacy item stack data * Fix syntax errors * Minor method refactor in items command * Fixup case-sensitive parsing in HuskSync command * Start API work * More work on API, fix potion effects * Fix cross-server, config formatting for auto-pinned issue * Fix confusion with UserData command, update docs images * Update commands docs * More docs updating * Fix sync feature enabled/disabled checking logic * Fix `#isCustom()` * Enable persistent_data syncing by default * docs: update Sync-Features config snippet * docs: correct typo in Sync Features * More API work * bukkit: slightly optimized schedulers * More API work, various refactorings * docs: Start new API docs * bump dependencies * Add some basic unit tests * docs: Correct typos * More docs work, annotate DB methods as `@Blocking` * Encapsulate `RedisMessage`, minor optimisations * api: Simplify `#getCurrentData` * api: Simplify `editCurrentData`, using `ThrowingConsumers` for better error handling * docs: More Data Snapshot API documenting * docs: add TOC to Data Snapshot API page * bukkit: Make data types extend BukkitData * Move where custom data is stored, finish up Custom Data API docs * Optimise imports * Fix `data_manager_advancements_preview_remaining` locale * Fix advancement and playtime previews * Fix potion effect deserialization * Make snapshot_backup_frequency default to 4, more error handling/logging * docs: Add ToC to Custom Data API * docs: Minor legacy API tweaks * Remove some unneeded catch logic * Suppress a few warnings * Fix Effect constructor being supplied in wrong order --- .gitignore | 5 + LICENSE | 4 +- README.md | 6 +- build.gradle | 7 +- bukkit/build.gradle | 20 +- .../william278/husksync/BukkitHuskSync.java | 401 +++--- .../husksync/api/BukkitHuskSyncAPI.java | 270 ++++ .../william278/husksync/api/HuskSyncAPI.java | 226 ---- .../husksync/command/BrigadierUtil.java | 36 +- .../husksync/command/BukkitCommand.java | 169 ++- .../husksync/command/BukkitCommandType.java | 40 - .../william278/husksync/data/BukkitData.java | 1093 +++++++++++++++++ .../husksync/data/BukkitInventoryMap.java | 147 --- .../husksync/data/BukkitMapHandler.java | 233 ---- .../data/BukkitPersistentTypeMapping.java | 73 -- .../husksync/data/BukkitSerializer.java | 424 +++---- .../husksync/data/BukkitUserDataHolder.java | 151 +++ .../husksync/event/BukkitDataSaveEvent.java | 34 +- .../husksync/event/BukkitEvent.java | 19 - .../husksync/event/BukkitEventCannon.java | 52 - .../husksync/event/BukkitEventDispatcher.java | 54 + .../husksync/event/BukkitPlayerEvent.java | 25 +- .../husksync/event/BukkitPreSyncEvent.java | 23 +- .../event/BukkitSyncCompleteEvent.java | 5 +- .../listener/BukkitDeathEventListener.java | 9 +- .../listener/BukkitEventListener.java | 61 +- .../listener/BukkitJoinEventListener.java | 23 +- .../listener/BukkitQuitEventListener.java | 23 +- .../husksync/migrator/LegacyMigrator.java | 160 +-- .../husksync/migrator/MpdbMigrator.java | 111 +- .../husksync/player/BukkitPlayer.java | 655 ---------- .../william278/husksync/user/BukkitUser.java | 152 +++ .../husksync/util/BukkitLegacyConverter.java | 279 +++++ .../husksync/util/BukkitMapPersister.java | 378 ++++++ .../william278/husksync/util/BukkitTask.java | 172 +++ bukkit/src/main/resources/plugin.yml | 17 +- common/build.gradle | 51 +- .../net/william278/husksync/HuskSync.java | 217 +++- .../Adaptable.java} | 10 +- .../husksync/adapter/DataAdapter.java | 108 ++ .../husksync/adapter/GsonAdapter.java | 72 ++ .../husksync/adapter/SnappyGsonAdapter.java | 68 + .../husksync/api/BaseHuskSyncAPI.java | 157 --- .../william278/husksync/api/HuskSyncAPI.java | 458 +++++++ .../william278/husksync/command/Command.java | 84 ++ .../husksync/command/CommandBase.java | 77 -- .../husksync/command/EnderChestCommand.java | 140 +-- ...ConsoleExecutable.java => Executable.java} | 13 +- .../husksync/command/HuskSyncCommand.java | 196 ++- .../husksync/command/InventoryCommand.java | 139 +-- .../husksync/command/ItemsCommand.java | 108 ++ .../net/william278/husksync/command/Node.java | 105 ++ .../husksync/command/Permission.java | 120 -- .../husksync/command/TabCompletable.java | 39 - .../husksync/command/TabProvider.java | 50 + .../husksync/command/UserDataCommand.java | 403 +++--- .../william278/husksync/config/Locales.java | 35 +- .../william278/husksync/config/Settings.java | 231 ++-- .../husksync/data/AdvancementData.java | 53 - .../husksync/data/CompressedDataAdapter.java | 46 - .../net/william278/husksync/data/Data.java | 368 ++++++ .../william278/husksync/data/DataAdapter.java | 59 - .../william278/husksync/data/DataHolder.java | 140 +++ .../husksync/data/DataSaveCause.java | 130 -- .../husksync/data/DataSnapshot.java | 819 ++++++++++++ .../william278/husksync/data/Identifier.java | 177 +++ .../william278/husksync/data/ItemData.java | 63 - .../husksync/data/JsonDataAdapter.java | 48 - .../husksync/data/LocationData.java | 92 -- .../data/PersistentDataContainerData.java | 73 -- .../husksync/data/PersistentDataTag.java | 54 - ...istentDataTagType.java => Serializer.java} | 42 +- .../husksync/data/StatisticsData.java | 70 -- .../william278/husksync/data/StatusData.java | 123 -- .../husksync/data/StatusDataFlag.java | 77 -- .../william278/husksync/data/UserData.java | 376 ------ .../husksync/data/UserDataBuilder.java | 159 --- .../husksync/data/UserDataHolder.java | 167 +++ .../husksync/data/UserDataSnapshot.java | 145 --- .../husksync/database/Database.java | 188 ++- .../husksync/database/MySqlDatabase.java | 457 ++++--- ...CancellableEvent.java => Cancellable.java} | 4 +- .../husksync/event/DataSaveEvent.java | 29 +- .../net/william278/husksync/event/Event.java | 4 - .../husksync/event/EventCannon.java | 65 - .../husksync/event/EventDispatcher.java | 72 ++ .../husksync/event/PlayerEvent.java | 4 +- .../husksync/event/PreSyncEvent.java | 24 +- .../husksync/hook/PlanDataExtension.java | 240 ---- .../william278/husksync/hook/PlanHook.java | 210 +++- .../husksync/listener/EventListener.java | 254 ++-- .../husksync/migrator/Migrator.java | 3 +- .../husksync/player/OnlineUser.java | 423 ------- .../husksync/redis/RedisKeyType.java | 16 +- .../husksync/redis/RedisManager.java | 330 ++--- .../husksync/redis/RedisMessage.java | 54 +- .../husksync/redis/RedisMessageType.java | 21 +- .../CommandUser.java} | 25 +- .../ConsoleUser.java} | 27 +- .../william278/husksync/user/OnlineUser.java | 188 +++ .../husksync/{player => user}/User.java | 33 +- .../william278/husksync/util/DataDumper.java | 37 +- .../husksync/util/DataSnapshotList.java | 70 +- .../husksync/util/DataSnapshotOverview.java | 135 ++ .../LegacyConverter.java} | 22 +- .../net/william278/husksync/util/Task.java | 144 +++ .../main/resources/database/mysql_schema.sql | 12 +- common/src/main/resources/locales/bg-bg.yml | 38 +- common/src/main/resources/locales/de-de.yml | 36 +- common/src/main/resources/locales/en-gb.yml | 38 +- common/src/main/resources/locales/es-es.yml | 38 +- common/src/main/resources/locales/it-it.yml | 36 +- common/src/main/resources/locales/ja-jp.yml | 38 +- common/src/main/resources/locales/pt-br.yml | 38 +- common/src/main/resources/locales/uk-ua.yml | 38 +- common/src/main/resources/locales/zh-cn.yml | 38 +- common/src/main/resources/locales/zh-tw.yml | 42 +- .../william278/husksync/DummyHuskSync.java | 134 -- .../husksync/config/LocalesTests.java | 81 ++ .../husksync/data/DataAdaptionTests.java | 105 -- ...Tests.java => PlanDataExtensionTests.java} | 17 +- .../husksync/player/DummyPlayer.java | 205 ---- docs/API-Events.md | 12 +- docs/{UserData-API.md => API-v2.md} | 84 +- docs/API.md | 76 +- docs/Commands.md | 112 +- docs/Config-File.md | 71 +- docs/Custom-Data-API.md | 131 ++ docs/Data-Rotation.md | 22 +- docs/Data-Snapshot-API.md | 458 +++++++ docs/Dumping-UserData.md | 323 +---- docs/FAQs.md | 8 +- docs/Home.md | 14 +- docs/Keep-Inventory.md | 6 +- docs/Legacy-Migration.md | 10 +- docs/MPDB-Migration.md | 2 +- docs/Plan-Hook.md | 2 +- docs/Setup.md | 8 +- docs/Sync-Features.md | 60 +- docs/Troubleshooting.md | 8 +- docs/_Sidebar.md | 12 +- gradle.properties | 9 +- images/data-dumping.png | Bin 114059 -> 310680 bytes images/data-snapshot-list.png | Bin 1146767 -> 592774 bytes images/data-snapshot-viewer.png | Bin 808612 -> 738708 bytes images/rich-syntax-highlighting.png | Bin 439842 -> 476871 bytes plugin/build.gradle | 3 - test/requirements.txt | 7 + test/spin_network.py | 311 +++++ 149 files changed, 10039 insertions(+), 7442 deletions(-) create mode 100644 bukkit/src/main/java/net/william278/husksync/api/BukkitHuskSyncAPI.java delete mode 100644 bukkit/src/main/java/net/william278/husksync/api/HuskSyncAPI.java delete mode 100644 bukkit/src/main/java/net/william278/husksync/command/BukkitCommandType.java create mode 100644 bukkit/src/main/java/net/william278/husksync/data/BukkitData.java delete mode 100644 bukkit/src/main/java/net/william278/husksync/data/BukkitInventoryMap.java delete mode 100644 bukkit/src/main/java/net/william278/husksync/data/BukkitMapHandler.java delete mode 100644 bukkit/src/main/java/net/william278/husksync/data/BukkitPersistentTypeMapping.java create mode 100644 bukkit/src/main/java/net/william278/husksync/data/BukkitUserDataHolder.java delete mode 100644 bukkit/src/main/java/net/william278/husksync/event/BukkitEventCannon.java create mode 100644 bukkit/src/main/java/net/william278/husksync/event/BukkitEventDispatcher.java delete mode 100644 bukkit/src/main/java/net/william278/husksync/player/BukkitPlayer.java create mode 100644 bukkit/src/main/java/net/william278/husksync/user/BukkitUser.java create mode 100644 bukkit/src/main/java/net/william278/husksync/util/BukkitLegacyConverter.java create mode 100644 bukkit/src/main/java/net/william278/husksync/util/BukkitMapPersister.java create mode 100644 bukkit/src/main/java/net/william278/husksync/util/BukkitTask.java rename common/src/main/java/net/william278/husksync/{data/DataAdaptionException.java => adapter/Adaptable.java} (70%) create mode 100644 common/src/main/java/net/william278/husksync/adapter/DataAdapter.java create mode 100644 common/src/main/java/net/william278/husksync/adapter/GsonAdapter.java create mode 100644 common/src/main/java/net/william278/husksync/adapter/SnappyGsonAdapter.java delete mode 100644 common/src/main/java/net/william278/husksync/api/BaseHuskSyncAPI.java create mode 100644 common/src/main/java/net/william278/husksync/api/HuskSyncAPI.java create mode 100644 common/src/main/java/net/william278/husksync/command/Command.java delete mode 100644 common/src/main/java/net/william278/husksync/command/CommandBase.java rename common/src/main/java/net/william278/husksync/command/{ConsoleExecutable.java => Executable.java} (75%) create mode 100644 common/src/main/java/net/william278/husksync/command/ItemsCommand.java create mode 100644 common/src/main/java/net/william278/husksync/command/Node.java delete mode 100644 common/src/main/java/net/william278/husksync/command/Permission.java delete mode 100644 common/src/main/java/net/william278/husksync/command/TabCompletable.java create mode 100644 common/src/main/java/net/william278/husksync/command/TabProvider.java delete mode 100644 common/src/main/java/net/william278/husksync/data/AdvancementData.java delete mode 100644 common/src/main/java/net/william278/husksync/data/CompressedDataAdapter.java create mode 100644 common/src/main/java/net/william278/husksync/data/Data.java delete mode 100644 common/src/main/java/net/william278/husksync/data/DataAdapter.java create mode 100644 common/src/main/java/net/william278/husksync/data/DataHolder.java delete mode 100644 common/src/main/java/net/william278/husksync/data/DataSaveCause.java create mode 100644 common/src/main/java/net/william278/husksync/data/DataSnapshot.java create mode 100644 common/src/main/java/net/william278/husksync/data/Identifier.java delete mode 100644 common/src/main/java/net/william278/husksync/data/ItemData.java delete mode 100644 common/src/main/java/net/william278/husksync/data/JsonDataAdapter.java delete mode 100644 common/src/main/java/net/william278/husksync/data/LocationData.java delete mode 100644 common/src/main/java/net/william278/husksync/data/PersistentDataContainerData.java delete mode 100644 common/src/main/java/net/william278/husksync/data/PersistentDataTag.java rename common/src/main/java/net/william278/husksync/data/{PersistentDataTagType.java => Serializer.java} (57%) delete mode 100644 common/src/main/java/net/william278/husksync/data/StatisticsData.java delete mode 100644 common/src/main/java/net/william278/husksync/data/StatusData.java delete mode 100644 common/src/main/java/net/william278/husksync/data/StatusDataFlag.java delete mode 100644 common/src/main/java/net/william278/husksync/data/UserData.java delete mode 100644 common/src/main/java/net/william278/husksync/data/UserDataBuilder.java create mode 100644 common/src/main/java/net/william278/husksync/data/UserDataHolder.java delete mode 100644 common/src/main/java/net/william278/husksync/data/UserDataSnapshot.java rename common/src/main/java/net/william278/husksync/event/{CancellableEvent.java => Cancellable.java} (89%) delete mode 100644 common/src/main/java/net/william278/husksync/event/EventCannon.java create mode 100644 common/src/main/java/net/william278/husksync/event/EventDispatcher.java delete mode 100644 common/src/main/java/net/william278/husksync/hook/PlanDataExtension.java delete mode 100644 common/src/main/java/net/william278/husksync/player/OnlineUser.java rename common/src/main/java/net/william278/husksync/{HuskSyncInitializationException.java => user/CommandUser.java} (59%) rename common/src/main/java/net/william278/husksync/{data/PotionEffectData.java => user/ConsoleUser.java} (62%) create mode 100644 common/src/main/java/net/william278/husksync/user/OnlineUser.java rename common/src/main/java/net/william278/husksync/{player => user}/User.java (72%) create mode 100644 common/src/main/java/net/william278/husksync/util/DataSnapshotOverview.java rename common/src/main/java/net/william278/husksync/{data/DataSerializationException.java => util/LegacyConverter.java} (62%) create mode 100644 common/src/main/java/net/william278/husksync/util/Task.java delete mode 100644 common/src/test/java/net/william278/husksync/DummyHuskSync.java create mode 100644 common/src/test/java/net/william278/husksync/config/LocalesTests.java delete mode 100644 common/src/test/java/net/william278/husksync/data/DataAdaptionTests.java rename common/src/test/java/net/william278/husksync/hook/{PlanHookTests.java => PlanDataExtensionTests.java} (71%) delete mode 100644 common/src/test/java/net/william278/husksync/player/DummyPlayer.java rename docs/{UserData-API.md => API-v2.md} (73%) create mode 100644 docs/Custom-Data-API.md create mode 100644 docs/Data-Snapshot-API.md create mode 100644 test/requirements.txt create mode 100644 test/spin_network.py diff --git a/.gitignore b/.gitignore index 68b6a914..cfbf48c4 100644 --- a/.gitignore +++ b/.gitignore @@ -118,3 +118,8 @@ run/ !gradle-wrapper.jar /build-output-final/ /target/ + +# Don't include generated test suite files +/test/servers/ +/test/HuskSync +/test/config.yml \ No newline at end of file diff --git a/LICENSE b/LICENSE index 7a4a3ea2..8dc622b9 100644 --- a/LICENSE +++ b/LICENSE @@ -16,7 +16,7 @@ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the + "control" means (i) the power, direct or indirect, to saveCause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. @@ -95,7 +95,7 @@ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - (b) You must cause any modified files to carry prominent notices + (b) You must saveCause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works diff --git a/README.md b/README.md index 34ffb477..4fcad8ca 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,12 @@


-**HuskSync** is a modern, cross-server player data synchronisation system that enables the comprehensive synchronisation of your user's data across multiple proxied servers. It does this by making use of Redis and MySQL to optimally cache data while players change servers. +**HuskSync** is a modern, cross-server player data synchronization system that enables the comprehensive synchronization of your user's data across multiple proxied servers. It does this by making use of Redis and MySQL to optimally cache data while players change servers. ## Features -**⭐ Seamless synchronisation** — Utilises optimised Redis caching when players change server to sync player data super quickly for a seamless experience. +**⭐ Seamless synchronization** — Utilises optimised Redis caching when players change server to sync player data super quickly for a seamless experience. -**⭐ Complete player synchronisation** — Sync inventories, Ender Chests, health, hunger, effects, advancements, statistics, locked maps & [more](https://william278.net/docs/husksync/sync-features)—no data left behind! +**⭐ Complete player synchronization** — Sync inventories, Ender Chests, health, hunger, effects, advancements, statistics, locked maps & [more](https://william278.net/docs/husksync/sync-features)—no data left behind! **⭐ Backup, restore & rotate** — Something gone wrong? Restore players back to a previous data state. Rotate and manage data snapshots in-game! diff --git a/build.gradle b/build.gradle index 66d1c5f8..6a385620 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,6 @@ ext { set 'mysql_driver_version', mysql_driver_version.toString() set 'mariadb_driver_version', mariadb_driver_version.toString() set 'snappy_version', snappy_version.toString() - set 'commons_text_version', commons_text_version.toString() } import org.apache.tools.ant.filters.ReplaceTokens @@ -39,16 +38,18 @@ allprojects { mavenLocal() mavenCentral() maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } + maven { url 'https://repo.codemc.io/repository/maven-public/' } maven { url 'https://repo.minebench.de/' } maven { url 'https://repo.alessiodp.com/releases/' } - maven { url 'https://repo.mattstudios.me/artifactory/public/' } maven { url 'https://jitpack.io' } + maven { url 'https://mvn-repo.arim.space/lesser-gpl3/' } maven { url 'https://libraries.minecraft.net/' } - maven { url 'https://william278.net/releases/' } + maven { url 'https://repo.william278.net/releases/' } } dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.0' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' } diff --git a/bukkit/build.gradle b/bukkit/build.gradle index 24b5db59..547a61a6 100644 --- a/bukkit/build.gradle +++ b/bukkit/build.gradle @@ -1,23 +1,27 @@ dependencies { implementation project(path: ':common') + implementation 'org.bstats:bstats-bukkit:3.0.2' implementation 'net.william278:mpdbdataconverter:1.0.1' implementation 'net.william278:hsldataconverter:1.0' - implementation 'net.william278:MapDataAPI:1.0.2' - implementation 'net.william278:AndJam:1.0.2' + implementation 'net.william278:mapdataapi:1.0.3' + implementation 'net.william278:andjam:1.0.2' implementation 'me.lucko:commodore:2.2' implementation 'net.kyori:adventure-platform-bukkit:4.3.0' implementation 'dev.triumphteam:triumph-gui:3.1.5' + implementation 'space.arim.morepaperlib:morepaperlib:0.4.3' + implementation 'de.tr7zw:item-nbt-api:2.12.0-RC1' compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT' compileOnly 'commons-io:commons-io:2.13.0' + compileOnly 'org.json:json:20230618' compileOnly 'de.themoep:minedown-adventure:1.7.2-SNAPSHOT' compileOnly 'dev.dejvokep:boosted-yaml:1.3.1' compileOnly 'com.zaxxer:HikariCP:5.0.1' - compileOnly 'redis.clients:jedis:' + jedis_version compileOnly 'net.william278:DesertWell:2.0.4' - compileOnly 'net.william278:Annotaml:2.0.1' + compileOnly 'net.william278:annotaml:2.0.7' compileOnly 'net.william278:AdvancementAPI:97a9583413' + compileOnly "redis.clients:jedis:$jedis_version" } shadowJar { @@ -26,7 +30,11 @@ shadowJar { } relocate 'org.apache.commons.io', 'net.william278.husksync.libraries.commons.io' + relocate 'org.apache.commons.text', 'net.william278.husksync.libraries.commons.text' + relocate 'org.apache.commons.lang3', 'net.william278.husksync.libraries.commons.lang3' relocate 'com.google.gson', 'net.william278.husksync.libraries.gson' + relocate 'org.json', 'net.william278.husksync.libraries.json' + relocate 'com.fatboyindustrial', 'net.william278.husktowns.libraries' relocate 'de.themoep', 'net.william278.husksync.libraries' relocate 'net.kyori', 'net.william278.husksync.libraries' relocate 'org.jetbrains', 'net.william278.husksync.libraries' @@ -37,7 +45,7 @@ shadowJar { relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown' relocate 'net.william278.mapdataapi', 'net.william278.husksync.libraries.mapdataapi' relocate 'net.william278.andjam', 'net.william278.husksync.libraries.andjam' - relocate 'net.querz', 'net.william278.husksync.libraries.nbt' + relocate 'net.querz', 'net.william278.husksync.libraries.nbtparser' relocate 'net.roxeez', 'net.william278.husksync.libraries' relocate 'me.lucko.commodore', 'net.william278.husksync.libraries.commodore' @@ -47,4 +55,6 @@ shadowJar { relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter' relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter' relocate 'net.william278.annotaml', 'net.william278.husksync.libraries.annotaml' + relocate 'space.arim.morepaperlib', 'net.william278.husksync.libraries.paperlib' + relocate 'de.tr7zw.changeme.nbtapi', 'net.william278.husksync.libraries.nbtapi' } \ No newline at end of file diff --git a/bukkit/src/main/java/net/william278/husksync/BukkitHuskSync.java b/bukkit/src/main/java/net/william278/husksync/BukkitHuskSync.java index e62be5a7..9c9a5a42 100644 --- a/bukkit/src/main/java/net/william278/husksync/BukkitHuskSync.java +++ b/bukkit/src/main/java/net/william278/husksync/BukkitHuskSync.java @@ -19,253 +19,215 @@ package net.william278.husksync; +import com.google.gson.Gson; import net.kyori.adventure.platform.bukkit.BukkitAudiences; -import net.william278.annotaml.Annotaml; import net.william278.desertwell.util.Version; +import net.william278.husksync.adapter.DataAdapter; +import net.william278.husksync.adapter.GsonAdapter; +import net.william278.husksync.adapter.SnappyGsonAdapter; +import net.william278.husksync.api.BukkitHuskSyncAPI; import net.william278.husksync.command.BukkitCommand; -import net.william278.husksync.command.BukkitCommandType; -import net.william278.husksync.command.Permission; import net.william278.husksync.config.Locales; import net.william278.husksync.config.Settings; -import net.william278.husksync.data.CompressedDataAdapter; -import net.william278.husksync.data.DataAdapter; -import net.william278.husksync.data.JsonDataAdapter; +import net.william278.husksync.data.BukkitSerializer; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.Identifier; +import net.william278.husksync.data.Serializer; import net.william278.husksync.database.Database; import net.william278.husksync.database.MySqlDatabase; -import net.william278.husksync.event.BukkitEventCannon; -import net.william278.husksync.event.EventCannon; +import net.william278.husksync.event.BukkitEventDispatcher; import net.william278.husksync.hook.PlanHook; import net.william278.husksync.listener.BukkitEventListener; import net.william278.husksync.listener.EventListener; import net.william278.husksync.migrator.LegacyMigrator; import net.william278.husksync.migrator.Migrator; import net.william278.husksync.migrator.MpdbMigrator; -import net.william278.husksync.player.BukkitPlayer; -import net.william278.husksync.player.OnlineUser; import net.william278.husksync.redis.RedisManager; +import net.william278.husksync.user.BukkitUser; +import net.william278.husksync.user.ConsoleUser; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.util.BukkitLegacyConverter; +import net.william278.husksync.util.BukkitMapPersister; +import net.william278.husksync.util.BukkitTask; +import net.william278.husksync.util.LegacyConverter; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; -import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; -import org.bukkit.permissions.PermissionDefault; -import org.bukkit.plugin.Plugin; +import org.bukkit.map.MapView; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; +import space.arim.morepaperlib.MorePaperLib; +import space.arim.morepaperlib.commands.CommandRegistration; +import space.arim.morepaperlib.scheduling.AsynchronousScheduler; +import space.arim.morepaperlib.scheduling.GracefulScheduling; +import space.arim.morepaperlib.scheduling.RegionalScheduler; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.stream.Collectors; -public class BukkitHuskSync extends JavaPlugin implements HuskSync { +public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.Supplier, BukkitEventDispatcher, + BukkitMapPersister { /** * Metrics ID for HuskSync on Bukkit. */ private static final int METRICS_ID = 13140; + private static final String PLATFORM_TYPE_ID = "bukkit"; + private Database database; private RedisManager redisManager; private EventListener eventListener; private DataAdapter dataAdapter; - private EventCannon eventCannon; + private Map> serializers; + private Map> playerCustomDataStore; private Settings settings; private Locales locales; private List availableMigrators; - + private LegacyConverter legacyConverter; + private Map mapViews; private BukkitAudiences audiences; - private static BukkitHuskSync instance; - - /** - * (Internal use only) Returns the instance of the implementing Bukkit plugin - * - * @return the instance of the Bukkit plugin - */ - public static BukkitHuskSync getInstance() { - return instance; - } - - @Override - public void onLoad() { - instance = this; - } + private MorePaperLib paperLib; + private AsynchronousScheduler asyncScheduler; + private RegionalScheduler regionalScheduler; + private Gson gson; @Override public void onEnable() { - // Initialize HuskSync - final AtomicBoolean initialized = new AtomicBoolean(true); - try { - // Create adventure audience - this.audiences = BukkitAudiences.create(this); - - // Load settings and locales - log(Level.INFO, "Loading plugin configuration settings & locales..."); - initialized.set(reload().join()); - if (initialized.get()) { - log(Level.INFO, "Successfully loaded plugin configuration settings & locales"); - } else { - throw new HuskSyncInitializationException("Failed to load plugin configuration settings and/or locales"); - } - - // Prepare data adapter + // Initial plugin setup + this.gson = createGson(); + this.audiences = BukkitAudiences.create(this); + this.paperLib = new MorePaperLib(this); + this.availableMigrators = new ArrayList<>(); + this.serializers = new LinkedHashMap<>(); + this.playerCustomDataStore = new ConcurrentHashMap<>(); + this.mapViews = new ConcurrentHashMap<>(); + + // Load settings and locales + initialize("plugin config & locale files", (plugin) -> this.loadConfigs()); + + // Prepare data adapter + initialize("data adapter", (plugin) -> { if (settings.doCompressData()) { - dataAdapter = new CompressedDataAdapter(); + dataAdapter = new SnappyGsonAdapter(this); } else { - dataAdapter = new JsonDataAdapter(); + dataAdapter = new GsonAdapter(this); } + }); - // Prepare event cannon - eventCannon = new BukkitEventCannon(); + // Prepare serializers + initialize("data serializers", (plugin) -> { + registerSerializer(Identifier.INVENTORY, new BukkitSerializer.Inventory(this)); + registerSerializer(Identifier.ENDER_CHEST, new BukkitSerializer.EnderChest(this)); + registerSerializer(Identifier.ADVANCEMENTS, new BukkitSerializer.Advancements(this)); + registerSerializer(Identifier.LOCATION, new BukkitSerializer.Location(this)); + registerSerializer(Identifier.HEALTH, new BukkitSerializer.Health(this)); + registerSerializer(Identifier.HUNGER, new BukkitSerializer.Hunger(this)); + registerSerializer(Identifier.GAME_MODE, new BukkitSerializer.GameMode(this)); + registerSerializer(Identifier.POTION_EFFECTS, new BukkitSerializer.PotionEffects(this)); + registerSerializer(Identifier.STATISTICS, new BukkitSerializer.Statistics(this)); + registerSerializer(Identifier.EXPERIENCE, new BukkitSerializer.Experience(this)); + registerSerializer(Identifier.PERSISTENT_DATA, new BukkitSerializer.PersistentData(this)); + }); - // Prepare migrators - availableMigrators = new ArrayList<>(); + // Setup available migrators + initialize("data migrators/converters", (plugin) -> { availableMigrators.add(new LegacyMigrator(this)); - final Plugin mySqlPlayerDataBridge = Bukkit.getPluginManager().getPlugin("MySqlPlayerDataBridge"); - if (mySqlPlayerDataBridge != null) { - availableMigrators.add(new MpdbMigrator(this, mySqlPlayerDataBridge)); + if (isDependencyLoaded("MySqlPlayerDataBridge")) { + availableMigrators.add(new MpdbMigrator(this)); } + legacyConverter = new BukkitLegacyConverter(this); + }); - // Prepare database connection + // Initialize the database + initialize(getSettings().getDatabaseType().getDisplayName() + " database connection", (plugin) -> { this.database = new MySqlDatabase(this); - log(Level.INFO, String.format("Attempting to establish connection to the %s database...", - settings.getDatabaseType().getDisplayName())); this.database.initialize(); - if (initialized.get()) { - log(Level.INFO, String.format("Successfully established a connection to the %s database", - settings.getDatabaseType().getDisplayName())); - } else { - throw new HuskSyncInitializationException("Failed to establish a connection to the database. " + - "Please check the supplied database credentials in the config file"); - } + }); - // Prepare redis connection + // Prepare redis connection + initialize("Redis server connection", (plugin) -> { this.redisManager = new RedisManager(this); - log(Level.INFO, "Attempting to establish connection to the Redis server..."); - initialized.set(this.redisManager.initialize()); - if (initialized.get()) { - log(Level.INFO, "Successfully established a connection to the Redis server"); - } else { - throw new HuskSyncInitializationException("Failed to establish a connection to the Redis server. " + - "Please check the supplied Redis credentials in the config file"); - } + this.redisManager.initialize(); + }); - // Register events - log(Level.INFO, "Registering events..."); - this.eventListener = new BukkitEventListener(this); - log(Level.INFO, "Successfully registered events listener"); - - // Register permissions - log(Level.INFO, "Registering permissions & commands..."); - Arrays.stream(Permission.values()).forEach(permission -> getServer().getPluginManager() - .addPermission(new org.bukkit.permissions.Permission(permission.node, switch (permission.defaultAccess) { - case EVERYONE -> PermissionDefault.TRUE; - case NOBODY -> PermissionDefault.FALSE; - case OPERATORS -> PermissionDefault.OP; - }))); - - // Register commands - for (final BukkitCommandType bukkitCommandType : BukkitCommandType.values()) { - final PluginCommand pluginCommand = getCommand(bukkitCommandType.commandBase.command); - if (pluginCommand != null) { - new BukkitCommand(bukkitCommandType.commandBase, this).register(pluginCommand); - } - } - log(Level.INFO, "Successfully registered permissions & commands"); + // Register events + initialize("events", (plugin) -> this.eventListener = new BukkitEventListener(this)); - // Hook into plan - if (Bukkit.getPluginManager().getPlugin("Plan") != null) { - log(Level.INFO, "Enabling Plan integration..."); + // Register commands + initialize("commands", (plugin) -> BukkitCommand.Type.registerCommands(this)); + + // Register plugin hooks + initialize("hooks", (plugin) -> { + if (isDependencyLoaded("Plan") && getSettings().usePlanHook()) { new PlanHook(this).hookIntoPlan(); - log(Level.INFO, "Plan integration enabled!"); } + }); - // Hook into bStats metrics - try { - new Metrics(this, METRICS_ID); - } catch (final Exception e) { - log(Level.WARNING, "Skipped bStats metrics initialization due to an exception."); - } + // Register API + initialize("api", (plugin) -> BukkitHuskSyncAPI.register(this)); - // Check for updates - if (settings.doCheckForUpdates()) { - log(Level.INFO, "Checking for updates..."); - getLatestVersionIfOutdated().thenAccept(newestVersion -> - newestVersion.ifPresent(newVersion -> log(Level.WARNING, - "An update is available for HuskSync, v" + newVersion - + " (Currently running v" + getPluginVersion() + ")"))); - } - } catch (IllegalStateException exception) { - log(Level.SEVERE, """ - *************************************************** - - Failed to initialize HuskSync! - - *************************************************** - The plugin was disabled due to an error. Please check - the logs below for details. - No user data will be synchronised. - *************************************************** - Caused by: %error_message% - """ - .replaceAll("%error_message%", exception.getMessage())); - initialized.set(false); - } catch (Exception exception) { - log(Level.SEVERE, "An unhandled exception occurred initializing HuskSync!", exception); - initialized.set(false); - } finally { - // Validate initialization - if (initialized.get()) { - log(Level.INFO, "Successfully enabled HuskSync v" + getPluginVersion()); - } else { - log(Level.SEVERE, "Failed to initialize HuskSync. The plugin will now be disabled"); - getServer().getPluginManager().disablePlugin(this); - } - } + // Hook into bStats and check for updates + initialize("metrics", (plugin) -> this.registerMetrics(METRICS_ID)); + this.checkForUpdates(); } @Override public void onDisable() { + // Handle shutdown if (this.eventListener != null) { this.eventListener.handlePluginDisable(); } + + // Unregister API and cancel tasks + BukkitHuskSyncAPI.unregister(); + this.cancelTasks(); + + // Complete shutdown log(Level.INFO, "Successfully disabled HuskSync v" + getPluginVersion()); } @Override - public @NotNull Set getOnlineUsers() { - return Bukkit.getOnlinePlayers().stream().map(BukkitPlayer::adapt).collect(Collectors.toSet()); + @NotNull + public Set getOnlineUsers() { + return Bukkit.getOnlinePlayers().stream() + .map(player -> BukkitUser.adapt(player, this)) + .collect(Collectors.toSet()); } @Override - public @NotNull Optional getOnlineUser(@NotNull UUID uuid) { + @NotNull + public Optional getOnlineUser(@NotNull UUID uuid) { final Player player = Bukkit.getPlayer(uuid); if (player == null) { return Optional.empty(); } - return Optional.of(BukkitPlayer.adapt(player)); + return Optional.of(BukkitUser.adapt(player, this)); } @Override - public @NotNull Database getDatabase() { + @NotNull + public Database getDatabase() { return database; } @Override - public @NotNull RedisManager getRedisManager() { + @NotNull + public RedisManager getRedisManager() { return redisManager; } + @NotNull @Override - public @NotNull DataAdapter getDataAdapter() { + public DataAdapter getDataAdapter() { return dataAdapter; } + @NotNull @Override - public @NotNull EventCannon getEventCannon() { - return eventCannon; + public Map> getSerializers() { + return serializers; } @NotNull @@ -274,16 +236,57 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync { return availableMigrators; } + @NotNull @Override - public @NotNull Settings getSettings() { + public Map getPlayerCustomDataStore(@NotNull OnlineUser user) { + if (playerCustomDataStore.containsKey(user.getUuid())) { + return playerCustomDataStore.get(user.getUuid()); + } + final Map data = new HashMap<>(); + playerCustomDataStore.put(user.getUuid(), data); + return data; + } + + @Override + @NotNull + public Settings getSettings() { return settings; } @Override - public @NotNull Locales getLocales() { + public void setSettings(@NotNull Settings settings) { + this.settings = settings; + } + + @Override + @NotNull + public Locales getLocales() { return locales; } + @Override + public void setLocales(@NotNull Locales locales) { + this.locales = locales; + } + + @Override + public boolean isDependencyLoaded(@NotNull String name) { + return Bukkit.getPluginManager().getPlugin(name) != null; + } + + // Register bStats metrics + public void registerMetrics(int metricsId) { + if (!getPluginVersion().getMetadata().isBlank()) { + return; + } + + try { + new Metrics(this, metricsId); + } catch (Throwable e) { + log(Level.WARNING, "Failed to register bStats metrics (" + e.getMessage() + ")"); + } + } + @Override public void log(@NotNull Level level, @NotNull String message, @NotNull Throwable... throwable) { if (throwable.length > 0) { @@ -293,6 +296,12 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync { } } + @NotNull + @Override + public ConsoleUser getConsole() { + return new ConsoleUser(audiences.console()); + } + @NotNull @Override public Version getPluginVersion() { @@ -305,39 +314,65 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync { return Version.fromString(Bukkit.getBukkitVersion()); } - /** - * Returns the adventure Bukkit audiences - * - * @return The adventure Bukkit audiences - */ @NotNull - public BukkitAudiences getAudiences() { - return audiences; + @Override + public String getPlatformType() { + return PLATFORM_TYPE_ID; + } + + @Override + public Optional getLegacyConverter() { + return Optional.of(legacyConverter); } + @NotNull @Override public Set getLockedPlayers() { return this.eventListener.getLockedPlayers(); } + @NotNull @Override - public CompletableFuture reload() { - return CompletableFuture.supplyAsync(() -> { - try { - // Load plugin settings - this.settings = Annotaml.create(new File(getDataFolder(), "config.yml"), new Settings()).get(); - - // Load locales from language preset default - final Locales languagePresets = Annotaml.create(Locales.class, - Objects.requireNonNull(getResource("locales/" + settings.getLanguage() + ".yml"))).get(); - this.locales = Annotaml.create(new File(getDataFolder(), "messages_" + settings.getLanguage() + ".yml"), - languagePresets).get(); - return true; - } catch (IOException | NullPointerException | InvocationTargetException | IllegalAccessException | - InstantiationException e) { - log(Level.SEVERE, "Failed to load data from the config", e); - return false; - } - }); + public Gson getGson() { + return gson; } + + @NotNull + public Map getMapViews() { + return mapViews; + } + + @NotNull + public GracefulScheduling getScheduler() { + return paperLib.scheduling(); + } + + @NotNull + public AsynchronousScheduler getAsyncScheduler() { + return asyncScheduler == null + ? asyncScheduler = getScheduler().asyncScheduler() : asyncScheduler; + } + + @NotNull + public RegionalScheduler getRegionalScheduler() { + return regionalScheduler == null + ? regionalScheduler = getScheduler().globalRegionalScheduler() : regionalScheduler; + } + + @NotNull + public BukkitAudiences getAudiences() { + return audiences; + } + + @NotNull + public CommandRegistration getCommandRegistrar() { + return paperLib.commandRegistration(); + } + + @Override + @NotNull + public HuskSync getPlugin() { + return this; + } + } diff --git a/bukkit/src/main/java/net/william278/husksync/api/BukkitHuskSyncAPI.java b/bukkit/src/main/java/net/william278/husksync/api/BukkitHuskSyncAPI.java new file mode 100644 index 00000000..6abf75c0 --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/api/BukkitHuskSyncAPI.java @@ -0,0 +1,270 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.api; + +import net.william278.desertwell.util.ThrowingConsumer; +import net.william278.husksync.BukkitHuskSync; +import net.william278.husksync.data.BukkitData; +import net.william278.husksync.data.DataHolder; +import net.william278.husksync.user.BukkitUser; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.user.User; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +/** + * The HuskSync API implementation for the Bukkit platform + *

+ * Retrieve an instance of the API class via {@link #getInstance()}. + */ +@SuppressWarnings("unused") +public class BukkitHuskSyncAPI extends HuskSyncAPI { + + // Instance of the plugin + private static BukkitHuskSyncAPI instance; + + /** + * (Internal use only) - Constructor, instantiating the API. + */ + @ApiStatus.Internal + private BukkitHuskSyncAPI(@NotNull BukkitHuskSync plugin) { + super(plugin); + } + + /** + * Entrypoint to the HuskSync API - returns an instance of the API + * + * @return instance of the HuskSync API + * @since 3.0 + */ + @NotNull + public static BukkitHuskSyncAPI getInstance() { + if (instance == null) { + throw new NotRegisteredException(); + } + return instance; + } + + /** + * (Internal use only) - Register the API for this platform. + * + * @param plugin the plugin instance + * @since 3.0 + */ + @ApiStatus.Internal + public static void register(@NotNull BukkitHuskSync plugin) { + instance = new BukkitHuskSyncAPI(plugin); + } + + /** + * (Internal use only) - Unregister the API for this platform. + */ + @ApiStatus.Internal + public static void unregister() { + instance = null; + } + + /** + * Returns a {@link OnlineUser} instance for the given bukkit {@link Player}. + * + * @param player the bukkit player to get the {@link OnlineUser} instance for + * @return the {@link OnlineUser} instance for the given bukkit {@link Player} + * @since 2.0 + */ + @NotNull + public BukkitUser getUser(@NotNull Player player) { + return BukkitUser.adapt(player, plugin); + } + + /** + * Get the current {@link BukkitData.Items.Inventory} of the given {@link User} + * + * @param user the user to get the inventory of + * @return the {@link BukkitData.Items.Inventory} of the given {@link User} + * @since 3.0 + */ + public CompletableFuture> getCurrentInventory(@NotNull User user) { + return getCurrentData(user).thenApply(data -> data.flatMap(DataHolder::getInventory) + .map(BukkitData.Items.Inventory.class::cast)); + } + + /** + * Get the current {@link BukkitData.Items.Inventory} of the given {@link Player} + * + * @param user the user to get the inventory of + * @return the {@link BukkitData.Items.Inventory} of the given {@link Player} + * @since 3.0 + */ + public CompletableFuture> getCurrentInventoryContents(@NotNull User user) { + return getCurrentInventory(user) + .thenApply(inventory -> inventory.map(BukkitData.Items.Inventory::getContents)); + } + + /** + * Set the current {@link BukkitData.Items.Inventory} of the given {@link User} + * + * @param user the user to set the inventory of + * @param contents the contents to set the inventory to + * @since 3.0 + */ + public void setCurrentInventory(@NotNull User user, @NotNull BukkitData.Items.Inventory contents) { + editCurrentData(user, dataHolder -> dataHolder.setInventory(contents)); + } + + /** + * Set the current {@link BukkitData.Items.Inventory} of the given {@link User} + * + * @param user the user to set the inventory of + * @param contents the contents to set the inventory to + * @since 3.0 + */ + public void setCurrentInventoryContents(@NotNull User user, @NotNull ItemStack[] contents) { + editCurrentData( + user, + dataHolder -> dataHolder.getInventory().ifPresent( + inv -> inv.setContents(adaptItems(contents)) + ) + ); + } + + /** + * Edit the current {@link BukkitData.Items.Inventory} of the given {@link User} + * + * @param user the user to edit the inventory of + * @param editor the editor to apply to the inventory + * @since 3.0 + */ + public void editCurrentInventory(@NotNull User user, ThrowingConsumer editor) { + editCurrentData(user, dataHolder -> dataHolder.getInventory() + .map(BukkitData.Items.Inventory.class::cast) + .ifPresent(editor)); + } + + /** + * Edit the current {@link BukkitData.Items.Inventory} of the given {@link User} + * + * @param user the user to edit the inventory of + * @param editor the editor to apply to the inventory + * @since 3.0 + */ + public void editCurrentInventoryContents(@NotNull User user, ThrowingConsumer editor) { + editCurrentData(user, dataHolder -> dataHolder.getInventory() + .map(BukkitData.Items.Inventory.class::cast) + .ifPresent(inventory -> editor.accept(inventory.getContents()))); + } + + /** + * Get the current {@link BukkitData.Items.EnderChest} of the given {@link User} + * + * @param user the user to get the ender chest of + * @return the {@link BukkitData.Items.EnderChest} of the given {@link User}, or {@link Optional#empty()} if the + * user data could not be found + * @since 3.0 + */ + public CompletableFuture> getCurrentEnderChest(@NotNull User user) { + return getCurrentData(user).thenApply(data -> data.flatMap(DataHolder::getEnderChest) + .map(BukkitData.Items.EnderChest.class::cast)); + } + + /** + * Get the current {@link BukkitData.Items.EnderChest} of the given {@link Player} + * + * @param user the user to get the ender chest of + * @return the {@link BukkitData.Items.EnderChest} of the given {@link Player}, or {@link Optional#empty()} if the + * user data could not be found + * @since 3.0 + */ + public CompletableFuture> getCurrentEnderChestContents(@NotNull User user) { + return getCurrentEnderChest(user) + .thenApply(enderChest -> enderChest.map(BukkitData.Items.EnderChest::getContents)); + } + + /** + * Set the current {@link BukkitData.Items.EnderChest} of the given {@link User} + * + * @param user the user to set the ender chest of + * @param contents the contents to set the ender chest to + * @since 3.0 + */ + public void setCurrentEnderChest(@NotNull User user, @NotNull BukkitData.Items.EnderChest contents) { + editCurrentData(user, dataHolder -> dataHolder.setEnderChest(contents)); + } + + /** + * Set the current {@link BukkitData.Items.EnderChest} of the given {@link User} + * + * @param user the user to set the ender chest of + * @param contents the contents to set the ender chest to + * @since 3.0 + */ + public void setCurrentEnderChestContents(@NotNull User user, @NotNull ItemStack[] contents) { + editCurrentData( + user, + dataHolder -> dataHolder.getEnderChest().ifPresent( + enderChest -> enderChest.setContents(adaptItems(contents)) + ) + ); + } + + /** + * Edit the current {@link BukkitData.Items.EnderChest} of the given {@link User} + * + * @param user the user to edit the ender chest of + * @param editor the editor to apply to the ender chest + * @since 3.0 + */ + public void editCurrentEnderChest(@NotNull User user, Consumer editor) { + editCurrentData(user, dataHolder -> dataHolder.getEnderChest() + .map(BukkitData.Items.EnderChest.class::cast) + .ifPresent(editor)); + } + + /** + * Edit the current {@link BukkitData.Items.EnderChest} of the given {@link User} + * + * @param user the user to edit the ender chest of + * @param editor the editor to apply to the ender chest + * @since 3.0 + */ + public void editCurrentEnderChestContents(@NotNull User user, Consumer editor) { + editCurrentData(user, dataHolder -> dataHolder.getEnderChest() + .map(BukkitData.Items.EnderChest.class::cast) + .ifPresent(enderChest -> editor.accept(enderChest.getContents()))); + } + + /** + * Adapts an array of {@link ItemStack} to a {@link BukkitData.Items} instance + * + * @param contents the contents to adapt + * @return the adapted {@link BukkitData.Items} instance + * @since 3.0 + */ + @NotNull + public BukkitData.Items adaptItems(@NotNull ItemStack[] contents) { + return BukkitData.Items.ItemArray.adapt(contents); + } + +} diff --git a/bukkit/src/main/java/net/william278/husksync/api/HuskSyncAPI.java b/bukkit/src/main/java/net/william278/husksync/api/HuskSyncAPI.java deleted file mode 100644 index 0b5f7116..00000000 --- a/bukkit/src/main/java/net/william278/husksync/api/HuskSyncAPI.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.api; - -import net.william278.husksync.BukkitHuskSync; -import net.william278.husksync.data.*; -import net.william278.husksync.player.BukkitPlayer; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; - -import java.util.Optional; -import java.util.concurrent.CompletableFuture; - -/** - * The HuskSync API implementation for the Bukkit platform, providing methods to access and modify player {@link UserData} held by {@link User}s. - *

- * Retrieve an instance of the API class via {@link #getInstance()}. - */ -@SuppressWarnings("unused") -public class HuskSyncAPI extends BaseHuskSyncAPI { - - /** - * (Internal use only) - Instance of the API class - */ - private static final HuskSyncAPI INSTANCE = new HuskSyncAPI(); - - /** - * (Internal use only) - Constructor, instantiating the API - */ - private HuskSyncAPI() { - super(BukkitHuskSync.getInstance()); - } - - /** - * Entrypoint to the HuskSync API - returns an instance of the API - * - * @return instance of the HuskSync API - */ - public static @NotNull HuskSyncAPI getInstance() { - return INSTANCE; - } - - /** - * Returns a {@link User} instance for the given bukkit {@link Player}. - * - * @param player the bukkit player to get the {@link User} instance for - * @return the {@link User} instance for the given bukkit {@link Player} - * @since 2.0 - */ - @NotNull - public OnlineUser getUser(@NotNull Player player) { - return BukkitPlayer.adapt(player); - } - - /** - * Set the inventory in the database of the given {@link User} to the given {@link ItemStack} contents - * - * @param user the {@link User} to set the inventory of - * @param inventoryContents the {@link ItemStack} contents to set the inventory to - * @return future returning void when complete - * @since 2.0 - */ - public CompletableFuture setInventoryData(@NotNull User user, @NotNull ItemStack[] inventoryContents) { - return CompletableFuture.runAsync(() -> getUserData(user).thenAccept(userData -> - userData.ifPresent(data -> serializeItemStackArray(inventoryContents) - .thenAccept(serializedInventory -> { - data.getInventory().orElse(ItemData.empty()).serializedItems = serializedInventory; - setUserData(user, data).join(); - })))); - } - - /** - * Set the inventory in the database of the given {@link User} to the given {@link BukkitInventoryMap} contents - * - * @param user the {@link User} to set the inventory of - * @param inventoryMap the {@link BukkitInventoryMap} contents to set the inventory to - * @return future returning void when complete - * @since 2.0 - */ - public CompletableFuture setInventoryData(@NotNull User user, @NotNull BukkitInventoryMap inventoryMap) { - return setInventoryData(user, inventoryMap.getContents()); - } - - /** - * Set the Ender Chest in the database of the given {@link User} to the given {@link ItemStack} contents - * - * @param user the {@link User} to set the Ender Chest of - * @param enderChestContents the {@link ItemStack} contents to set the Ender Chest to - * @return future returning void when complete - * @since 2.0 - */ - public CompletableFuture setEnderChestData(@NotNull User user, @NotNull ItemStack[] enderChestContents) { - return CompletableFuture.runAsync(() -> getUserData(user).thenAccept(userData -> - userData.ifPresent(data -> serializeItemStackArray(enderChestContents) - .thenAccept(serializedInventory -> { - data.getEnderChest().orElse(ItemData.empty()).serializedItems = serializedInventory; - setUserData(user, data).join(); - })))); - } - - /** - * Returns a {@link BukkitInventoryMap} for the given {@link User}, containing their current inventory item data - * - * @param user the {@link User} to get the {@link BukkitInventoryMap} for - * @return future returning the {@link BukkitInventoryMap} for the given {@link User} if they exist, - * otherwise an empty {@link Optional} - * @apiNote If the {@link UserData} does not contain an inventory (i.e. inventory synchronisation is disabled), the - * returned {@link BukkitInventoryMap} will be equivalent an empty inventory. - * @since 2.0 - */ - public CompletableFuture> getPlayerInventory(@NotNull User user) { - return CompletableFuture.supplyAsync(() -> getUserData(user).join() - .map(userData -> deserializeInventory(userData.getInventory() - .orElse(ItemData.empty()).serializedItems).join())); - } - - /** - * Returns the {@link ItemStack}s array contents of the given {@link User}'s Ender Chest data - * - * @param user the {@link User} to get the Ender Chest contents of - * @return future returning the {@link ItemStack} array of Ender Chest items for the user if they exist, - * otherwise an empty {@link Optional} - * @apiNote If the {@link UserData} does not contain an Ender Chest (i.e. Ender Chest synchronisation is disabled), - * the returned {@link BukkitInventoryMap} will be equivalent to an empty inventory. - * @since 2.0 - */ - public CompletableFuture> getPlayerEnderChest(@NotNull User user) { - return CompletableFuture.supplyAsync(() -> getUserData(user).join() - .map(userData -> deserializeItemStackArray(userData.getEnderChest() - .orElse(ItemData.empty()).serializedItems).join())); - } - - /** - * Deserialize a Base-64 encoded inventory array string into a {@link ItemStack} array. - * - * @param serializedItemStackArray The Base-64 encoded inventory array string. - * @return The deserialized {@link ItemStack} array. - * @throws DataSerializationException If an error occurs during deserialization. - * @since 2.0 - */ - public CompletableFuture deserializeItemStackArray(@NotNull String serializedItemStackArray) - throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> BukkitSerializer - .deserializeItemStackArray(serializedItemStackArray).join()); - } - - /** - * Deserialize a serialized {@link ItemStack} array of player inventory contents into a {@link BukkitInventoryMap} - * - * @param serializedInventory The serialized {@link ItemStack} array of player inventory contents. - * @return A {@link BukkitInventoryMap} of the deserialized {@link ItemStack} contents array - * @throws DataSerializationException If an error occurs during deserialization. - * @since 2.0 - */ - public CompletableFuture deserializeInventory(@NotNull String serializedInventory) - throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> BukkitSerializer - .deserializeInventory(serializedInventory).join()); - } - - /** - * Serialize an {@link ItemStack} array into a Base-64 encoded string. - * - * @param itemStacks The {@link ItemStack} array to serialize. - * @return The serialized Base-64 encoded string. - * @throws DataSerializationException If an error occurs during serialization. - * @see #deserializeItemStackArray(String) - * @see ItemData - * @since 2.0 - */ - public CompletableFuture serializeItemStackArray(@NotNull ItemStack[] itemStacks) - throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> BukkitSerializer.serializeItemStackArray(itemStacks).join()); - } - - /** - * Deserialize a Base-64 encoded potion effect array string into a {@link PotionEffect} array. - * - * @param serializedPotionEffectArray The Base-64 encoded potion effect array string. - * @return The deserialized {@link PotionEffect} array. - * @throws DataSerializationException If an error occurs during deserialization. - * @since 2.0 - */ - public CompletableFuture deserializePotionEffectArray(@NotNull String serializedPotionEffectArray) - throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> BukkitSerializer - .deserializePotionEffectArray(serializedPotionEffectArray).join()); - } - - /** - * Serialize a {@link PotionEffect} array into a Base-64 encoded string. - * - * @param potionEffects The {@link PotionEffect} array to serialize. - * @return The serialized Base-64 encoded string. - * @throws DataSerializationException If an error occurs during serialization. - * @see #deserializePotionEffectArray(String) - * @see PotionEffectData - * @since 2.0 - */ - public CompletableFuture serializePotionEffectArray(@NotNull PotionEffect[] potionEffects) - throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> BukkitSerializer.serializePotionEffectArray(potionEffects).join()); - } - -} diff --git a/bukkit/src/main/java/net/william278/husksync/command/BrigadierUtil.java b/bukkit/src/main/java/net/william278/husksync/command/BrigadierUtil.java index fbac0c9d..8b35ac38 100644 --- a/bukkit/src/main/java/net/william278/husksync/command/BrigadierUtil.java +++ b/bukkit/src/main/java/net/william278/husksync/command/BrigadierUtil.java @@ -22,28 +22,38 @@ package net.william278.husksync.command; import me.lucko.commodore.CommodoreProvider; import me.lucko.commodore.file.CommodoreFileReader; import net.william278.husksync.BukkitHuskSync; -import org.bukkit.command.PluginCommand; import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.io.InputStream; import java.util.logging.Level; -/** - * Used for registering Brigadier hooks on platforms that support commodore for rich command syntax - */ public class BrigadierUtil { - protected static void registerCommodore(@NotNull BukkitHuskSync plugin, @NotNull PluginCommand pluginCommand, - @NotNull CommandBase command) { - // Register command descriptions via commodore (brigadier wrapper) - try (InputStream pluginFile = plugin.getResource("commodore/" + command.command + ".commodore")) { - CommodoreProvider.getCommodore(plugin).register(pluginCommand, - CommodoreFileReader.INSTANCE.parse(pluginFile), - player -> player.hasPermission(command.permission)); + /** + * Uses commodore to register command completions. + * + * @param plugin instance of the registering Bukkit plugin + * @param bukkitCommand the Bukkit PluginCommand to register completions for + * @param command the {@link Command} to register completions for + */ + protected static void registerCommodore(@NotNull BukkitHuskSync plugin, + @NotNull org.bukkit.command.Command bukkitCommand, + @NotNull Command command) { + final InputStream commodoreFile = plugin.getResource( + "commodore/" + bukkitCommand.getName() + ".commodore" + ); + if (commodoreFile == null) { + return; + } + try { + CommodoreProvider.getCommodore(plugin).register(bukkitCommand, + CommodoreFileReader.INSTANCE.parse(commodoreFile), + player -> player.hasPermission(command.getPermission())); } catch (IOException e) { - plugin.log(Level.SEVERE, - "Failed to load " + command.command + ".commodore command definitions", e); + plugin.log(Level.SEVERE, String.format( + "Failed to read command commodore completions for %s", bukkitCommand.getName()), e + ); } } diff --git a/bukkit/src/main/java/net/william278/husksync/command/BukkitCommand.java b/bukkit/src/main/java/net/william278/husksync/command/BukkitCommand.java index 178ac885..5229d11b 100644 --- a/bukkit/src/main/java/net/william278/husksync/command/BukkitCommand.java +++ b/bukkit/src/main/java/net/william278/husksync/command/BukkitCommand.java @@ -19,77 +19,146 @@ package net.william278.husksync.command; + import me.lucko.commodore.CommodoreProvider; import net.william278.husksync.BukkitHuskSync; -import net.william278.husksync.player.BukkitPlayer; -import org.bukkit.command.*; +import net.william278.husksync.user.BukkitUser; +import net.william278.husksync.user.CommandUser; +import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; +import org.bukkit.plugin.PluginManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.List; - -/** - * Bukkit executor that implements and executes {@link CommandBase}s - */ -public class BukkitCommand implements CommandExecutor, TabExecutor { +import java.util.*; +import java.util.function.Function; - /** - * The {@link CommandBase} that will be executed - */ - protected final CommandBase command; +public class BukkitCommand extends org.bukkit.command.Command { - /** - * The implementing plugin - */ private final BukkitHuskSync plugin; + private final Command command; - public BukkitCommand(@NotNull CommandBase command, @NotNull BukkitHuskSync implementor) { + public BukkitCommand(@NotNull Command command, @NotNull BukkitHuskSync plugin) { + super(command.getName(), command.getDescription(), command.getUsage(), command.getAliases()); this.command = command; - this.plugin = implementor; + this.plugin = plugin; } - /** - * Registers a {@link PluginCommand} to this implementation - * - * @param pluginCommand {@link PluginCommand} to register - */ - public void register(@NotNull PluginCommand pluginCommand) { - pluginCommand.setExecutor(this); - pluginCommand.setTabCompleter(this); - pluginCommand.setPermission(command.permission); - pluginCommand.setDescription(command.getDescription()); - if (CommodoreProvider.isSupported()) { - BrigadierUtil.registerCommodore(plugin, pluginCommand, command); - } + @Override + public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { + this.command.onExecuted(sender instanceof Player p ? BukkitUser.adapt(p, plugin) : plugin.getConsole(), args); + return true; } + @NotNull @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, - @NotNull String label, @NotNull String[] args) { - if (sender instanceof Player player) { - this.command.onExecute(BukkitPlayer.adapt(player), args); - } else { - if (this.command instanceof ConsoleExecutable consoleExecutable) { - consoleExecutable.onConsoleExecute(args); - } else { - plugin.getLocales().getLocale("error_in_game_command_only") - .ifPresent(locale -> plugin.getAudiences().sender(sender) - .sendMessage(locale.toComponent())); - } + public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, + @NotNull String[] args) throws IllegalArgumentException { + if (!(this.command instanceof TabProvider provider)) { + return List.of(); + } + final CommandUser user = sender instanceof Player p ? BukkitUser.adapt(p, plugin) : plugin.getConsole(); + if (getPermission() == null || user.hasPermission(getPermission())) { + return provider.getSuggestions(user, args); + } + return List.of(); + } + + public void register() { + // Register with bukkit + plugin.getCommandRegistrar().getServerCommandMap().register("husksync", this); + + // Register permissions + BukkitCommand.addPermission( + plugin, + command.getPermission(), + command.getUsage(), + BukkitCommand.getPermissionDefault(command.isOperatorCommand()) + ); + final List childNodes = command.getAdditionalPermissions() + .entrySet().stream() + .map((entry) -> BukkitCommand.addPermission( + plugin, + entry.getKey(), + "", + BukkitCommand.getPermissionDefault(entry.getValue())) + ) + .filter(Objects::nonNull) + .toList(); + if (!childNodes.isEmpty()) { + BukkitCommand.addPermission( + plugin, + command.getPermission("*"), + command.getUsage(), + PermissionDefault.FALSE, + childNodes.toArray(new Permission[0]) + ); + } + + // Register commodore TAB completion + if (CommodoreProvider.isSupported() && plugin.getSettings().doBrigadierTabCompletion()) { + BrigadierUtil.registerCommodore(plugin, this, command); } - return true; } @Nullable - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, - @NotNull String alias, @NotNull String[] args) { - if (this.command instanceof TabCompletable tabCompletable) { - return tabCompletable.onTabComplete(args); + protected static Permission addPermission(@NotNull BukkitHuskSync plugin, @NotNull String node, + @NotNull String description, @NotNull PermissionDefault permissionDefault, + @NotNull Permission... children) { + final Map childNodes = Arrays.stream(children) + .map(Permission::getName) + .collect(HashMap::new, (map, child) -> map.put(child, true), HashMap::putAll); + + final PluginManager manager = plugin.getServer().getPluginManager(); + if (manager.getPermission(node) != null) { + return null; + } + + Permission permission; + if (description.isEmpty()) { + permission = new Permission(node, permissionDefault, childNodes); + } else { + permission = new Permission(node, description, permissionDefault, childNodes); } - return Collections.emptyList(); + manager.addPermission(permission); + + return permission; } + @NotNull + protected static PermissionDefault getPermissionDefault(boolean isOperatorCommand) { + return isOperatorCommand ? PermissionDefault.OP : PermissionDefault.TRUE; + } + + /** + * Commands available on the Bukkit HuskSync implementation + */ + public enum Type { + + HUSKSYNC_COMMAND(HuskSyncCommand::new), + USERDATA_COMMAND(UserDataCommand::new), + INVENTORY_COMMAND(InventoryCommand::new), + ENDER_CHEST_COMMAND(EnderChestCommand::new); + + public final Function commandSupplier; + + Type(@NotNull Function supplier) { + this.commandSupplier = supplier; + } + + @NotNull + public Command createCommand(@NotNull BukkitHuskSync plugin) { + return commandSupplier.apply(plugin); + } + + public static void registerCommands(@NotNull BukkitHuskSync plugin) { + Arrays.stream(values()) + .map((type) -> type.createCommand(plugin)) + .forEach((command) -> new BukkitCommand(command, plugin).register()); + } + + + } } diff --git a/bukkit/src/main/java/net/william278/husksync/command/BukkitCommandType.java b/bukkit/src/main/java/net/william278/husksync/command/BukkitCommandType.java deleted file mode 100644 index a69e0229..00000000 --- a/bukkit/src/main/java/net/william278/husksync/command/BukkitCommandType.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.command; - -import net.william278.husksync.BukkitHuskSync; -import org.jetbrains.annotations.NotNull; - -/** - * Commands available on the Bukkit HuskSync implementation - */ -public enum BukkitCommandType { - - HUSKSYNC_COMMAND(new HuskSyncCommand(BukkitHuskSync.getInstance())), - USERDATA_COMMAND(new UserDataCommand(BukkitHuskSync.getInstance())), - INVENTORY_COMMAND(new InventoryCommand(BukkitHuskSync.getInstance())), - ENDER_CHEST_COMMAND(new EnderChestCommand(BukkitHuskSync.getInstance())); - - public final CommandBase commandBase; - - BukkitCommandType(@NotNull CommandBase commandBase) { - this.commandBase = commandBase; - } -} diff --git a/bukkit/src/main/java/net/william278/husksync/data/BukkitData.java b/bukkit/src/main/java/net/william278/husksync/data/BukkitData.java new file mode 100644 index 00000000..7416306f --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/data/BukkitData.java @@ -0,0 +1,1093 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.data; + +import com.google.gson.annotations.SerializedName; +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.NBTPersistentDataContainer; +import net.william278.desertwell.util.ThrowingConsumer; +import net.william278.husksync.BukkitHuskSync; +import net.william278.husksync.HuskSync; +import net.william278.husksync.adapter.Adaptable; +import net.william278.husksync.user.BukkitUser; +import org.apache.commons.lang.NotImplementedException; +import org.bukkit.Bukkit; +import org.bukkit.GameRule; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.advancement.AdvancementProgress; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.logging.Level; +import java.util.stream.Collectors; + +public abstract class BukkitData implements Data { + + @Override + public final void apply(@NotNull UserDataHolder dataHolder, @NotNull HuskSync plugin) { + final BukkitUser user = (BukkitUser) dataHolder; + try { + this.apply(user, (BukkitHuskSync) plugin); + } catch (Throwable e) { + plugin.log(Level.WARNING, String.format("[%s] Failed to apply %s data object; skipping", + user.getUsername(), this.getClass().getSimpleName()), e); + } + } + + public abstract void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException; + + public static abstract class Items extends BukkitData implements Data.Items { + + private final ItemStack[] contents; + + private Items(@NotNull ItemStack[] contents) { + this.contents = Arrays.stream(contents) + .map(i -> i == null || i.getType() == Material.AIR ? null : i) + .toArray(ItemStack[]::new); + } + + @NotNull + @Override + public Stack[] getStack() { + return Arrays.stream(contents) + .map(stack -> stack != null ? new Stack( + stack.getType().getKey().toString(), + stack.getAmount(), + stack.hasItemMeta() ? (Objects.requireNonNull( + stack.getItemMeta()).hasDisplayName() ? stack.getItemMeta().getDisplayName() : null) + : null, + stack.hasItemMeta() ? (Objects.requireNonNull( + stack.getItemMeta()).hasLore() ? stack.getItemMeta().getLore() : null) + : null, + stack.hasItemMeta() && Objects.requireNonNull(stack.getItemMeta()).hasEnchants() ? + stack.getItemMeta().getEnchants().keySet().stream() + .map(enchantment -> enchantment.getKey().getKey()) + .toList() + : List.of() + ) : null) + .toArray(Stack[]::new); + } + + @Override + public void clear() { + Arrays.fill(contents, null); + } + + @Override + public void setContents(@NotNull Data.Items contents) { + System.arraycopy( + ((BukkitData.Items) contents).getContents(), + 0, this.contents, + 0, this.contents.length + ); + } + + @SuppressWarnings("unused") + public void setContents(@NotNull ItemStack[] contents) { + System.arraycopy(contents, 0, this.contents, 0, this.contents.length); + } + + @NotNull + public ItemStack[] getContents() { + return contents; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof BukkitData.Items items) { + return Arrays.equals(contents, items.getContents()); + } + return false; + } + + public static class Inventory extends BukkitData.Items implements Data.Items.Inventory { + + public static final int INVENTORY_SLOT_COUNT = 41; + private int heldItemSlot; + + private Inventory(@NotNull ItemStack[] contents, int heldItemSlot) { + super(contents); + this.heldItemSlot = heldItemSlot; + } + + @NotNull + public static BukkitData.Items.Inventory from(@NotNull ItemStack[] contents, int heldItemSlot) { + return new BukkitData.Items.Inventory(contents, heldItemSlot); + } + + @NotNull + public static BukkitData.Items.Inventory empty() { + return new BukkitData.Items.Inventory(new ItemStack[INVENTORY_SLOT_COUNT], 0); + } + + @Override + public int getSlotCount() { + return INVENTORY_SLOT_COUNT; + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + final Player player = user.getPlayer(); + this.clearInventoryCraftingSlots(player); + player.setItemOnCursor(null); + player.getInventory().setContents(plugin.setMapViews(getContents())); + player.updateInventory(); + player.getInventory().setHeldItemSlot(heldItemSlot); + } + + private void clearInventoryCraftingSlots(@NotNull Player player) { + final org.bukkit.inventory.Inventory inventory = player.getOpenInventory().getTopInventory(); + if (inventory.getType() == InventoryType.CRAFTING) { + for (int slot = 0; slot < 5; slot++) { + inventory.setItem(slot, null); + } + } + } + + @Override + public int getHeldItemSlot() { + return heldItemSlot; + } + + @Override + public void setHeldItemSlot(int heldItemSlot) throws IllegalArgumentException { + if (heldItemSlot < 0 || heldItemSlot > 8) { + throw new IllegalArgumentException("Held item slot must be between 0 and 8"); + } + this.heldItemSlot = heldItemSlot; + } + + } + + public static class EnderChest extends BukkitData.Items implements Data.Items.EnderChest { + + public static final int ENDER_CHEST_SLOT_COUNT = 27; + + private EnderChest(@NotNull ItemStack[] contents) { + super(contents); + } + + @NotNull + public static BukkitData.Items.EnderChest adapt(@NotNull ItemStack[] items) { + return new BukkitData.Items.EnderChest(items); + } + + @NotNull + public static BukkitData.Items.EnderChest empty() { + return new BukkitData.Items.EnderChest(new ItemStack[ENDER_CHEST_SLOT_COUNT]); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + user.getPlayer().getEnderChest().setContents(plugin.setMapViews(getContents())); + } + + } + + public static class ItemArray extends BukkitData.Items implements Data.Items { + + private ItemArray(@NotNull ItemStack[] contents) { + super(contents); + } + + @NotNull + public static ItemArray adapt(@NotNull Collection drops) { + return new ItemArray(drops.toArray(ItemStack[]::new)); + } + + @NotNull + public static ItemArray adapt(@NotNull ItemStack[] drops) { + return new ItemArray(drops); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + throw new NotImplementedException("A generic item array cannot be applied to a player"); + } + + } + + } + + public static class PotionEffects extends BukkitData implements Data.PotionEffects { + + private final Collection effects; + + private PotionEffects(@NotNull Collection effects) { + this.effects = effects; + } + + @NotNull + public static BukkitData.PotionEffects from(@NotNull Collection effects) { + return new BukkitData.PotionEffects(effects); + } + + @NotNull + public static BukkitData.PotionEffects adapt(@NotNull Collection effects) { + return from( + effects.stream() + .map(effect -> new PotionEffect( + Objects.requireNonNull( + PotionEffectType.getByName(effect.type()), + "Invalid potion effect type" + ), + effect.duration(), + effect.amplifier(), + effect.isAmbient(), + effect.showParticles(), + effect.hasIcon() + )) + .toList() + ); + } + + @NotNull + @SuppressWarnings("unused") + public static BukkitData.PotionEffects empty() { + return new BukkitData.PotionEffects(List.of()); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + final Player player = user.getPlayer(); + for (PotionEffect effect : player.getActivePotionEffects()) { + player.removePotionEffect(effect.getType()); + } + for (PotionEffect effect : this.getEffects()) { + player.addPotionEffect(effect); + } + } + + @NotNull + @Override + public List getActiveEffects() { + return effects.stream() + .map(potionEffect -> new Effect( + potionEffect.getType().getName().toLowerCase(Locale.ENGLISH), + potionEffect.getAmplifier(), + potionEffect.getDuration(), + potionEffect.isAmbient(), + potionEffect.hasParticles(), + potionEffect.hasIcon() + )) + .toList(); + } + + @NotNull + public Collection getEffects() { + return effects; + } + + } + + public static class Advancements extends BukkitData implements Data.Advancements { + + private List completed; + + private Advancements(@NotNull List advancements) { + this.completed = advancements; + } + + // Iterate through the server advancement set and add all advancements to the list + @NotNull + public static BukkitData.Advancements adapt(@NotNull Player player) { + final List advancements = new ArrayList<>(); + forEachAdvancement(advancement -> { + final AdvancementProgress advancementProgress = player.getAdvancementProgress(advancement); + final Map awardedCriteria = new HashMap<>(); + + advancementProgress.getAwardedCriteria().forEach(criteriaKey -> awardedCriteria.put(criteriaKey, + advancementProgress.getDateAwarded(criteriaKey))); + + // Only save the advancement if criteria has been completed + if (!awardedCriteria.isEmpty()) { + advancements.add(Advancement.adapt(advancement.getKey().toString(), awardedCriteria)); + } + }); + return new BukkitData.Advancements(advancements); + } + + @NotNull + public static BukkitData.Advancements from(@NotNull List advancements) { + return new BukkitData.Advancements(advancements); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + plugin.runAsync(() -> forEachAdvancement(advancement -> { + final Player player = user.getPlayer(); + final AdvancementProgress progress = player.getAdvancementProgress(advancement); + final Optional record = completed.stream() + .filter(r -> r.getKey().equals(advancement.getKey().toString())) + .findFirst(); + if (record.isEmpty()) { + this.setAdvancement(plugin, advancement, player, List.of(), progress.getAwardedCriteria()); + return; + } + + final Map criteria = record.get().getCompletedCriteria(); + this.setAdvancement( + plugin, advancement, player, + criteria.keySet().stream().filter(key -> !progress.getAwardedCriteria().contains(key)).toList(), + progress.getAwardedCriteria().stream().filter(key -> !criteria.containsKey(key)).toList() + ); + })); + } + + private void setAdvancement(@NotNull HuskSync plugin, + @NotNull org.bukkit.advancement.Advancement advancement, @NotNull Player player, + @NotNull Collection toAward, @NotNull Collection toRevoke) { + plugin.runSync(() -> { + // Track player exp level & progress + final int expLevel = player.getLevel(); + final float expProgress = player.getExp(); + boolean gameRuleUpdated = false; + if (Boolean.TRUE.equals(player.getWorld().getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS))) { + player.getWorld().setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false); + gameRuleUpdated = true; + } + + // Award and revoke advancement criteria + final AdvancementProgress progress = player.getAdvancementProgress(advancement); + toAward.forEach(progress::awardCriteria); + toRevoke.forEach(progress::revokeCriteria); + + // Set player experience and level (prevent advancement awards applying twice), reset game rule + if (!toAward.isEmpty() && player.getLevel() != expLevel || player.getExp() != expProgress) { + player.setLevel(expLevel); + player.setExp(expProgress); + } + if (gameRuleUpdated) { + player.getWorld().setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, true); + } + }); + } + + // Performs a consuming function for every advancement registered on the server + private static void forEachAdvancement(@NotNull ThrowingConsumer consumer) { + Bukkit.getServer().advancementIterator().forEachRemaining(consumer); + } + + @NotNull + @Override + public List getCompleted() { + return completed; + } + + @Override + public void setCompleted(@NotNull List completed) { + this.completed = completed; + } + + } + + public static class Location extends BukkitData implements Data.Location, Adaptable { + @SerializedName("x") + private double x; + @SerializedName("y") + private double y; + @SerializedName("z") + private double z; + @SerializedName("yaw") + private float yaw; + @SerializedName("pitch") + private float pitch; + @SerializedName("world") + private World world; + + private Location(double x, double y, double z, float yaw, float pitch, @NotNull World world) { + this.x = x; + this.y = y; + this.z = z; + this.yaw = yaw; + this.pitch = pitch; + this.world = world; + } + + @SuppressWarnings("unused") + private Location() { + } + + @NotNull + public static BukkitData.Location from(double x, double y, double z, + float yaw, float pitch, @NotNull World world) { + return new BukkitData.Location(x, y, z, yaw, pitch, world); + } + + @NotNull + public static BukkitData.Location adapt(@NotNull org.bukkit.Location location) { + return from( + location.getX(), + location.getY(), + location.getZ(), + location.getYaw(), + location.getPitch(), + new World( + Objects.requireNonNull(location.getWorld(), "World is null").getName(), + location.getWorld().getUID(), + location.getWorld().getEnvironment().name() + ) + ); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + try { + final org.bukkit.Location location = new org.bukkit.Location( + Bukkit.getWorld(world.name()), x, y, z, yaw, pitch + ); + user.getPlayer().teleport(location); + } catch (Throwable e) { + throw new IllegalStateException("Failed to apply location", e); + } + } + + @Override + public double getX() { + return x; + } + + @Override + public void setX(double x) { + this.x = x; + } + + @Override + public double getY() { + return y; + } + + @Override + public void setY(double y) { + this.y = y; + } + + @Override + public double getZ() { + return z; + } + + @Override + public void setZ(double z) { + this.z = z; + } + + @Override + public float getYaw() { + return yaw; + } + + @Override + public void setYaw(float yaw) { + this.yaw = yaw; + } + + @Override + public float getPitch() { + return pitch; + } + + @Override + public void setPitch(float pitch) { + this.pitch = pitch; + } + + @NotNull + @Override + public World getWorld() { + return world; + } + + @Override + public void setWorld(@NotNull World world) { + this.world = world; + } + + } + + public static class Statistics extends BukkitData implements Data.Statistics { + private Map untypedStatistics; + private Map> blockStatistics; + private Map> itemStatistics; + private Map> entityStatistics; + + private Statistics(@NotNull Map genericStatistics, + @NotNull Map> blockStatistics, + @NotNull Map> itemStatistics, + @NotNull Map> entityStatistics) { + this.untypedStatistics = genericStatistics; + this.blockStatistics = blockStatistics; + this.itemStatistics = itemStatistics; + this.entityStatistics = entityStatistics; + } + + @SuppressWarnings("unused") + private Statistics() { + } + + @NotNull + public static BukkitData.Statistics adapt(@NotNull Player player) { + return new BukkitData.Statistics( + // Generic (untyped) stats + Arrays.stream(Statistic.values()) + .filter(stat -> stat.getType() == Statistic.Type.UNTYPED) + .filter(stat -> player.getStatistic(stat) != 0) + .map(stat -> Map.entry(stat, player.getStatistic(stat))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)), + + // Block stats + Arrays.stream(Statistic.values()) + .filter(stat -> stat.getType() == Statistic.Type.BLOCK) + .map(stat -> Map.entry(stat, Arrays.stream(Material.values()) + .filter(Material::isBlock) + .filter(material -> player.getStatistic(stat, material) != 0) + .map(material -> Map.entry(material, player.getStatistic(stat, material))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))) + .filter(entry -> !entry.getValue().isEmpty()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)), + + // Item stats + Arrays.stream(Statistic.values()) + .filter(stat -> stat.getType() == Statistic.Type.ITEM) + .map(stat -> Map.entry(stat, Arrays.stream(Material.values()) + .filter(Material::isItem) + .filter(material -> player.getStatistic(stat, material) != 0) + .map(material -> Map.entry(material, player.getStatistic(stat, material))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))) + .filter(entry -> !entry.getValue().isEmpty()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)), + + // Entity stats + Arrays.stream(Statistic.values()) + .filter(stat -> stat.getType() == Statistic.Type.ENTITY) + .map(stat -> Map.entry(stat, Arrays.stream(EntityType.values()) + .filter(EntityType::isAlive) + .filter(entityType -> player.getStatistic(stat, entityType) != 0) + .map(entityType -> Map.entry(entityType, player.getStatistic(stat, entityType))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))) + .filter(entry -> !entry.getValue().isEmpty()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) + ); + } + + @NotNull + public static BukkitData.Statistics from(@NotNull StatisticsMap stats) { + return new BukkitData.Statistics( + stats.genericStats().entrySet().stream().collect(Collectors.toMap( + entry -> matchStatistic(entry.getKey()), + Map.Entry::getValue + )), + stats.blockStats().entrySet().stream().collect(Collectors.toMap( + entry -> matchStatistic(entry.getKey()), + entry -> entry.getValue().entrySet().stream().collect(Collectors.toMap( + blockEntry -> Material.matchMaterial(blockEntry.getKey()), + Map.Entry::getValue + )) + )), + stats.itemStats().entrySet().stream().collect(Collectors.toMap( + entry -> matchStatistic(entry.getKey()), + entry -> entry.getValue().entrySet().stream().collect(Collectors.toMap( + itemEntry -> Material.matchMaterial(itemEntry.getKey()), + Map.Entry::getValue + )) + )), + stats.entityStats().entrySet().stream().collect(Collectors.toMap( + entry -> matchStatistic(entry.getKey()), + entry -> entry.getValue().entrySet().stream().collect(Collectors.toMap( + entityEntry -> matchEntityType(entityEntry.getKey()), + Map.Entry::getValue + )) + )) + ); + } + + @NotNull + public static BukkitData.Statistics from(@NotNull Map genericStats, + @NotNull Map> blockStats, + @NotNull Map> itemStats, + @NotNull Map> entityStats) { + return new BukkitData.Statistics(genericStats, blockStats, itemStats, entityStats); + } + + @NotNull + @ApiStatus.Internal + public static StatisticsMap createStatisticsMap(@NotNull Map genericStats, + @NotNull Map> blockStats, + @NotNull Map> itemStats, + @NotNull Map> entityStats) { + return new StatisticsMap(genericStats, blockStats, itemStats, entityStats); + } + + @NotNull + private static Statistic matchStatistic(@NotNull String key) { + return Arrays.stream(Statistic.values()) + .filter(stat -> stat.getKey().toString().equals(key)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(String.format("Invalid statistic key: %s", key))); + } + + @NotNull + private static EntityType matchEntityType(@NotNull String key) { + return Arrays.stream(EntityType.values()) + .filter(entityType -> entityType.getKey().toString().equals(key)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(String.format("Invalid entity type key: %s", key))); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + untypedStatistics.forEach((stat, value) -> applyStat(user, stat, null, value)); + blockStatistics.forEach((stat, m) -> m.forEach((block, value) -> applyStat(user, stat, block, value))); + itemStatistics.forEach((stat, m) -> m.forEach((item, value) -> applyStat(user, stat, item, value))); + entityStatistics.forEach((stat, m) -> m.forEach((entity, value) -> applyStat(user, stat, entity, value))); + } + + private void applyStat(@NotNull UserDataHolder user, @NotNull Statistic stat, @Nullable Object type, int value) { + try { + final Player player = ((BukkitUser) user).getPlayer(); + if (type == null) { + player.setStatistic(stat, value); + } else if (type instanceof Material) { + player.setStatistic(stat, (Material) type, value); + } else if (type instanceof EntityType) { + player.setStatistic(stat, (EntityType) type, value); + } + } catch (IllegalArgumentException ignored) { + } + } + + @NotNull + @Override + public Map getGenericStatistics() { + return untypedStatistics.entrySet().stream().collect( + TreeMap::new, + (m, e) -> m.put(e.getKey().getKey().toString(), e.getValue()), TreeMap::putAll + ); + } + + @NotNull + @Override + public Map> getBlockStatistics() { + return blockStatistics.entrySet().stream().collect( + TreeMap::new, + (m, e) -> m.put(e.getKey().getKey().toString(), e.getValue().entrySet().stream().collect( + TreeMap::new, + (m2, e2) -> m2.put(e2.getKey().getKey().toString(), e2.getValue()), TreeMap::putAll + )), TreeMap::putAll + ); + } + + @NotNull + @Override + public Map> getItemStatistics() { + return itemStatistics.entrySet().stream().collect( + TreeMap::new, + (m, e) -> m.put(e.getKey().getKey().toString(), e.getValue().entrySet().stream().collect( + TreeMap::new, + (m2, e2) -> m2.put(e2.getKey().getKey().toString(), e2.getValue()), TreeMap::putAll + )), TreeMap::putAll + ); + } + + @NotNull + @Override + public Map> getEntityStatistics() { + return entityStatistics.entrySet().stream().collect( + TreeMap::new, + (m, e) -> m.put(e.getKey().getKey().toString(), e.getValue().entrySet().stream().collect( + TreeMap::new, + (m2, e2) -> m2.put(e2.getKey().getKey().toString(), e2.getValue()), TreeMap::putAll + )), TreeMap::putAll + ); + } + + @NotNull + protected StatisticsMap getStatisticsSet() { + return new StatisticsMap( + getGenericStatistics(), + getBlockStatistics(), + getItemStatistics(), + getEntityStatistics() + ); + } + + public record StatisticsMap( + @SerializedName("generic") @NotNull Map genericStats, + @SerializedName("blocks") @NotNull Map> blockStats, + @SerializedName("items") @NotNull Map> itemStats, + @SerializedName("entities") @NotNull Map> entityStats + ) { + } + + } + + public static class PersistentData extends BukkitData implements Data.PersistentData { + private final NBTCompound persistentData; + + private PersistentData(@NotNull NBTCompound persistentData) { + this.persistentData = persistentData; + } + + @NotNull + public static BukkitData.PersistentData adapt(@NotNull PersistentDataContainer persistentData) { + return new BukkitData.PersistentData(new NBTPersistentDataContainer(persistentData)); + } + + @NotNull + public static BukkitData.PersistentData from(@NotNull NBTCompound compound) { + return new BukkitData.PersistentData(compound); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + final NBTPersistentDataContainer container = new NBTPersistentDataContainer( + user.getPlayer().getPersistentDataContainer() + ); + container.clearNBT(); + container.mergeCompound(persistentData); + } + + @NotNull + public NBTCompound getPersistentData() { + return persistentData; + } + + } + + public static class Health extends BukkitData implements Data.Health, Adaptable { + @SerializedName("health") + private double health; + @SerializedName("max_health") + private double maxHealth; + @SerializedName("health_scale") + private double healthScale; + + private Health(double health, double maxHealth, double healthScale) { + this.health = health; + this.maxHealth = maxHealth; + this.healthScale = healthScale; + } + + @SuppressWarnings("unused") + private Health() { + } + + @NotNull + public static BukkitData.Health from(double health, double maxHealth, double healthScale) { + return new BukkitData.Health(health, maxHealth, healthScale); + } + + @NotNull + public static BukkitData.Health adapt(@NotNull Player player) { + return from( + player.getHealth(), + Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH), + "Missing max health attribute").getValue(), + player.getHealthScale() + ); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + final Player player = user.getPlayer(); + + // Set base max health + final AttributeInstance maxHealthAttribute = Objects.requireNonNull( + player.getAttribute(Attribute.GENERIC_MAX_HEALTH), "Missing max health attribute"); + double currentMaxHealth = maxHealthAttribute.getBaseValue(); + if (maxHealth != 0d) { + maxHealthAttribute.setBaseValue(maxHealth); + currentMaxHealth = maxHealth; + } + + // Set health + final double currentHealth = player.getHealth(); + if (health != currentHealth) { + final double healthToSet = currentHealth > currentMaxHealth ? currentMaxHealth : health; + try { + player.setHealth(Math.min(healthToSet, currentMaxHealth)); + } catch (IllegalArgumentException e) { + plugin.log(Level.WARNING, "Failed to set player health", e); + } + } + + // Set health scale + try { + if (healthScale != 0d) { + player.setHealthScale(healthScale); + } else { + player.setHealthScale(maxHealth); + } + player.setHealthScaled(healthScale != 0D); + } catch (IllegalArgumentException e) { + plugin.log(Level.WARNING, "Failed to set player health scale", e); + } + } + + @Override + public double getHealth() { + return health; + } + + @Override + public void setHealth(double health) { + this.health = health; + } + + @Override + public double getMaxHealth() { + return maxHealth; + } + + @Override + public void setMaxHealth(double maxHealth) { + this.maxHealth = maxHealth; + } + + @Override + public double getHealthScale() { + return healthScale; + } + + @Override + public void setHealthScale(double healthScale) { + this.healthScale = healthScale; + } + + } + + public static class Hunger extends BukkitData implements Data.Hunger, Adaptable { + + @SerializedName("food_level") + private int foodLevel; + @SerializedName("saturation") + private float saturation; + @SerializedName("exhaustion") + private float exhaustion; + + private Hunger(int foodLevel, float saturation, float exhaustion) { + this.foodLevel = foodLevel; + this.saturation = saturation; + this.exhaustion = exhaustion; + } + + @SuppressWarnings("unused") + private Hunger() { + } + + @NotNull + public static BukkitData.Hunger adapt(@NotNull Player player) { + return from(player.getFoodLevel(), player.getSaturation(), player.getExhaustion()); + } + + @NotNull + public static BukkitData.Hunger from(int foodLevel, float saturation, float exhaustion) { + return new BukkitData.Hunger(foodLevel, saturation, exhaustion); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + final Player player = user.getPlayer(); + player.setFoodLevel(foodLevel); + player.setSaturation(saturation); + player.setExhaustion(exhaustion); + } + + @Override + public int getFoodLevel() { + return foodLevel; + } + + @Override + public void setFoodLevel(int foodLevel) { + this.foodLevel = foodLevel; + } + + @Override + public float getSaturation() { + return saturation; + } + + @Override + public void setSaturation(float saturation) { + this.saturation = saturation; + } + + @Override + public float getExhaustion() { + return exhaustion; + } + + @Override + public void setExhaustion(float exhaustion) { + this.exhaustion = exhaustion; + } + } + + public static class Experience extends BukkitData implements Data.Experience, Adaptable { + + @SerializedName("total_experience") + private int totalExperience; + + @SerializedName("exp_level") + private int expLevel; + + @SerializedName("exp_progress") + private float expProgress; + + private Experience(int totalExperience, int expLevel, float expProgress) { + this.totalExperience = totalExperience; + this.expLevel = expLevel; + this.expProgress = expProgress; + } + + @SuppressWarnings("unused") + private Experience() { + } + + @NotNull + public static BukkitData.Experience from(int totalExperience, int expLevel, float expProgress) { + return new BukkitData.Experience(totalExperience, expLevel, expProgress); + } + + @NotNull + public static BukkitData.Experience adapt(@NotNull Player player) { + return from(player.getTotalExperience(), player.getLevel(), player.getExp()); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + final Player player = user.getPlayer(); + player.setTotalExperience(totalExperience); + player.setLevel(expLevel); + player.setExp(expProgress); + } + + @Override + public int getTotalExperience() { + return totalExperience; + } + + @Override + public void setTotalExperience(int totalExperience) { + this.totalExperience = totalExperience; + } + + @Override + public int getExpLevel() { + return expLevel; + } + + @Override + public void setExpLevel(int expLevel) { + this.expLevel = expLevel; + } + + @Override + public float getExpProgress() { + return expProgress; + } + + @Override + public void setExpProgress(float expProgress) { + this.expProgress = expProgress; + } + + } + + public static class GameMode extends BukkitData implements Data.GameMode, Adaptable { + + @SerializedName("game_mode") + private String gameMode; + @SerializedName("allow_flight") + private boolean allowFlight; + @SerializedName("is_flying") + private boolean isFlying; + + private GameMode(@NotNull String gameMode, boolean allowFlight, boolean isFlying) { + this.gameMode = gameMode; + this.allowFlight = allowFlight; + this.isFlying = isFlying; + } + + @NotNull + public static BukkitData.GameMode from(@NotNull String gameMode, boolean allowFlight, boolean isFlying) { + return new BukkitData.GameMode(gameMode, allowFlight, isFlying); + } + + @NotNull + public static BukkitData.GameMode adapt(@NotNull Player player) { + return from(player.getGameMode().name(), player.getAllowFlight(), player.isFlying()); + } + + @Override + public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException { + final Player player = user.getPlayer(); + player.setGameMode(org.bukkit.GameMode.valueOf(gameMode)); + player.setAllowFlight(allowFlight); + player.setFlying(isFlying); + } + + @NotNull + @Override + public String getGameMode() { + return gameMode; + } + + @Override + public void setGameMode(@NotNull String gameMode) { + this.gameMode = gameMode; + } + + @Override + public boolean getAllowFlight() { + return allowFlight; + } + + @Override + public void setAllowFlight(boolean allowFlight) { + this.allowFlight = allowFlight; + } + + @Override + public boolean getIsFlying() { + return isFlying; + } + + @Override + public void setIsFlying(boolean isFlying) { + this.isFlying = isFlying; + } + + } + +} diff --git a/bukkit/src/main/java/net/william278/husksync/data/BukkitInventoryMap.java b/bukkit/src/main/java/net/william278/husksync/data/BukkitInventoryMap.java deleted file mode 100644 index 7175e1c4..00000000 --- a/bukkit/src/main/java/net/william278/husksync/data/BukkitInventoryMap.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; - -import java.util.Optional; - -/** - * A mapped player inventory, providing methods to easily access a player's inventory. - */ -@SuppressWarnings("unused") -public class BukkitInventoryMap { - - public static final int INVENTORY_SLOT_COUNT = 41; - - private ItemStack[] contents; - - /** - * Creates a new mapped inventory from the given contents. - * - * @param contents the contents of the inventory - */ - protected BukkitInventoryMap(ItemStack[] contents) { - this.contents = contents; - } - - /** - * Gets the contents of the inventory. - * - * @return the contents of the inventory - */ - public ItemStack[] getContents() { - return contents; - } - - /** - * Set the contents of the inventory. - * - * @param contents the contents of the inventory - */ - public void setContents(ItemStack[] contents) { - this.contents = contents; - } - - /** - * Gets the size of the inventory. - * - * @return the size of the inventory - */ - public int getSize() { - return contents.length; - } - - /** - * Gets the item at the given index. - * - * @param index the index of the item to get - * @return the item at the given index - */ - public Optional getItemAt(int index) { - if (contents.length >= index) { - if (contents[index] == null) { - return Optional.empty(); - } - return Optional.of(contents[index]); - } - return Optional.empty(); - } - - /** - * Sets the item at the given index. - * - * @param itemStack the item to set at the given index - * @param index the index of the item to set - * @throws IllegalArgumentException if the index is out of bounds - */ - public void setItemAt(@NotNull ItemStack itemStack, int index) throws IllegalArgumentException { - contents[index] = itemStack; - } - - /** - * Returns the main inventory contents. - * - * @return the main inventory contents - */ - public ItemStack[] getInventory() { - final ItemStack[] inventory = new ItemStack[36]; - System.arraycopy(contents, 0, inventory, 0, Math.min(contents.length, inventory.length)); - return inventory; - } - - public ItemStack[] getHotbar() { - final ItemStack[] armor = new ItemStack[9]; - for (int i = 0; i <= 9; i++) { - armor[i] = getItemAt(i).orElse(null); - } - return armor; - } - - public Optional getOffHand() { - return getItemAt(40); - } - - public Optional getHelmet() { - return getItemAt(39); - } - - public Optional getChestplate() { - return getItemAt(38); - } - - public Optional getLeggings() { - return getItemAt(37); - } - - public Optional getBoots() { - return getItemAt(36); - } - - public ItemStack[] getArmor() { - final ItemStack[] armor = new ItemStack[4]; - for (int i = 36; i < 40; i++) { - armor[i - 36] = getItemAt(i).orElse(null); - } - return armor; - } - -} diff --git a/bukkit/src/main/java/net/william278/husksync/data/BukkitMapHandler.java b/bukkit/src/main/java/net/william278/husksync/data/BukkitMapHandler.java deleted file mode 100644 index f603aac4..00000000 --- a/bukkit/src/main/java/net/william278/husksync/data/BukkitMapHandler.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import net.william278.husksync.BukkitHuskSync; -import net.william278.mapdataapi.MapData; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.MapMeta; -import org.bukkit.map.*; -import org.bukkit.persistence.PersistentDataType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.io.IOException; -import java.util.Objects; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; - -/** - * Handles the persistence of {@link MapData} into {@link ItemStack}s. - */ -public class BukkitMapHandler { - - private static final BukkitHuskSync plugin = BukkitHuskSync.getInstance(); - private static final NamespacedKey MAP_DATA_KEY = new NamespacedKey(plugin, "map_data"); - - /** - * Get the {@link MapData} from the given {@link ItemStack} and persist it in its' data container - * - * @param itemStack the {@link ItemStack} to get the {@link MapData} from - */ - @SuppressWarnings("ConstantConditions") - public static void persistMapData(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() != Material.FILLED_MAP) { - return; - } - final MapMeta mapMeta = (MapMeta) itemStack.getItemMeta(); - if (mapMeta == null || !mapMeta.hasMapView()) { - return; - } - - // Get the map view from the map - final MapView mapView; - try { - mapView = Bukkit.getScheduler().callSyncMethod(plugin, mapMeta::getMapView).get(); - if (mapView == null || !mapView.isLocked() || mapView.isVirtual()) { - return; - } - } catch (InterruptedException | ExecutionException e) { - plugin.getLogger().log(Level.WARNING, "Failed to save map data for a player", e); - return; - } - - // Get the map data - plugin.debug("Rendering map view onto canvas for locked map"); - final LockedMapCanvas canvas = new LockedMapCanvas(mapView); - for (MapRenderer renderer : mapView.getRenderers()) { - renderer.render(mapView, canvas, Bukkit.getServer() - .getOnlinePlayers().stream() - .findAny() - .orElse(null)); - } - - // Save the extracted rendered map data - plugin.debug("Saving pixel canvas data for locked map"); - if (!mapMeta.getPersistentDataContainer().has(MAP_DATA_KEY, PersistentDataType.BYTE_ARRAY)) { - mapMeta.getPersistentDataContainer().set(MAP_DATA_KEY, PersistentDataType.BYTE_ARRAY, - canvas.extractMapData().toBytes()); - itemStack.setItemMeta(mapMeta); - } - } - - /** - * Set the map data of the given {@link ItemStack} to the given {@link MapData}, applying a map view to the item stack - * - * @param itemStack the {@link ItemStack} to set the map data of - */ - public static void setMapRenderer(@Nullable ItemStack itemStack) { - if (itemStack == null || itemStack.getType() != Material.FILLED_MAP) { - return; - } - - final MapMeta mapMeta = (MapMeta) itemStack.getItemMeta(); - if (mapMeta == null) { - return; - } - - if (!itemStack.getItemMeta().getPersistentDataContainer().has(MAP_DATA_KEY, PersistentDataType.BYTE_ARRAY)) { - return; - } - - try { - final byte[] serializedData = itemStack.getItemMeta().getPersistentDataContainer() - .get(MAP_DATA_KEY, PersistentDataType.BYTE_ARRAY); - final MapData mapData = MapData.fromByteArray(Objects.requireNonNull(serializedData)); - plugin.debug("Setting deserialized map data for an item stack"); - - // Create a new map view renderer with the map data color at each pixel - final MapView view = Bukkit.createMap(Bukkit.getWorlds().get(0)); - view.getRenderers().clear(); - view.addRenderer(new PersistentMapRenderer(mapData)); - view.setLocked(true); - view.setScale(MapView.Scale.NORMAL); - view.setTrackingPosition(false); - view.setUnlimitedTracking(false); - mapMeta.setMapView(view); - itemStack.setItemMeta(mapMeta); - plugin.debug("Successfully applied renderer to map item stack"); - } catch (IOException | NullPointerException e) { - plugin.getLogger().log(Level.WARNING, "Failed to deserialize map data for a player", e); - } - } - - /** - * A {@link MapRenderer} that can be used to render persistently serialized {@link MapData} to a {@link MapView} - */ - public static class PersistentMapRenderer extends MapRenderer { - - private final MapData mapData; - - private PersistentMapRenderer(@NotNull MapData mapData) { - super(false); - this.mapData = mapData; - } - - @Override - public void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player) { - for (int i = 0; i < 128; i++) { - for (int j = 0; j < 128; j++) { - // We set the pixels in this order to avoid the map being rendered upside down - canvas.setPixel(j, i, (byte) mapData.getColorAt(i, j)); - } - } - } - } - - /** - * A {@link MapCanvas} implementation used for pre-rendering maps to be converted into {@link MapData} - */ - public static class LockedMapCanvas implements MapCanvas { - - private final MapView mapView; - private final int[][] pixels = new int[128][128]; - private MapCursorCollection cursors; - - private LockedMapCanvas(@NotNull MapView mapView) { - this.mapView = mapView; - } - - @NotNull - @Override - public MapView getMapView() { - return mapView; - } - - @NotNull - @Override - public MapCursorCollection getCursors() { - return cursors == null ? (cursors = new MapCursorCollection()) : cursors; - } - - @Override - public void setCursors(@NotNull MapCursorCollection cursors) { - this.cursors = cursors; - } - - @Override - public void setPixel(int x, int y, byte color) { - pixels[x][y] = color; - } - - @Override - public byte getPixel(int x, int y) { - return (byte) pixels[x][y]; - } - - @Override - public byte getBasePixel(int x, int y) { - return getPixel(x, y); - } - - @Override - public void drawImage(int x, int y, @NotNull Image image) { - // Not implemented - } - - @Override - public void drawText(int x, int y, @NotNull MapFont font, @NotNull String text) { - // Not implemented - } - - @NotNull - private String getDimension() { - return mapView.getWorld() == null ? "minecraft:overworld" - : switch (mapView.getWorld().getEnvironment()) { - case NETHER -> "minecraft:the_nether"; - case THE_END -> "minecraft:the_end"; - default -> "minecraft:overworld"; - }; - } - - /** - * Extract the map data from the canvas. Must be rendered first - * @return the extracted map data - */ - @NotNull - private MapData extractMapData() { - return MapData.fromPixels(pixels, getDimension(), (byte) 2); - } - } -} diff --git a/bukkit/src/main/java/net/william278/husksync/data/BukkitPersistentTypeMapping.java b/bukkit/src/main/java/net/william278/husksync/data/BukkitPersistentTypeMapping.java deleted file mode 100644 index 4102842f..00000000 --- a/bukkit/src/main/java/net/william278/husksync/data/BukkitPersistentTypeMapping.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import org.bukkit.NamespacedKey; -import org.bukkit.entity.Player; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; -import java.util.Optional; - -public record BukkitPersistentTypeMapping(PersistentDataTagType type, PersistentDataType bukkitType) { - - public static final BukkitPersistentTypeMapping[] PRIMITIVE_TYPE_MAPPINGS = new BukkitPersistentTypeMapping[]{ - new BukkitPersistentTypeMapping<>(PersistentDataTagType.BYTE, PersistentDataType.BYTE), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.SHORT, PersistentDataType.SHORT), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.INTEGER, PersistentDataType.INTEGER), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.LONG, PersistentDataType.LONG), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.FLOAT, PersistentDataType.FLOAT), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.DOUBLE, PersistentDataType.DOUBLE), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.STRING, PersistentDataType.STRING), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.BYTE_ARRAY, PersistentDataType.BYTE_ARRAY), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.INTEGER_ARRAY, PersistentDataType.INTEGER_ARRAY), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.LONG_ARRAY, PersistentDataType.LONG_ARRAY), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.TAG_CONTAINER_ARRAY, PersistentDataType.TAG_CONTAINER_ARRAY), - new BukkitPersistentTypeMapping<>(PersistentDataTagType.TAG_CONTAINER, PersistentDataType.TAG_CONTAINER) - }; - - public BukkitPersistentTypeMapping(@NotNull PersistentDataTagType type, @NotNull PersistentDataType bukkitType) { - this.type = type; - this.bukkitType = bukkitType; - } - - @NotNull - public PersistentDataTag getContainerValue(@NotNull PersistentDataContainer container, @NotNull NamespacedKey key) throws NullPointerException { - return new PersistentDataTag<>(type, Objects.requireNonNull(container.get(key, bukkitType))); - } - - public void setContainerValue(@NotNull PersistentDataContainerData container, @NotNull Player player, @NotNull NamespacedKey key) throws NullPointerException { - container.getTagValue(key.toString(), bukkitType.getComplexType()) - .ifPresent(value -> player.getPersistentDataContainer().set(key, bukkitType, value)); - } - - public static Optional> getMapping(@NotNull PersistentDataTagType type) { - for (BukkitPersistentTypeMapping mapping : PRIMITIVE_TYPE_MAPPINGS) { - if (mapping.type().equals(type)) { - return Optional.of(mapping); - } - } - return Optional.empty(); - } - - -} diff --git a/bukkit/src/main/java/net/william278/husksync/data/BukkitSerializer.java b/bukkit/src/main/java/net/william278/husksync/data/BukkitSerializer.java index 1c4b57ac..0f6e0232 100644 --- a/bukkit/src/main/java/net/william278/husksync/data/BukkitSerializer.java +++ b/bukkit/src/main/java/net/william278/husksync/data/BukkitSerializer.java @@ -19,235 +19,247 @@ package net.william278.husksync.data; -import net.william278.husksync.BukkitHuskSync; -import net.william278.husksync.config.Settings; +import com.google.gson.reflect.TypeToken; +import de.tr7zw.changeme.nbtapi.NBT; +import de.tr7zw.changeme.nbtapi.NBTContainer; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; +import net.william278.husksync.HuskSync; +import net.william278.husksync.adapter.Adaptable; +import net.william278.husksync.api.HuskSyncAPI; import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; -import org.bukkit.util.io.BukkitObjectInputStream; -import org.bukkit.util.io.BukkitObjectOutputStream; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Level; +import java.util.List; + +import static net.william278.husksync.data.BukkitData.Items.Inventory.INVENTORY_SLOT_COUNT; public class BukkitSerializer { - /** - * Returns a serialized array of {@link ItemStack}s - * - * @param inventoryContents The contents of the inventory - * @return The serialized inventory contents - */ - public static CompletableFuture serializeItemStackArray(@NotNull ItemStack[] inventoryContents) - throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> { - // Return an empty string if there is no inventory item data to serialize - if (inventoryContents.length == 0) { - return ""; - } - - // Create an output stream that will be encoded into base 64 - ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); - - try (BukkitObjectOutputStream bukkitOutputStream = new BukkitObjectOutputStream(byteOutputStream)) { - // Define the length of the inventory array to serialize - bukkitOutputStream.writeInt(inventoryContents.length); - - // Write each serialize each ItemStack to the output stream - final boolean persistLockedMaps = BukkitHuskSync.getInstance().getSettings().getSynchronizationFeature(Settings.SynchronizationFeature.LOCKED_MAPS); - for (ItemStack inventoryItem : inventoryContents) { - if (persistLockedMaps) { - BukkitMapHandler.persistMapData(inventoryItem); - } - bukkitOutputStream.writeObject(serializeItemStack(inventoryItem)); - } - - // Return encoded data, using the encoder from SnakeYaml to get a ByteArray conversion - return Base64Coder.encodeLines(byteOutputStream.toByteArray()); - } catch (IOException e) { - BukkitHuskSync.getInstance().log(Level.SEVERE, "Failed to serialize item stack data", e); - throw new DataSerializationException("Failed to serialize item stack data", e); - } - }); + protected final HuskSync plugin; + + private BukkitSerializer(@NotNull HuskSync plugin) { + this.plugin = plugin; } - /** - * Returns a {@link BukkitInventoryMap} from a serialized array of ItemStacks representing the contents of a player's inventory. - * - * @param serializedPlayerInventory The serialized {@link ItemStack} inventory array - * @return The deserialized ItemStacks, mapped for convenience as a {@link BukkitInventoryMap} - * @throws DataSerializationException If the serialized item stack array could not be deserialized - */ - public static CompletableFuture deserializeInventory(@NotNull String serializedPlayerInventory) - throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> new BukkitInventoryMap(deserializeItemStackArray(serializedPlayerInventory).join())); + @SuppressWarnings("unused") + public BukkitSerializer(@NotNull HuskSyncAPI api) { + this.plugin = api.getPlugin(); } - /** - * Returns an array of ItemStacks from serialized inventory data. - * - * @param serializeItemStackArray The serialized {@link ItemStack} array - * @return The deserialized array of {@link ItemStack}s - * @throws DataSerializationException If the serialized item stack array could not be deserialized - * @implNote Empty slots will be represented by {@code null} - */ - public static CompletableFuture deserializeItemStackArray(@NotNull String serializeItemStackArray) - throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> { - // Return empty array if there is no inventory data (set the player as having an empty inventory) - if (serializeItemStackArray.isEmpty()) { - return new ItemStack[0]; - } - - // Create a byte input stream to read the serialized data - try (ByteArrayInputStream byteInputStream = new ByteArrayInputStream(Base64Coder.decodeLines(serializeItemStackArray))) { - try (BukkitObjectInputStream bukkitInputStream = new BukkitObjectInputStream(byteInputStream)) { - // Read the length of the Bukkit input stream and set the length of the array to this value - ItemStack[] inventoryContents = new ItemStack[bukkitInputStream.readInt()]; - - // Set the ItemStacks in the array from deserialized ItemStack data - int slotIndex = 0; - final boolean persistLockedMaps = BukkitHuskSync.getInstance().getSettings().getSynchronizationFeature(Settings.SynchronizationFeature.LOCKED_MAPS); - for (ItemStack ignored : inventoryContents) { - final ItemStack deserialized = deserializeItemStack(bukkitInputStream.readObject()); - if (persistLockedMaps) { - BukkitMapHandler.setMapRenderer(deserialized); - } - inventoryContents[slotIndex] = deserialized; - slotIndex++; - } - - // Return the finished, serialized inventory contents - return inventoryContents; - } - } catch (IOException | ClassNotFoundException e) { - BukkitHuskSync.getInstance().log(Level.SEVERE, "Failed to deserialize item stack data", e); - throw new DataSerializationException("Failed to deserialize item stack data", e); - } - }); + @ApiStatus.Internal + @NotNull + public HuskSync getPlugin() { + return plugin; } - /** - * Returns the serialized version of an {@link ItemStack} as a string to object Map - * - * @param item The {@link ItemStack} to serialize - * @return The serialized {@link ItemStack} - */ - @Nullable - private static Map serializeItemStack(@Nullable ItemStack item) { - return item != null ? item.serialize() : null; + public static class Inventory extends BukkitSerializer implements Serializer { + private static final String ITEMS_TAG = "items"; + private static final String HELD_ITEM_SLOT_TAG = "held_item_slot"; + + public Inventory(@NotNull HuskSync plugin) { + super(plugin); + } + + @Override + public BukkitData.Items.Inventory deserialize(@NotNull String serialized) throws DeserializationException { + final ReadWriteNBT root = NBT.parseNBT(serialized); + final ItemStack[] items = root.getItemStackArray(ITEMS_TAG); + final int heldItemSlot = root.getInteger(HELD_ITEM_SLOT_TAG); + return BukkitData.Items.Inventory.from( + items == null ? new ItemStack[INVENTORY_SLOT_COUNT] : items, + heldItemSlot + ); + } + + @NotNull + @Override + public String serialize(@NotNull BukkitData.Items.Inventory data) throws SerializationException { + final ReadWriteNBT root = NBT.createNBTObject(); + root.setItemStackArray(ITEMS_TAG, data.getContents()); + root.setInteger(HELD_ITEM_SLOT_TAG, data.getHeldItemSlot()); + return root.toString(); + } + } - /** - * Returns the deserialized {@link ItemStack} from the Object read from the {@link BukkitObjectInputStream} - * - * @param serializedItemStack The serialized item stack; a String-Object map - * @return The deserialized {@link ItemStack} - */ - @SuppressWarnings("unchecked") // Ignore the "Unchecked cast" warning - @Nullable - private static ItemStack deserializeItemStack(@Nullable Object serializedItemStack) { - return serializedItemStack != null ? ItemStack.deserialize((Map) serializedItemStack) : null; + public static class EnderChest extends BukkitSerializer implements Serializer { + + public EnderChest(@NotNull HuskSync plugin) { + super(plugin); + } + + @Override + public BukkitData.Items.EnderChest deserialize(@NotNull String serialized) throws DeserializationException { + final ItemStack[] items = NBT.itemStackArrayFromNBT(NBT.parseNBT(serialized)); + return items == null ? BukkitData.Items.EnderChest.empty() : BukkitData.Items.EnderChest.adapt(items); + } + + @NotNull + @Override + public String serialize(@NotNull BukkitData.Items.EnderChest data) throws SerializationException { + return NBT.itemStackArrayToNBT(data.getContents()).toString(); + } } - /** - * Returns a serialized array of {@link PotionEffect}s - * - * @param potionEffects The potion effect array - * @return The serialized potion effects - */ - public static CompletableFuture serializePotionEffectArray(@NotNull PotionEffect[] potionEffects) throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> { - // Return an empty string if there are no effects to serialize - if (potionEffects.length == 0) { - return ""; - } - - // Create an output stream that will be encoded into base 64 - ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); - - try (BukkitObjectOutputStream bukkitOutputStream = new BukkitObjectOutputStream(byteOutputStream)) { - // Define the length of the potion effect array to serialize - bukkitOutputStream.writeInt(potionEffects.length); - - // Write each serialize each PotionEffect to the output stream - for (PotionEffect potionEffect : potionEffects) { - bukkitOutputStream.writeObject(serializePotionEffect(potionEffect)); - } - - // Return encoded data, using the encoder from SnakeYaml to get a ByteArray conversion - return Base64Coder.encodeLines(byteOutputStream.toByteArray()); - } catch (IOException e) { - BukkitHuskSync.getInstance().log(Level.SEVERE, "Failed to serialize potion effect data", e); - throw new DataSerializationException("Failed to serialize potion effect data", e); - } - }); + public static class PotionEffects extends BukkitSerializer implements Serializer { + + private static final TypeToken> TYPE = new TypeToken<>() { + }; + + public PotionEffects(@NotNull HuskSync plugin) { + super(plugin); + } + + @Override + public BukkitData.PotionEffects deserialize(@NotNull String serialized) throws DeserializationException { + return BukkitData.PotionEffects.adapt( + plugin.getGson().fromJson(serialized, TYPE.getType()) + ); + } + + @NotNull + @Override + public String serialize(@NotNull BukkitData.PotionEffects element) throws SerializationException { + return plugin.getGson().toJson(element.getActiveEffects()); + } + } - /** - * Returns an array of ItemStacks from serialized potion effect data - * - * @param potionEffectData The serialized {@link PotionEffect} array - * @return The {@link PotionEffect}s - */ - public static CompletableFuture deserializePotionEffectArray(@NotNull String potionEffectData) throws DataSerializationException { - return CompletableFuture.supplyAsync(() -> { - // Return empty array if there is no potion effect data (don't apply any effects to the player) - if (potionEffectData.isEmpty()) { - return new PotionEffect[0]; - } - - // Create a byte input stream to read the serialized data - try (ByteArrayInputStream byteInputStream = new ByteArrayInputStream(Base64Coder.decodeLines(potionEffectData))) { - try (BukkitObjectInputStream bukkitInputStream = new BukkitObjectInputStream(byteInputStream)) { - // Read the length of the Bukkit input stream and set the length of the array to this value - PotionEffect[] potionEffects = new PotionEffect[bukkitInputStream.readInt()]; - - // Set the potion effects in the array from deserialized PotionEffect data - int potionIndex = 0; - for (PotionEffect ignored : potionEffects) { - potionEffects[potionIndex] = deserializePotionEffect(bukkitInputStream.readObject()); - potionIndex++; - } - - // Return the finished, serialized potion effect array - return potionEffects; - } - } catch (IOException | ClassNotFoundException e) { - BukkitHuskSync.getInstance().log(Level.SEVERE, "Failed to deserialize potion effect data", e); - throw new DataSerializationException("Failed to deserialize potion effects", e); - } - }); + public static class Advancements extends BukkitSerializer implements Serializer { + + private static final TypeToken> TYPE = new TypeToken<>() { + }; + + public Advancements(@NotNull HuskSync plugin) { + super(plugin); + } + + @Override + public BukkitData.Advancements deserialize(@NotNull String serialized) throws DeserializationException { + return BukkitData.Advancements.from( + plugin.getGson().fromJson(serialized, TYPE.getType()) + ); + } + + @NotNull + @Override + public String serialize(@NotNull BukkitData.Advancements element) throws SerializationException { + return plugin.getGson().toJson(element.getCompleted()); + } } - /** - * Returns the serialized version of an {@link ItemStack} as a string to object Map - * - * @param potionEffect The {@link ItemStack} to serialize - * @return The serialized {@link ItemStack} - */ - @Nullable - private static Map serializePotionEffect(@Nullable PotionEffect potionEffect) { - return potionEffect != null ? potionEffect.serialize() : null; + public static class Location extends BukkitSerializer implements Serializer { + + public Location(@NotNull HuskSync plugin) { + super(plugin); + } + + @Override + public BukkitData.Location deserialize(@NotNull String serialized) throws DeserializationException { + return plugin.getDataAdapter().fromJson(serialized, BukkitData.Location.class); + } + + @NotNull + @Override + public String serialize(@NotNull BukkitData.Location element) throws SerializationException { + return plugin.getDataAdapter().toJson(element); + } } - /** - * Returns the deserialized {@link PotionEffect} from the Object read from the {@link BukkitObjectInputStream} - * - * @param serializedPotionEffect The serialized potion effect; a String-Object map - * @return The deserialized {@link PotionEffect} - */ - @SuppressWarnings("unchecked") // Ignore the "Unchecked cast" warning - @Nullable - private static PotionEffect deserializePotionEffect(@Nullable Object serializedPotionEffect) { - return serializedPotionEffect != null ? new PotionEffect((Map) serializedPotionEffect) : null; + public static class Statistics extends BukkitSerializer implements Serializer { + + public Statistics(@NotNull HuskSync plugin) { + super(plugin); + } + + @Override + public BukkitData.Statistics deserialize(@NotNull String serialized) throws DeserializationException { + return BukkitData.Statistics.from(plugin.getGson().fromJson( + serialized, + BukkitData.Statistics.StatisticsMap.class + )); + } + + @NotNull + @Override + public String serialize(@NotNull BukkitData.Statistics element) throws SerializationException { + return plugin.getGson().toJson(element.getStatisticsSet()); + } + } + public static class PersistentData extends BukkitSerializer implements Serializer { + + public PersistentData(@NotNull HuskSync plugin) { + super(plugin); + } + + @Override + public BukkitData.PersistentData deserialize(@NotNull String serialized) throws DeserializationException { + return BukkitData.PersistentData.from(new NBTContainer(serialized)); + } + + @NotNull + @Override + public String serialize(@NotNull BukkitData.PersistentData element) throws SerializationException { + return element.getPersistentData().toString(); + } + + } + + public static class Health extends Json implements Serializer { + + public Health(@NotNull HuskSync plugin) { + super(plugin, BukkitData.Health.class); + } + + } + + public static class Hunger extends Json implements Serializer { + + public Hunger(@NotNull HuskSync plugin) { + super(plugin, BukkitData.Hunger.class); + } + + } + + public static class Experience extends Json implements Serializer { + + public Experience(@NotNull HuskSync plugin) { + super(plugin, BukkitData.Experience.class); + } + + } + + public static class GameMode extends Json implements Serializer { + + public GameMode(@NotNull HuskSync plugin) { + super(plugin, BukkitData.GameMode.class); + } + + } + + public static abstract class Json extends BukkitSerializer implements Serializer { + + private final Class type; + + protected Json(@NotNull HuskSync plugin, Class type) { + super(plugin); + this.type = type; + } + + @Override + public T deserialize(@NotNull String serialized) throws DeserializationException { + return plugin.getDataAdapter().fromJson(serialized, type); + } + + @NotNull + @Override + public String serialize(@NotNull T element) throws SerializationException { + return plugin.getDataAdapter().toJson(element); + } + + } } diff --git a/bukkit/src/main/java/net/william278/husksync/data/BukkitUserDataHolder.java b/bukkit/src/main/java/net/william278/husksync/data/BukkitUserDataHolder.java new file mode 100644 index 00000000..7754ad8d --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/data/BukkitUserDataHolder.java @@ -0,0 +1,151 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.data; + +import net.william278.husksync.BukkitHuskSync; +import net.william278.husksync.util.BukkitMapPersister; +import org.bukkit.entity.Player; +import org.bukkit.inventory.PlayerInventory; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Optional; + +public interface BukkitUserDataHolder extends UserDataHolder { + + @Override + default Optional getData(@NotNull Identifier id) { + if (!id.isCustom()) { + return switch (id.getKeyValue()) { + case "inventory" -> getInventory(); + case "ender_chest" -> getEnderChest(); + case "potion_effects" -> getPotionEffects(); + case "advancements" -> getAdvancements(); + case "location" -> getLocation(); + case "statistics" -> getStatistics(); + case "health" -> getHealth(); + case "hunger" -> getHunger(); + case "experience" -> getExperience(); + case "game_mode" -> getGameMode(); + case "persistent_data" -> getPersistentData(); + default -> throw new IllegalStateException(String.format("Unexpected data type: %s", id)); + }; + } + return Optional.ofNullable(getCustomDataStore().get(id)); + } + + @Override + default void setData(@NotNull Identifier id, @NotNull Data data) { + if (id.isCustom()) { + getCustomDataStore().put(id, data); + } + UserDataHolder.super.setData(id, data); + } + + @NotNull + @Override + default Optional getInventory() { + if ((isDead() && !getPlugin().getSettings().doSynchronizeDeadPlayersChangingServer())) { + return Optional.of(BukkitData.Items.Inventory.empty()); + } + final PlayerInventory inventory = getBukkitPlayer().getInventory(); + return Optional.of(BukkitData.Items.Inventory.from( + getMapPersister().persistLockedMaps(inventory.getContents(), getBukkitPlayer()), + inventory.getHeldItemSlot() + )); + } + + @NotNull + @Override + default Optional getEnderChest() { + return Optional.of(BukkitData.Items.EnderChest.adapt( + getMapPersister().persistLockedMaps(getBukkitPlayer().getEnderChest().getContents(), getBukkitPlayer()) + )); + } + + @NotNull + @Override + default Optional getPotionEffects() { + return Optional.of(BukkitData.PotionEffects.from(getBukkitPlayer().getActivePotionEffects())); + } + + @NotNull + @Override + default Optional getAdvancements() { + return Optional.of(BukkitData.Advancements.adapt(getBukkitPlayer())); + } + + @NotNull + @Override + default Optional getLocation() { + return Optional.of(BukkitData.Location.adapt(getBukkitPlayer().getLocation())); + } + + @NotNull + @Override + default Optional getStatistics() { + return Optional.of(BukkitData.Statistics.adapt(getBukkitPlayer())); + } + + @NotNull + @Override + default Optional getHealth() { + return Optional.of(BukkitData.Health.adapt(getBukkitPlayer())); + } + + @NotNull + @Override + default Optional getHunger() { + return Optional.of(BukkitData.Hunger.adapt(getBukkitPlayer())); + } + + @NotNull + @Override + default Optional getExperience() { + return Optional.of(BukkitData.Experience.adapt(getBukkitPlayer())); + } + + @NotNull + @Override + default Optional getGameMode() { + return Optional.of(BukkitData.GameMode.adapt(getBukkitPlayer())); + } + + @NotNull + @Override + default Optional getPersistentData() { + return Optional.of(BukkitData.PersistentData.adapt(getBukkitPlayer().getPersistentDataContainer())); + } + + boolean isDead(); + + @NotNull + Player getBukkitPlayer(); + + @NotNull + Map getCustomDataStore(); + + @NotNull + default BukkitMapPersister getMapPersister() { + return (BukkitHuskSync) getPlugin(); + } + + +} diff --git a/bukkit/src/main/java/net/william278/husksync/event/BukkitDataSaveEvent.java b/bukkit/src/main/java/net/william278/husksync/event/BukkitDataSaveEvent.java index 2a8ef3cd..4159dcba 100644 --- a/bukkit/src/main/java/net/william278/husksync/event/BukkitDataSaveEvent.java +++ b/bukkit/src/main/java/net/william278/husksync/event/BukkitDataSaveEvent.java @@ -19,9 +19,9 @@ package net.william278.husksync.event; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.player.User; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.User; import org.bukkit.event.Cancellable; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -29,16 +29,15 @@ import org.jetbrains.annotations.NotNull; @SuppressWarnings("unused") public class BukkitDataSaveEvent extends BukkitEvent implements DataSaveEvent, Cancellable { private static final HandlerList HANDLER_LIST = new HandlerList(); - private boolean cancelled = false; - private UserData userData; + private final HuskSync plugin; + private final DataSnapshot.Packed snapshot; private final User user; - private final DataSaveCause saveCause; + private boolean cancelled = false; - protected BukkitDataSaveEvent(@NotNull User user, @NotNull UserData userData, - @NotNull DataSaveCause saveCause) { + protected BukkitDataSaveEvent(@NotNull User user, @NotNull DataSnapshot.Packed snapshot, @NotNull HuskSync plugin) { this.user = user; - this.userData = userData; - this.saveCause = saveCause; + this.snapshot = snapshot; + this.plugin = plugin; } @Override @@ -58,18 +57,15 @@ public class BukkitDataSaveEvent extends BukkitEvent implements DataSaveEvent, C } @Override - public @NotNull UserData getUserData() { - return userData; - } - - @Override - public void setUserData(@NotNull UserData userData) { - this.userData = userData; + @NotNull + public DataSnapshot.Packed getData() { + return snapshot; } + @NotNull @Override - public @NotNull DataSaveCause getSaveCause() { - return saveCause; + public HuskSync getPlugin() { + return plugin; } @NotNull diff --git a/bukkit/src/main/java/net/william278/husksync/event/BukkitEvent.java b/bukkit/src/main/java/net/william278/husksync/event/BukkitEvent.java index 5e3a54e2..29ec1ccf 100644 --- a/bukkit/src/main/java/net/william278/husksync/event/BukkitEvent.java +++ b/bukkit/src/main/java/net/william278/husksync/event/BukkitEvent.java @@ -19,14 +19,10 @@ package net.william278.husksync.event; -import net.william278.husksync.BukkitHuskSync; -import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; - @SuppressWarnings("unused") public abstract class BukkitEvent extends Event implements net.william278.husksync.event.Event { @@ -35,21 +31,6 @@ public abstract class BukkitEvent extends Event implements net.william278.husksy protected BukkitEvent() { } - @Override - public CompletableFuture fire() { - final CompletableFuture eventFireFuture = new CompletableFuture<>(); - // Don't fire events while the server is shutting down - if (!BukkitHuskSync.getInstance().isEnabled()) { - eventFireFuture.complete(this); - } else { - Bukkit.getScheduler().runTask(BukkitHuskSync.getInstance(), () -> { - Bukkit.getServer().getPluginManager().callEvent(this); - eventFireFuture.complete(this); - }); - } - return eventFireFuture; - } - @NotNull @Override public HandlerList getHandlers() { diff --git a/bukkit/src/main/java/net/william278/husksync/event/BukkitEventCannon.java b/bukkit/src/main/java/net/william278/husksync/event/BukkitEventCannon.java deleted file mode 100644 index 5bf3c9c5..00000000 --- a/bukkit/src/main/java/net/william278/husksync/event/BukkitEventCannon.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.event; - -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.player.BukkitPlayer; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; - -public class BukkitEventCannon extends EventCannon { - - public BukkitEventCannon() { - } - - @Override - public CompletableFuture firePreSyncEvent(@NotNull OnlineUser user, @NotNull UserData userData) { - return new BukkitPreSyncEvent(((BukkitPlayer) user).getPlayer(), userData).fire(); - } - - @Override - public CompletableFuture fireDataSaveEvent(@NotNull User user, @NotNull UserData userData, - @NotNull DataSaveCause saveCause) { - return new BukkitDataSaveEvent(user, userData, saveCause).fire(); - } - - @Override - public void fireSyncCompleteEvent(@NotNull OnlineUser user) { - new BukkitSyncCompleteEvent(((BukkitPlayer) user).getPlayer()).fire(); - } - -} diff --git a/bukkit/src/main/java/net/william278/husksync/event/BukkitEventDispatcher.java b/bukkit/src/main/java/net/william278/husksync/event/BukkitEventDispatcher.java new file mode 100644 index 00000000..28a78eae --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/event/BukkitEventDispatcher.java @@ -0,0 +1,54 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.event; + +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.user.User; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; + +public interface BukkitEventDispatcher extends EventDispatcher { + + @Override + default boolean fireIsCancelled(@NotNull T event) { + Bukkit.getPluginManager().callEvent((org.bukkit.event.Event) event); + return event instanceof Cancellable cancellable && cancellable.isCancelled(); + } + + @NotNull + @Override + default PreSyncEvent getPreSyncEvent(@NotNull OnlineUser user, @NotNull DataSnapshot.Packed data) { + return new BukkitPreSyncEvent(user, data, getPlugin()); + } + + @NotNull + @Override + default DataSaveEvent getDataSaveEvent(@NotNull User user, @NotNull DataSnapshot.Packed data) { + return new BukkitDataSaveEvent(user, data, getPlugin()); + } + + @NotNull + @Override + default SyncCompleteEvent getSyncCompleteEvent(@NotNull OnlineUser user) { + return new BukkitSyncCompleteEvent(user, getPlugin()); + } + +} diff --git a/bukkit/src/main/java/net/william278/husksync/event/BukkitPlayerEvent.java b/bukkit/src/main/java/net/william278/husksync/event/BukkitPlayerEvent.java index 8664a0f5..6b0df5bd 100644 --- a/bukkit/src/main/java/net/william278/husksync/event/BukkitPlayerEvent.java +++ b/bukkit/src/main/java/net/william278/husksync/event/BukkitPlayerEvent.java @@ -19,40 +19,25 @@ package net.william278.husksync.event; -import net.william278.husksync.BukkitHuskSync; -import net.william278.husksync.player.BukkitPlayer; -import net.william278.husksync.player.OnlineUser; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; +import net.william278.husksync.user.OnlineUser; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; - @SuppressWarnings("unused") public abstract class BukkitPlayerEvent extends BukkitEvent implements PlayerEvent { private static final HandlerList HANDLER_LIST = new HandlerList(); - protected final Player player; + protected final OnlineUser player; - protected BukkitPlayerEvent(@NotNull Player player) { + protected BukkitPlayerEvent(@NotNull OnlineUser player) { this.player = player; } @Override + @NotNull public OnlineUser getUser() { - return BukkitPlayer.adapt(player); - } - - @Override - public CompletableFuture fire() { - final CompletableFuture eventFireFuture = new CompletableFuture<>(); - Bukkit.getScheduler().runTask(BukkitHuskSync.getInstance(), () -> { - Bukkit.getServer().getPluginManager().callEvent(this); - eventFireFuture.complete(this); - }); - return eventFireFuture; + return player; } @NotNull diff --git a/bukkit/src/main/java/net/william278/husksync/event/BukkitPreSyncEvent.java b/bukkit/src/main/java/net/william278/husksync/event/BukkitPreSyncEvent.java index a0ce94b8..9d5431e3 100644 --- a/bukkit/src/main/java/net/william278/husksync/event/BukkitPreSyncEvent.java +++ b/bukkit/src/main/java/net/william278/husksync/event/BukkitPreSyncEvent.java @@ -19,8 +19,9 @@ package net.william278.husksync.event; -import net.william278.husksync.data.UserData; -import org.bukkit.entity.Player; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.OnlineUser; import org.bukkit.event.Cancellable; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -28,12 +29,14 @@ import org.jetbrains.annotations.NotNull; @SuppressWarnings("unused") public class BukkitPreSyncEvent extends BukkitPlayerEvent implements PreSyncEvent, Cancellable { private static final HandlerList HANDLER_LIST = new HandlerList(); + private final HuskSync plugin; + private final DataSnapshot.Packed data; private boolean cancelled = false; - private UserData userData; - protected BukkitPreSyncEvent(@NotNull Player player, @NotNull UserData userData) { + protected BukkitPreSyncEvent(@NotNull OnlineUser player, @NotNull DataSnapshot.Packed data, @NotNull HuskSync plugin) { super(player); - this.userData = userData; + this.data = data; + this.plugin = plugin; } @Override @@ -47,13 +50,15 @@ public class BukkitPreSyncEvent extends BukkitPlayerEvent implements PreSyncEven } @Override - public @NotNull UserData getUserData() { - return userData; + @NotNull + public DataSnapshot.Packed getData() { + return data; } + @NotNull @Override - public void setUserData(@NotNull UserData userData) { - this.userData = userData; + public HuskSync getPlugin() { + return plugin; } @NotNull diff --git a/bukkit/src/main/java/net/william278/husksync/event/BukkitSyncCompleteEvent.java b/bukkit/src/main/java/net/william278/husksync/event/BukkitSyncCompleteEvent.java index 18abd1b5..840c08c8 100644 --- a/bukkit/src/main/java/net/william278/husksync/event/BukkitSyncCompleteEvent.java +++ b/bukkit/src/main/java/net/william278/husksync/event/BukkitSyncCompleteEvent.java @@ -19,7 +19,8 @@ package net.william278.husksync.event; -import org.bukkit.entity.Player; +import net.william278.husksync.HuskSync; +import net.william278.husksync.user.OnlineUser; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -27,7 +28,7 @@ import org.jetbrains.annotations.NotNull; public class BukkitSyncCompleteEvent extends BukkitPlayerEvent implements SyncCompleteEvent { private static final HandlerList HANDLER_LIST = new HandlerList(); - protected BukkitSyncCompleteEvent(@NotNull Player player) { + protected BukkitSyncCompleteEvent(@NotNull OnlineUser player, @NotNull HuskSync plugin) { super(player); } diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitDeathEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitDeathEventListener.java index 5bb2db75..b6418a1e 100644 --- a/bukkit/src/main/java/net/william278/husksync/listener/BukkitDeathEventListener.java +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitDeathEventListener.java @@ -19,7 +19,6 @@ package net.william278.husksync.listener; -import net.william278.husksync.config.Settings; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -28,25 +27,25 @@ import org.jetbrains.annotations.NotNull; public interface BukkitDeathEventListener extends Listener { - boolean handleEvent(@NotNull Settings.EventType type, @NotNull Settings.EventPriority priority); + boolean handleEvent(@NotNull EventListener.ListenerType type, @NotNull EventListener.Priority priority); @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) default void onPlayerDeathHighest(@NotNull PlayerDeathEvent event) { - if (handleEvent(Settings.EventType.DEATH_LISTENER, Settings.EventPriority.HIGHEST)) { + if (handleEvent(EventListener.ListenerType.DEATH_LISTENER, EventListener.Priority.HIGHEST)) { handlePlayerDeath(event); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) default void onPlayerDeath(@NotNull PlayerDeathEvent event) { - if (handleEvent(Settings.EventType.DEATH_LISTENER, Settings.EventPriority.NORMAL)) { + if (handleEvent(EventListener.ListenerType.DEATH_LISTENER, EventListener.Priority.NORMAL)) { handlePlayerDeath(event); } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) default void onPlayerDeathLowest(@NotNull PlayerDeathEvent event) { - if (handleEvent(Settings.EventType.DEATH_LISTENER, Settings.EventPriority.LOWEST)) { + if (handleEvent(EventListener.ListenerType.DEATH_LISTENER, EventListener.Priority.LOWEST)) { handlePlayerDeath(event); } } diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java index 516f6732..432a1b67 100644 --- a/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitEventListener.java @@ -20,12 +20,10 @@ package net.william278.husksync.listener; import net.william278.husksync.BukkitHuskSync; -import net.william278.husksync.config.Settings; -import net.william278.husksync.data.BukkitInventoryMap; -import net.william278.husksync.data.BukkitSerializer; -import net.william278.husksync.data.ItemData; -import net.william278.husksync.player.BukkitPlayer; -import net.william278.husksync.player.OnlineUser; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.BukkitData; +import net.william278.husksync.user.BukkitUser; +import net.william278.husksync.user.OnlineUser; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; @@ -46,12 +44,10 @@ import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.world.WorldSaveEvent; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Locale; -import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; public class BukkitEventListener extends EventListener implements BukkitJoinEventListener, BukkitQuitEventListener, @@ -65,54 +61,57 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven } @Override - public boolean handleEvent(@NotNull Settings.EventType type, @NotNull Settings.EventPriority priority) { + public boolean handleEvent(@NotNull ListenerType type, @NotNull Priority priority) { return plugin.getSettings().getEventPriority(type).equals(priority); } @Override - public void handlePlayerQuit(@NotNull BukkitPlayer bukkitPlayer) { - final Player player = bukkitPlayer.getPlayer(); - if (!bukkitPlayer.isLocked() && !player.getItemOnCursor().getType().isAir()) { + public void handlePlayerQuit(@NotNull BukkitUser bukkitUser) { + final Player player = bukkitUser.getPlayer(); + if (!bukkitUser.isLocked() && !player.getItemOnCursor().getType().isAir()) { player.getWorld().dropItem(player.getLocation(), player.getItemOnCursor()); player.setItemOnCursor(null); } - super.handlePlayerQuit(bukkitPlayer); + super.handlePlayerQuit(bukkitUser); } @Override - public void handlePlayerJoin(@NotNull BukkitPlayer bukkitPlayer) { - super.handlePlayerJoin(bukkitPlayer); + public void handlePlayerJoin(@NotNull BukkitUser bukkitUser) { + super.handlePlayerJoin(bukkitUser); } @Override public void handlePlayerDeath(@NotNull PlayerDeathEvent event) { - final OnlineUser user = BukkitPlayer.adapt(event.getEntity()); + final OnlineUser user = BukkitUser.adapt(event.getEntity(), plugin); // If the player is locked or the plugin disabling, clear their drops - if (cancelPlayerEvent(user.uuid)) { + if (cancelPlayerEvent(user.getUuid())) { event.getDrops().clear(); return; } // Handle saving player data snapshots on death - if (!plugin.getSettings().doSaveOnDeath()) return; + if (!plugin.getSettings().doSaveOnDeath()) { + return; + } - // Truncate the drops list to the inventory size and save the player's inventory - final int maxInventorySize = BukkitInventoryMap.INVENTORY_SLOT_COUNT; + // Truncate the dropped items list to the inventory size and save the player's inventory + final int maxInventorySize = BukkitData.Items.Inventory.INVENTORY_SLOT_COUNT; if (event.getDrops().size() > maxInventorySize) { event.getDrops().subList(maxInventorySize, event.getDrops().size()).clear(); } - BukkitSerializer.serializeItemStackArray(event.getDrops().toArray(new ItemStack[0])) - .thenAccept(serializedDrops -> super.saveOnPlayerDeath(user, new ItemData(serializedDrops))); + super.saveOnPlayerDeath(user, BukkitData.Items.ItemArray.adapt(event.getDrops())); } @EventHandler(ignoreCancelled = true) public void onWorldSave(@NotNull WorldSaveEvent event) { - // Handle saving player data snapshots when the world saves - if (!plugin.getSettings().doSaveOnWorldSave()) return; + if (!plugin.getSettings().doSaveOnWorldSave()) { + return; + } - CompletableFuture.runAsync(() -> super.saveOnWorldSave(event.getWorld().getPlayers() - .stream().map(BukkitPlayer::adapt) + // Handle saving player data snapshots when the world saves + plugin.runAsync(() -> super.saveOnWorldSave(event.getWorld().getPlayers() + .stream().map(player -> BukkitUser.adapt(player, plugin)) .collect(Collectors.toList()))); } @@ -186,12 +185,18 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPermissionCommand(@NotNull PlayerCommandPreprocessEvent event) { - String[] commandArgs = event.getMessage().substring(1).split(" "); - String commandLabel = commandArgs[0].toLowerCase(Locale.ENGLISH); + final String[] commandArgs = event.getMessage().substring(1).split(" "); + final String commandLabel = commandArgs[0].toLowerCase(Locale.ENGLISH); if (blacklistedCommands.contains("*") || blacklistedCommands.contains(commandLabel)) { event.setCancelled(cancelPlayerEvent(event.getPlayer().getUniqueId())); } } + @NotNull + @Override + public HuskSync getPlugin() { + return plugin; + } + } diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitJoinEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitJoinEventListener.java index a2f69776..26144419 100644 --- a/bukkit/src/main/java/net/william278/husksync/listener/BukkitJoinEventListener.java +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitJoinEventListener.java @@ -19,8 +19,8 @@ package net.william278.husksync.listener; -import net.william278.husksync.config.Settings; -import net.william278.husksync.player.BukkitPlayer; +import net.william278.husksync.HuskSync; +import net.william278.husksync.user.BukkitUser; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -29,29 +29,32 @@ import org.jetbrains.annotations.NotNull; public interface BukkitJoinEventListener extends Listener { - boolean handleEvent(@NotNull Settings.EventType type, @NotNull Settings.EventPriority priority); + boolean handleEvent(@NotNull EventListener.ListenerType type, @NotNull EventListener.Priority priority); @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) default void onPlayerJoinHighest(@NotNull PlayerJoinEvent event) { - if (handleEvent(Settings.EventType.JOIN_LISTENER, Settings.EventPriority.HIGHEST)) { - handlePlayerJoin(BukkitPlayer.adapt(event.getPlayer())); + if (handleEvent(EventListener.ListenerType.JOIN_LISTENER, EventListener.Priority.HIGHEST)) { + handlePlayerJoin(BukkitUser.adapt(event.getPlayer(), getPlugin())); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) default void onPlayerJoin(@NotNull PlayerJoinEvent event) { - if (handleEvent(Settings.EventType.JOIN_LISTENER, Settings.EventPriority.NORMAL)) { - handlePlayerJoin(BukkitPlayer.adapt(event.getPlayer())); + if (handleEvent(EventListener.ListenerType.JOIN_LISTENER, EventListener.Priority.NORMAL)) { + handlePlayerJoin(BukkitUser.adapt(event.getPlayer(), getPlugin())); } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) default void onPlayerJoinLowest(@NotNull PlayerJoinEvent event) { - if (handleEvent(Settings.EventType.JOIN_LISTENER, Settings.EventPriority.LOWEST)) { - handlePlayerJoin(BukkitPlayer.adapt(event.getPlayer())); + if (handleEvent(EventListener.ListenerType.JOIN_LISTENER, EventListener.Priority.LOWEST)) { + handlePlayerJoin(BukkitUser.adapt(event.getPlayer(), getPlugin())); } } - void handlePlayerJoin(@NotNull BukkitPlayer player); + void handlePlayerJoin(@NotNull BukkitUser player); + + @NotNull + HuskSync getPlugin(); } diff --git a/bukkit/src/main/java/net/william278/husksync/listener/BukkitQuitEventListener.java b/bukkit/src/main/java/net/william278/husksync/listener/BukkitQuitEventListener.java index 133513f7..c0eec1c4 100644 --- a/bukkit/src/main/java/net/william278/husksync/listener/BukkitQuitEventListener.java +++ b/bukkit/src/main/java/net/william278/husksync/listener/BukkitQuitEventListener.java @@ -19,8 +19,8 @@ package net.william278.husksync.listener; -import net.william278.husksync.config.Settings; -import net.william278.husksync.player.BukkitPlayer; +import net.william278.husksync.HuskSync; +import net.william278.husksync.user.BukkitUser; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -29,29 +29,32 @@ import org.jetbrains.annotations.NotNull; public interface BukkitQuitEventListener extends Listener { - boolean handleEvent(@NotNull Settings.EventType type, @NotNull Settings.EventPriority priority); + boolean handleEvent(@NotNull EventListener.ListenerType type, @NotNull EventListener.Priority priority); @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) default void onPlayerQuitHighest(@NotNull PlayerQuitEvent event) { - if (handleEvent(Settings.EventType.QUIT_LISTENER, Settings.EventPriority.HIGHEST)) { - handlePlayerQuit(BukkitPlayer.adapt(event.getPlayer())); + if (handleEvent(EventListener.ListenerType.QUIT_LISTENER, EventListener.Priority.HIGHEST)) { + handlePlayerQuit(BukkitUser.adapt(event.getPlayer(), getPlugin())); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) default void onPlayerQuit(@NotNull PlayerQuitEvent event) { - if (handleEvent(Settings.EventType.QUIT_LISTENER, Settings.EventPriority.NORMAL)) { - handlePlayerQuit(BukkitPlayer.adapt(event.getPlayer())); + if (handleEvent(EventListener.ListenerType.QUIT_LISTENER, EventListener.Priority.NORMAL)) { + handlePlayerQuit(BukkitUser.adapt(event.getPlayer(), getPlugin())); } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) default void onPlayerQuitLowest(@NotNull PlayerQuitEvent event) { - if (handleEvent(Settings.EventType.QUIT_LISTENER, Settings.EventPriority.LOWEST)) { - handlePlayerQuit(BukkitPlayer.adapt(event.getPlayer())); + if (handleEvent(EventListener.ListenerType.QUIT_LISTENER, EventListener.Priority.LOWEST)) { + handlePlayerQuit(BukkitUser.adapt(event.getPlayer(), getPlugin())); } } - void handlePlayerQuit(@NotNull BukkitPlayer player); + void handlePlayerQuit(@NotNull BukkitUser player); + + @NotNull + HuskSync getPlugin(); } diff --git a/bukkit/src/main/java/net/william278/husksync/migrator/LegacyMigrator.java b/bukkit/src/main/java/net/william278/husksync/migrator/LegacyMigrator.java index bd6e2335..5487d6e7 100644 --- a/bukkit/src/main/java/net/william278/husksync/migrator/LegacyMigrator.java +++ b/bukkit/src/main/java/net/william278/husksync/migrator/LegacyMigrator.java @@ -23,14 +23,16 @@ import com.zaxxer.hikari.HikariDataSource; import me.william278.husksync.bukkit.data.DataSerializer; import net.william278.hslmigrator.HSLConverter; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.*; -import net.william278.husksync.player.User; +import net.william278.husksync.data.BukkitData; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.User; +import net.william278.husksync.util.BukkitLegacyConverter; import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; -import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -51,8 +53,6 @@ public class LegacyMigrator extends Migrator { private String sourcePlayersTable; private String sourceDataTable; - private final String minecraftVersion; - public LegacyMigrator(@NotNull HuskSync plugin) { super(plugin); this.hslConverter = HSLConverter.getInstance(); @@ -63,17 +63,16 @@ public class LegacyMigrator extends Migrator { this.sourceDatabase = plugin.getSettings().getMySqlDatabase(); this.sourcePlayersTable = "husksync_players"; this.sourceDataTable = "husksync_data"; - this.minecraftVersion = plugin.getMinecraftVersion().toString(); } @Override public CompletableFuture start() { plugin.log(Level.INFO, "Starting migration of legacy HuskSync v1.x data..."); final long startTime = System.currentTimeMillis(); - return CompletableFuture.supplyAsync(() -> { + return plugin.supplyAsync(() -> { // Wipe the existing database, preparing it for data import plugin.log(Level.INFO, "Preparing existing database (wiping)..."); - plugin.getDatabase().wipeDatabase().join(); + plugin.getDatabase().wipeDatabase(); plugin.log(Level.INFO, "Successfully wiped user data database (took " + (System.currentTimeMillis() - startTime) + "ms)"); // Create jdbc driver connection url @@ -135,23 +134,25 @@ public class LegacyMigrator extends Migrator { plugin.log(Level.INFO, "Converting HuskSync 1.x data to the new user data format (this might take a while)..."); final AtomicInteger playersConverted = new AtomicInteger(); - dataToMigrate.forEach(data -> data.toUserData(hslConverter, minecraftVersion).thenAccept(convertedData -> { - plugin.getDatabase().ensureUser(data.user()).thenRun(() -> - plugin.getDatabase().setUserData(data.user(), convertedData, DataSaveCause.LEGACY_MIGRATION) - .exceptionally(exception -> { - plugin.log(Level.SEVERE, "Failed to migrate legacy data for " + data.user().username + ": " + exception.getMessage()); - return null; - })).join(); + dataToMigrate.forEach(data -> { + final DataSnapshot.Packed convertedData = data.toUserData(hslConverter, plugin); + plugin.getDatabase().ensureUser(data.user()); + try { + plugin.getDatabase().addSnapshot(data.user(), convertedData); + } catch (Throwable e) { + plugin.log(Level.SEVERE, "Failed to migrate legacy data for " + data.user().getUsername() + ": " + e.getMessage()); + return; + } playersConverted.getAndIncrement(); if (playersConverted.get() % 50 == 0) { plugin.log(Level.INFO, "Converted legacy data for " + playersConverted + " players..."); } - }).join()); + }); plugin.log(Level.INFO, "Migration complete for " + dataToMigrate.size() + " users in " + ((System.currentTimeMillis() - startTime) / 1000) + " seconds!"); return true; - } catch (Exception e) { - plugin.log(Level.SEVERE, "Error while migrating legacy data: " + e.getMessage() + " - are your source database credentials correct?"); + } catch (Throwable e) { + plugin.log(Level.SEVERE, "Error while migrating legacy data: " + e.getMessage() + " - are your source database credentials correct?", e); return false; } }); @@ -197,10 +198,10 @@ public class LegacyMigrator extends Migrator { }) { plugin.log(Level.INFO, getHelpMenu()); plugin.log(Level.INFO, "Successfully set " + args[0] + " to " + - obfuscateDataString(args[1])); + obfuscateDataString(args[1])); } else { plugin.log(Level.INFO, "Invalid operation, could not set " + args[0] + " to " + - obfuscateDataString(args[1]) + " (is it a valid option?)"); + obfuscateDataString(args[1]) + " (is it a valid option?)"); } } else { plugin.log(Level.INFO, getHelpMenu()); @@ -227,11 +228,11 @@ public class LegacyMigrator extends Migrator { This will migrate all user data from HuskSync v1.x to HuskSync v2.x's new format. To perform the migration, please follow the steps below carefully. - + [!] Existing data in the database will be wiped. [!] - + STEP 1] Please ensure no players are on any servers. - + STEP 2] HuskSync will need to connect to the database used to hold the existing, legacy HuskSync data. If this is the same database as the one you are @@ -251,12 +252,12 @@ public class LegacyMigrator extends Migrator { using the command: "husksync migrate legacy set " (e.g.: "husksync migrate legacy set host 1.2.3.4") - + STEP 3] HuskSync will migrate data into the database tables configures in the config.yml file of this server. Please make sure you're happy with this before proceeding. - + STEP 4] To start the migration, please run: "husksync migrate legacy start" """.replaceAll(Pattern.quote("%source_host%"), obfuscateDataString(sourceHost)) @@ -277,54 +278,69 @@ public class LegacyMigrator extends Migrator { @NotNull String serializedAdvancements, @NotNull String serializedLocation) { @NotNull - public CompletableFuture toUserData(@NotNull HSLConverter converter, - @NotNull String minecraftVersion) { - return CompletableFuture.supplyAsync(() -> { - try { - final DataSerializer.StatisticData legacyStatisticData = converter - .deserializeStatisticData(serializedStatistics); - final StatisticsData convertedStatisticData = new StatisticsData( - convertStatisticMap(legacyStatisticData.untypedStatisticValues()), - convertMaterialStatisticMap(legacyStatisticData.blockStatisticValues()), - convertMaterialStatisticMap(legacyStatisticData.itemStatisticValues()), - convertEntityStatisticMap(legacyStatisticData.entityStatisticValues())); - - final List convertedAdvancements = converter - .deserializeAdvancementData(serializedAdvancements) - .stream().map(data -> new AdvancementData(data.key(), data.criteriaMap())).toList(); - - final DataSerializer.PlayerLocation legacyLocationData = converter - .deserializePlayerLocationData(serializedLocation); - final LocationData convertedLocationData = new LocationData( - legacyLocationData == null ? "world" : legacyLocationData.worldName(), - UUID.randomUUID(), - "NORMAL", - legacyLocationData == null ? 0d : legacyLocationData.x(), - legacyLocationData == null ? 64d : legacyLocationData.y(), - legacyLocationData == null ? 0d : legacyLocationData.z(), - legacyLocationData == null ? 90f : legacyLocationData.yaw(), - legacyLocationData == null ? 180f : legacyLocationData.pitch()); - - return UserData.builder(minecraftVersion) - .setStatus(new StatusData(health, maxHealth, healthScale, hunger, saturation, - saturationExhaustion, selectedSlot, totalExp, expLevel, expProgress, gameMode, isFlying)) - .setInventory(new ItemData(serializedInventory)) - .setEnderChest(new ItemData(serializedEnderChest)) - .setPotionEffects(new PotionEffectData(serializedPotionEffects)) - .setAdvancements(convertedAdvancements) - .setStatistics(convertedStatisticData) - .setLocation(convertedLocationData) - .build(); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); + public DataSnapshot.Packed toUserData(@NotNull HSLConverter converter, @NotNull HuskSync plugin) { + try { + final DataSerializer.StatisticData stats = converter.deserializeStatisticData(serializedStatistics); + final DataSerializer.PlayerLocation loc = converter.deserializePlayerLocationData(serializedLocation); + final BukkitLegacyConverter adapter = (BukkitLegacyConverter) plugin.getLegacyConverter() + .orElseThrow(() -> new IllegalStateException("Legacy converter not present")); + + return DataSnapshot.builder(plugin) + // Inventory + .inventory(BukkitData.Items.Inventory.from( + adapter.deserializeLegacyItemStacks(serializedInventory), + selectedSlot + )) + + // Ender chest + .enderChest(BukkitData.Items.EnderChest.adapt( + adapter.deserializeLegacyItemStacks(serializedEnderChest) + )) + + // Location + .location(BukkitData.Location.from( + loc == null ? 0d : loc.x(), + loc == null ? 64d : loc.y(), + loc == null ? 0d : loc.z(), + loc == null ? 90f : loc.yaw(), + loc == null ? 180f : loc.pitch(), + new Data.Location.World( + loc == null ? "world" : loc.worldName(), + UUID.randomUUID(), "NORMAL" + ))) + + // Advancements + .advancements(BukkitData.Advancements.from(converter + .deserializeAdvancementData(serializedAdvancements).stream() + .map(data -> Data.Advancements.Advancement.adapt(data.key(), data.criteriaMap())) + .toList())) + + // Stats + .statistics(BukkitData.Statistics.from( + BukkitData.Statistics.createStatisticsMap( + convertStatisticMap(stats.untypedStatisticValues()), + convertMaterialStatisticMap(stats.blockStatisticValues()), + convertMaterialStatisticMap(stats.itemStatisticValues()), + convertEntityStatisticMap(stats.entityStatisticValues()) + ))) + + // Health, hunger, experience & game mode + .health(BukkitData.Health.from(health, maxHealth, healthScale)) + .hunger(BukkitData.Hunger.from(hunger, saturation, saturationExhaustion)) + .experience(BukkitData.Experience.from(totalExp, expLevel, expProgress)) + .gameMode(BukkitData.GameMode.from(gameMode, isFlying, isFlying)) + + // Build & pack into new format + .saveCause(DataSnapshot.SaveCause.LEGACY_MIGRATION).buildAndPack(); + } catch (Throwable e) { + throw new IllegalStateException(e); + } } private Map convertStatisticMap(@NotNull HashMap rawMap) { final HashMap convertedMap = new HashMap<>(); for (Map.Entry entry : rawMap.entrySet()) { - convertedMap.put(entry.getKey().toString(), entry.getValue()); + convertedMap.put(entry.getKey().getKey().toString(), entry.getValue()); } return convertedMap; } @@ -333,8 +349,8 @@ public class LegacyMigrator extends Migrator { final Map> convertedMap = new HashMap<>(); for (Map.Entry> entry : rawMap.entrySet()) { for (Map.Entry materialEntry : entry.getValue().entrySet()) { - convertedMap.computeIfAbsent(entry.getKey().toString(), k -> new HashMap<>()) - .put(materialEntry.getKey().toString(), materialEntry.getValue()); + convertedMap.computeIfAbsent(entry.getKey().getKey().toString(), k -> new HashMap<>()) + .put(materialEntry.getKey().getKey().toString(), materialEntry.getValue()); } } return convertedMap; @@ -344,8 +360,8 @@ public class LegacyMigrator extends Migrator { final Map> convertedMap = new HashMap<>(); for (Map.Entry> entry : rawMap.entrySet()) { for (Map.Entry materialEntry : entry.getValue().entrySet()) { - convertedMap.computeIfAbsent(entry.getKey().toString(), k -> new HashMap<>()) - .put(materialEntry.getKey().toString(), materialEntry.getValue()); + convertedMap.computeIfAbsent(entry.getKey().getKey().toString(), k -> new HashMap<>()) + .put(materialEntry.getKey().getKey().toString(), materialEntry.getValue()); } } return convertedMap; diff --git a/bukkit/src/main/java/net/william278/husksync/migrator/MpdbMigrator.java b/bukkit/src/main/java/net/william278/husksync/migrator/MpdbMigrator.java index 8b929c88..c039d13b 100644 --- a/bukkit/src/main/java/net/william278/husksync/migrator/MpdbMigrator.java +++ b/bukkit/src/main/java/net/william278/husksync/migrator/MpdbMigrator.java @@ -21,30 +21,28 @@ package net.william278.husksync.migrator; import com.zaxxer.hikari.HikariDataSource; import net.william278.husksync.BukkitHuskSync; -import net.william278.husksync.data.*; -import net.william278.husksync.player.User; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.BukkitData; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.User; import net.william278.mpdbconverter.MPDBConverter; import org.bukkit.Bukkit; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.regex.Pattern; /** - * A migrator for migrating MySQLPlayerDataBridge data to HuskSync {@link UserData} + * A migrator for migrating MySQLPlayerDataBridge data to HuskSync {@link DataSnapshot}s */ public class MpdbMigrator extends Migrator { @@ -57,11 +55,13 @@ public class MpdbMigrator extends Migrator { private String sourceInventoryTable; private String sourceEnderChestTable; private String sourceExperienceTable; - private final String minecraftVersion; - public MpdbMigrator(@NotNull BukkitHuskSync plugin, @NotNull Plugin mySqlPlayerDataBridge) { + public MpdbMigrator(@NotNull BukkitHuskSync plugin) { super(plugin); - this.mpdbConverter = MPDBConverter.getInstance(mySqlPlayerDataBridge); + this.mpdbConverter = MPDBConverter.getInstance(Objects.requireNonNull( + Bukkit.getPluginManager().getPlugin("MySQLPlayerDataBridge"), + "MySQLPlayerDataBridge dependency not found!" + )); this.sourceHost = plugin.getSettings().getMySqlHost(); this.sourcePort = plugin.getSettings().getMySqlPort(); this.sourceUsername = plugin.getSettings().getMySqlUsername(); @@ -70,7 +70,6 @@ public class MpdbMigrator extends Migrator { this.sourceInventoryTable = "mpdb_inventory"; this.sourceEnderChestTable = "mpdb_enderchest"; this.sourceExperienceTable = "mpdb_experience"; - this.minecraftVersion = plugin.getMinecraftVersion().toString(); } @@ -78,10 +77,10 @@ public class MpdbMigrator extends Migrator { public CompletableFuture start() { plugin.log(Level.INFO, "Starting migration from MySQLPlayerDataBridge to HuskSync..."); final long startTime = System.currentTimeMillis(); - return CompletableFuture.supplyAsync(() -> { + return plugin.supplyAsync(() -> { // Wipe the existing database, preparing it for data import plugin.log(Level.INFO, "Preparing existing database (wiping)..."); - plugin.getDatabase().wipeDatabase().join(); + plugin.getDatabase().wipeDatabase(); plugin.log(Level.INFO, "Successfully wiped user data database (took " + (System.currentTimeMillis() - startTime) + "ms)"); // Create jdbc driver connection url @@ -133,18 +132,15 @@ public class MpdbMigrator extends Migrator { plugin.log(Level.INFO, "Converting raw MySQLPlayerDataBridge data to HuskSync user data (this might take a while)..."); final AtomicInteger playersConverted = new AtomicInteger(); - dataToMigrate.forEach(data -> data.toUserData(mpdbConverter, minecraftVersion).thenAccept(convertedData -> { - plugin.getDatabase().ensureUser(data.user()).thenRun(() -> - plugin.getDatabase().setUserData(data.user(), convertedData, DataSaveCause.MPDB_MIGRATION)) - .exceptionally(exception -> { - plugin.log(Level.SEVERE, "Failed to migrate MySQLPlayerDataBridge data for " + data.user().username + ": " + exception.getMessage()); - return null; - }).join(); + dataToMigrate.forEach(data -> { + final DataSnapshot.Packed convertedData = data.toUserData(mpdbConverter, plugin); + plugin.getDatabase().ensureUser(data.user()); + plugin.getDatabase().addSnapshot(data.user(), convertedData); playersConverted.getAndIncrement(); if (playersConverted.get() % 50 == 0) { plugin.log(Level.INFO, "Converted MySQLPlayerDataBridge data for " + playersConverted + " players..."); } - }).join()); + }); plugin.log(Level.INFO, "Migration complete for " + dataToMigrate.size() + " users in " + ((System.currentTimeMillis() - startTime) / 1000) + " seconds!"); return true; } catch (Exception e) { @@ -198,10 +194,10 @@ public class MpdbMigrator extends Migrator { }) { plugin.log(Level.INFO, getHelpMenu()); plugin.log(Level.INFO, "Successfully set " + args[0] + " to " + - obfuscateDataString(args[1])); + obfuscateDataString(args[1])); } else { plugin.log(Level.INFO, "Invalid operation, could not set " + args[0] + " to " + - obfuscateDataString(args[1]) + " (is it a valid option?)"); + obfuscateDataString(args[1]) + " (is it a valid option?)"); } } else { plugin.log(Level.INFO, getHelpMenu()); @@ -227,14 +223,14 @@ public class MpdbMigrator extends Migrator { === MySQLPlayerDataBridge Migration Wizard ========== This will migrate inventories, ender chests and XP from the MySQLPlayerDataBridge plugin to HuskSync. - + To prevent excessive migration times, other non-vital data will not be transferred. - + [!] Existing data in the database will be wiped. [!] - + STEP 1] Please ensure no players are on any servers. - + STEP 2] HuskSync will need to connect to the database used to hold the source MySQLPlayerDataBridge data. Please check these database parameters are OK: @@ -250,12 +246,12 @@ public class MpdbMigrator extends Migrator { using the command: "husksync migrate mpdb set " (e.g.: "husksync migrate mpdb set host 1.2.3.4") - + STEP 3] HuskSync will migrate data into the database tables configures in the config.yml file of this server. Please make sure you're happy with this before proceeding. - + STEP 4] To start the migration, please run: "husksync migrate mpdb start" """.replaceAll(Pattern.quote("%source_host%"), obfuscateDataString(sourceHost)) @@ -279,38 +275,43 @@ public class MpdbMigrator extends Migrator { * @param expProgress The player's current XP progress * @param totalExp The player's total XP score */ - private record MpdbData(@NotNull User user, @NotNull String serializedInventory, - @NotNull String serializedArmor, @NotNull String serializedEnderChest, - int expLevel, float expProgress, int totalExp) { + private record MpdbData( + @NotNull User user, + @NotNull String serializedInventory, + @NotNull String serializedArmor, + @NotNull String serializedEnderChest, + int expLevel, + float expProgress, + int totalExp + ) { + /** - * Converts exported MySQLPlayerDataBridge data into HuskSync's {@link UserData} object format + * Converts exported MySQLPlayerDataBridge data into HuskSync's {@link DataSnapshot} object format * * @param converter The {@link MPDBConverter} to use for converting to {@link ItemStack}s - * @return A {@link CompletableFuture} that will resolve to the converted {@link UserData} object + * @return A {@link CompletableFuture} that will resolve to the converted {@link DataSnapshot} object */ @NotNull - public CompletableFuture toUserData(@NotNull MPDBConverter converter, - @NotNull String minecraftVersion) { - return CompletableFuture.supplyAsync(() -> { - // Combine inventory and armour - final Inventory inventory = Bukkit.createInventory(null, InventoryType.PLAYER); - inventory.setContents(converter.getItemStackFromSerializedData(serializedInventory)); - final ItemStack[] armor = converter.getItemStackFromSerializedData(serializedArmor).clone(); - for (int i = 36; i < 36 + armor.length; i++) { - inventory.setItem(i, armor[i - 36]); - } + public DataSnapshot.Packed toUserData(@NotNull MPDBConverter converter, @NotNull HuskSync plugin) { + // Combine inventory and armor + final Inventory inventory = Bukkit.createInventory(null, InventoryType.PLAYER); + inventory.setContents(converter.getItemStackFromSerializedData(serializedInventory)); + final ItemStack[] armor = converter.getItemStackFromSerializedData(serializedArmor).clone(); + for (int i = 36; i < 36 + armor.length; i++) { + inventory.setItem(i, armor[i - 36]); + } + final ItemStack[] enderChest = converter.getItemStackFromSerializedData(serializedEnderChest); - // Create user data record - return UserData.builder(minecraftVersion) - .setStatus(new StatusData(20, 20, 0, 20, 10, - 1, 0, totalExp, expLevel, expProgress, "SURVIVAL", - false)) - .setInventory(new ItemData(BukkitSerializer.serializeItemStackArray(inventory.getContents()).join())) - .setEnderChest(new ItemData(BukkitSerializer.serializeItemStackArray(converter - .getItemStackFromSerializedData(serializedEnderChest)).join())) - .build(); - }); + // Create user data record + return DataSnapshot.builder(plugin) + .inventory(BukkitData.Items.Inventory.from(inventory.getContents(), 0)) + .enderChest(BukkitData.Items.EnderChest.adapt(enderChest)) + .experience(BukkitData.Experience.from(totalExp, expLevel, expProgress)) + .gameMode(BukkitData.GameMode.from("SURVIVAL", false, false)) + .saveCause(DataSnapshot.SaveCause.MPDB_MIGRATION) + .buildAndPack(); } + } } diff --git a/bukkit/src/main/java/net/william278/husksync/player/BukkitPlayer.java b/bukkit/src/main/java/net/william278/husksync/player/BukkitPlayer.java deleted file mode 100644 index a44beb13..00000000 --- a/bukkit/src/main/java/net/william278/husksync/player/BukkitPlayer.java +++ /dev/null @@ -1,655 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.player; - -import de.themoep.minedown.adventure.MineDown; -import dev.triumphteam.gui.builder.gui.StorageBuilder; -import dev.triumphteam.gui.guis.Gui; -import dev.triumphteam.gui.guis.StorageGui; -import net.kyori.adventure.audience.Audience; -import net.roxeez.advancement.display.FrameType; -import net.william278.andjam.Toast; -import net.william278.desertwell.util.Version; -import net.william278.husksync.BukkitHuskSync; -import net.william278.husksync.config.Settings; -import net.william278.husksync.data.*; -import org.bukkit.*; -import org.bukkit.advancement.Advancement; -import org.bukkit.advancement.AdvancementProgress; -import org.bukkit.attribute.Attribute; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.jetbrains.annotations.NotNull; - -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; - -/** - * Bukkit implementation of an {@link OnlineUser} - */ -public class BukkitPlayer extends OnlineUser { - - private final BukkitHuskSync plugin; - private final Player player; - - private BukkitPlayer(@NotNull Player player) { - super(player.getUniqueId(), player.getName()); - this.plugin = BukkitHuskSync.getInstance(); - this.player = player; - } - - @NotNull - public static BukkitPlayer adapt(@NotNull Player player) { - return new BukkitPlayer(player); - } - - public Player getPlayer() { - return player; - } - - @Override - public CompletableFuture getStatus() { - return CompletableFuture.supplyAsync(() -> { - final double maxHealth = getMaxHealth(player); - return new StatusData(Math.min(player.getHealth(), maxHealth), - maxHealth, - player.isHealthScaled() ? player.getHealthScale() : 0d, - player.getFoodLevel(), - player.getSaturation(), - player.getExhaustion(), - player.getInventory().getHeldItemSlot(), - player.getTotalExperience(), - player.getLevel(), - player.getExp(), - player.getGameMode().name(), - player.getAllowFlight() && player.isFlying()); - }); - } - - @Override - public CompletableFuture setStatus(@NotNull StatusData statusData, @NotNull Settings settings) { - return CompletableFuture.runAsync(() -> { - // Set max health - double currentMaxHealth = Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).getBaseValue(); - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.MAX_HEALTH)) { - if (statusData.maxHealth != 0d) { - Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)) - .setBaseValue(statusData.maxHealth); - currentMaxHealth = statusData.maxHealth; - } - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.HEALTH)) { - // Set health - final double currentHealth = player.getHealth(); - if (statusData.health != currentHealth) { - final double healthToSet = currentHealth > currentMaxHealth ? currentMaxHealth : statusData.health; - final double maxHealth = currentMaxHealth; - Bukkit.getScheduler().runTask(plugin, () -> { - try { - player.setHealth(Math.min(healthToSet, maxHealth)); - } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, - "Failed to set health of player " + player.getName() + " to " + healthToSet); - } - }); - } - - // Set health scale - try { - if (statusData.healthScale != 0d) { - player.setHealthScale(statusData.healthScale); - } else { - player.setHealthScale(statusData.maxHealth); - } - player.setHealthScaled(statusData.healthScale != 0D); - } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, - "Failed to set health scale of player " + player.getName() + " to " + statusData.healthScale); - } - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.HUNGER)) { - player.setFoodLevel(statusData.hunger); - player.setSaturation(statusData.saturation); - player.setExhaustion(statusData.saturationExhaustion); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.INVENTORIES)) { - player.getInventory().setHeldItemSlot(statusData.selectedItemSlot); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.EXPERIENCE)) { - player.setTotalExperience(statusData.totalExperience); - player.setLevel(statusData.expLevel); - player.setExp(statusData.expProgress); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.GAME_MODE)) { - Bukkit.getScheduler().runTask(plugin, () -> - player.setGameMode(GameMode.valueOf(statusData.gameMode))); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.LOCATION)) { - Bukkit.getScheduler().runTask(plugin, () -> { - if (statusData.isFlying) { - player.setAllowFlight(true); - player.setFlying(true); - } - player.setFlying(false); - }); - } - }); - } - - @Override - public CompletableFuture getInventory() { - final PlayerInventory inventory = player.getInventory(); - if (inventory.isEmpty()) { - return CompletableFuture.completedFuture(ItemData.empty()); - } - return BukkitSerializer.serializeItemStackArray(inventory.getContents()) - .thenApply(ItemData::new); - } - - @Override - public CompletableFuture setInventory(@NotNull ItemData itemData) { - return BukkitSerializer.deserializeInventory(itemData.serializedItems).thenApplyAsync(contents -> { - final CompletableFuture inventorySetFuture = new CompletableFuture<>(); - Bukkit.getScheduler().runTask(plugin, () -> { - this.clearInventoryCraftingSlots(); - player.setItemOnCursor(null); - player.getInventory().setContents(contents.getContents()); - player.updateInventory(); - inventorySetFuture.complete(null); - }); - return inventorySetFuture.join(); - }); - } - - // Clears any items the player may have in the crafting slots of their inventory - private void clearInventoryCraftingSlots() { - final Inventory inventory = player.getOpenInventory().getTopInventory(); - if (inventory.getType() == InventoryType.CRAFTING) { - for (int slot = 0; slot < 5; slot++) { - inventory.setItem(slot, null); - } - } - } - - @Override - public CompletableFuture getEnderChest() { - final Inventory enderChest = player.getEnderChest(); - if (enderChest.isEmpty()) { - return CompletableFuture.completedFuture(ItemData.empty()); - } - return BukkitSerializer.serializeItemStackArray(enderChest.getContents()) - .thenApply(ItemData::new); - } - - @Override - public CompletableFuture setEnderChest(@NotNull ItemData enderChestData) { - return BukkitSerializer.deserializeItemStackArray(enderChestData.serializedItems).thenApplyAsync(contents -> { - final CompletableFuture enderChestSetFuture = new CompletableFuture<>(); - Bukkit.getScheduler().runTask(plugin, () -> { - player.getEnderChest().setContents(contents); - enderChestSetFuture.complete(null); - }); - return enderChestSetFuture.join(); - }); - } - - @Override - public CompletableFuture getPotionEffects() { - return BukkitSerializer.serializePotionEffectArray(player.getActivePotionEffects() - .toArray(new PotionEffect[0])).thenApply(PotionEffectData::new); - } - - @Override - public CompletableFuture setPotionEffects(@NotNull PotionEffectData potionEffectData) { - return BukkitSerializer.deserializePotionEffectArray(potionEffectData.serializedPotionEffects) - .thenApplyAsync(effects -> { - final CompletableFuture potionEffectsSetFuture = new CompletableFuture<>(); - Bukkit.getScheduler().runTask(plugin, () -> { - for (PotionEffect effect : player.getActivePotionEffects()) { - player.removePotionEffect(effect.getType()); - } - for (PotionEffect effect : effects) { - player.addPotionEffect(effect); - } - potionEffectsSetFuture.complete(null); - }); - return potionEffectsSetFuture.join(); - }); - } - - @Override - public CompletableFuture> getAdvancements() { - return CompletableFuture.supplyAsync(() -> { - final Iterator serverAdvancements = Bukkit.getServer().advancementIterator(); - final ArrayList advancementData = new ArrayList<>(); - - // Iterate through the server advancement set and add all advancements to the list - serverAdvancements.forEachRemaining(advancement -> { - final AdvancementProgress advancementProgress = player.getAdvancementProgress(advancement); - final Map awardedCriteria = new HashMap<>(); - - advancementProgress.getAwardedCriteria().forEach(criteriaKey -> awardedCriteria.put(criteriaKey, - advancementProgress.getDateAwarded(criteriaKey))); - - // Only save the advancement if criteria has been completed - if (!awardedCriteria.isEmpty()) { - advancementData.add(new AdvancementData(advancement.getKey().toString(), awardedCriteria)); - } - }); - return advancementData; - }); - } - - @Override - public CompletableFuture setAdvancements(@NotNull List advancementData) { - return CompletableFuture.runAsync(() -> Bukkit.getScheduler().runTask(plugin, () -> { - - // Temporarily disable advancement announcing if needed - boolean announceAdvancementUpdate = false; - if (Boolean.TRUE.equals(player.getWorld().getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS))) { - player.getWorld().setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false); - announceAdvancementUpdate = true; - } - final boolean finalAnnounceAdvancementUpdate = announceAdvancementUpdate; - - // Save current experience and level - final int experienceLevel = player.getLevel(); - final float expProgress = player.getExp(); - - // Determines whether the experience might have changed warranting an update - final AtomicBoolean correctExperience = new AtomicBoolean(false); - - // Run asynchronously as advancement setting is expensive - CompletableFuture.runAsync(() -> { - // Apply the advancements to the player - final Iterator serverAdvancements = Bukkit.getServer().advancementIterator(); - while (serverAdvancements.hasNext()) { - // Iterate through all advancements - final Advancement advancement = serverAdvancements.next(); - final AdvancementProgress playerProgress = player.getAdvancementProgress(advancement); - - advancementData.stream().filter(record -> record.key.equals(advancement.getKey().toString())).findFirst().ifPresentOrElse( - // Award all criteria that the player does not have that they do on the cache - record -> { - record.completedCriteria.keySet().stream() - .filter(criterion -> !playerProgress.getAwardedCriteria().contains(criterion)) - .forEach(criterion -> { - Bukkit.getScheduler().runTask(plugin, - () -> player.getAdvancementProgress(advancement).awardCriteria(criterion)); - correctExperience.set(true); - }); - - // Revoke all criteria that the player does have but should not - new ArrayList<>(playerProgress.getAwardedCriteria()).stream().filter(criterion -> !record.completedCriteria.containsKey(criterion)) - .forEach(criterion -> Bukkit.getScheduler().runTask(plugin, - () -> player.getAdvancementProgress(advancement).revokeCriteria(criterion))); - - }, - // Revoke the criteria as the player shouldn't have any - () -> new ArrayList<>(playerProgress.getAwardedCriteria()).forEach(criterion -> - Bukkit.getScheduler().runTask(plugin, - () -> player.getAdvancementProgress(advancement).revokeCriteria(criterion)))); - - // Update the player's experience in case the advancement changed that - if (correctExperience.get()) { - player.setLevel(experienceLevel); - player.setExp(expProgress); - correctExperience.set(false); - } - } - - // Re-enable announcing advancements (back on main thread again) - Bukkit.getScheduler().runTask(plugin, () -> { - if (finalAnnounceAdvancementUpdate) { - player.getWorld().setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, true); - } - }); - }); - })); - } - - @Override - public CompletableFuture getStatistics() { - return CompletableFuture.supplyAsync(() -> { - final Map untypedStatisticValues = new HashMap<>(); - final Map> blockStatisticValues = new HashMap<>(); - final Map> itemStatisticValues = new HashMap<>(); - final Map> entityStatisticValues = new HashMap<>(); - - for (Statistic statistic : Statistic.values()) { - switch (statistic.getType()) { - case ITEM -> { - final Map itemValues = new HashMap<>(); - Arrays.stream(Material.values()).filter(Material::isItem) - .filter(itemMaterial -> (player.getStatistic(statistic, itemMaterial)) != 0) - .forEach(itemMaterial -> itemValues.put(itemMaterial.name(), - player.getStatistic(statistic, itemMaterial))); - if (!itemValues.isEmpty()) { - itemStatisticValues.put(statistic.name(), itemValues); - } - } - case BLOCK -> { - final Map blockValues = new HashMap<>(); - Arrays.stream(Material.values()).filter(Material::isBlock) - .filter(blockMaterial -> (player.getStatistic(statistic, blockMaterial)) != 0) - .forEach(blockMaterial -> blockValues.put(blockMaterial.name(), - player.getStatistic(statistic, blockMaterial))); - if (!blockValues.isEmpty()) { - blockStatisticValues.put(statistic.name(), blockValues); - } - } - case ENTITY -> { - final Map entityValues = new HashMap<>(); - Arrays.stream(EntityType.values()).filter(EntityType::isAlive) - .filter(entityType -> (player.getStatistic(statistic, entityType)) != 0) - .forEach(entityType -> entityValues.put(entityType.name(), - player.getStatistic(statistic, entityType))); - if (!entityValues.isEmpty()) { - entityStatisticValues.put(statistic.name(), entityValues); - } - } - case UNTYPED -> { - if (player.getStatistic(statistic) != 0) { - untypedStatisticValues.put(statistic.name(), player.getStatistic(statistic)); - } - } - } - } - - return new StatisticsData(untypedStatisticValues, blockStatisticValues, - itemStatisticValues, entityStatisticValues); - }); - } - - @Override - public CompletableFuture setStatistics(@NotNull StatisticsData statisticsData) { - return CompletableFuture.runAsync(() -> { - // Set generic statistics - for (String statistic : statisticsData.untypedStatistics.keySet()) { - try { - player.setStatistic(Statistic.valueOf(statistic), statisticsData.untypedStatistics.get(statistic)); - } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, - "Failed to set generic statistic " + statistic + " for " + username); - } - } - - // Set block statistics - for (String statistic : statisticsData.blockStatistics.keySet()) { - for (String blockMaterial : statisticsData.blockStatistics.get(statistic).keySet()) { - try { - player.setStatistic(Statistic.valueOf(statistic), Material.valueOf(blockMaterial), - statisticsData.blockStatistics.get(statistic).get(blockMaterial)); - } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, - "Failed to set " + blockMaterial + " statistic " + statistic + " for " + username); - } - } - } - - // Set item statistics - for (String statistic : statisticsData.itemStatistics.keySet()) { - for (String itemMaterial : statisticsData.itemStatistics.get(statistic).keySet()) { - try { - player.setStatistic(Statistic.valueOf(statistic), Material.valueOf(itemMaterial), - statisticsData.itemStatistics.get(statistic).get(itemMaterial)); - } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, - "Failed to set " + itemMaterial + " statistic " + statistic + " for " + username); - } - } - } - - // Set entity statistics - for (String statistic : statisticsData.entityStatistics.keySet()) { - for (String entityType : statisticsData.entityStatistics.get(statistic).keySet()) { - try { - player.setStatistic(Statistic.valueOf(statistic), EntityType.valueOf(entityType), - statisticsData.entityStatistics.get(statistic).get(entityType)); - } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, - "Failed to set " + entityType + " statistic " + statistic + " for " + username); - } - } - } - }); - } - - @Override - public CompletableFuture getLocation() { - return CompletableFuture.supplyAsync(() -> - new LocationData(player.getWorld().getName(), player.getWorld().getUID(), player.getWorld().getEnvironment().name(), - player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), - player.getLocation().getYaw(), player.getLocation().getPitch())); - } - - @Override - public CompletableFuture setLocation(@NotNull LocationData locationData) { - final CompletableFuture teleportFuture = new CompletableFuture<>(); - AtomicReference bukkitWorld = new AtomicReference<>(Bukkit.getWorld(locationData.worldName)); - if (bukkitWorld.get() == null) { - bukkitWorld.set(Bukkit.getWorld(locationData.worldUuid)); - } - if (bukkitWorld.get() == null) { - Bukkit.getWorlds().stream().filter(world -> world.getEnvironment() == World.Environment - .valueOf(locationData.worldEnvironment)).findFirst().ifPresent(bukkitWorld::set); - } - if (bukkitWorld.get() != null) { - Bukkit.getScheduler().runTask(plugin, () -> { - player.teleport(new Location(bukkitWorld.get(), - locationData.x, locationData.y, locationData.z, - locationData.yaw, locationData.pitch), PlayerTeleportEvent.TeleportCause.PLUGIN); - teleportFuture.complete(null); - }); - } - return teleportFuture; - } - - @Override - public CompletableFuture getPersistentDataContainer() { - final Map> persistentDataMap = new HashMap<>(); - final PersistentDataContainer container = player.getPersistentDataContainer(); - return CompletableFuture.supplyAsync(() -> { - container.getKeys().forEach(key -> { - BukkitPersistentTypeMapping type = null; - for (BukkitPersistentTypeMapping dataType : BukkitPersistentTypeMapping.PRIMITIVE_TYPE_MAPPINGS) { - if (container.has(key, dataType.bukkitType())) { - type = dataType; - break; - } - } - if (type != null) { - persistentDataMap.put(key.toString(), type.getContainerValue(container, key)); - } - }); - return new PersistentDataContainerData(persistentDataMap); - }).exceptionally(throwable -> { - plugin.log(Level.WARNING, - "Could not read " + player.getName() + "'s persistent data map, skipping!"); - throwable.printStackTrace(); - return new PersistentDataContainerData(new HashMap<>()); - }); - } - - @Override - public CompletableFuture setPersistentDataContainer(@NotNull PersistentDataContainerData container) { - return CompletableFuture.runAsync(() -> { - player.getPersistentDataContainer().getKeys().forEach(namespacedKey -> - player.getPersistentDataContainer().remove(namespacedKey)); - container.getTags().forEach(keyString -> { - final NamespacedKey key = NamespacedKey.fromString(keyString); - if (key != null) { - container.getTagType(keyString) - .flatMap(BukkitPersistentTypeMapping::getMapping) - .ifPresentOrElse(mapping -> mapping.setContainerValue(container, player, key), - () -> plugin.log(Level.WARNING, - "Could not set " + player.getName() + "'s persistent data key " + keyString + - " as it has an invalid type. Skipping!")); - } - }); - }).exceptionally(throwable -> { - plugin.log(Level.WARNING, - "Could not write " + player.getName() + "'s persistent data map, skipping!"); - throwable.printStackTrace(); - return null; - }); - } - - - @Override - @NotNull - public Audience getAudience() { - return plugin.getAudiences().player(player); - } - - @Override - public boolean isOffline() { - try { - return player == null; - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @NotNull - @Override - public Version getMinecraftVersion() { - return Version.fromString(Bukkit.getBukkitVersion()); - } - - @Override - public boolean hasPermission(@NotNull String node) { - return player.hasPermission(node); - } - - @Override - public CompletableFuture> showMenu(@NotNull ItemData itemData, boolean editable, - int minimumRows, @NotNull MineDown title) { - final CompletableFuture> updatedData = new CompletableFuture<>(); - - // Deserialize the item data to be shown and show it in a triumph GUI - BukkitSerializer.deserializeItemStackArray(itemData.serializedItems).thenAccept(items -> { - // Build the GUI and populate with items - final int itemCount = items.length; - final StorageBuilder guiBuilder = Gui.storage() - .title(title.toComponent()) - .rows(Math.max(minimumRows, (int) Math.ceil(itemCount / 9.0))) - .disableAllInteractions() - .enableOtherActions(); - final StorageGui gui = editable ? guiBuilder.enableAllInteractions().create() : guiBuilder.create(); - for (int i = 0; i < itemCount; i++) { - if (items[i] != null) { - gui.getInventory().setItem(i, items[i]); - } - } - - // Complete the future with updated data (if editable) when the GUI is closed - gui.setCloseGuiAction(event -> { - if (!editable) { - updatedData.complete(Optional.empty()); - return; - } - - // Get and save the updated items - final ItemStack[] updatedItems = Arrays.copyOf(event.getPlayer().getOpenInventory() - .getTopInventory().getContents().clone(), itemCount); - BukkitSerializer.serializeItemStackArray(updatedItems).thenAccept(serializedItems -> { - if (serializedItems.equals(itemData.serializedItems)) { - updatedData.complete(Optional.empty()); - return; - } - updatedData.complete(Optional.of(new ItemData(serializedItems))); - }); - }); - - // Display the GUI (synchronously; on the main server thread) - Bukkit.getScheduler().runTask(plugin, () -> gui.open(player)); - }).exceptionally(throwable -> { - // Handle exceptions - updatedData.completeExceptionally(throwable); - return null; - }); - return updatedData; - } - - @Override - public boolean isDead() { - return player.getHealth() <= 0; - } - - @Override - public void sendToast(@NotNull MineDown title, @NotNull MineDown description, - @NotNull String iconMaterial, @NotNull String backgroundType) { - try { - final Material material = Material.matchMaterial(iconMaterial); - Toast.builder(plugin) - .setTitle(title.toComponent()) - .setDescription(description.toComponent()) - .setIcon(material != null ? material : Material.BARRIER) - .setFrameType(FrameType.valueOf(backgroundType)) - .build() - .show(player); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * Returns a {@link Player}'s maximum health, minus any health boost effects - * - * @param player The {@link Player} to get the maximum health of - * @return The {@link Player}'s max health - */ - private static double getMaxHealth(@NotNull Player player) { - double maxHealth = Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).getBaseValue(); - - // If the player has additional health bonuses from synchronised potion effects, subtract these from this number as they are synchronised separately - if (player.hasPotionEffect(PotionEffectType.HEALTH_BOOST) && maxHealth > 20D) { - PotionEffect healthBoostEffect = player.getPotionEffect(PotionEffectType.HEALTH_BOOST); - assert healthBoostEffect != null; - double healthBoostBonus = 4 * (healthBoostEffect.getAmplifier() + 1); - maxHealth -= healthBoostBonus; - } - return maxHealth; - } - - @Override - public boolean isLocked() { - return plugin.getLockedPlayers().contains(player.getUniqueId()); - } - - @Override - public boolean isNpc() { - return player.hasMetadata("NPC"); - } - -} diff --git a/bukkit/src/main/java/net/william278/husksync/user/BukkitUser.java b/bukkit/src/main/java/net/william278/husksync/user/BukkitUser.java new file mode 100644 index 00000000..27c07d36 --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/user/BukkitUser.java @@ -0,0 +1,152 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.user; + +import de.themoep.minedown.adventure.MineDown; +import dev.triumphteam.gui.builder.gui.StorageBuilder; +import dev.triumphteam.gui.guis.Gui; +import dev.triumphteam.gui.guis.StorageGui; +import net.kyori.adventure.audience.Audience; +import net.roxeez.advancement.display.FrameType; +import net.william278.andjam.Toast; +import net.william278.husksync.BukkitHuskSync; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.BukkitData; +import net.william278.husksync.data.BukkitUserDataHolder; +import net.william278.husksync.data.Data; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.function.Consumer; +import java.util.logging.Level; + +/** + * Bukkit platform implementation of an {@link OnlineUser} + */ +public class BukkitUser extends OnlineUser implements BukkitUserDataHolder { + + private final HuskSync plugin; + private final Player player; + + private BukkitUser(@NotNull Player player, @NotNull HuskSync plugin) { + super(player.getUniqueId(), player.getName()); + this.player = player; + this.plugin = plugin; + } + + @NotNull + @ApiStatus.Internal + public static BukkitUser adapt(@NotNull Player player, @NotNull HuskSync plugin) { + return new BukkitUser(player, plugin); + } + + /** + * Get the Bukkit {@link Player} instance of this user + * + * @return the {@link Player} instance + * @since 3.0 + */ + @NotNull + public Player getPlayer() { + return player; + } + + @Override + public boolean isOffline() { + return player == null || !player.isOnline(); + } + + @NotNull + @Override + public Audience getAudience() { + return ((BukkitHuskSync) plugin).getAudiences().player(player); + } + + @Override + public void sendToast(@NotNull MineDown title, @NotNull MineDown description, + @NotNull String iconMaterial, @NotNull String backgroundType) { + try { + final Material material = Material.matchMaterial(iconMaterial); + Toast.builder((BukkitHuskSync) plugin) + .setTitle(title.toComponent()) + .setDescription(description.toComponent()) + .setIcon(material != null ? material : Material.BARRIER) + .setFrameType(FrameType.valueOf(backgroundType)) + .build() + .show(player); + } catch (Throwable e) { + plugin.log(Level.WARNING, "Failed to send toast to player " + player.getName(), e); + } + } + + @Override + public void showGui(@NotNull Data.Items items, @NotNull MineDown title, boolean editable, int size, + @NotNull Consumer onClose) { + final ItemStack[] contents = ((BukkitData.Items) items).getContents(); + final StorageBuilder builder = Gui.storage().rows((int) Math.ceil(size / 9.0d)); + if (!editable) { + builder.disableAllInteractions(); + } + final StorageGui gui = builder.enableOtherActions() + .apply(a -> a.getInventory().setContents(contents)) + .title(title.toComponent()).create(); + gui.setCloseGuiAction((close) -> onClose.accept(BukkitData.Items.ItemArray.adapt( + Arrays.stream(close.getInventory().getContents()).limit(size).toArray(ItemStack[]::new) + ))); + plugin.runSync(() -> gui.open(player)); + } + + @Override + public boolean hasPermission(@NotNull String node) { + return player.hasPermission(node); + } + + @Override + public boolean isDead() { + return player.getHealth() <= 0; + } + + @Override + public boolean isLocked() { + return plugin.getLockedPlayers().contains(player.getUniqueId()); + } + + @Override + public boolean isNpc() { + return player.hasMetadata("NPC"); + } + + @NotNull + @Override + public Player getBukkitPlayer() { + return player; + } + + @NotNull + @Override + @ApiStatus.Internal + public HuskSync getPlugin() { + return plugin; + } +} diff --git a/bukkit/src/main/java/net/william278/husksync/util/BukkitLegacyConverter.java b/bukkit/src/main/java/net/william278/husksync/util/BukkitLegacyConverter.java new file mode 100644 index 00000000..56be8c18 --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/util/BukkitLegacyConverter.java @@ -0,0 +1,279 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.util; + +import net.william278.husksync.HuskSync; +import net.william278.husksync.adapter.DataAdapter; +import net.william278.husksync.data.BukkitData; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.data.Identifier; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.io.BukkitObjectInputStream; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.json.JSONArray; +import org.json.JSONObject; +import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; + +import java.io.ByteArrayInputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class BukkitLegacyConverter extends LegacyConverter { + + public BukkitLegacyConverter(@NotNull HuskSync plugin) { + super(plugin); + } + + @NotNull + @Override + public DataSnapshot.Packed convert(@NotNull byte[] data) throws DataAdapter.AdaptionException { + final JSONObject object = new JSONObject(plugin.getDataAdapter().bytesToString(data)); + final int version = object.getInt("format_version"); + if (version != 3) { + throw new DataAdapter.AdaptionException(String.format( + "Unsupported legacy data format version: %s. Please downgrade to an earlier version of HuskSync, " + + "perform a manual legacy migration, then attempt to upgrade again.", version + )); + } + + // Read legacy data from the JSON object + final DataSnapshot.Builder builder = DataSnapshot.builder(plugin) + .saveCause(DataSnapshot.SaveCause.CONVERTED_FROM_V2) + .data(readStatusData(object)); + readInventory(object).ifPresent(builder::inventory); + readEnderChest(object).ifPresent(builder::enderChest); + readLocation(object).ifPresent(builder::location); + readAdvancements(object).ifPresent(builder::advancements); + readStatistics(object).ifPresent(builder::statistics); + return builder.buildAndPack(); + } + + @NotNull + private Map readStatusData(@NotNull JSONObject object) { + if (!object.has("status_data")) { + return Map.of(); + } + + final JSONObject status = object.getJSONObject("status_data"); + final HashMap containers = new HashMap<>(); + if (shouldImport(Identifier.HEALTH)) { + containers.put(Identifier.HEALTH, BukkitData.Health.from( + status.getDouble("health"), + status.getDouble("max_health"), + status.getDouble("health_scale") + )); + } + if (shouldImport(Identifier.HUNGER)) { + containers.put(Identifier.HUNGER, BukkitData.Hunger.from( + status.getInt("hunger"), + status.getFloat("saturation"), + status.getFloat("saturation_exhaustion") + )); + } + if (shouldImport(Identifier.EXPERIENCE)) { + containers.put(Identifier.EXPERIENCE, BukkitData.Experience.from( + status.getInt("total_experience"), + status.getInt("experience_level"), + status.getFloat("experience_progress") + )); + } + if (shouldImport(Identifier.GAME_MODE)) { + containers.put(Identifier.GAME_MODE, BukkitData.GameMode.from( + status.getString("game_mode"), + status.getBoolean("is_flying"), + status.getBoolean("is_flying") + )); + } + return containers; + } + + @NotNull + private Optional readInventory(@NotNull JSONObject object) { + if (!object.has("inventory") || !shouldImport(Identifier.INVENTORY)) { + return Optional.empty(); + } + + final JSONObject inventoryData = object.getJSONObject("inventory"); + return Optional.of(BukkitData.Items.Inventory.from( + deserializeLegacyItemStacks(inventoryData.getString("serialized_items")), 0 + )); + } + + @NotNull + private Optional readEnderChest(@NotNull JSONObject object) { + if (!object.has("ender_chest") || !shouldImport(Identifier.ENDER_CHEST)) { + return Optional.empty(); + } + + final JSONObject inventoryData = object.getJSONObject("ender_chest"); + return Optional.of(BukkitData.Items.EnderChest.adapt( + deserializeLegacyItemStacks(inventoryData.getString("serialized_items")) + )); + } + + @NotNull + private Optional readLocation(@NotNull JSONObject object) { + if (!object.has("location") || !shouldImport(Identifier.LOCATION)) { + return Optional.empty(); + } + + final JSONObject locationData = object.getJSONObject("location"); + return Optional.of(BukkitData.Location.from( + locationData.getDouble("x"), + locationData.getDouble("y"), + locationData.getDouble("z"), + locationData.getFloat("yaw"), + locationData.getFloat("pitch"), + new Data.Location.World( + locationData.getString("world_name"), + UUID.fromString(locationData.getString("world_uuid")), + locationData.getString("world_environment") + ) + )); + } + + @NotNull + private Optional readAdvancements(@NotNull JSONObject object) { + if (!object.has("advancements") || !shouldImport(Identifier.ADVANCEMENTS)) { + return Optional.empty(); + } + + final JSONArray advancements = object.getJSONArray("advancements"); + final List converted = new ArrayList<>(); + advancements.iterator().forEachRemaining(o -> { + final JSONObject advancement = (JSONObject) JSONObject.wrap(o); + final String key = advancement.getString("key"); + + final JSONObject criteria = advancement.getJSONObject("completed_criteria"); + final Map criteriaMap = new LinkedHashMap<>(); + criteria.keys().forEachRemaining(criteriaKey -> criteriaMap.put( + criteriaKey, parseDate(criteria.getString(criteriaKey))) + ); + converted.add(Data.Advancements.Advancement.adapt(key, criteriaMap)); + }); + + return Optional.of(BukkitData.Advancements.from(converted)); + } + + @NotNull + private Optional readStatistics(@NotNull JSONObject object) { + if (!object.has("statistics") || !shouldImport(Identifier.ADVANCEMENTS)) { + return Optional.empty(); + } + + final JSONObject stats = object.getJSONObject("statistics"); + return Optional.of(readStatisticMaps( + stats.getJSONObject("untyped_statistics"), + stats.getJSONObject("block_statistics"), + stats.getJSONObject("item_statistics"), + stats.getJSONObject("entity_statistics") + )); + } + + @NotNull + private BukkitData.Statistics readStatisticMaps(@NotNull JSONObject untyped, @NotNull JSONObject blocks, + @NotNull JSONObject items, @NotNull JSONObject entities) { + final Map genericStats = new HashMap<>(); + untyped.keys().forEachRemaining(stat -> genericStats.put(Statistic.valueOf(stat), untyped.getInt(stat))); + + final Map> blockStats = new HashMap<>(); + blocks.keys().forEachRemaining(stat -> { + final JSONObject blockStat = blocks.getJSONObject(stat); + final Map blockMap = new HashMap<>(); + blockStat.keys().forEachRemaining(block -> blockMap.put(Material.valueOf(block), blockStat.getInt(block))); + blockStats.put(Statistic.valueOf(stat), blockMap); + }); + + final Map> itemStats = new HashMap<>(); + items.keys().forEachRemaining(stat -> { + final JSONObject itemStat = items.getJSONObject(stat); + final Map itemMap = new HashMap<>(); + itemStat.keys().forEachRemaining(item -> itemMap.put(Material.valueOf(item), itemStat.getInt(item))); + itemStats.put(Statistic.valueOf(stat), itemMap); + }); + + final Map> entityStats = new HashMap<>(); + entities.keys().forEachRemaining(stat -> { + final JSONObject entityStat = entities.getJSONObject(stat); + final Map entityMap = new HashMap<>(); + entityStat.keys().forEachRemaining(entity -> entityMap.put(EntityType.valueOf(entity), entityStat.getInt(entity))); + entityStats.put(Statistic.valueOf(stat), entityMap); + }); + + return BukkitData.Statistics.from(genericStats, blockStats, itemStats, entityStats); + } + + // Deserialize a legacy item stack array + @NotNull + public ItemStack[] deserializeLegacyItemStacks(@NotNull String items) { + // Return an empty array if there is no inventory data (set the player as having an empty inventory) + if (items.isEmpty()) { + return new ItemStack[0]; + } + + // Create a byte input stream to read the serialized data + try (ByteArrayInputStream byteInputStream = new ByteArrayInputStream(Base64Coder.decodeLines(items))) { + try (BukkitObjectInputStream bukkitInputStream = new BukkitObjectInputStream(byteInputStream)) { + // Read the length of the Bukkit input stream and set the length of the array to this value + final ItemStack[] inventoryContents = new ItemStack[bukkitInputStream.readInt()]; + + // Set the ItemStacks in the array from deserialized ItemStack data + int slotIndex = 0; + for (ItemStack ignored : inventoryContents) { + final ItemStack deserialized = deserializeLegacyItemStack(bukkitInputStream.readObject()); + inventoryContents[slotIndex] = deserialized; + slotIndex++; + } + + // Return the converted contents + return inventoryContents; + } + } catch (Throwable e) { + throw new DataAdapter.AdaptionException("Failed to deserialize legacy item stack data", e); + } + } + + // Deserialize a single legacy item stack + @Nullable + private static ItemStack deserializeLegacyItemStack(@Nullable Object serializedItemStack) { + return serializedItemStack != null ? ItemStack.deserialize((Map) serializedItemStack) : null; + } + + + private boolean shouldImport(@NotNull Identifier type) { + return plugin.getSettings().isSyncFeatureEnabled(type); + } + + @NotNull + private Date parseDate(@NotNull String dateString) { + try { + return new SimpleDateFormat().parse(dateString); + } catch (ParseException e) { + return new Date(); + } + } + +} diff --git a/bukkit/src/main/java/net/william278/husksync/util/BukkitMapPersister.java b/bukkit/src/main/java/net/william278/husksync/util/BukkitMapPersister.java new file mode 100644 index 00000000..aa98fd9b --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/util/BukkitMapPersister.java @@ -0,0 +1,378 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.util; + +import de.tr7zw.changeme.nbtapi.NBT; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; +import de.tr7zw.changeme.nbtapi.iface.ReadableNBT; +import net.william278.husksync.HuskSync; +import net.william278.mapdataapi.MapBanner; +import net.william278.mapdataapi.MapData; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.MapMeta; +import org.bukkit.map.*; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.util.List; +import java.util.*; +import java.util.function.Function; +import java.util.logging.Level; + +public interface BukkitMapPersister { + + // The map used to store HuskSync data in ItemStack NBT + String MAP_DATA_KEY = "husksync:persisted_locked_map"; + // The key used to store the serialized map data in NBT + String MAP_PIXEL_DATA_KEY = "canvas_data"; + // The key used to store the map of World UIDs to MapView IDs in NBT + String MAP_VIEW_ID_MAPPINGS_KEY = "id_mappings"; + + /** + * Persist locked maps in an array of {@link ItemStack}s + * + * @param items the array of {@link ItemStack}s to persist locked maps in + * @param delegateRenderer the player to delegate the rendering of map pixel canvases to + * @return the array of {@link ItemStack}s with locked maps persisted to serialized NBT + */ + @NotNull + default ItemStack[] persistLockedMaps(@NotNull ItemStack[] items, @NotNull Player delegateRenderer) { + if (!getPlugin().getSettings().doPersistLockedMaps()) { + return items; + } + return forEachMap(items, map -> this.persistMapView(map, delegateRenderer)); + } + + /** + * Apply persisted locked maps to an array of {@link ItemStack}s + * + * @param items the array of {@link ItemStack}s to apply persisted locked maps to + * @return the array of {@link ItemStack}s with persisted locked maps applied + */ + @NotNull + default ItemStack[] setMapViews(@NotNull ItemStack[] items) { + if (!getPlugin().getSettings().doPersistLockedMaps()) { + return items; + } + return forEachMap(items, this::applyMapView); + } + + // Perform an operation on each map in an array of ItemStacks + @NotNull + private ItemStack[] forEachMap(@NotNull ItemStack[] items, @NotNull Function function) { + for (int i = 0; i < items.length; i++) { + final ItemStack item = items[i]; + if (item == null) { + continue; + } + if (item.getType() == Material.FILLED_MAP && item.hasItemMeta()) { + items[i] = function.apply(item); + } + } + return items; + } + + @NotNull + private ItemStack persistMapView(@NotNull ItemStack map, @NotNull Player delegateRenderer) { + final MapMeta meta = Objects.requireNonNull((MapMeta) map.getItemMeta()); + if (!meta.hasMapView()) { + return map; + } + final MapView view = meta.getMapView(); + if (view == null || view.getWorld() == null || !view.isLocked() || view.isVirtual()) { + return map; + } + + NBT.modify(map, nbt -> { + // Don't save the map's data twice + if (nbt.hasTag(MAP_DATA_KEY)) { + return; + } + + // Render the map + final PersistentMapCanvas canvas = new PersistentMapCanvas(view); + for (MapRenderer renderer : view.getRenderers()) { + renderer.render(view, canvas, delegateRenderer); + getPlugin().debug(String.format("Rendered locked map canvas to view (#%s)", view.getId())); + } + + // Persist map data + final ReadWriteNBT mapData = nbt.getOrCreateCompound(MAP_DATA_KEY); + final String worldUid = view.getWorld().getUID().toString(); + mapData.setByteArray(MAP_PIXEL_DATA_KEY, canvas.extractMapData().toBytes()); + nbt.getOrCreateCompound(MAP_VIEW_ID_MAPPINGS_KEY).setInteger(worldUid, view.getId()); + getPlugin().debug(String.format("Saved data for locked map (#%s, UID: %s)", view.getId(), worldUid)); + }); + return map; + } + + @NotNull + private ItemStack applyMapView(@NotNull ItemStack map) { + final MapMeta meta = Objects.requireNonNull((MapMeta) map.getItemMeta()); + NBT.get(map, nbt -> { + if (!nbt.hasTag(MAP_DATA_KEY)) { + return nbt; + } + final ReadableNBT mapData = nbt.getCompound(MAP_DATA_KEY); + + // Search for an existing map view + final ReadableNBT mapIds = nbt.getCompound(MAP_VIEW_ID_MAPPINGS_KEY); + Optional world = Optional.empty(); + for (String worldUid : mapIds.getKeys()) { + world = Bukkit.getWorlds().stream() + .map(w -> w.getUID().toString()).filter(u -> u.equals(worldUid)) + .findFirst(); + if (world.isPresent()) { + break; + } + } + if (world.isPresent()) { + final String uid = world.get(); + final Optional existingView = this.getMapView(mapIds.getInteger(uid)); + if (existingView.isPresent()) { + final MapView view = existingView.get(); + view.setLocked(true); + meta.setMapView(view); + map.setItemMeta(meta); + getPlugin().debug(String.format("View exists (#%s); updated map (UID: %s)", view.getId(), uid)); + return nbt; + } + } + + // Read the pixel data and generate a map view otherwise + final MapData canvasData; + try { + getPlugin().debug("Deserializing map data from NBT and generating view..."); + canvasData = MapData.fromByteArray(mapData.getByteArray(MAP_PIXEL_DATA_KEY)); + } catch (Throwable e) { + getPlugin().log(Level.WARNING, "Failed to deserialize map data from NBT", e); + return nbt; + } + + // Add a renderer to the map with the data + final MapView view = generateRenderedMap(canvasData); + final String worldUid = getDefaultMapWorld().getUID().toString(); + meta.setMapView(view); + map.setItemMeta(meta); + + // Set the map view ID in NBT + NBT.modify(map, editable -> { + editable.getCompound(MAP_VIEW_ID_MAPPINGS_KEY).setInteger(worldUid, view.getId()); + }); + getPlugin().debug(String.format("Generated view (#%s) and updated map (UID: %s)", view.getId(), worldUid)); + return nbt; + }); + return map; + } + + // Sets the renderer of a map, and returns the generated MapView + @NotNull + private MapView generateRenderedMap(@NotNull MapData canvasData) { + final MapView view = Bukkit.createMap(getDefaultMapWorld()); + view.getRenderers().clear(); + + // Create a new map view renderer with the map data color at each pixel + view.addRenderer(new PersistentMapRenderer(canvasData)); + view.setLocked(true); + view.setScale(MapView.Scale.NORMAL); + view.setTrackingPosition(false); + view.setUnlimitedTracking(false); + + // Set the view to the map and return it + setMapView(view); + return view; + } + + @NotNull + private static World getDefaultMapWorld() { + final World world = Bukkit.getWorlds().get(0); + if (world == null) { + throw new IllegalStateException("No worlds are loaded on the server!"); + } + return world; + } + + default Optional getMapView(int id) { + return getMapViews().containsKey(id) ? Optional.of(getMapViews().get(id)) : Optional.empty(); + } + + default void setMapView(@NotNull MapView view) { + getMapViews().put(view.getId(), view); + } + + /** + * A {@link MapRenderer} that can be used to render persistently serialized {@link MapData} to a {@link MapView} + */ + class PersistentMapRenderer extends MapRenderer { + + private final MapData canvasData; + + private PersistentMapRenderer(@NotNull MapData canvasData) { + super(false); + this.canvasData = canvasData; + } + + @Override + public void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player) { + // We set the pixels in this order to avoid the map being rendered upside down + for (int i = 0; i < 128; i++) { + for (int j = 0; j < 128; j++) { + canvas.setPixel(j, i, (byte) canvasData.getColorAt(i, j)); + } + } + + // Set the map banners and markers + final MapCursorCollection cursors = canvas.getCursors(); + canvasData.getBanners().forEach(banner -> cursors.addCursor(createBannerCursor(banner))); + canvas.setCursors(cursors); + } + } + + @NotNull + private static MapCursor createBannerCursor(@NotNull MapBanner banner) { + return new MapCursor( + (byte) banner.getPosition().getX(), + (byte) banner.getPosition().getZ(), + (byte) 0, + switch (banner.getColor().toLowerCase(Locale.ENGLISH)) { + case "white" -> MapCursor.Type.BANNER_WHITE; + case "orange" -> MapCursor.Type.BANNER_ORANGE; + case "magenta" -> MapCursor.Type.BANNER_MAGENTA; + case "light_blue" -> MapCursor.Type.BANNER_LIGHT_BLUE; + case "yellow" -> MapCursor.Type.BANNER_YELLOW; + case "lime" -> MapCursor.Type.BANNER_LIME; + case "pink" -> MapCursor.Type.BANNER_PINK; + case "gray" -> MapCursor.Type.BANNER_GRAY; + case "light_gray" -> MapCursor.Type.BANNER_LIGHT_GRAY; + case "cyan" -> MapCursor.Type.BANNER_CYAN; + case "purple" -> MapCursor.Type.BANNER_PURPLE; + case "blue" -> MapCursor.Type.BANNER_BLUE; + case "brown" -> MapCursor.Type.BANNER_BROWN; + case "green" -> MapCursor.Type.BANNER_GREEN; + case "red" -> MapCursor.Type.BANNER_RED; + default -> MapCursor.Type.BANNER_BLACK; + }, + true, + banner.getText().isEmpty() ? null : banner.getText() + ); + } + + /** + * A {@link MapCanvas} implementation used for pre-rendering maps to be converted into {@link MapData} + */ + class PersistentMapCanvas implements MapCanvas { + + private final MapView mapView; + private final int[][] pixels = new int[128][128]; + private MapCursorCollection cursors; + + private PersistentMapCanvas(@NotNull MapView mapView) { + this.mapView = mapView; + } + + @NotNull + @Override + public MapView getMapView() { + return mapView; + } + + @NotNull + @Override + public MapCursorCollection getCursors() { + return cursors == null ? (cursors = new MapCursorCollection()) : cursors; + } + + @Override + public void setCursors(@NotNull MapCursorCollection cursors) { + this.cursors = cursors; + } + + @Override + public void setPixel(int x, int y, byte color) { + pixels[x][y] = color; + } + + @Override + public byte getPixel(int x, int y) { + return (byte) pixels[x][y]; + } + + @Override + public byte getBasePixel(int x, int y) { + return getPixel(x, y); + } + + @Override + public void drawImage(int x, int y, @NotNull Image image) { + // Not implemented + } + + @Override + public void drawText(int x, int y, @NotNull MapFont font, @NotNull String text) { + // Not implemented + } + + @NotNull + private String getDimension() { + return mapView.getWorld() != null ? switch (mapView.getWorld().getEnvironment()) { + case NETHER -> "minecraft:the_nether"; + case THE_END -> "minecraft:the_end"; + default -> "minecraft:overworld"; + } : "minecraft:overworld"; + } + + /** + * Extract the map data from the canvas. Must be rendered first + * + * @return the extracted map data + */ + @NotNull + private MapData extractMapData() { + final List banners = new ArrayList<>(); + for (int i = 0; i < getCursors().size(); i++) { + final MapCursor cursor = getCursors().getCursor(i); + final String type = cursor.getType().name().toLowerCase(Locale.ENGLISH); + if (type.startsWith("banner_")) { + banners.add(new MapBanner( + type.replaceAll("banner_", ""), + cursor.getCaption() == null ? "" : cursor.getCaption(), + cursor.getX(), + mapView.getWorld() != null ? mapView.getWorld().getSeaLevel() : 128, + cursor.getY() + )); + } + } + return MapData.fromPixels(pixels, getDimension(), (byte) 2, banners, List.of()); + } + } + + @NotNull + Map getMapViews(); + + @ApiStatus.Internal + @NotNull + HuskSync getPlugin(); + +} diff --git a/bukkit/src/main/java/net/william278/husksync/util/BukkitTask.java b/bukkit/src/main/java/net/william278/husksync/util/BukkitTask.java new file mode 100644 index 00000000..a9381425 --- /dev/null +++ b/bukkit/src/main/java/net/william278/husksync/util/BukkitTask.java @@ -0,0 +1,172 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.util; + +import net.william278.husksync.BukkitHuskSync; +import net.william278.husksync.HuskSync; +import org.jetbrains.annotations.NotNull; +import space.arim.morepaperlib.scheduling.AsynchronousScheduler; +import space.arim.morepaperlib.scheduling.RegionalScheduler; +import space.arim.morepaperlib.scheduling.ScheduledTask; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; + +public interface BukkitTask extends Task { + + class Sync extends Task.Sync implements BukkitTask { + + private ScheduledTask task; + + protected Sync(@NotNull HuskSync plugin, @NotNull Runnable runnable, long delayTicks) { + super(plugin, runnable, delayTicks); + } + + @Override + public void cancel() { + if (task != null && !cancelled) { + task.cancel(); + } + super.cancel(); + } + + @Override + public void run() { + if (isPluginDisabled()) { + runnable.run(); + return; + } + if (cancelled) { + return; + } + + final RegionalScheduler scheduler = ((BukkitHuskSync) getPlugin()).getRegionalScheduler(); + if (delayTicks > 0) { + this.task = scheduler.runDelayed(runnable, delayTicks); + } else { + this.task = scheduler.run(runnable); + } + } + } + + class Async extends Task.Async implements BukkitTask { + + private ScheduledTask task; + + protected Async(@NotNull HuskSync plugin, @NotNull Runnable runnable, long delayTicks) { + super(plugin, runnable, delayTicks); + } + + @Override + public void cancel() { + if (task != null && !cancelled) { + task.cancel(); + } + super.cancel(); + } + + @Override + public void run() { + if (isPluginDisabled()) { + runnable.run(); + return; + } + if (cancelled) { + return; + } + + final AsynchronousScheduler scheduler = ((BukkitHuskSync) getPlugin()).getAsyncScheduler(); + if (delayTicks > 0) { + plugin.debug("Running async task with delay of " + delayTicks + " ticks"); + this.task = scheduler.runDelayed( + runnable, + Duration.of(delayTicks * 50L, ChronoUnit.MILLIS) + ); + } else { + this.task = scheduler.run(runnable); + } + } + } + + class Repeating extends Task.Repeating implements BukkitTask { + + private ScheduledTask task; + + protected Repeating(@NotNull HuskSync plugin, @NotNull Runnable runnable, long repeatingTicks) { + super(plugin, runnable, repeatingTicks); + } + + @Override + public void cancel() { + if (task != null && !cancelled) { + task.cancel(); + } + super.cancel(); + } + + @Override + public void run() { + if (isPluginDisabled()) { + return; + } + + if (!cancelled) { + final AsynchronousScheduler scheduler = ((BukkitHuskSync) getPlugin()).getAsyncScheduler(); + this.task = scheduler.runAtFixedRate( + runnable, Duration.ZERO, + Duration.of(repeatingTicks * 50L, ChronoUnit.MILLIS) + ); + } + } + } + + // Returns if the Bukkit HuskSync plugin is disabled + default boolean isPluginDisabled() { + return !((BukkitHuskSync) getPlugin()).isEnabled(); + } + + interface Supplier extends Task.Supplier { + + @NotNull + @Override + default Task.Sync getSyncTask(@NotNull Runnable runnable, long delayTicks) { + return new Sync(getPlugin(), runnable, delayTicks); + } + + @NotNull + @Override + default Task.Async getAsyncTask(@NotNull Runnable runnable, long delayTicks) { + return new Async(getPlugin(), runnable, delayTicks); + } + + @NotNull + @Override + default Task.Repeating getRepeatingTask(@NotNull Runnable runnable, long repeatingTicks) { + return new Repeating(getPlugin(), runnable, repeatingTicks); + } + + @Override + default void cancelTasks() { + ((BukkitHuskSync) getPlugin()).getScheduler().cancelGlobalTasks(); + } + + } + +} \ No newline at end of file diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml index b337a9eb..07051d89 100644 --- a/bukkit/src/main/resources/plugin.yml +++ b/bukkit/src/main/resources/plugin.yml @@ -12,19 +12,4 @@ libraries: - 'redis.clients:jedis:${jedis_version}' - 'com.mysql:mysql-connector-j:${mysql_driver_version}' - 'org.mariadb.jdbc:mariadb-java-client:${mariadb_driver_version}' - - 'org.xerial.snappy:snappy-java:${snappy_version}' - - 'org.apache.commons:commons-text:${commons_text_version}' - -commands: - husksync: - usage: '/ ' - description: 'Manage the HuskSync plugin' - userdata: - usage: '/ [version_uuid]' - description: 'View, manage & restore player userdata' - inventory: - usage: '/ [version_uuid]' - description: 'View & edit a player''s inventory' - enderchest: - usage: '/ [version_uuid]' - description: 'View & edit a player''s Ender Chest' \ No newline at end of file + - 'org.xerial.snappy:snappy-java:${snappy_version}' \ No newline at end of file diff --git a/common/build.gradle b/common/build.gradle index 81f85f22..a21899eb 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,40 +1,33 @@ +plugins { + id 'java-library' +} + dependencies { - implementation 'commons-io:commons-io:2.13.0' - implementation 'de.themoep:minedown-adventure:1.7.2-SNAPSHOT' - implementation 'net.kyori:adventure-api:4.14.0' - implementation 'com.google.code.gson:gson:2.10.1' - implementation 'dev.dejvokep:boosted-yaml:1.3.1' - implementation 'net.william278:Annotaml:2.0.1' - implementation 'net.william278:DesertWell:2.0.4' - implementation 'net.william278:PagineDown:1.1' - implementation('com.zaxxer:HikariCP:5.0.1') { + api 'commons-io:commons-io:2.13.0' + api 'org.apache.commons:commons-text:1.10.0' + api 'de.themoep:minedown-adventure:1.7.2-SNAPSHOT' + api 'net.kyori:adventure-api:4.14.0' + api 'org.json:json:20230618' + api 'com.google.code.gson:gson:2.10.1' + api 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.2' + api 'dev.dejvokep:boosted-yaml:1.3.1' + api 'net.william278:annotaml:2.0.7' + api 'net.william278:DesertWell:2.0.4' + api 'net.william278:PagineDown:1.1' + api('com.zaxxer:HikariCP:5.0.1') { exclude module: 'slf4j-api' } compileOnly 'org.jetbrains:annotations:24.0.1' compileOnly 'com.github.plan-player-analytics:Plan:5.5.2272' - compileOnly 'redis.clients:jedis:' + jedis_version - compileOnly 'org.xerial.snappy:snappy-java:' + snappy_version - compileOnly 'org.apache.commons:commons-text:' + commons_text_version + compileOnly "redis.clients:jedis:$jedis_version" + compileOnly "com.mysql:mysql-connector-j:$mysql_driver_version" + compileOnly "org.mariadb.jdbc:mariadb-java-client:$mariadb_driver_version" + compileOnly "org.xerial.snappy:snappy-java:$snappy_version" testImplementation 'com.github.plan-player-analytics:Plan:5.5.2272' - testImplementation 'redis.clients:jedis:' + jedis_version - testImplementation 'org.xerial.snappy:snappy-java:' + snappy_version - testImplementation 'org.apache.commons:commons-text:' + commons_text_version + testImplementation "redis.clients:jedis:$jedis_version" + testImplementation "org.xerial.snappy:snappy-java:$snappy_version" testCompileOnly 'dev.dejvokep:boosted-yaml:1.3.1' testCompileOnly 'org.jetbrains:annotations:24.0.1' -} - -shadowJar { - relocate 'org.apache.commons.io', 'net.william278.husksync.libraries.commons.io' - relocate 'com.google.gson', 'net.william278.husksync.libraries.gson' - relocate 'de.themoep', 'net.william278.husksync.libraries' - relocate 'net.kyori', 'net.william278.husksync.libraries' - relocate 'org.jetbrains', 'net.william278.husksync.libraries' - relocate 'org.intellij', 'net.william278.husksync.libraries' - relocate 'com.zaxxer', 'net.william278.husksync.libraries' - relocate 'dev.dejvokep', 'net.william278.husksync.libraries' - relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell' - relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown' - relocate 'net.william278.annotaml', 'net.william278.husksync.libraries.annotaml' } \ No newline at end of file diff --git a/common/src/main/java/net/william278/husksync/HuskSync.java b/common/src/main/java/net/william278/husksync/HuskSync.java index a579ff57..6c8324b0 100644 --- a/common/src/main/java/net/william278/husksync/HuskSync.java +++ b/common/src/main/java/net/william278/husksync/HuskSync.java @@ -19,31 +19,40 @@ package net.william278.husksync; +import com.fatboyindustrial.gsonjavatime.Converters; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import net.william278.annotaml.Annotaml; +import net.william278.desertwell.util.ThrowingConsumer; import net.william278.desertwell.util.UpdateChecker; import net.william278.desertwell.util.Version; +import net.william278.husksync.adapter.DataAdapter; import net.william278.husksync.config.Locales; import net.william278.husksync.config.Settings; -import net.william278.husksync.data.DataAdapter; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.Identifier; +import net.william278.husksync.data.Serializer; import net.william278.husksync.database.Database; -import net.william278.husksync.event.EventCannon; +import net.william278.husksync.event.EventDispatcher; import net.william278.husksync.migrator.Migrator; -import net.william278.husksync.player.OnlineUser; import net.william278.husksync.redis.RedisManager; +import net.william278.husksync.user.ConsoleUser; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.util.LegacyConverter; +import net.william278.husksync.util.Task; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.IOException; import java.io.InputStream; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; +import java.lang.reflect.InvocationTargetException; +import java.util.*; import java.util.logging.Level; /** * Abstract implementation of the HuskSync plugin. */ -public interface HuskSync { +public interface HuskSync extends Task.Supplier, EventDispatcher { int SPIGOT_RESOURCE_ID = 97144; @@ -81,21 +90,45 @@ public interface HuskSync { @NotNull RedisManager getRedisManager(); + @NotNull + DataAdapter getDataAdapter(); + /** - * Returns the data adapter implementation - * - * @return the {@link DataAdapter} implementation + * Returns the data serializer for the given {@link Identifier} */ @NotNull - DataAdapter getDataAdapter(); + Map> getSerializers(); /** - * Returns the event firing cannon + * Register a data serializer for the given {@link Identifier} * - * @return the {@link EventCannon} implementation + * @param identifier the {@link Identifier} + * @param serializer the {@link Serializer} + */ + default void registerSerializer(@NotNull Identifier identifier, + @NotNull Serializer serializer) { + if (identifier.isCustom()) { + log(Level.INFO, String.format("Registered custom data type: %s", identifier)); + } + getSerializers().put(identifier, (Serializer) serializer); + } + + /** + * Get the {@link Identifier} for the given key + */ + default Optional getIdentifier(@NotNull String key) { + return getSerializers().keySet().stream().filter(identifier -> identifier.toString().equals(key)).findFirst(); + } + + /** + * Get the set of registered data types + * + * @return the set of registered data types */ @NotNull - EventCannon getEventCannon(); + default Set getRegisteredDataTypes() { + return getSerializers().keySet(); + } /** * Returns a list of available data {@link Migrator}s @@ -105,6 +138,25 @@ public interface HuskSync { @NotNull List getAvailableMigrators(); + @NotNull + Map getPlayerCustomDataStore(@NotNull OnlineUser user); + + /** + * Initialize a faucet of the plugin. + * + * @param name the name of the faucet + * @param runner a runnable for initializing the faucet + */ + default void initialize(@NotNull String name, @NotNull ThrowingConsumer runner) { + log(Level.INFO, "Initializing " + name + "..."); + try { + runner.accept(this); + } catch (Throwable e) { + throw new FailedToLoadException("Failed to initialize " + name, e); + } + log(Level.INFO, "Successfully initialized " + name); + } + /** * Returns the plugin {@link Settings} * @@ -113,6 +165,8 @@ public interface HuskSync { @NotNull Settings getSettings(); + void setSettings(@NotNull Settings settings); + /** * Returns the plugin {@link Locales} * @@ -121,6 +175,16 @@ public interface HuskSync { @NotNull Locales getLocales(); + void setLocales(@NotNull Locales locales); + + /** + * Returns if a dependency is loaded + * + * @param name the name of the dependency + * @return {@code true} if the dependency is loaded, {@code false} otherwise + */ + boolean isDependencyLoaded(@NotNull String name); + /** * Get a resource as an {@link InputStream} from the plugin jar * @@ -129,6 +193,14 @@ public interface HuskSync { */ InputStream getResource(@NotNull String name); + /** + * Returns the plugin data folder + * + * @return the plugin data folder as a {@link File} + */ + @NotNull + File getDataFolder(); + /** * Log a message to the console * @@ -146,10 +218,18 @@ public interface HuskSync { */ default void debug(@NotNull String message, @NotNull Throwable... throwable) { if (getSettings().doDebugLogging()) { - log(Level.INFO, "[DEBUG] " + message, throwable); + log(Level.INFO, String.format("[DEBUG] %s", message), throwable); } } + /** + * Get the console user + * + * @return the {@link ConsoleUser} + */ + @NotNull + ConsoleUser getConsole(); + /** * Returns the plugin version * @@ -159,44 +239,103 @@ public interface HuskSync { Version getPluginVersion(); /** - * Returns the plugin data folder + * Returns the Minecraft version implementation * - * @return the plugin data folder as a {@link File} + * @return the Minecraft {@link Version} */ @NotNull - File getDataFolder(); + Version getMinecraftVersion(); /** - * Returns a future returning the latest plugin {@link Version} if the plugin is out-of-date + * Returns the platform type * - * @return a {@link CompletableFuture} returning the latest {@link Version} if the current one is out-of-date + * @return the platform type */ - default CompletableFuture> getLatestVersionIfOutdated() { + @NotNull + String getPlatformType(); + + /** + * Returns the legacy data converter, if it exists + * + * @return the {@link LegacyConverter} + */ + Optional getLegacyConverter(); + + /** + * Reloads the {@link Settings} and {@link Locales} from their respective config files. + */ + default void loadConfigs() { + try { + // Load settings + setSettings(Annotaml.create(new File(getDataFolder(), "config.yml"), Settings.class).get()); + + // Load locales from language preset default + final Locales languagePresets = Annotaml.create( + Locales.class, + Objects.requireNonNull(getResource(String.format("locales/%s.yml", getSettings().getLanguage()))) + ).get(); + setLocales(Annotaml.create(new File( + getDataFolder(), + String.format("messages_%s.yml", getSettings().getLanguage()) + ), languagePresets).get()); + } catch (IOException | InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new FailedToLoadException("Failed to load config or message files", e); + } + } + + @NotNull + default UpdateChecker getUpdateChecker() { return UpdateChecker.builder() .currentVersion(getPluginVersion()) .endpoint(UpdateChecker.Endpoint.SPIGOT) - .resource(Integer.toString(SPIGOT_RESOURCE_ID)).build() - .check() - .thenApply(checked -> checked.isUpToDate() - ? Optional.empty() - : Optional.of(checked.getLatestVersion())); + .resource(Integer.toString(SPIGOT_RESOURCE_ID)) + .build(); + } + + default void checkForUpdates() { + if (getSettings().doCheckForUpdates()) { + getUpdateChecker().check().thenAccept(checked -> { + if (!checked.isUpToDate()) { + log(Level.WARNING, String.format( + "A new version of HuskSync is available: v%s (running v%s)", + checked.getLatestVersion(), getPluginVersion()) + ); + } + }); + } } - /** - * Returns the Minecraft version implementation - * - * @return the Minecraft {@link Version} - */ @NotNull - Version getMinecraftVersion(); + Set getLockedPlayers(); + + @NotNull + Gson getGson(); + + @NotNull + default Gson createGson() { + return Converters.registerOffsetDateTime(new GsonBuilder()).create(); + } /** - * Reloads the {@link Settings} and {@link Locales} from their respective config files - * - * @return a {@link CompletableFuture} that will be completed when the plugin reload is complete and if it was successful + * An exception indicating the plugin has been accessed before it has been registered. */ - CompletableFuture reload(); + final class FailedToLoadException extends IllegalStateException { - Set getLockedPlayers(); + private static final String FORMAT = """ + HuskSync has failed to load! The plugin will not be enabled and no data will be synchronized. + Please make sure the plugin has been setup correctly (https://william278.net/docs/husksync/setup): + + 1) Make sure you've entered your MySQL or MariaDB database details correctly in config.yml + 2) Make sure your Redis server details are also correct in config.yml + 3) Make sure your config is up-to-date (https://william278.net/docs/husksync/config-files) + 4) Check the error below for more details + + Caused by: %s"""; + + FailedToLoadException(@NotNull String message, @NotNull Throwable cause) { + super(String.format(FORMAT, message), cause); + } + + } } diff --git a/common/src/main/java/net/william278/husksync/data/DataAdaptionException.java b/common/src/main/java/net/william278/husksync/adapter/Adaptable.java similarity index 70% rename from common/src/main/java/net/william278/husksync/data/DataAdaptionException.java rename to common/src/main/java/net/william278/husksync/adapter/Adaptable.java index c88f158b..4742fe1d 100644 --- a/common/src/main/java/net/william278/husksync/data/DataAdaptionException.java +++ b/common/src/main/java/net/william278/husksync/adapter/Adaptable.java @@ -17,14 +17,8 @@ * limitations under the License. */ -package net.william278.husksync.data; +package net.william278.husksync.adapter; -/** - * Indicates an error occurred during {@link UserData} adaptation to and from (compressed) json. - */ -public class DataAdaptionException extends RuntimeException { - protected DataAdaptionException(String message, Throwable cause) { - super(message, cause); - } +public interface Adaptable { } diff --git a/common/src/main/java/net/william278/husksync/adapter/DataAdapter.java b/common/src/main/java/net/william278/husksync/adapter/DataAdapter.java new file mode 100644 index 00000000..53ea2b19 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/adapter/DataAdapter.java @@ -0,0 +1,108 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.adapter; + +import org.jetbrains.annotations.NotNull; + +import java.nio.charset.StandardCharsets; + +/** + * An adapter that adapts data to and from a portable byte array. + */ +public interface DataAdapter { + + /** + * Converts an {@link Adaptable} to a string. + * + * @param data The {@link Adaptable} to adapt + * @param The type of the {@link Adaptable} + * @return The string + * @throws AdaptionException If an error occurred during adaptation. + */ + @NotNull + default String toString(@NotNull A data) throws AdaptionException { + return new String(this.toBytes(data), StandardCharsets.UTF_8); + } + + /** + * Converts an {@link Adaptable} to a byte array. + * + * @param data The {@link Adaptable} to adapt + * @param The type of the {@link Adaptable} + * @return The byte array + * @throws AdaptionException If an error occurred during adaptation. + */ + byte[] toBytes(@NotNull A data) throws AdaptionException; + + /** + * Converts a JSON string to an {@link Adaptable}. + * + * @param data The JSON string to adapt. + * @param type The class type of the {@link Adaptable} to adapt to. + * @param The type of the {@link Adaptable} + * @return The {@link Adaptable} + * @throws AdaptionException If an error occurred during adaptation. + */ + @NotNull + A fromJson(@NotNull String data, @NotNull Class type) throws AdaptionException; + + /** + * Converts an {@link Adaptable} to a JSON string. + * + * @param data The {@link Adaptable} to adapt + * @param The type of the {@link Adaptable} + * @return The JSON string + * @throws AdaptionException If an error occurred during adaptation. + */ + @NotNull + String toJson(@NotNull A data) throws AdaptionException; + + /** + * Converts a byte array to an {@link Adaptable}. + * + * @param data The byte array to adapt. + * @param type The class type of the {@link Adaptable} to adapt to. + * @param The type of the {@link Adaptable} + * @return The {@link Adaptable} + * @throws AdaptionException If an error occurred during adaptation. + */ + A fromBytes(@NotNull byte[] data, @NotNull Class type) throws AdaptionException; + + /** + * Converts a byte array to a string, including decompression if required. + * + * @param bytes The byte array to convert + * @return the string form of the bytes + */ + @NotNull + String bytesToString(byte[] bytes); + + final class AdaptionException extends IllegalStateException { + static final String FORMAT = "An exception occurred when adapting serialized/deserialized data: %s"; + + public AdaptionException(@NotNull String message, @NotNull Throwable cause) { + super(String.format(FORMAT, message), cause); + } + + public AdaptionException(@NotNull String message) { + super(String.format(FORMAT, message)); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/net/william278/husksync/adapter/GsonAdapter.java b/common/src/main/java/net/william278/husksync/adapter/GsonAdapter.java new file mode 100644 index 00000000..ba3d0514 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/adapter/GsonAdapter.java @@ -0,0 +1,72 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.adapter; + +import net.william278.husksync.HuskSync; +import org.jetbrains.annotations.NotNull; + +import java.nio.charset.StandardCharsets; + +public class GsonAdapter implements DataAdapter { + + private final HuskSync plugin; + + public GsonAdapter(@NotNull HuskSync plugin) { + this.plugin = plugin; + } + + @Override + public byte[] toBytes(@NotNull A data) throws AdaptionException { + return this.toJson(data).getBytes(StandardCharsets.UTF_8); + } + + @NotNull + @Override + public String toJson(@NotNull A data) throws AdaptionException { + try { + return plugin.getGson().toJson(data); + } catch (Throwable e) { + throw new AdaptionException("Failed to adapt data to JSON via Gson", e); + } + } + + @Override + @NotNull + public A fromBytes(@NotNull byte[] data, @NotNull Class type) throws AdaptionException { + return this.fromJson(new String(data, StandardCharsets.UTF_8), type); + } + + @NotNull + @Override + public String bytesToString(byte[] bytes) { + return new String(bytes, StandardCharsets.UTF_8); + } + + @Override + @NotNull + public A fromJson(@NotNull String data, @NotNull Class type) throws AdaptionException { + try { + return plugin.getGson().fromJson(data, type); + } catch (Throwable e) { + throw new AdaptionException("Failed to adapt data from JSON via Gson", e); + } + } + +} diff --git a/common/src/main/java/net/william278/husksync/adapter/SnappyGsonAdapter.java b/common/src/main/java/net/william278/husksync/adapter/SnappyGsonAdapter.java new file mode 100644 index 00000000..22af6ce0 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/adapter/SnappyGsonAdapter.java @@ -0,0 +1,68 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.adapter; + +import net.william278.husksync.HuskSync; +import org.jetbrains.annotations.NotNull; +import org.xerial.snappy.Snappy; + +import java.io.IOException; + +public class SnappyGsonAdapter extends GsonAdapter { + + public SnappyGsonAdapter(@NotNull HuskSync plugin) { + super(plugin); + } + + @NotNull + @Override + public byte[] toBytes(@NotNull A data) throws AdaptionException { + try { + return Snappy.compress(super.toBytes(data)); + } catch (IOException e) { + throw new AdaptionException("Failed to compress data through Snappy", e); + } + } + + @NotNull + @Override + public A fromBytes(@NotNull byte[] data, @NotNull Class type) throws AdaptionException { + try { + return super.fromBytes(decompressBytes(data), type); + } catch (IOException e) { + throw new AdaptionException("Failed to decompress data through Snappy", e); + } + } + + @Override + @NotNull + public String bytesToString(byte[] bytes) { + try { + return super.bytesToString(decompressBytes(bytes)); + } catch (IOException e) { + throw new AdaptionException("Failed to decompress data through Snappy", e); + } + } + + private byte[] decompressBytes(byte[] bytes) throws IOException { + return Snappy.uncompress(bytes); + } + +} diff --git a/common/src/main/java/net/william278/husksync/api/BaseHuskSyncAPI.java b/common/src/main/java/net/william278/husksync/api/BaseHuskSyncAPI.java deleted file mode 100644 index 70caae4b..00000000 --- a/common/src/main/java/net/william278/husksync/api/BaseHuskSyncAPI.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.api; - -import net.william278.husksync.HuskSync; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.data.UserDataSnapshot; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -/** - * The base implementation of the HuskSync API, containing cross-platform API calls. - *

- * This class should not be used directly, but rather through platform-specific extending API classes. - */ -@SuppressWarnings("unused") -public abstract class BaseHuskSyncAPI { - - /** - * (Internal use only) - Instance of the implementing plugin. - */ - protected final HuskSync plugin; - - protected BaseHuskSyncAPI(@NotNull HuskSync plugin) { - this.plugin = plugin; - } - - /** - * Returns a {@link User} by the given player's account {@link UUID}, if they exist. - * - * @param uuid the unique id of the player to get the {@link User} instance for - * @return future returning the {@link User} instance for the given player's unique id if they exist, otherwise an empty {@link Optional} - * @apiNote The player does not have to be online - * @since 2.0 - */ - public final CompletableFuture> getUser(@NotNull UUID uuid) { - return plugin.getDatabase().getUser(uuid); - } - - /** - * Returns a {@link User} by the given player's username (case-insensitive), if they exist. - * - * @param username the username of the {@link User} instance for - * @return future returning the {@link User} instance for the given player's username if they exist, - * otherwise an empty {@link Optional} - * @apiNote The player does not have to be online, though their username has to be the username - * they had when they last joined the server. - * @since 2.0 - */ - public final CompletableFuture> getUser(@NotNull String username) { - return plugin.getDatabase().getUserByName(username); - } - - /** - * Returns a {@link User}'s current {@link UserData} - * - * @param user the {@link User} to get the {@link UserData} for - * @return future returning the {@link UserData} for the given {@link User} if they exist, otherwise an empty {@link Optional} - * @apiNote If the user is not online on the implementing bukkit server, - * the {@link UserData} returned will be their last database-saved UserData. - *

- * Because of this, if the user is online on another server on the network, - * then the {@link UserData} returned by this method will not necessarily reflective of - * their current state - * @since 2.0 - */ - public final CompletableFuture> getUserData(@NotNull User user) { - return CompletableFuture.supplyAsync(() -> { - if (user instanceof OnlineUser) { - return ((OnlineUser) user).getUserData(plugin).join(); - } else { - return plugin.getDatabase().getCurrentUserData(user).join().map(UserDataSnapshot::userData); - } - }); - } - - /** - * Sets the {@link UserData} to the database for the given {@link User}. - *

- * If the user is online and on the same cluster, their data will be updated in game. - * - * @param user the {@link User} to set the {@link UserData} for - * @param userData the {@link UserData} to set for the given {@link User} - * @return future returning void when complete - * @since 2.0 - */ - public final CompletableFuture setUserData(@NotNull User user, @NotNull UserData userData) { - return CompletableFuture.runAsync(() -> - plugin.getDatabase().setUserData(user, userData, DataSaveCause.API) - .thenRun(() -> plugin.getRedisManager().sendUserDataUpdate(user, userData).join())); - } - - /** - * Saves the {@link UserData} of an {@link OnlineUser} to the database - * - * @param user the {@link OnlineUser} to save the {@link UserData} of - * @return future returning void when complete - * @since 2.0 - */ - public final CompletableFuture saveUserData(@NotNull OnlineUser user) { - return CompletableFuture.runAsync(() -> user.getUserData(plugin) - .thenAccept(optionalUserData -> optionalUserData.ifPresent( - userData -> plugin.getDatabase().setUserData(user, userData, DataSaveCause.API).join()))); - } - - /** - * Returns the saved {@link UserDataSnapshot} records for the given {@link User} - * - * @param user the {@link User} to get the {@link UserDataSnapshot} for - * @return future returning a list {@link UserDataSnapshot} for the given {@link User} if they exist, - * otherwise an empty {@link Optional} - * @apiNote The length of the list of VersionedUserData will correspond to the configured - * {@code max_user_data_records} config option - * @since 2.0 - */ - public final CompletableFuture> getSavedUserData(@NotNull User user) { - return CompletableFuture.supplyAsync(() -> plugin.getDatabase().getUserData(user).join()); - } - - /** - * Returns the JSON string representation of the given {@link UserData} - * - * @param userData the {@link UserData} to get the JSON string representation of - * @param prettyPrint whether to pretty print the JSON string - * @return the JSON string representation of the given {@link UserData} - * @since 2.0 - */ - @NotNull - public final String getUserDataJson(@NotNull UserData userData, boolean prettyPrint) { - return plugin.getDataAdapter().toJson(userData, prettyPrint); - } - -} diff --git a/common/src/main/java/net/william278/husksync/api/HuskSyncAPI.java b/common/src/main/java/net/william278/husksync/api/HuskSyncAPI.java new file mode 100644 index 00000000..a0d832f0 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/api/HuskSyncAPI.java @@ -0,0 +1,458 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.api; + +import net.william278.desertwell.util.ThrowingConsumer; +import net.william278.husksync.HuskSync; +import net.william278.husksync.adapter.Adaptable; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.data.Identifier; +import net.william278.husksync.data.Serializer; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.user.User; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +/** + * The base implementation of the HuskSync API, containing cross-platform API calls. + *

+ * This class should not be used directly, but rather through platform-specific extending API classes. + * + * @since 2.0 + */ +@SuppressWarnings("unused") +public abstract class HuskSyncAPI { + + /** + * (Internal use only) - Instance of the implementing plugin. + */ + protected final HuskSync plugin; + + /** + * (Internal use only) - Constructor, instantiating the base API class. + */ + @ApiStatus.Internal + protected HuskSyncAPI(@NotNull HuskSync plugin) { + this.plugin = plugin; + } + + /** + * Get a {@link User} by their UUID + * + * @param uuid The UUID of the user to get + * @return A future containing the user, or an empty optional if the user doesn't exist + * @since 3.0 + */ + @NotNull + public CompletableFuture> getUser(@NotNull UUID uuid) { + return plugin.supplyAsync(() -> plugin.getDatabase().getUser(uuid)); + } + + /** + * Get a {@link User} by their username + * + * @param username The username of the user to get + * @return A future containing the user, or an empty optional if the user doesn't exist + * @since 3.0 + */ + @NotNull + public CompletableFuture> getUser(@NotNull String username) { + return plugin.supplyAsync(() -> plugin.getDatabase().getUserByName(username)); + } + + /** + * Create a new data snapshot of an {@link OnlineUser}'s data. + * + * @param user The user to create the snapshot of + * @return The snapshot of the user's data + * @since 3.0 + */ + @NotNull + public DataSnapshot.Packed createSnapshot(@NotNull OnlineUser user) { + return snapshotBuilder().saveCause(DataSnapshot.SaveCause.API).buildAndPack(); + } + + /** + * Get a {@link User}'s current data, as a {@link DataSnapshot.Unpacked} + *

+ * If the user is online, this will create a new snapshot of their data with the {@code API} data save cause. + *

+ * If the user is offline, this will return the latest snapshot of their data if that exists + * (an empty optional will be returned otherwise). + * + * @param user The user to get the data of + * @return A future containing the user's current data, or an empty optional if the user has no data + * @since 3.0 + */ + public CompletableFuture> getCurrentData(@NotNull User user) { + return plugin.getRedisManager() + .getUserData(UUID.randomUUID(), user) + .thenApply(data -> data.or(() -> plugin.getDatabase().getLatestSnapshot(user))) + .thenApply(data -> data.map(snapshot -> snapshot.unpack(plugin))); + } + + /** + * Set a user's current data. + *

+ * This will update the user's data in the database (creating a new snapshot) and send a data update, + * updating the user if they are online. + * + * @param user The user to set the data of + * @param data The data to set + * @since 3.0 + */ + public void setCurrentData(@NotNull User user, @NotNull DataSnapshot data) { + plugin.runAsync(() -> { + final DataSnapshot.Packed packed = data instanceof DataSnapshot.Unpacked unpacked + ? unpacked.pack(plugin) : (DataSnapshot.Packed) data; + addSnapshot(user, packed); + plugin.getRedisManager().sendUserDataUpdate(user, packed); + }); + } + + /** + * Edit a user's current data. + *

+ * This will update the user's data in the database (creating a new snapshot) and send a data update, + * updating the user if they are online. + * + * @param user The user to edit the data of + * @param editor The editor function + * @since 3.0 + */ + public void editCurrentData(@NotNull User user, @NotNull ThrowingConsumer editor) { + getCurrentData(user).thenAccept(optional -> optional.ifPresent(data -> { + editor.accept(data); + setCurrentData(user, data); + })); + } + + /** + * Get a list of all saved data snapshots for a user + * + * @param user The user to get the data snapshots of + * @return The user's data snapshots + * @since 3.0 + */ + public CompletableFuture> getSnapshots(@NotNull User user) { + return plugin.supplyAsync( + () -> plugin.getDatabase().getAllSnapshots(user).stream() + .map(snapshot -> snapshot.unpack(plugin)) + .toList() + ); + } + + /** + * Get a specific data snapshot for a user + * + * @param user The user to get the data snapshot of + * @param versionId The version ID of the snapshot to get + * @return The user's data snapshot, or an empty optional if the user has no data + * @see #getSnapshots(User) + * @since 3.0 + */ + public CompletableFuture> getSnapshot(@NotNull User user, @NotNull UUID versionId) { + return plugin.supplyAsync( + () -> plugin.getDatabase().getSnapshot(user, versionId).stream() + .map(snapshot -> snapshot.unpack(plugin)) + .toList() + ); + } + + /** + * Edit a data snapshot for a user + * + * @param user The user to edit the snapshot of + * @param versionId The version ID of the snapshot to edit + * @param editor The editor function + * @since 3.0 + */ + public void editSnapshot(@NotNull User user, @NotNull UUID versionId, + @NotNull ThrowingConsumer editor) { + plugin.runAsync(() -> plugin.getDatabase().getSnapshot(user, versionId).ifPresent(snapshot -> { + final DataSnapshot.Unpacked unpacked = snapshot.unpack(plugin); + editor.accept(unpacked); + plugin.getDatabase().updateSnapshot(user, unpacked.pack(plugin)); + })); + } + + /** + * Get the latest data snapshot for a user that has been saved in the database. + *

+ * Not to be confused with {@link #getCurrentData(User)}, which will return the current data of a user + * if they are online (this method will only return their latest saved snapshot). + *

+ * + * @param user The user to get the latest data snapshot of + * @return The user's latest data snapshot, or an empty optional if the user has no data + * @since 3.0 + */ + public CompletableFuture> getLatestSnapshot(@NotNull User user) { + return plugin.supplyAsync( + () -> plugin.getDatabase().getLatestSnapshot(user).map(snapshot -> snapshot.unpack(plugin)) + ); + } + + /** + * Edit the latest data snapshot for a user + * + * @param user The user to edit the latest snapshot of + * @param editor The editor function + * @since 3.0 + */ + public void editLatestSnapshot(@NotNull User user, @NotNull ThrowingConsumer editor) { + plugin.runAsync(() -> plugin.getDatabase().getLatestSnapshot(user).ifPresent(snapshot -> { + final DataSnapshot.Unpacked unpacked = snapshot.unpack(plugin); + editor.accept(unpacked); + plugin.getDatabase().updateSnapshot(user, unpacked.pack(plugin)); + })); + } + + /** + * Adds a data snapshot to the database + * + * @param user The user to save the data for + * @param snapshot The snapshot to save + * @since 3.0 + */ + public void addSnapshot(@NotNull User user, @NotNull DataSnapshot snapshot) { + plugin.runAsync(() -> plugin.getDatabase().addSnapshot( + user, snapshot instanceof DataSnapshot.Unpacked unpacked + ? unpacked.pack(plugin) : (DataSnapshot.Packed) snapshot + )); + } + + /** + * Update an existing data snapshot in the database. + * Not to be confused with {@link #addSnapshot(User, DataSnapshot)}, which will add a new snapshot if one + * snapshot doesn't exist. + * + * @param user The user to update the snapshot of + * @param snapshot The snapshot to update + * @since 3.0 + */ + public void updateSnapshot(@NotNull User user, @NotNull DataSnapshot snapshot) { + plugin.runAsync(() -> plugin.getDatabase().updateSnapshot( + user, snapshot instanceof DataSnapshot.Unpacked unpacked + ? unpacked.pack(plugin) : (DataSnapshot.Packed) snapshot + )); + } + + /** + * Pin a data snapshot, preventing it from being rotated + * + * @param user The user to pin the snapshot of + * @param snapshotVersion The version ID of the snapshot to pin + * @since 3.0 + */ + public void pinSnapshot(@NotNull User user, @NotNull UUID snapshotVersion) { + plugin.runAsync(() -> plugin.getDatabase().pinSnapshot(user, snapshotVersion)); + } + + /** + * Unpin a data snapshot, allowing it to be rotated + * + * @param user The user to unpin the snapshot of + * @param snapshotVersion The version ID of the snapshot to unpin + * @since 3.0 + */ + public void unpinSnapshot(@NotNull User user, @NotNull UUID snapshotVersion) { + plugin.runAsync(() -> plugin.getDatabase().unpinSnapshot(user, snapshotVersion)); + } + + /** + * Delete a data snapshot from the database + * + * @param user The user to delete the snapshot of + * @param versionId The version ID of the snapshot to delete + * @return A future which will complete with true if the snapshot was deleted, or false if it wasn't + * (e.g., if the snapshot didn't exist) + * @since 3.0 + */ + public CompletableFuture deleteSnapshot(@NotNull User user, @NotNull UUID versionId) { + return plugin.supplyAsync(() -> plugin.getDatabase().deleteSnapshot(user, versionId)); + } + + /** + * Delete a data snapshot from the database + * + * @param user The user to delete the snapshot of + * @param snapshot The snapshot to delete + * @return A future which will complete with true if the snapshot was deleted, or false if it wasn't + * (e.g., if the snapshot hasn't been saved to the database yet) + * @since 3.0 + */ + public CompletableFuture deleteSnapshot(@NotNull User user, @NotNull DataSnapshot snapshot) { + return deleteSnapshot(user, snapshot.getId()); + } + + /** + * Registers a new custom data type serializer. + *

+ * This allows for custom {@link Data} types to be persisted in {@link DataSnapshot}s. To register + * a new data type, you must provide a {@link Serializer} for serializing and deserializing the data type + * and invoke this method. + *

+ * You'll need to do this on every server you wish to sync data between. On servers where the registered + * data type is not present, the data will be ignored and snapshots created on that server will not + * contain the data. + * + * @param identifier The identifier of the data type to register. + * Create one using {@code Identifier.from(Key.of("your_plugin_name", "key"))} + * @param serializer An implementation of {@link Serializer} for serializing and deserializing the {@link Data} + * @param A type extending {@link Data}; this will represent the data being held. + */ + public void registerDataSerializer(@NotNull Identifier identifier, + @NotNull Serializer serializer) { + plugin.registerSerializer(identifier, serializer); + } + + /** + * Get a {@link DataSnapshot.Unpacked} from a {@link DataSnapshot.Packed} + * + * @param unpacked The unpacked snapshot + * @return The packed snapshot + * @since 3.0 + */ + @NotNull + public DataSnapshot.Packed packSnapshot(@NotNull DataSnapshot.Unpacked unpacked) { + return unpacked.pack(plugin); + } + + /** + * Get a {@link DataSnapshot.Unpacked} from a {@link DataSnapshot.Packed} + * + * @param packed The packed snapshot + * @return The unpacked snapshot + * @since 3.0 + */ + @NotNull + public DataSnapshot.Unpacked unpackSnapshot(@NotNull DataSnapshot.Packed packed) { + return packed.unpack(plugin); + } + + /** + * Unpack, edit, and repack a data snapshot. + *

+ * This won't save the snapshot to the database; it'll just edit the data snapshot in place. + * + * @param packed The packed snapshot + * @param editor An editor function for editing the unpacked snapshot + * @return The edited packed snapshot + * @since 3.0 + */ + @NotNull + public DataSnapshot.Packed editPackedSnapshot(@NotNull DataSnapshot.Packed packed, + @NotNull ThrowingConsumer editor) { + final DataSnapshot.Unpacked unpacked = packed.unpack(plugin); + editor.accept(unpacked); + return unpacked.pack(plugin); + } + + /** + * Get the estimated size of a {@link DataSnapshot} in bytes + * + * @param snapshot The snapshot to get the size of + * @return The size of the snapshot in bytes + * @since 3.0 + */ + public int getSnapshotFileSize(@NotNull DataSnapshot snapshot) { + return (snapshot instanceof DataSnapshot.Packed packed) + ? packed.getFileSize(plugin) + : ((DataSnapshot.Unpacked) snapshot).pack(plugin).getFileSize(plugin); + } + + /** + * Get a builder for creating a new data snapshot + * + * @return The builder + * @since 3.0 + */ + @NotNull + public DataSnapshot.Builder snapshotBuilder() { + return DataSnapshot.builder(plugin).saveCause(DataSnapshot.SaveCause.API); + } + + /** + * Deserialize a JSON string to an {@link Adaptable} + * + * @param serialized The serialized JSON string + * @param type The type of the element + * @param The type of the element + * @return The deserialized element + * @throws Serializer.DeserializationException If the element could not be deserialized + */ + @NotNull + public T deserializeData(@NotNull String serialized, Class type) + throws Serializer.DeserializationException { + return plugin.getDataAdapter().fromJson(serialized, type); + } + + /** + * Serialize an {@link Adaptable} to a JSON string + * + * @param element The element to serialize + * @param The type of the element + * @return The serialized JSON string + * @throws Serializer.SerializationException If the element could not be serialized + */ + @NotNull + public String serializeData(@NotNull T element) + throws Serializer.SerializationException { + return plugin.getDataAdapter().toJson(element); + } + + /** + * (Internal use only) - Get the plugin instance + * + * @return The plugin instance + */ + @ApiStatus.Internal + public HuskSync getPlugin() { + return plugin; + } + + /** + * An exception indicating the plugin has been accessed before it has been registered. + */ + static final class NotRegisteredException extends IllegalStateException { + + private static final String MESSAGE = """ + Could not access the HuskSync API as it has not yet been registered. This could be because: + 1) HuskSync has failed to enable successfully + 2) Your plugin isn't set to load after HuskSync has + (Check if it set as a (soft)depend in plugin.yml or to load: BEFORE in paper-plugin.yml?) + 3) You are attempting to access HuskSync on plugin construction/before your plugin has enabled. + 4) You have shaded HuskSync into your plugin jar and need to fix your maven/gradle/build script + to only include HuskSync as a dependency and not as a shaded dependency."""; + + NotRegisteredException() { + super(MESSAGE); + } + + } + +} diff --git a/common/src/main/java/net/william278/husksync/command/Command.java b/common/src/main/java/net/william278/husksync/command/Command.java new file mode 100644 index 00000000..5e9fb59b --- /dev/null +++ b/common/src/main/java/net/william278/husksync/command/Command.java @@ -0,0 +1,84 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.command; + +import net.william278.husksync.HuskSync; +import net.william278.husksync.user.CommandUser; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class Command extends Node { + + private final String usage; + private final Map additionalPermissions; + + protected Command(@NotNull String name, @NotNull List aliases, @NotNull String usage, + @NotNull HuskSync plugin) { + super(name, aliases, plugin); + this.usage = usage; + this.additionalPermissions = new HashMap<>(); + } + + @Override + public final void onExecuted(@NotNull CommandUser executor, @NotNull String[] args) { + if (!executor.hasPermission(getPermission())) { + plugin.getLocales().getLocale("error_no_permission") + .ifPresent(executor::sendMessage); + return; + } + plugin.runAsync(() -> this.execute(executor, args)); + } + + public abstract void execute(@NotNull CommandUser executor, @NotNull String[] args); + + @NotNull + public final String getRawUsage() { + return usage; + } + + @NotNull + public final String getUsage() { + return "/" + getName() + " " + getRawUsage(); + } + + public final void addAdditionalPermissions(@NotNull Map permissions) { + permissions.forEach((permission, value) -> this.additionalPermissions.put(getPermission(permission), value)); + } + + @NotNull + public final Map getAdditionalPermissions() { + return additionalPermissions; + } + + @NotNull + public String getDescription() { + return plugin.getLocales().getRawLocale(getName() + "_command_description") + .orElse(getUsage()); + } + + @NotNull + public final HuskSync getPlugin() { + return plugin; + } + +} \ No newline at end of file diff --git a/common/src/main/java/net/william278/husksync/command/CommandBase.java b/common/src/main/java/net/william278/husksync/command/CommandBase.java deleted file mode 100644 index d4fb126a..00000000 --- a/common/src/main/java/net/william278/husksync/command/CommandBase.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.command; - -import net.william278.husksync.HuskSync; -import net.william278.husksync.player.OnlineUser; -import org.jetbrains.annotations.NotNull; - -/** - * Represents an abstract cross-platform representation for a plugin command - */ -public abstract class CommandBase { - - /** - * The input string to match for this command - */ - public final String command; - - /** - * The permission node required to use this command - */ - public final String permission; - - /** - * Alias input strings for this command - */ - public final String[] aliases; - - /** - * Instance of the implementing plugin - */ - public final HuskSync plugin; - - - public CommandBase(@NotNull String command, @NotNull Permission permission, @NotNull HuskSync implementor, String... aliases) { - this.command = command; - this.permission = permission.node; - this.plugin = implementor; - this.aliases = aliases; - } - - /** - * Fires when the command is executed - * - * @param player {@link OnlineUser} executing the command - * @param args Command arguments - */ - public abstract void onExecute(@NotNull OnlineUser player, @NotNull String[] args); - - /** - * Returns the localised description string of this command - * - * @return the command description - */ - public String getDescription() { - return plugin.getLocales().getRawLocale(command + "_command_description") - .orElse("A HuskSync command"); - } - -} diff --git a/common/src/main/java/net/william278/husksync/command/EnderChestCommand.java b/common/src/main/java/net/william278/husksync/command/EnderChestCommand.java index c7071d41..ea09088f 100644 --- a/common/src/main/java/net/william278/husksync/command/EnderChestCommand.java +++ b/common/src/main/java/net/william278/husksync/command/EnderChestCommand.java @@ -21,112 +21,72 @@ package net.william278.husksync.command; import de.themoep.minedown.adventure.MineDown; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.data.UserDataBuilder; -import net.william278.husksync.data.UserDataSnapshot; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.user.User; import org.jetbrains.annotations.NotNull; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; import java.util.List; -import java.util.Locale; import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Level; -import java.util.stream.Collectors; -public class EnderChestCommand extends CommandBase implements TabCompletable { +public class EnderChestCommand extends ItemsCommand { - public EnderChestCommand(@NotNull HuskSync implementor) { - super("enderchest", Permission.COMMAND_ENDER_CHEST, implementor, "echest", "openechest"); + public EnderChestCommand(@NotNull HuskSync plugin) { + super(plugin, List.of("enderchest", "echest", "openechest")); } @Override - public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) { - if (args.length == 0 || args.length > 2) { - plugin.getLocales().getLocale("error_invalid_syntax", "/enderchest ") - .ifPresent(player::sendMessage); + protected void showItems(@NotNull OnlineUser viewer, @NotNull DataSnapshot.Unpacked snapshot, + @NotNull User user, boolean allowEdit) { + final Optional optionalEnderChest = snapshot.getEnderChest(); + if (optionalEnderChest.isEmpty()) { + plugin.getLocales().getLocale("error_no_data_to_display") + .ifPresent(viewer::sendMessage); return; } - plugin.getDatabase().getUserByName(args[0].toLowerCase(Locale.ENGLISH)).thenAccept(optionalUser -> - optionalUser.ifPresentOrElse(user -> { - if (args.length == 2) { - // View user data by specified UUID - try { - final UUID versionUuid = UUID.fromString(args[1]); - plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data -> data.ifPresentOrElse( - userData -> showEnderChestMenu(player, userData, user, false), - () -> plugin.getLocales().getLocale("error_invalid_version_uuid") - .ifPresent(player::sendMessage))); - } catch (IllegalArgumentException e) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/enderchest [version_uuid]").ifPresent(player::sendMessage); - } - } else { - // View (and edit) the latest user data - plugin.getDatabase().getCurrentUserData(user).thenAccept(optionalData -> optionalData.ifPresentOrElse( - versionedUserData -> showEnderChestMenu(player, versionedUserData, user, - player.hasPermission(Permission.COMMAND_ENDER_CHEST_EDIT.node)), - () -> plugin.getLocales().getLocale("error_no_data_to_display") - .ifPresent(player::sendMessage))); - } - }, () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage))); - } - private void showEnderChestMenu(@NotNull OnlineUser player, @NotNull UserDataSnapshot userDataSnapshot, - @NotNull User dataOwner, boolean allowEdit) { - CompletableFuture.runAsync(() -> { - final UserData data = userDataSnapshot.userData(); - data.getEnderChest().ifPresent(itemData -> { - // Show message - plugin.getLocales().getLocale("ender_chest_viewer_opened", dataOwner.username, - new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss") - .format(userDataSnapshot.versionTimestamp())) - .ifPresent(player::sendMessage); + // Display opening message + plugin.getLocales().getLocale("ender_chest_viewer_opened", user.getUsername(), + snapshot.getTimestamp().format(DateTimeFormatter.ofPattern("dd/MM/yyyy, HH:mm"))) + .ifPresent(viewer::sendMessage); - // Show inventory menu - player.showMenu(itemData, allowEdit, 3, plugin.getLocales() - .getLocale("ender_chest_viewer_menu_title", dataOwner.username) - .orElse(new MineDown("Ender Chest Viewer"))) - .exceptionally(throwable -> { - plugin.log(Level.WARNING, "Exception displaying inventory menu to " + player.username, throwable); - return Optional.empty(); - }) - .thenAccept(dataOnClose -> { - if (dataOnClose.isEmpty() || !allowEdit) { - return; - } + // Show GUI + final Data.Items.EnderChest enderChest = optionalEnderChest.get(); + viewer.showGui( + enderChest, + plugin.getLocales().getLocale("ender_chest_viewer_menu_title", user.getUsername()) + .orElse(new MineDown(String.format("%s's Ender Chest", user.getUsername()))), + allowEdit, + enderChest.getSlotCount(), + (itemsOnClose) -> { + if (allowEdit && !enderChest.equals(itemsOnClose)) { + plugin.runAsync(() -> this.updateItems(viewer, itemsOnClose, user)); + } + } + ); + } - // Create the updated data - final UserDataBuilder builder = UserData.builder(plugin.getMinecraftVersion()); - data.getStatus().ifPresent(builder::setStatus); - data.getAdvancements().ifPresent(builder::setAdvancements); - data.getLocation().ifPresent(builder::setLocation); - data.getPersistentDataContainer().ifPresent(builder::setPersistentDataContainer); - data.getStatistics().ifPresent(builder::setStatistics); - data.getPotionEffects().ifPresent(builder::setPotionEffects); - data.getInventory().ifPresent(builder::setInventory); - builder.setEnderChest(dataOnClose.get()); + // Creates a new snapshot with the updated enderChest + @SuppressWarnings("DuplicatedCode") + private void updateItems(@NotNull OnlineUser viewer, @NotNull Data.Items.Items items, @NotNull User user) { + final Optional latestData = plugin.getDatabase().getLatestSnapshot(user); + if (latestData.isEmpty()) { + plugin.getLocales().getLocale("error_no_data_to_display") + .ifPresent(viewer::sendMessage); + return; + } - // Set the updated data - final UserData updatedUserData = builder.build(); - plugin.getDatabase() - .setUserData(dataOwner, updatedUserData, DataSaveCause.INVENTORY_COMMAND) - .thenRun(() -> plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData)); - }); - }); + // Create and pack the snapshot with the updated enderChest + final DataSnapshot.Packed snapshot = latestData.get().copy(); + snapshot.edit(plugin, (data) -> { + data.setSaveCause(DataSnapshot.SaveCause.ENDERCHEST_COMMAND); + data.setPinned(plugin.getSettings().doAutoPin(DataSnapshot.SaveCause.ENDERCHEST_COMMAND)); + data.getEnderChest().ifPresent(enderChest -> enderChest.setContents(items)); }); - } - - @Override - public List onTabComplete(@NotNull String[] args) { - return plugin.getOnlineUsers().stream().map(user -> user.username) - .filter(argument -> argument.startsWith(args.length >= 1 ? args[0] : "")) - .sorted().collect(Collectors.toList()); + plugin.getDatabase().addSnapshot(user, snapshot); + plugin.getRedisManager().sendUserDataUpdate(user, snapshot); } } diff --git a/common/src/main/java/net/william278/husksync/command/ConsoleExecutable.java b/common/src/main/java/net/william278/husksync/command/Executable.java similarity index 75% rename from common/src/main/java/net/william278/husksync/command/ConsoleExecutable.java rename to common/src/main/java/net/william278/husksync/command/Executable.java index d633285a..cc7890a7 100644 --- a/common/src/main/java/net/william278/husksync/command/ConsoleExecutable.java +++ b/common/src/main/java/net/william278/husksync/command/Executable.java @@ -19,18 +19,11 @@ package net.william278.husksync.command; +import net.william278.husksync.user.CommandUser; import org.jetbrains.annotations.NotNull; -/** - * Interface providing console execution of commands - */ -public interface ConsoleExecutable { +public interface Executable { - /** - * What to do when console executes a command - * - * @param args command argument strings - */ - void onConsoleExecute(@NotNull String[] args); + void onExecuted(@NotNull CommandUser executor, @NotNull String[] args); } diff --git a/common/src/main/java/net/william278/husksync/command/HuskSyncCommand.java b/common/src/main/java/net/william278/husksync/command/HuskSyncCommand.java index 06f233c0..e6154a9f 100644 --- a/common/src/main/java/net/william278/husksync/command/HuskSyncCommand.java +++ b/common/src/main/java/net/william278/husksync/command/HuskSyncCommand.java @@ -23,26 +23,39 @@ import de.themoep.minedown.adventure.MineDown; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import net.william278.desertwell.about.AboutMenu; +import net.william278.desertwell.util.UpdateChecker; import net.william278.husksync.HuskSync; import net.william278.husksync.migrator.Migrator; -import net.william278.husksync.player.OnlineUser; +import net.william278.husksync.user.CommandUser; +import net.william278.husksync.user.OnlineUser; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.logging.Level; import java.util.stream.Collectors; -public class HuskSyncCommand extends CommandBase implements TabCompletable, ConsoleExecutable { +public class HuskSyncCommand extends Command implements TabProvider { - private final String[] SUB_COMMANDS = {"update", "about", "reload", "migrate"}; + private static final Map SUB_COMMANDS = Map.of( + "about", false, + "reload", true, + "migrate", true, + "update", true + ); + + private final UpdateChecker updateChecker; private final AboutMenu aboutMenu; - public HuskSyncCommand(@NotNull HuskSync implementor) { - super("husksync", Permission.COMMAND_HUSKSYNC, implementor); + public HuskSyncCommand(@NotNull HuskSync plugin) { + super("husksync", List.of(), "[" + String.join("|", SUB_COMMANDS.keySet()) + "]", plugin); + addAdditionalPermissions(SUB_COMMANDS); + + this.updateChecker = plugin.getUpdateChecker(); this.aboutMenu = AboutMenu.builder() .title(Component.text("HuskSync")) .description(Component.text("A modern, cross-server player data synchronization system")) - .version(implementor.getPluginVersion()) + .version(plugin.getPluginVersion()) .credits("Author", AboutMenu.Credit.of("William278").description("Click to visit website").url("https://william278.net")) .credits("Contributors", @@ -68,123 +81,104 @@ public class HuskSyncCommand extends CommandBase implements TabCompletable, Cons } @Override - public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) { - if (args.length < 1) { - sendAboutMenu(player); + public void execute(@NotNull CommandUser executor, @NotNull String[] args) { + final String subCommand = parseStringArg(args, 0).orElse("about").toLowerCase(Locale.ENGLISH); + if (SUB_COMMANDS.containsKey(subCommand) && !executor.hasPermission(getPermission(subCommand))) { + plugin.getLocales().getLocale("error_no_permission") + .ifPresent(executor::sendMessage); return; } - switch (args[0].toLowerCase(Locale.ENGLISH)) { - case "update", "version" -> { - if (!player.hasPermission(Permission.COMMAND_HUSKSYNC_UPDATE.node)) { - plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage); - return; + + switch (subCommand) { + case "about" -> executor.sendMessage(aboutMenu.toComponent()); + case "reload" -> { + try { + plugin.loadConfigs(); + plugin.getLocales().getLocale("reload_complete").ifPresent(executor::sendMessage); + } catch (Throwable e) { + executor.sendMessage(new MineDown( + "[Error:](#ff3300) [Failed to reload the plugin. Check console for errors.](#ff7e5e)" + )); + plugin.log(Level.SEVERE, "Failed to reload the plugin", e); } - plugin.getLatestVersionIfOutdated().thenAccept(newestVersion -> - newestVersion.ifPresentOrElse( - newVersion -> player.sendMessage( - new MineDown("[HuskSync](#00fb9a bold) [| A new version of HuskSync is available!" - + " (v" + newVersion + " (Running: v" + plugin.getPluginVersion() + ")](#00fb9a)")), - () -> player.sendMessage( - new MineDown("[HuskSync](#00fb9a bold) [| HuskSync is up-to-date." - + " (Running: v" + plugin.getPluginVersion() + ")](#00fb9a)")))); } - case "about", "info" -> sendAboutMenu(player); - case "reload" -> { - if (!player.hasPermission(Permission.COMMAND_HUSKSYNC_RELOAD.node)) { - plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage); + case "migrate" -> { + if (executor instanceof OnlineUser) { + plugin.getLocales().getLocale("error_console_command_only") + .ifPresent(executor::sendMessage); return; } - plugin.reload(); - plugin.getLocales().getLocale("reload_complete").ifPresent(player::sendMessage); + this.handleMigrationCommand(args); } - case "migrate" -> - plugin.getLocales().getLocale("error_console_command_only").ifPresent(player::sendMessage); - default -> plugin.getLocales().getLocale("error_invalid_syntax", - "/husksync ") - .ifPresent(player::sendMessage); + case "update" -> updateChecker.check().thenAccept(checked -> { + if (checked.isUpToDate()) { + plugin.getLocales().getLocale("up_to_date", plugin.getPluginVersion().toString()) + .ifPresent(executor::sendMessage); + return; + } + plugin.getLocales().getLocale("update_available", checked.getLatestVersion().toString(), + plugin.getPluginVersion().toString()).ifPresent(executor::sendMessage); + }); + default -> plugin.getLocales().getLocale("error_invalid_syntax", getUsage()) + .ifPresent(executor::sendMessage); } } - @Override - public void onConsoleExecute(@NotNull String[] args) { - if (args.length < 1) { - plugin.log(Level.INFO, "Console usage: \"husksync \""); + // Handle a migration console command input + private void handleMigrationCommand(@NotNull String[] args) { + if (args.length < 2) { + plugin.log(Level.INFO, + "Please choose a migrator, then run \"husksync migrate \""); + this.logMigratorList(); return; } - switch (args[0].toLowerCase(Locale.ENGLISH)) { - case "update", "version" -> plugin.getLatestVersionIfOutdated().thenAccept(newestVersion -> - newestVersion.ifPresentOrElse(newVersion -> plugin.log(Level.WARNING, - "An update is available for HuskSync, v" + newVersion - + " (Running v" + plugin.getPluginVersion() + ")"), - () -> plugin.log(Level.INFO, - "HuskSync is up to date" + - " (Running v" + plugin.getPluginVersion() + ")"))); - case "about", "info" -> aboutMenu.toString().lines().forEach(line -> plugin.log(Level.INFO, line)); - case "reload" -> { - plugin.reload(); - plugin.log(Level.INFO, "Reloaded config & message files."); + + final Optional selectedMigrator = plugin.getAvailableMigrators().stream() + .filter(available -> available.getIdentifier().equalsIgnoreCase(args[1])) + .findFirst(); + selectedMigrator.ifPresentOrElse(migrator -> { + if (args.length < 3) { + plugin.log(Level.INFO, migrator.getHelpMenu()); + return; } - case "migrate" -> { - if (args.length < 2) { - plugin.log(Level.INFO, - "Please choose a migrator, then run \"husksync migrate \""); - logMigratorsList(); - return; - } - final Optional selectedMigrator = plugin.getAvailableMigrators().stream().filter(availableMigrator -> - availableMigrator.getIdentifier().equalsIgnoreCase(args[1])).findFirst(); - selectedMigrator.ifPresentOrElse(migrator -> { - if (args.length < 3) { - plugin.log(Level.INFO, migrator.getHelpMenu()); - return; + switch (args[2]) { + case "start" -> migrator.start().thenAccept(succeeded -> { + if (succeeded) { + plugin.log(Level.INFO, "Migration completed successfully!"); + } else { + plugin.log(Level.WARNING, "Migration failed!"); } - switch (args[2]) { - case "start" -> migrator.start().thenAccept(succeeded -> { - if (succeeded) { - plugin.log(Level.INFO, "Migration completed successfully!"); - } else { - plugin.log(Level.WARNING, "Migration failed!"); - } - }); - case "set" -> migrator.handleConfigurationCommand(Arrays.copyOfRange(args, 3, args.length)); - default -> plugin.log(Level.INFO, - "Invalid syntax. Console usage: \"husksync migrate " + args[1] + " "); - } - }, () -> { - plugin.log(Level.INFO, - "Please specify a valid migrator.\n" + - "If a migrator is not available, please verify that you meet the prerequisites to use it."); - logMigratorsList(); }); + case "set" -> migrator.handleConfigurationCommand(Arrays.copyOfRange(args, 3, args.length)); + default -> plugin.log(Level.INFO, String.format( + "Invalid syntax. Console usage: \"husksync migrate %s ", args[1] + )); } - default -> plugin.log(Level.INFO, - "Invalid syntax. Console usage: \"husksync \""); - } + }, () -> { + plugin.log(Level.INFO, + "Please specify a valid migrator.\n" + + "If a migrator is not available, please verify that you meet the prerequisites to use it."); + this.logMigratorList(); + }); } - private void logMigratorsList() { - plugin.log(Level.INFO, - "List of available migrators:\nMigrator ID / Migrator Name:\n" + + // Log the list of available migrators + private void logMigratorList() { + plugin.log(Level.INFO, String.format( + "List of available migrators:\nMigrator ID / Migrator Name:\n%s", plugin.getAvailableMigrators().stream() - .map(migrator -> migrator.getIdentifier() + " - " + migrator.getName()) - .collect(Collectors.joining("\n"))); + .map(migrator -> String.format("%s - %s", migrator.getIdentifier(), migrator.getName())) + .collect(Collectors.joining("\n")) + )); } + @Nullable @Override - public List onTabComplete(@NotNull String[] args) { - if (args.length <= 1) { - return Arrays.stream(SUB_COMMANDS) - .filter(argument -> argument.startsWith(args.length == 1 ? args[0] : "")) - .sorted().collect(Collectors.toList()); - } - return Collections.emptyList(); + public List suggest(@NotNull CommandUser user, @NotNull String[] args) { + return switch (args.length) { + case 0, 1 -> SUB_COMMANDS.keySet().stream().sorted().toList(); + default -> null; + }; } - private void sendAboutMenu(@NotNull OnlineUser player) { - if (!player.hasPermission(Permission.COMMAND_HUSKSYNC_ABOUT.node)) { - plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage); - return; - } - player.sendMessage(aboutMenu.toComponent()); - } } diff --git a/common/src/main/java/net/william278/husksync/command/InventoryCommand.java b/common/src/main/java/net/william278/husksync/command/InventoryCommand.java index 9d1fa651..3cfa93e6 100644 --- a/common/src/main/java/net/william278/husksync/command/InventoryCommand.java +++ b/common/src/main/java/net/william278/husksync/command/InventoryCommand.java @@ -21,111 +21,72 @@ package net.william278.husksync.command; import de.themoep.minedown.adventure.MineDown; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.data.UserDataBuilder; -import net.william278.husksync.data.UserDataSnapshot; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.user.User; import org.jetbrains.annotations.NotNull; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; import java.util.List; -import java.util.Locale; import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Level; -import java.util.stream.Collectors; -public class InventoryCommand extends CommandBase implements TabCompletable { +public class InventoryCommand extends ItemsCommand { - public InventoryCommand(@NotNull HuskSync implementor) { - super("inventory", Permission.COMMAND_INVENTORY, implementor, "invsee", "openinv"); + public InventoryCommand(@NotNull HuskSync plugin) { + super(plugin, List.of("inventory", "invsee", "openinv")); } @Override - public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) { - if (args.length == 0 || args.length > 2) { - plugin.getLocales().getLocale("error_invalid_syntax", "/inventory ") - .ifPresent(player::sendMessage); + protected void showItems(@NotNull OnlineUser viewer, @NotNull DataSnapshot.Unpacked snapshot, + @NotNull User user, boolean allowEdit) { + final Optional optionalInventory = snapshot.getInventory(); + if (optionalInventory.isEmpty()) { + plugin.getLocales().getLocale("error_no_data_to_display") + .ifPresent(viewer::sendMessage); return; } - plugin.getDatabase().getUserByName(args[0].toLowerCase(Locale.ENGLISH)).thenAccept(optionalUser -> - optionalUser.ifPresentOrElse(user -> { - if (args.length == 2) { - // View user data by specified UUID - try { - final UUID versionUuid = UUID.fromString(args[1]); - plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data -> data.ifPresentOrElse( - userData -> showInventoryMenu(player, userData, user, false), - () -> plugin.getLocales().getLocale("error_invalid_version_uuid") - .ifPresent(player::sendMessage))); - } catch (IllegalArgumentException e) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/inventory [version_uuid]").ifPresent(player::sendMessage); - } - } else { - // View (and edit) the latest user data - plugin.getDatabase().getCurrentUserData(user).thenAccept(optionalData -> optionalData.ifPresentOrElse( - versionedUserData -> showInventoryMenu(player, versionedUserData, user, - player.hasPermission(Permission.COMMAND_INVENTORY_EDIT.node)), - () -> plugin.getLocales().getLocale("error_no_data_to_display") - .ifPresent(player::sendMessage))); - } - }, () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage))); - } - private void showInventoryMenu(@NotNull OnlineUser player, @NotNull UserDataSnapshot userDataSnapshot, - @NotNull User dataOwner, boolean allowEdit) { - CompletableFuture.runAsync(() -> { - final UserData data = userDataSnapshot.userData(); - data.getInventory().ifPresent(itemData -> { - // Show message - plugin.getLocales().getLocale("inventory_viewer_opened", dataOwner.username, - new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss") - .format(userDataSnapshot.versionTimestamp())) - .ifPresent(player::sendMessage); + // Display opening message + plugin.getLocales().getLocale("inventory_viewer_opened", user.getUsername(), + snapshot.getTimestamp().format(DateTimeFormatter.ofPattern("dd/MM/yyyy, HH:mm"))) + .ifPresent(viewer::sendMessage); - // Show inventory menu - player.showMenu(itemData, allowEdit, 5, plugin.getLocales() - .getLocale("inventory_viewer_menu_title", dataOwner.username) - .orElse(new MineDown("Inventory Viewer"))) - .exceptionally(throwable -> { - plugin.log(Level.WARNING, "Exception displaying inventory menu to " + player.username, throwable); - return Optional.empty(); - }) - .thenAccept(dataOnClose -> { - if (dataOnClose.isEmpty() || !allowEdit) { - return; - } + // Show GUI + final Data.Items.Inventory inventory = optionalInventory.get(); + viewer.showGui( + inventory, + plugin.getLocales().getLocale("inventory_viewer_menu_title", user.getUsername()) + .orElse(new MineDown(String.format("%s's Inventory", user.getUsername()))), + allowEdit, + inventory.getSlotCount(), + (itemsOnClose) -> { + if (allowEdit && !inventory.equals(itemsOnClose)) { + plugin.runAsync(() -> this.updateItems(viewer, itemsOnClose, user)); + } + } + ); + } - // Create the updated data - final UserDataBuilder builder = UserData.builder(plugin.getMinecraftVersion()); - data.getStatus().ifPresent(builder::setStatus); - data.getAdvancements().ifPresent(builder::setAdvancements); - data.getLocation().ifPresent(builder::setLocation); - data.getPersistentDataContainer().ifPresent(builder::setPersistentDataContainer); - data.getStatistics().ifPresent(builder::setStatistics); - data.getPotionEffects().ifPresent(builder::setPotionEffects); - data.getEnderChest().ifPresent(builder::setEnderChest); - builder.setInventory(dataOnClose.get()); + // Creates a new snapshot with the updated inventory + @SuppressWarnings("DuplicatedCode") + private void updateItems(@NotNull OnlineUser viewer, @NotNull Data.Items.Items items, @NotNull User user) { + final Optional latestData = plugin.getDatabase().getLatestSnapshot(user); + if (latestData.isEmpty()) { + plugin.getLocales().getLocale("error_no_data_to_display") + .ifPresent(viewer::sendMessage); + return; + } - // Set the updated data - final UserData updatedUserData = builder.build(); - plugin.getDatabase() - .setUserData(dataOwner, updatedUserData, DataSaveCause.INVENTORY_COMMAND) - .thenRun(() -> plugin.getRedisManager().sendUserDataUpdate(dataOwner, updatedUserData)); - }); - }); + // Create and pack the snapshot with the updated inventory + final DataSnapshot.Packed snapshot = latestData.get().copy(); + snapshot.edit(plugin, (data) -> { + data.setSaveCause(DataSnapshot.SaveCause.INVENTORY_COMMAND); + data.setPinned(plugin.getSettings().doAutoPin(DataSnapshot.SaveCause.INVENTORY_COMMAND)); + data.getInventory().ifPresent(inventory -> inventory.setContents(items)); }); + plugin.getDatabase().addSnapshot(user, snapshot); + plugin.getRedisManager().sendUserDataUpdate(user, snapshot); } - @Override - public List onTabComplete(@NotNull String[] args) { - return plugin.getOnlineUsers().stream().map(user -> user.username) - .filter(argument -> argument.startsWith(args.length >= 1 ? args[0] : "")) - .sorted().collect(Collectors.toList()); - } } diff --git a/common/src/main/java/net/william278/husksync/command/ItemsCommand.java b/common/src/main/java/net/william278/husksync/command/ItemsCommand.java new file mode 100644 index 00000000..c8687141 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/command/ItemsCommand.java @@ -0,0 +1,108 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.command; + +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.CommandUser; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.user.User; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public abstract class ItemsCommand extends Command implements TabProvider { + + protected ItemsCommand(@NotNull HuskSync plugin, @NotNull List aliases) { + super(aliases.get(0), aliases.subList(1, aliases.size()), " [version_uuid]", plugin); + setOperatorCommand(true); + addAdditionalPermissions(Map.of("edit", true)); + } + + + @Override + public void execute(@NotNull CommandUser executor, @NotNull String[] args) { + if (!(executor instanceof OnlineUser player)) { + plugin.getLocales().getLocale("error_in_game_command_only") + .ifPresent(executor::sendMessage); + return; + } + + // Find the user to view the items for + final Optional optionalUser = parseStringArg(args, 0) + .flatMap(name -> plugin.getDatabase().getUserByName(name)); + if (optionalUser.isEmpty()) { + plugin.getLocales().getLocale( + args.length >= 1 ? "error_invalid_player" : "error_invalid_syntax", getUsage() + ).ifPresent(player::sendMessage); + return; + } + + // Show the user data + final User user = optionalUser.get(); + parseUUIDArg(args, 1).ifPresentOrElse( + version -> this.showSnapshotItems(player, user, version), + () -> this.showLatestItems(player, user) + ); + } + + // View (and edit) the latest user data + private void showLatestItems(@NotNull OnlineUser viewer, @NotNull User user) { + plugin.getRedisManager().getUserData(user.getUuid(), user).thenAccept(data -> data + .or(() -> plugin.getDatabase().getLatestSnapshot(user)) + .ifPresentOrElse( + snapshot -> this.showItems( + viewer, snapshot.unpack(plugin), user, + viewer.hasPermission(getPermission("edit")) + ), + () -> plugin.getLocales().getLocale("error_no_data_to_display") + .ifPresent(viewer::sendMessage) + )); + } + + // View a specific version of the user data + private void showSnapshotItems(@NotNull OnlineUser viewer, @NotNull User user, @NotNull UUID version) { + plugin.getDatabase().getSnapshot(user, version) + .ifPresentOrElse( + snapshot -> this.showItems( + viewer, snapshot.unpack(plugin), user, false + ), + () -> plugin.getLocales().getLocale("error_invalid_version_uuid") + .ifPresent(viewer::sendMessage) + ); + } + + // Show a GUI menu with the correct item data from the snapshot + protected abstract void showItems(@NotNull OnlineUser viewer, @NotNull DataSnapshot.Unpacked snapshot, + @NotNull User user, boolean allowEdit); + + @Nullable + @Override + public List suggest(@NotNull CommandUser executor, @NotNull String[] args) { + return switch (args.length) { + case 0, 1 -> plugin.getOnlineUsers().stream().map(User::getUsername).toList(); + default -> null; + }; + } +} diff --git a/common/src/main/java/net/william278/husksync/command/Node.java b/common/src/main/java/net/william278/husksync/command/Node.java new file mode 100644 index 00000000..86635e2f --- /dev/null +++ b/common/src/main/java/net/william278/husksync/command/Node.java @@ -0,0 +1,105 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.command; + +import net.william278.husksync.HuskSync; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Optional; +import java.util.StringJoiner; +import java.util.UUID; + +public abstract class Node implements Executable { + + protected static final String PERMISSION_PREFIX = "husksync.command"; + + protected final HuskSync plugin; + private final String name; + private final List aliases; + private boolean operatorCommand = false; + + protected Node(@NotNull String name, @NotNull List aliases, @NotNull HuskSync plugin) { + if (name.isBlank()) { + throw new IllegalArgumentException("Command name cannot be blank"); + } + this.name = name; + this.aliases = aliases; + this.plugin = plugin; + } + + @NotNull + public String getName() { + return name; + } + + @NotNull + public List getAliases() { + return aliases; + } + + @NotNull + public String getPermission(@NotNull String... child) { + final StringJoiner joiner = new StringJoiner(".") + .add(PERMISSION_PREFIX) + .add(getName()); + for (final String node : child) { + joiner.add(node); + } + return joiner.toString().trim(); + } + + public boolean isOperatorCommand() { + return operatorCommand; + } + + public void setOperatorCommand(boolean operatorCommand) { + this.operatorCommand = operatorCommand; + } + + protected Optional parseStringArg(@NotNull String[] args, int index) { + if (args.length > index) { + return Optional.of(args[index]); + } + return Optional.empty(); + } + + protected Optional parseIntArg(@NotNull String[] args, int index) { + return parseStringArg(args, index).flatMap(arg -> { + try { + return Optional.of(Integer.parseInt(arg)); + } catch (NumberFormatException e) { + return Optional.empty(); + } + }); + } + + protected Optional parseUUIDArg(@NotNull String[] args, int index) { + return parseStringArg(args, index).flatMap(arg -> { + try { + return Optional.of(UUID.fromString(arg)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + }); + } + + +} \ No newline at end of file diff --git a/common/src/main/java/net/william278/husksync/command/Permission.java b/common/src/main/java/net/william278/husksync/command/Permission.java deleted file mode 100644 index 93af4228..00000000 --- a/common/src/main/java/net/william278/husksync/command/Permission.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.command; - -import org.jetbrains.annotations.NotNull; - -/** - * Static plugin permission nodes required to execute commands - */ -public enum Permission { - - /* - * /husksync command permissions - */ - - /** - * Lets the user use the {@code /husksync} command (subcommand permissions required) - */ - COMMAND_HUSKSYNC("husksync.command.husksync", DefaultAccess.EVERYONE), - /** - * Lets the user view plugin info {@code /husksync info} - */ - COMMAND_HUSKSYNC_ABOUT("husksync.command.husksync.info", DefaultAccess.EVERYONE), - /** - * Lets the user reload the plugin {@code /husksync reload} - */ - COMMAND_HUSKSYNC_RELOAD("husksync.command.husksync.reload", DefaultAccess.OPERATORS), - /** - * Lets the user view the plugin version and check for updates {@code /husksync update} - */ - COMMAND_HUSKSYNC_UPDATE("husksync.command.husksync.update", DefaultAccess.OPERATORS), - - /* - * /userdata command permissions - */ - - /** - * Lets the user view user data {@code /userdata view/list (player) (version_uuid)} - */ - COMMAND_USER_DATA("husksync.command.userdata", DefaultAccess.OPERATORS), - /** - * Lets the user restore and delete user data {@code /userdata restore/delete (player) (version_uuid)} - */ - COMMAND_USER_DATA_MANAGE("husksync.command.userdata.manage", DefaultAccess.OPERATORS), - - /** - * Lets the user dump user data to a file or the web {@code /userdata dump (player) (version_uuid)} - */ - COMMAND_USER_DATA_DUMP("husksync.command.userdata.dump", DefaultAccess.NOBODY), - - /* - * /inventory command permissions - */ - - /** - * Lets the user use the {@code /inventory (player)} command and view offline players' inventories - */ - COMMAND_INVENTORY("husksync.command.inventory", DefaultAccess.OPERATORS), - /** - * Lets the user edit the contents of offline players' inventories - */ - COMMAND_INVENTORY_EDIT("husksync.command.inventory.edit", DefaultAccess.OPERATORS), - - /* - * /enderchest command permissions - */ - - /** - * Lets the user use the {@code /enderchest (player)} command and view offline players' ender chests - */ - COMMAND_ENDER_CHEST("husksync.command.enderchest", DefaultAccess.OPERATORS), - /** - * Lets the user edit the contents of offline players' ender chests - */ - COMMAND_ENDER_CHEST_EDIT("husksync.command.enderchest.edit", DefaultAccess.OPERATORS); - - - public final String node; - public final DefaultAccess defaultAccess; - - Permission(@NotNull String node, @NotNull DefaultAccess defaultAccess) { - this.node = node; - this.defaultAccess = defaultAccess; - } - - /** - * Identifies who gets what permissions by default - */ - public enum DefaultAccess { - /** - * Everyone gets this permission node by default - */ - EVERYONE, - /** - * Nobody gets this permission node by default - */ - NOBODY, - /** - * Server operators ({@code /op}) get this permission node by default - */ - OPERATORS - } -} diff --git a/common/src/main/java/net/william278/husksync/command/TabCompletable.java b/common/src/main/java/net/william278/husksync/command/TabCompletable.java deleted file mode 100644 index a7e7e183..00000000 --- a/common/src/main/java/net/william278/husksync/command/TabCompletable.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.command; - -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -/** - * Interface providing tab completions for a command - */ -public interface TabCompletable { - - /** - * What should be returned when the player or console attempts to TAB-complete a command - * - * @param args Current command arguments - * @return List of String arguments to offer TAB suggestions - */ - List onTabComplete(@NotNull String[] args); - -} diff --git a/common/src/main/java/net/william278/husksync/command/TabProvider.java b/common/src/main/java/net/william278/husksync/command/TabProvider.java new file mode 100644 index 00000000..48c2b72b --- /dev/null +++ b/common/src/main/java/net/william278/husksync/command/TabProvider.java @@ -0,0 +1,50 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.command; + +import net.william278.husksync.user.CommandUser; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public interface TabProvider { + + @Nullable + List suggest(@NotNull CommandUser user, @NotNull String[] args); + + @NotNull + default List getSuggestions(@NotNull CommandUser user, @NotNull String[] args) { + List suggestions = suggest(user, args); + if (suggestions == null) { + suggestions = List.of(); + } + return filter(suggestions, args); + } + + @NotNull + default List filter(@NotNull List suggestions, @NotNull String[] args) { + return suggestions.stream() + .filter(suggestion -> args.length == 0 || suggestion.toLowerCase() + .startsWith(args[args.length - 1].toLowerCase().trim())) + .toList(); + } + +} \ No newline at end of file diff --git a/common/src/main/java/net/william278/husksync/command/UserDataCommand.java b/common/src/main/java/net/william278/husksync/command/UserDataCommand.java index 518df8fd..3bc55343 100644 --- a/common/src/main/java/net/william278/husksync/command/UserDataCommand.java +++ b/common/src/main/java/net/william278/husksync/command/UserDataCommand.java @@ -20,309 +20,216 @@ package net.william278.husksync.command; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.player.OnlineUser; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.CommandUser; +import net.william278.husksync.user.User; import net.william278.husksync.util.DataDumper; import net.william278.husksync.util.DataSnapshotList; +import net.william278.husksync.util.DataSnapshotOverview; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.io.IOException; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.logging.Level; -import java.util.stream.Collectors; -public class UserDataCommand extends CommandBase implements TabCompletable { +public class UserDataCommand extends Command implements TabProvider { - private final String[] COMMAND_ARGUMENTS = {"view", "list", "delete", "restore", "pin", "dump"}; + private static final Map SUB_COMMANDS = Map.of( + "view", false, + "list", false, + "delete", true, + "restore", true, + "pin", true, + "dump", true + ); - public UserDataCommand(@NotNull HuskSync implementor) { - super("userdata", Permission.COMMAND_USER_DATA, implementor, "playerdata"); + public UserDataCommand(@NotNull HuskSync plugin) { + super("userdata", List.of("playerdata"), String.format( + "<%s> [username] [version_uuid]", String.join("/", SUB_COMMANDS.keySet()) + ), plugin); + setOperatorCommand(true); + addAdditionalPermissions(SUB_COMMANDS); } @Override - public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) { - if (args.length < 1) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata [version_uuid]") - .ifPresent(player::sendMessage); + public void execute(@NotNull CommandUser executor, @NotNull String[] args) { + final String subCommand = parseStringArg(args, 0).orElse("view").toLowerCase(Locale.ENGLISH); + final Optional optionalUser = parseStringArg(args, 1) + .flatMap(name -> plugin.getDatabase().getUserByName(name)) + .or(() -> parseStringArg(args, 0).flatMap(name -> plugin.getDatabase().getUserByName(name))) + .or(() -> args.length < 2 && executor instanceof User userExecutor + ? Optional.of(userExecutor) : Optional.empty()); + final Optional optionalUuid = parseUUIDArg(args, 2).or(() -> parseUUIDArg(args, 1)); + if (optionalUser.isEmpty()) { + plugin.getLocales().getLocale("error_invalid_player") + .ifPresent(executor::sendMessage); return; } - switch (args[0].toLowerCase(Locale.ENGLISH)) { - case "view" -> { - if (args.length < 2) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata view [version_uuid]") - .ifPresent(player::sendMessage); - return; - } - final String username = args[1]; - if (args.length >= 3) { - try { - final UUID versionUuid = UUID.fromString(args[2]); - CompletableFuture.runAsync(() -> plugin.getDatabase() - .getUserByName(username.toLowerCase(Locale.ENGLISH)) - .thenAccept(optionalUser -> optionalUser - .ifPresentOrElse(user -> plugin.getDatabase().getUserData(user, versionUuid) - .thenAccept(data -> data.ifPresentOrElse( - userData -> userData.displayDataOverview(player, user, plugin.getLocales()), - () -> plugin.getLocales().getLocale("error_invalid_version_uuid") - .ifPresent(player::sendMessage))), - () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage)))); - } catch (IllegalArgumentException e) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata view [version_uuid]") - .ifPresent(player::sendMessage); - } - } else { - CompletableFuture.runAsync(() -> plugin.getDatabase() - .getUserByName(username.toLowerCase(Locale.ENGLISH)) - .thenAccept(optionalUser -> optionalUser - .ifPresentOrElse(user -> plugin.getDatabase().getCurrentUserData(user) - .thenAccept(latestData -> latestData.ifPresentOrElse( - userData -> userData.displayDataOverview(player, user, plugin.getLocales()), - () -> plugin.getLocales().getLocale("error_no_data_to_display") - .ifPresent(player::sendMessage))), - () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage)))); - } - } + final User user = optionalUser.get(); + switch (subCommand) { + case "view" -> optionalUuid.ifPresentOrElse( + // Show the specified snapshot + version -> plugin.getDatabase().getSnapshot(user, version).ifPresentOrElse( + data -> DataSnapshotOverview.of( + data.unpack(plugin), data.getFileSize(plugin), user, plugin + ).show(executor), + () -> plugin.getLocales().getLocale("error_invalid_version_uuid") + .ifPresent(executor::sendMessage)), + + // Show the latest snapshot + () -> plugin.getDatabase().getLatestSnapshot(user).ifPresentOrElse( + data -> DataSnapshotOverview.of( + data.unpack(plugin), data.getFileSize(plugin), user, plugin + ).show(executor), + () -> plugin.getLocales().getLocale("error_no_data_to_display") + .ifPresent(executor::sendMessage)) + ); + case "list" -> { - if (!player.hasPermission(Permission.COMMAND_USER_DATA_MANAGE.node)) { - plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage); - return; - } - if (args.length < 2) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata list [page]") - .ifPresent(player::sendMessage); + // Check if there is data to display + final List dataList = plugin.getDatabase().getAllSnapshots(user); + if (dataList.isEmpty()) { + plugin.getLocales().getLocale("error_no_data_to_display") + .ifPresent(executor::sendMessage); return; } - final String username = args[1]; - CompletableFuture.runAsync(() -> plugin.getDatabase() - .getUserByName(username.toLowerCase(Locale.ENGLISH)) - .thenAccept(optionalUser -> optionalUser.ifPresentOrElse( - user -> plugin.getDatabase().getUserData(user).thenAccept(dataList -> { - // Check if there is data to display - if (dataList.isEmpty()) { - plugin.getLocales().getLocale("error_no_data_to_display") - .ifPresent(player::sendMessage); - return; - } - // Determine page to display - int page = 1; - if (args.length >= 3) { - try { - page = Integer.parseInt(args[2]); - } catch (NumberFormatException e) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata list [page]") - .ifPresent(player::sendMessage); - return; - } - } - - // Show the list to the player - DataSnapshotList.create(dataList, user, plugin.getLocales()) - .displayPage(player, page); - }), - () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage)))); + // Show the list to the player + DataSnapshotList.create(dataList, user, plugin).displayPage( + executor, + parseIntArg(args, 2).or(() -> parseIntArg(args, 1)).orElse(1) + ); } + case "delete" -> { - if (!player.hasPermission(Permission.COMMAND_USER_DATA_MANAGE.node)) { - plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage); - return; - } - // Delete user data by specified UUID - if (args.length < 3) { + if (optionalUuid.isEmpty()) { plugin.getLocales().getLocale("error_invalid_syntax", "/userdata delete ") - .ifPresent(player::sendMessage); + .ifPresent(executor::sendMessage); return; } - final String username = args[1]; - try { - final UUID versionUuid = UUID.fromString(args[2]); - CompletableFuture.runAsync(() -> plugin.getDatabase() - .getUserByName(username.toLowerCase(Locale.ENGLISH)) - .thenAccept(optionalUser -> optionalUser.ifPresentOrElse( - user -> plugin.getDatabase().deleteUserData(user, versionUuid).thenAccept(deleted -> { - if (deleted) { - plugin.getLocales().getLocale("data_deleted", - versionUuid.toString().split("-")[0], - versionUuid.toString(), - user.username, - user.uuid.toString()) - .ifPresent(player::sendMessage); - } else { - plugin.getLocales().getLocale("error_invalid_version_uuid") - .ifPresent(player::sendMessage); - } - }), - () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage)))); - } catch (IllegalArgumentException e) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata delete ") - .ifPresent(player::sendMessage); + + // Delete user data by specified UUID + final UUID version = optionalUuid.get(); + if (!plugin.getDatabase().deleteSnapshot(user, version)) { + plugin.getLocales().getLocale("error_invalid_version_uuid") + .ifPresent(executor::sendMessage); + return; } + + plugin.getLocales().getLocale("data_deleted", + version.toString().split("-")[0], + version.toString(), + user.getUsername(), + user.getUuid().toString()) + .ifPresent(executor::sendMessage); } + case "restore" -> { - if (!player.hasPermission(Permission.COMMAND_USER_DATA_MANAGE.node)) { - plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage); + if (optionalUuid.isEmpty()) { + plugin.getLocales().getLocale("error_invalid_syntax", + "/userdata delete ") + .ifPresent(executor::sendMessage); return; } - // Get user data by specified uuid and username - if (args.length < 3) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata restore ") - .ifPresent(player::sendMessage); + + // Restore user data by specified UUID + final Optional optionalData = plugin.getDatabase().getSnapshot(user, optionalUuid.get()); + if (optionalData.isEmpty()) { + plugin.getLocales().getLocale("error_invalid_version_uuid") + .ifPresent(executor::sendMessage); return; } - final String username = args[1]; - try { - final UUID versionUuid = UUID.fromString(args[2]); - CompletableFuture.runAsync(() -> plugin.getDatabase() - .getUserByName(username.toLowerCase(Locale.ENGLISH)) - .thenAccept(optionalUser -> optionalUser.ifPresentOrElse( - user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept(data -> { - if (data.isEmpty()) { - plugin.getLocales().getLocale("error_invalid_version_uuid") - .ifPresent(player::sendMessage); - return; - } - // Restore users with a minimum of one health (prevent restoring players with <=0 health) - final UserData userData = data.get().userData(); - userData.getStatus().ifPresent(status -> status.health = Math.max(1, status.health)); + // Restore users with a minimum of one health (prevent restoring players with <=0 health) + final DataSnapshot.Packed data = optionalData.get().copy(); + data.edit(plugin, (unpacked -> { + unpacked.getHealth().ifPresent(status -> status.setHealth(Math.max(1, status.getHealth()))); + unpacked.setSaveCause(DataSnapshot.SaveCause.BACKUP_RESTORE); + unpacked.setPinned(plugin.getSettings().doAutoPin(DataSnapshot.SaveCause.BACKUP_RESTORE)); + })); - // Set the users data and send a message - plugin.getDatabase().setUserData(user, userData, DataSaveCause.BACKUP_RESTORE); - plugin.getRedisManager().sendUserDataUpdate(user, data.get().userData()).join(); - plugin.getLocales().getLocale("data_restored", - user.username, - user.uuid.toString(), - versionUuid.toString().split("-")[0], - versionUuid.toString()) - .ifPresent(player::sendMessage); - }), - () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage)))); - } catch (IllegalArgumentException e) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata restore ") - .ifPresent(player::sendMessage); - } + // Set the user's data and send a message + plugin.getDatabase().addSnapshot(user, data); + plugin.getRedisManager().sendUserDataUpdate(user, data); + plugin.getLocales().getLocale("data_restored", user.getUsername(), user.getUuid().toString(), + data.getShortId(), data.getId().toString()).ifPresent(executor::sendMessage); } + case "pin" -> { - if (!player.hasPermission(Permission.COMMAND_USER_DATA_MANAGE.node)) { - plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage); - return; - } - if (args.length < 3) { + if (optionalUuid.isEmpty()) { plugin.getLocales().getLocale("error_invalid_syntax", "/userdata pin ") - .ifPresent(player::sendMessage); + .ifPresent(executor::sendMessage); return; } - final String username = args[1]; - try { - final UUID versionUuid = UUID.fromString(args[2]); - CompletableFuture.runAsync(() -> plugin.getDatabase() - .getUserByName(username.toLowerCase(Locale.ENGLISH)) - .thenAccept(optionalUser -> optionalUser.ifPresentOrElse( - user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept( - optionalUserData -> optionalUserData.ifPresentOrElse(userData -> { - if (userData.pinned()) { - plugin.getDatabase().unpinUserData(user, versionUuid).join(); - plugin.getLocales().getLocale("data_unpinned", - versionUuid.toString().split("-")[0], - versionUuid.toString(), - user.username, - user.uuid.toString()) - .ifPresent(player::sendMessage); - } else { - plugin.getDatabase().pinUserData(user, versionUuid).join(); - plugin.getLocales().getLocale("data_pinned", - versionUuid.toString().split("-")[0], - versionUuid.toString(), - user.username, - user.uuid.toString()) - .ifPresent(player::sendMessage); - } - }, () -> plugin.getLocales().getLocale("error_invalid_version_uuid") - .ifPresent(player::sendMessage))), - () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage)))); - } catch (IllegalArgumentException e) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata pin ") - .ifPresent(player::sendMessage); + // Check that the data exists + final Optional optionalData = plugin.getDatabase().getSnapshot(user, optionalUuid.get()); + if (optionalData.isEmpty()) { + plugin.getLocales().getLocale("error_invalid_version_uuid") + .ifPresent(executor::sendMessage); + return; + } + + // Pin or unpin the data + final DataSnapshot.Packed data = optionalData.get(); + if (data.isPinned()) { + plugin.getDatabase().unpinSnapshot(user, data.getId()); + } else { + plugin.getDatabase().pinSnapshot(user, data.getId()); } + plugin.getLocales().getLocale(data.isPinned() ? "data_unpinned" : "data_pinned", data.getShortId(), + data.getId().toString(), user.getUsername(), user.getUuid().toString()) + .ifPresent(executor::sendMessage); } + case "dump" -> { - if (!player.hasPermission(Permission.COMMAND_USER_DATA_DUMP.node)) { - plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage); - return; - } - if (args.length < 3) { + if (optionalUuid.isEmpty()) { plugin.getLocales().getLocale("error_invalid_syntax", "/userdata dump ") - .ifPresent(player::sendMessage); + .ifPresent(executor::sendMessage); + return; + } + + // Determine dump type + final boolean webDump = parseStringArg(args, 3) + .map(arg -> arg.equalsIgnoreCase("web")) + .orElse(false); + final Optional data = plugin.getDatabase().getSnapshot(user, optionalUuid.get()); + if (data.isEmpty()) { + plugin.getLocales().getLocale("error_invalid_version_uuid") + .ifPresent(executor::sendMessage); return; } - final boolean toWeb = args.length > 3 && args[3].equalsIgnoreCase("web"); - final String username = args[1]; + // Dump the data + final DataSnapshot.Packed userData = data.get(); + final DataDumper dumper = DataDumper.create(userData, user, plugin); try { - final UUID versionUuid = UUID.fromString(args[2]); - CompletableFuture.runAsync(() -> plugin.getDatabase() - .getUserByName(username.toLowerCase(Locale.ENGLISH)) - .thenAccept(optionalUser -> optionalUser.ifPresentOrElse( - user -> plugin.getDatabase().getUserData(user, versionUuid).thenAccept( - optionalUserData -> optionalUserData.ifPresentOrElse(userData -> { - try { - final DataDumper dumper = DataDumper.create(userData, user, plugin); - final String result = toWeb ? dumper.toWeb() : dumper.toFile(); - plugin.getLocales().getLocale("data_dumped", versionUuid.toString() - .split("-")[0], user.username, result) - .ifPresent(player::sendMessage); - } catch (IOException e) { - plugin.log(Level.SEVERE, "Failed to dump user data", e); - } - }, () -> plugin.getLocales().getLocale("error_invalid_version_uuid") - .ifPresent(player::sendMessage))), - () -> plugin.getLocales().getLocale("error_invalid_player") - .ifPresent(player::sendMessage)))); - } catch (IllegalArgumentException e) { - plugin.getLocales().getLocale("error_invalid_syntax", - "/userdata dump ") - .ifPresent(player::sendMessage); + plugin.getLocales().getLocale("data_dumped", userData.getShortId(), user.getUsername(), + (webDump ? dumper.toWeb() : dumper.toFile())).ifPresent(executor::sendMessage); + } catch (Throwable e) { + plugin.log(Level.SEVERE, "Failed to dump user data", e); } } + + default -> plugin.getLocales().getLocale("error_invalid_syntax", getUsage()) + .ifPresent(executor::sendMessage); } } + @Nullable @Override - public List onTabComplete(@NotNull String[] args) { - switch (args.length) { - case 0, 1 -> { - return Arrays.stream(COMMAND_ARGUMENTS) - .filter(argument -> argument.startsWith(args.length == 1 ? args[0] : "")) - .sorted().collect(Collectors.toList()); - } - case 2 -> { - return plugin.getOnlineUsers().stream().map(user -> user.username) - .filter(argument -> argument.startsWith(args[1])) - .sorted().collect(Collectors.toList()); - } - } - return Collections.emptyList(); + public List suggest(@NotNull CommandUser executor, @NotNull String[] args) { + return switch (args.length) { + case 0, 1 -> SUB_COMMANDS.keySet().stream().sorted().toList(); + case 2 -> plugin.getOnlineUsers().stream().map(User::getUsername).toList(); + case 4 -> parseStringArg(args, 0) + .map(arg -> arg.equalsIgnoreCase("dump") ? List.of("web", "file") : null) + .orElse(null); + default -> null; + }; } } diff --git a/common/src/main/java/net/william278/husksync/config/Locales.java b/common/src/main/java/net/william278/husksync/config/Locales.java index 361142ac..d72d8653 100644 --- a/common/src/main/java/net/william278/husksync/config/Locales.java +++ b/common/src/main/java/net/william278/husksync/config/Locales.java @@ -50,7 +50,7 @@ public class Locales { public Map rawLocales = new HashMap<>(); /** - * Returns a raw, un-formatted locale loaded from the locales file + * Returns a raw, unformatted locale loaded from the Locales file * * @param localeId String identifier of the locale, corresponding to a key in the file * @return An {@link Optional} containing the locale corresponding to the id, if it exists @@ -60,12 +60,12 @@ public class Locales { } /** - * Returns a raw, un-formatted locale loaded from the locales file, with replacements applied + * Returns a raw, unformatted locale loaded from the Locales file, with replacements applied *

* Note that replacements will not be MineDown-escaped; use {@link #escapeMineDown(String)} to escape replacements * * @param localeId String identifier of the locale, corresponding to a key in the file - * @param replacements Ordered array of replacement strings to fill in placeholders with + * @param replacements An ordered array of replacement strings to fill in placeholders with * @return An {@link Optional} containing the replacement-applied locale corresponding to the id, if it exists */ public Optional getRawLocale(@NotNull String localeId, @NotNull String... replacements) { @@ -73,7 +73,7 @@ public class Locales { } /** - * Returns a MineDown-formatted locale from the locales file + * Returns a MineDown-formatted locale from the Locales file * * @param localeId String identifier of the locale, corresponding to a key in the file * @return An {@link Optional} containing the formatted locale corresponding to the id, if it exists @@ -83,12 +83,12 @@ public class Locales { } /** - * Returns a MineDown-formatted locale from the locales file, with replacements applied + * Returns a MineDown-formatted locale from the Locales file, with replacements applied *

* Note that replacements will be MineDown-escaped before application * * @param localeId String identifier of the locale, corresponding to a key in the file - * @param replacements Ordered array of replacement strings to fill in placeholders with + * @param replacements An ordered array of replacement strings to fill in placeholders with * @return An {@link Optional} containing the replacement-applied, formatted locale corresponding to the id, if it exists */ public Optional getLocale(@NotNull String localeId, @NotNull String... replacements) { @@ -100,7 +100,7 @@ public class Locales { * Apply placeholder replacements to a raw locale * * @param rawLocale The raw, unparsed locale - * @param replacements Ordered array of replacement strings to fill in placeholders with + * @param replacements An ordered array of replacement strings to fill in placeholders with * @return the raw locale, with inserted placeholders */ @NotNull @@ -189,4 +189,25 @@ public class Locales { public Locales() { } + /** + * Determines the slot a system notification should be displayed in + */ + public enum NotificationSlot { + /** + * Displays the notification in the action bar + */ + ACTION_BAR, + /** + * Displays the notification in the chat + */ + CHAT, + /** + * Displays the notification in an Advancement Toast + */ + TOAST, + /** + * Does not display the notification + */ + NONE + } } diff --git a/common/src/main/java/net/william278/husksync/config/Settings.java b/common/src/main/java/net/william278/husksync/config/Settings.java index b8d0c475..95120caa 100644 --- a/common/src/main/java/net/william278/husksync/config/Settings.java +++ b/common/src/main/java/net/william278/husksync/config/Settings.java @@ -22,7 +22,10 @@ package net.william278.husksync.config; import net.william278.annotaml.YamlComment; import net.william278.annotaml.YamlFile; import net.william278.annotaml.YamlKey; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.data.Identifier; import net.william278.husksync.database.Database; +import net.william278.husksync.listener.EventListener; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -36,30 +39,43 @@ import java.util.*; ┃ Developed by William278 ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┣╸ Information: https://william278.net/project/husksync - ┗╸ Documentation: https://william278.net/docs/husksync""", - versionField = "config_version", versionNumber = 4) + ┣╸ Config Help: https://william278.net/docs/husksync/config-file/ + ┗╸ Documentation: https://william278.net/docs/husksync""") public class Settings { // Top-level settings + @YamlComment("Locale of the default language file to use. Docs: https://william278.net/docs/huskhomes/translations") @YamlKey("language") private String language = "en-gb"; + @YamlComment("Whether to automatically check for plugin updates on startup") @YamlKey("check_for_updates") private boolean checkForUpdates = true; + @YamlComment("Specify a common ID for grouping servers running HuskSync. " + + "Don't modify this unless you know what you're doing!") @YamlKey("cluster_id") private String clusterId = ""; + @YamlComment("Enable development debug logging") @YamlKey("debug_logging") private boolean debugLogging = false; + @YamlComment("Whether to provide modern, rich TAB suggestions for commands (if available)") + @YamlKey("brigadier_tab_completion") + private boolean brigadierTabCompletion = false; + + @YamlComment("Whether to enable the Player Analytics hook. Docs: https://william278.net/docs/husksync/plan-hook") + @YamlKey("enable_plan_hook") + private boolean enablePlanHook = true; + // Database settings @YamlComment("Type of database to use (MYSQL, MARIADB)") @YamlKey("database.type") private Database.Type databaseType = Database.Type.MYSQL; - - @YamlComment("Database connection settings") + + @YamlComment("Specify credentials here for your MYSQL or MARIADB database") @YamlKey("database.credentials.host") private String mySqlHost = "localhost"; @@ -76,9 +92,13 @@ public class Settings { private String mySqlPassword = "pa55w0rd"; @YamlKey("database.credentials.parameters") - private String mySqlConnectionParameters = "?autoReconnect=true&useSSL=false"; + private String mySqlConnectionParameters = "?autoReconnect=true" + + "&useSSL=false" + + "&useUnicode=true" + + "&characterEncoding=UTF-8"; - @YamlComment("MySQL connection pool properties") + @YamlComment("MYSQL / MARIADB database Hikari connection pool properties. " + + "Don't modify this unless you know what you're doing!") @YamlKey("database.connection_pool.maximum_pool_size") private int mySqlConnectionPoolSize = 10; @@ -94,12 +114,13 @@ public class Settings { @YamlKey("database.connection_pool.connection_timeout") private long mySqlConnectionPoolTimeout = 5000; + @YamlComment("Names of tables to use on your database. Don't modify this unless you know what you're doing!") @YamlKey("database.table_names") private Map tableNames = TableName.getDefaults(); // Redis settings - @YamlComment("Redis connection settings") + @YamlComment("Specify the credentials of your Redis database here. Set \"password\" to '' if you don't have one") @YamlKey("redis.credentials.host") private String redisHost = "localhost"; @@ -114,42 +135,75 @@ public class Settings { // Synchronization settings - @YamlComment("Synchronization settings") + @YamlComment("The number of data snapshot backups that should be kept at once per user") @YamlKey("synchronization.max_user_data_snapshots") - private int maxUserDataSnapshots = 5; - + private int maxUserDataSnapshots = 16; + + @YamlComment("Number of hours between new snapshots being saved as backups (Use \"0\" to backup all snapshots)") + @YamlKey("synchronization.snapshot_backup_frequency") + private int snapshotBackupFrequency = 4; + + @YamlComment("List of save cause IDs for which a snapshot will be automatically pinned (so it won't be rotated)." + + " Docs: https://william278.net/docs/husksync/data-rotation#save-causes") + @YamlKey("synchronization.auto_pinned_save_causes") + private List autoPinnedSaveCauses = List.of( + DataSnapshot.SaveCause.INVENTORY_COMMAND.name(), + DataSnapshot.SaveCause.ENDERCHEST_COMMAND.name(), + DataSnapshot.SaveCause.BACKUP_RESTORE.name(), + DataSnapshot.SaveCause.CONVERTED_FROM_V2.name(), + DataSnapshot.SaveCause.LEGACY_MIGRATION.name(), + DataSnapshot.SaveCause.MPDB_MIGRATION.name() + ); + + @YamlComment("Whether to create a snapshot for users on a world when the server saves that world") @YamlKey("synchronization.save_on_world_save") private boolean saveOnWorldSave = true; + @YamlComment("Whether to create a snapshot for users when they die (containing their death drops)") @YamlKey("synchronization.save_on_death") private boolean saveOnDeath = false; + @YamlComment("Whether to save empty death drops for users when they die") @YamlKey("synchronization.save_empty_drops_on_death") private boolean saveEmptyDropsOnDeath = true; + @YamlComment("Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing") @YamlKey("synchronization.compress_data") private boolean compressData = true; + @YamlComment("Where to display sync notifications (ACTION_BAR, CHAT, TOAST or NONE)") @YamlKey("synchronization.notification_display_slot") - private NotificationDisplaySlot notificationDisplaySlot = NotificationDisplaySlot.ACTION_BAR; + private Locales.NotificationSlot notificationSlot = Locales.NotificationSlot.ACTION_BAR; - @YamlKey("synchronization.synchronise_dead_players_changing_server") - private boolean synchroniseDeadPlayersChangingServer = true; + @YamlComment("(Experimental) Persist Cartography Table locked maps to let them be viewed on any server") + @YamlKey("synchronization.persist_locked_maps") + private boolean persistLockedMaps = false; + @YamlComment("Whether dead players who log out and log in to a different server should have their items saved. " + + "You may need to modify this if you're using the keepInventory gamerule.") + @YamlKey("synchronization.synchronize_dead_players_changing_server") + private boolean synchronizeDeadPlayersChangingServer = true; + + @YamlComment("How long, in milliseconds, this server should wait for a response from the redis server before " + + "pulling data from the database instead (i.e., if the user did not change servers).") @YamlKey("synchronization.network_latency_milliseconds") private int networkLatencyMilliseconds = 500; + @YamlComment("Which data types to synchronize (Docs: https://william278.net/docs/husksync/sync-features)") @YamlKey("synchronization.features") - private Map synchronizationFeatures = SynchronizationFeature.getDefaults(); + private Map synchronizationFeatures = Identifier.getConfigMap(); + @YamlComment("Commands which should be blocked before a player has finished syncing (Use * to block all commands)") @YamlKey("synchronization.blacklisted_commands_while_locked") private List blacklistedCommandsWhileLocked = new ArrayList<>(List.of("*")); + @YamlComment("Event priorities for listeners (HIGHEST, NORMAL, LOWEST). Change if you encounter plugin conflicts") @YamlKey("synchronization.event_priorities") - private Map synchronizationEventPriorities = EventType.getDefaults(); + private Map syncEventPriorities = EventListener.ListenerType.getDefaults(); // Zero-args constructor for instantiation via Annotaml + @SuppressWarnings("unused") public Settings() { } @@ -172,6 +226,13 @@ public class Settings { return debugLogging; } + public boolean doBrigadierTabCompletion() { + return brigadierTabCompletion; + } + + public boolean usePlanHook() { + return enablePlanHook; + } @NotNull public Database.Type getDatabaseType() { @@ -246,7 +307,7 @@ public class Settings { return redisPassword; } - public boolean isRedisUseSsl() { + public boolean redisUseSsl() { return redisUseSsl; } @@ -254,6 +315,10 @@ public class Settings { return maxUserDataSnapshots; } + public int getBackupFrequency() { + return snapshotBackupFrequency; + } + public boolean doSaveOnWorldSave() { return saveOnWorldSave; } @@ -270,13 +335,21 @@ public class Settings { return compressData; } + public boolean doAutoPin(@NotNull DataSnapshot.SaveCause cause) { + return autoPinnedSaveCauses.contains(cause.name()); + } + @NotNull - public NotificationDisplaySlot getNotificationDisplaySlot() { - return notificationDisplaySlot; + public Locales.NotificationSlot getNotificationDisplaySlot() { + return notificationSlot; + } + + public boolean doPersistLockedMaps() { + return persistLockedMaps; } - public boolean isSynchroniseDeadPlayersChangingServer() { - return synchroniseDeadPlayersChangingServer; + public boolean doSynchronizeDeadPlayersChangingServer() { + return synchronizeDeadPlayersChangingServer; } public int getNetworkLatencyMilliseconds() { @@ -288,8 +361,8 @@ public class Settings { return synchronizationFeatures; } - public boolean getSynchronizationFeature(@NotNull SynchronizationFeature feature) { - return getSynchronizationFeatures().getOrDefault(feature.name().toLowerCase(Locale.ENGLISH), feature.enabledByDefault); + public boolean isSyncFeatureEnabled(@NotNull Identifier id) { + return id.isCustom() || getSynchronizationFeatures().getOrDefault(id.getKeyValue(), id.isEnabledByDefault()); } @NotNull @@ -298,12 +371,11 @@ public class Settings { } @NotNull - public EventPriority getEventPriority(@NotNull Settings.EventType eventType) { + public EventListener.Priority getEventPriority(@NotNull EventListener.ListenerType type) { try { - return EventPriority.valueOf(synchronizationEventPriorities.get(eventType.name().toLowerCase(Locale.ENGLISH))); + return EventListener.Priority.valueOf(syncEventPriorities.get(type.name().toLowerCase(Locale.ENGLISH))); } catch (IllegalArgumentException e) { - e.printStackTrace(); - return EventPriority.NORMAL; + return EventListener.Priority.NORMAL; } } @@ -334,111 +406,4 @@ public class Settings { } } - /** - * Determines the slot a system notification should be displayed in - */ - public enum NotificationDisplaySlot { - /** - * Displays the notification in the action bar - */ - ACTION_BAR, - /** - * Displays the notification in the chat - */ - CHAT, - /** - * Displays the notification in an advancement toast - */ - TOAST, - /** - * Does not display the notification - */ - NONE - } - - /** - * Represents enabled synchronisation features - */ - public enum SynchronizationFeature { - INVENTORIES(true), - ENDER_CHESTS(true), - HEALTH(true), - MAX_HEALTH(true), - HUNGER(true), - EXPERIENCE(true), - POTION_EFFECTS(true), - ADVANCEMENTS(true), - GAME_MODE(true), - STATISTICS(true), - PERSISTENT_DATA_CONTAINER(false), - LOCKED_MAPS(false), - LOCATION(false); - - private final boolean enabledByDefault; - - SynchronizationFeature(boolean enabledByDefault) { - this.enabledByDefault = enabledByDefault; - } - - @NotNull - private Map.Entry toEntry() { - return Map.entry(name().toLowerCase(Locale.ENGLISH), enabledByDefault); - } - - @SuppressWarnings("unchecked") - @NotNull - private static Map getDefaults() { - return Map.ofEntries(Arrays.stream(values()) - .map(SynchronizationFeature::toEntry) - .toArray(Map.Entry[]::new)); - } - } - - /** - * Represents events that HuskSync listens to, with a configurable priority listener - */ - public enum EventType { - JOIN_LISTENER(EventPriority.LOWEST), - QUIT_LISTENER(EventPriority.LOWEST), - DEATH_LISTENER(EventPriority.NORMAL); - - private final EventPriority defaultPriority; - - EventType(@NotNull EventPriority defaultPriority) { - this.defaultPriority = defaultPriority; - } - - @NotNull - private Map.Entry toEntry() { - return Map.entry(name().toLowerCase(Locale.ENGLISH), defaultPriority.name()); - } - - - @SuppressWarnings("unchecked") - @NotNull - private static Map getDefaults() { - return Map.ofEntries(Arrays.stream(values()) - .map(EventType::toEntry) - .toArray(Map.Entry[]::new)); - } - } - - /** - * Represents priorities for events that HuskSync listens to - */ - public enum EventPriority { - /** - * Listens and processes the event execution last - */ - HIGHEST, - /** - * Listens in between {@link #HIGHEST} and {@link #LOWEST} priority marked - */ - NORMAL, - /** - * Listens and processes the event execution first - */ - LOWEST - } - } diff --git a/common/src/main/java/net/william278/husksync/data/AdvancementData.java b/common/src/main/java/net/william278/husksync/data/AdvancementData.java deleted file mode 100644 index 738a8013..00000000 --- a/common/src/main/java/net/william278/husksync/data/AdvancementData.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import com.google.gson.annotations.SerializedName; -import org.jetbrains.annotations.NotNull; - -import java.util.Date; -import java.util.Map; - -/** - * A mapped piece of advancement data - */ -public class AdvancementData { - - /** - * The advancement namespaced key - */ - @SerializedName("key") - public String key; - - /** - * A map of completed advancement criteria to when it was completed - */ - @SerializedName("completed_criteria") - public Map completedCriteria; - - public AdvancementData(@NotNull String key, @NotNull Map awardedCriteria) { - this.key = key; - this.completedCriteria = awardedCriteria; - } - - @SuppressWarnings("unused") - protected AdvancementData() { - } -} diff --git a/common/src/main/java/net/william278/husksync/data/CompressedDataAdapter.java b/common/src/main/java/net/william278/husksync/data/CompressedDataAdapter.java deleted file mode 100644 index 76d0f44e..00000000 --- a/common/src/main/java/net/william278/husksync/data/CompressedDataAdapter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import org.jetbrains.annotations.NotNull; -import org.xerial.snappy.Snappy; - -import java.io.IOException; - -public class CompressedDataAdapter extends JsonDataAdapter { - - @Override - public byte[] toBytes(@NotNull UserData data) throws DataAdaptionException { - try { - return Snappy.compress(super.toBytes(data)); - } catch (IOException e) { - throw new DataAdaptionException("Failed to compress data", e); - } - } - - @Override - public @NotNull UserData fromBytes(byte[] data) throws DataAdaptionException { - try { - return super.fromBytes(Snappy.uncompress(data)); - } catch (IOException e) { - throw new DataAdaptionException("Failed to decompress data", e); - } - } -} diff --git a/common/src/main/java/net/william278/husksync/data/Data.java b/common/src/main/java/net/william278/husksync/data/Data.java new file mode 100644 index 00000000..e192a4fb --- /dev/null +++ b/common/src/main/java/net/william278/husksync/data/Data.java @@ -0,0 +1,368 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.data; + +import com.google.gson.annotations.SerializedName; +import net.william278.husksync.HuskSync; +import net.william278.husksync.user.OnlineUser; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * A piece of data, held by a {@link DataHolder} + */ +@SuppressWarnings("unused") +public interface Data { + + /** + * Apply (set) this data container to the given {@link OnlineUser} + * + * @param user the user to apply this element to + * @param plugin the plugin instance + */ + void apply(@NotNull UserDataHolder user, @NotNull HuskSync plugin); + + /** + * A data container holding data for: + *

    + *
  • Inventories
  • + *
  • Ender Chests
  • + *
+ */ + interface Items extends Data { + + @NotNull + Stack[] getStack(); + + default int getSlotCount() { + return getStack().length; + } + + record Stack(@NotNull String material, int amount, @Nullable String name, + @Nullable List lore, @NotNull List enchantments) { + + } + + default boolean isEmpty() { + return Arrays.stream(getStack()).allMatch(Objects::isNull) || getStack().length == 0; + } + + void clear(); + + void setContents(@NotNull Items contents); + + /** + * A data container holding data for inventories and selected hotbar slot + */ + interface Inventory extends Items { + + int getHeldItemSlot(); + + void setHeldItemSlot(int heldItemSlot) throws IllegalArgumentException; + + default Optional getHelmet() { + return Optional.ofNullable(getStack()[39]); + } + + default Optional getChestplate() { + return Optional.ofNullable(getStack()[38]); + } + + default Optional getLeggings() { + return Optional.ofNullable(getStack()[37]); + } + + default Optional getBoots() { + return Optional.ofNullable(getStack()[36]); + } + + default Optional getOffHand() { + return Optional.ofNullable(getStack()[40]); + } + } + + /** + * Data container holding data for ender chests + */ + interface EnderChest extends Items { + + } + + } + + /** + * Data container holding data for potion effects + */ + interface PotionEffects extends Data { + + @NotNull + List getActiveEffects(); + + /** + * Represents a potion effect + * + * @param type the type of potion effect + * @param amplifier the amplifier of the potion effect + * @param duration the duration of the potion effect + * @param isAmbient whether the potion effect is ambient + * @param showParticles whether the potion effect shows particles + * @param hasIcon whether the potion effect displays a HUD icon + */ + record Effect(@SerializedName("type") @NotNull String type, + @SerializedName("amplifier") int amplifier, + @SerializedName("duration") int duration, + @SerializedName("is_ambient") boolean isAmbient, + @SerializedName("show_particles") boolean showParticles, + @SerializedName("has_icon") boolean hasIcon) { + + } + + } + + /** + * Data container holding data for advancements + */ + interface Advancements extends Data { + + @NotNull + List getCompleted(); + + @NotNull + default List getCompletedExcludingRecipes() { + return getCompleted().stream() + .filter(advancement -> !advancement.getKey().startsWith("minecraft:recipe")) + .collect(Collectors.toList()); + } + + void setCompleted(@NotNull List completed); + + class Advancement { + @SerializedName("key") + private String key; + + @SerializedName("completed_criteria") + private Map completedCriteria; + + private Advancement(@NotNull String key, @NotNull Map completedCriteria) { + this.key = key; + this.completedCriteria = adaptDateMap(completedCriteria); + } + + @SuppressWarnings("unused") + private Advancement() { + } + + @NotNull + public static Advancement adapt(@NotNull String key, @NotNull Map completedCriteria) { + return new Advancement(key, completedCriteria); + } + + @NotNull + private static Map adaptDateMap(@NotNull Map dateMap) { + return dateMap.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getTime())); + } + + @NotNull + private static Map adaptLongMap(@NotNull Map dateMap) { + return dateMap.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> new Date(e.getValue()))); + } + + @NotNull + public String getKey() { + return key; + } + + public void setKey(@NotNull String key) { + this.key = key; + } + + public Map getCompletedCriteria() { + return adaptLongMap(completedCriteria); + } + + public void setCompletedCriteria(Map completedCriteria) { + this.completedCriteria = adaptDateMap(completedCriteria); + } + } + + } + + /** + * Data container holding data for the player's location + */ + interface Location extends Data { + double getX(); + + void setX(double x); + + double getY(); + + void setY(double y); + + double getZ(); + + void setZ(double z); + + float getYaw(); + + void setYaw(float yaw); + + float getPitch(); + + void setPitch(float pitch); + + @NotNull + World getWorld(); + + void setWorld(@NotNull World world); + + record World( + @SerializedName("name") @NotNull String name, + @SerializedName("uuid") @NotNull UUID uuid, + @SerializedName("environment") @NotNull String environment + ) { + } + } + + /** + * Data container holding data for statistics + */ + interface Statistics extends Data { + @NotNull + Map getGenericStatistics(); + + @NotNull + Map> getBlockStatistics(); + + @NotNull + Map> getItemStatistics(); + + @NotNull + Map> getEntityStatistics(); + } + + /** + * Data container holding data for persistent data containers + */ + interface PersistentData extends Data { + + } + + /** + * A data container holding data for: + *
    + *
  • Health
  • + *
  • Max Health
  • + *
  • Health Scale
  • + *
+ */ + interface Health extends Data { + double getHealth(); + + void setHealth(double health); + + double getMaxHealth(); + + void setMaxHealth(double maxHealth); + + double getHealthScale(); + + void setHealthScale(double healthScale); + } + + /** + * A data container holding data for: + *
    + * + *
  • Food Level
  • + *
  • Saturation
  • + *
  • Exhaustion
  • + *
+ */ + interface Hunger extends Data { + + int getFoodLevel(); + + void setFoodLevel(int foodLevel); + + float getSaturation(); + + void setSaturation(float saturation); + + float getExhaustion(); + + void setExhaustion(float exhaustion); + + } + + /** + * A data container holding data for: + *
    + *
  • Total experience
  • + *
  • Experience level
  • + *
  • Experience progress
  • + *
+ */ + interface Experience extends Data { + + int getTotalExperience(); + + void setTotalExperience(int totalExperience); + + int getExpLevel(); + + void setExpLevel(int expLevel); + + float getExpProgress(); + + void setExpProgress(float expProgress); + } + + /** + * A data container holding data for: + *
    + *
  • Game mode
  • + *
  • Allow flight
  • + *
  • Is flying
  • + *
+ */ + interface GameMode extends Data { + + @NotNull + String getGameMode(); + + void setGameMode(@NotNull String gameMode); + + boolean getAllowFlight(); + + void setAllowFlight(boolean allowFlight); + + boolean getIsFlying(); + + void setIsFlying(boolean isFlying); + } + + +} diff --git a/common/src/main/java/net/william278/husksync/data/DataAdapter.java b/common/src/main/java/net/william278/husksync/data/DataAdapter.java deleted file mode 100644 index 8e568b33..00000000 --- a/common/src/main/java/net/william278/husksync/data/DataAdapter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import org.jetbrains.annotations.NotNull; - -/** - * An adapter that adapts {@link UserData} to and from a portable byte array. - */ -public interface DataAdapter { - - /** - * Converts {@link UserData} to a byte array - * - * @param data The {@link UserData} to adapt - * @return The byte array. - * @throws DataAdaptionException If an error occurred during adaptation. - */ - byte[] toBytes(@NotNull UserData data) throws DataAdaptionException; - - /** - * Serializes {@link UserData} to a JSON string. - * - * @param data The {@link UserData} to serialize - * @param pretty Whether to pretty print the JSON. - * @return The output json string. - * @throws DataAdaptionException If an error occurred during adaptation. - */ - @NotNull - String toJson(@NotNull UserData data, boolean pretty) throws DataAdaptionException; - - /** - * Converts a byte array to {@link UserData}. - * - * @param data The byte array to adapt. - * @return The {@link UserData}. - * @throws DataAdaptionException If an error occurred during adaptation, such as if the byte array is invalid. - */ - @NotNull - UserData fromBytes(final byte[] data) throws DataAdaptionException; - -} diff --git a/common/src/main/java/net/william278/husksync/data/DataHolder.java b/common/src/main/java/net/william278/husksync/data/DataHolder.java new file mode 100644 index 00000000..2fa1cae8 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/data/DataHolder.java @@ -0,0 +1,140 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.data; + +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Optional; + +@SuppressWarnings("unused") +public interface DataHolder { + + @NotNull + Map getData(); + + default Optional getData(@NotNull Identifier identifier) { + return Optional.ofNullable(getData().get(identifier)); + } + + default void setData(@NotNull Identifier identifier, @NotNull Data data) { + getData().put(identifier, data); + } + + @NotNull + default Optional getInventory() { + return getData(Identifier.INVENTORY).map(Data.Items.Inventory.class::cast); + } + + default void setInventory(@NotNull Data.Items.Inventory inventory) { + setData(Identifier.INVENTORY, inventory); + } + + @NotNull + default Optional getEnderChest() { + return getData(Identifier.ENDER_CHEST).map(Data.Items.EnderChest.class::cast); + } + + default void setEnderChest(@NotNull Data.Items.EnderChest enderChest) { + setData(Identifier.ENDER_CHEST, enderChest); + } + + @NotNull + default Optional getPotionEffects() { + return getData(Identifier.POTION_EFFECTS).map(Data.PotionEffects.class::cast); + } + + default void setPotionEffects(@NotNull Data.PotionEffects potionEffects) { + setData(Identifier.POTION_EFFECTS, potionEffects); + } + + @NotNull + default Optional getAdvancements() { + return getData(Identifier.ADVANCEMENTS).map(Data.Advancements.class::cast); + } + + default void setAdvancements(@NotNull Data.Advancements advancements) { + setData(Identifier.ADVANCEMENTS, advancements); + } + + @NotNull + default Optional getLocation() { + return Optional.ofNullable((Data.Location) getData().get(Identifier.LOCATION)); + } + + default void setLocation(@NotNull Data.Location location) { + getData().put(Identifier.LOCATION, location); + } + + @NotNull + default Optional getStatistics() { + return Optional.ofNullable((Data.Statistics) getData().get(Identifier.STATISTICS)); + } + + default void setStatistics(@NotNull Data.Statistics statistics) { + getData().put(Identifier.STATISTICS, statistics); + } + + @NotNull + default Optional getHealth() { + return Optional.ofNullable((Data.Health) getData().get(Identifier.HEALTH)); + } + + default void setHealth(@NotNull Data.Health health) { + getData().put(Identifier.HEALTH, health); + } + + @NotNull + default Optional getHunger() { + return Optional.ofNullable((Data.Hunger) getData().get(Identifier.HUNGER)); + } + + default void setHunger(@NotNull Data.Hunger hunger) { + getData().put(Identifier.HUNGER, hunger); + } + + @NotNull + default Optional getExperience() { + return Optional.ofNullable((Data.Experience) getData().get(Identifier.EXPERIENCE)); + } + + default void setExperience(@NotNull Data.Experience experience) { + getData().put(Identifier.EXPERIENCE, experience); + } + + @NotNull + default Optional getGameMode() { + return Optional.ofNullable((Data.GameMode) getData().get(Identifier.GAME_MODE)); + } + + default void setGameMode(@NotNull Data.GameMode gameMode) { + getData().put(Identifier.GAME_MODE, gameMode); + } + + @NotNull + default Optional getPersistentData() { + return Optional.ofNullable((Data.PersistentData) getData().get(Identifier.PERSISTENT_DATA)); + } + + default void setPersistentData(@NotNull Data.PersistentData persistentData) { + getData().put(Identifier.PERSISTENT_DATA, persistentData); + } + +} diff --git a/common/src/main/java/net/william278/husksync/data/DataSaveCause.java b/common/src/main/java/net/william278/husksync/data/DataSaveCause.java deleted file mode 100644 index 7b4c8671..00000000 --- a/common/src/main/java/net/william278/husksync/data/DataSaveCause.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import net.william278.husksync.api.BaseHuskSyncAPI; -import net.william278.husksync.config.Locales; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; -import org.jetbrains.annotations.NotNull; - -import java.util.Locale; - -/** - * Identifies the cause of a player data save. - * - * @implNote This enum is saved in the database. - *

- * Cause names have a max length of 32 characters. - */ -public enum DataSaveCause { - - /** - * Indicates data saved when a player disconnected from the server (either to change servers, or to log off) - * - * @since 2.0 - */ - DISCONNECT, - /** - * Indicates data saved when the world saved - * - * @since 2.0 - */ - WORLD_SAVE, - /** - * Indicates data saved when the user died - * - * @since 2.1 - */ - DEATH, - /** - * Indicates data saved when the server shut down - * - * @since 2.0 - */ - SERVER_SHUTDOWN, - /** - * Indicates data was saved by editing inventory contents via the {@code /inventory} command - * - * @since 2.0 - */ - INVENTORY_COMMAND, - /** - * Indicates data was saved by editing Ender Chest contents via the {@code /enderchest} command - * - * @since 2.0 - */ - ENDERCHEST_COMMAND, - /** - * Indicates data was saved by restoring it from a previous version - * - * @since 2.0 - */ - BACKUP_RESTORE, - /** - * Indicates data was saved by an API call - * - * @see BaseHuskSyncAPI#saveUserData(OnlineUser) - * @see BaseHuskSyncAPI#setUserData(User, UserData) - * @since 2.0 - */ - API, - /** - * Indicates data was saved from being imported from MySQLPlayerDataBridge - * - * @since 2.0 - */ - MPDB_MIGRATION, - /** - * Indicates data was saved from being imported from a legacy version (v1.x) - * - * @since 2.0 - */ - LEGACY_MIGRATION, - /** - * Indicates data was saved by an unknown cause. - *

- * This should not be used and is only used for error handling purposes. - * - * @since 2.0 - */ - UNKNOWN; - - /** - * Returns a {@link DataSaveCause} by name. - * - * @return the {@link DataSaveCause} or {@link #UNKNOWN} if the name is not valid. - */ - @NotNull - public static DataSaveCause getCauseByName(@NotNull String name) { - for (DataSaveCause cause : values()) { - if (cause.name().equalsIgnoreCase(name)) { - return cause; - } - } - return UNKNOWN; - } - - @NotNull - public String getDisplayName() { - return Locales.truncate(name().toLowerCase(Locale.ENGLISH), 10); - } - -} diff --git a/common/src/main/java/net/william278/husksync/data/DataSnapshot.java b/common/src/main/java/net/william278/husksync/data/DataSnapshot.java new file mode 100644 index 00000000..e1fafb2c --- /dev/null +++ b/common/src/main/java/net/william278/husksync/data/DataSnapshot.java @@ -0,0 +1,819 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.data; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import de.themoep.minedown.adventure.MineDown; +import net.william278.desertwell.util.Version; +import net.william278.husksync.HuskSync; +import net.william278.husksync.adapter.Adaptable; +import net.william278.husksync.adapter.DataAdapter; +import net.william278.husksync.config.Locales; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.time.OffsetDateTime; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * A snapshot of a {@link DataHolder} at a given time. + * + * @since 3.0 + */ +public class DataSnapshot { + + /* + * Current version of the snapshot data format. + * HuskSync v3.0 uses v4; HuskSync v2.0 uses v3. HuskSync v1.0 uses v1 or v2 + */ + protected static final int CURRENT_FORMAT_VERSION = 4; + + @SerializedName("id") + protected UUID id; + + @SerializedName("pinned") + protected boolean pinned; + + @SerializedName("timestamp") + protected OffsetDateTime timestamp; + + @SerializedName("save_cause") + protected SaveCause saveCause; + + @SerializedName("minecraft_version") + protected String minecraftVersion; + + @SerializedName("platform_type") + protected String platformType; + + @SerializedName("format_version") + protected int formatVersion; + + @SerializedName("data") + protected Map data; + + private DataSnapshot(@NotNull UUID id, boolean pinned, @NotNull OffsetDateTime timestamp, + @NotNull SaveCause saveCause, @NotNull Map data, + @NotNull Version minecraftVersion, @NotNull String platformType, int formatVersion) { + this.id = id; + this.pinned = pinned; + this.timestamp = timestamp; + this.saveCause = saveCause; + this.data = data; + this.minecraftVersion = minecraftVersion.toStringWithoutMetadata(); + this.platformType = platformType; + this.formatVersion = formatVersion; + } + + @SuppressWarnings("unused") + private DataSnapshot() { + } + + @NotNull + @ApiStatus.Internal + public static DataSnapshot.Builder builder(@NotNull HuskSync plugin) { + return new Builder(plugin); + } + + @NotNull + @ApiStatus.Internal + public static DataSnapshot.Packed deserialize(@NotNull HuskSync plugin, byte[] data) throws IllegalStateException { + final DataSnapshot.Packed snapshot = plugin.getDataAdapter().fromBytes(data, DataSnapshot.Packed.class); + if (snapshot.getMinecraftVersion().compareTo(plugin.getMinecraftVersion()) > 0) { + throw new IllegalStateException(String.format("Cannot set data for user because the Minecraft version of " + + "their user data (%s) is newer than the server's Minecraft version (%s)." + + "Please ensure each server is running the same version of Minecraft.", + snapshot.getMinecraftVersion(), plugin.getMinecraftVersion())); + } + if (snapshot.getFormatVersion() > CURRENT_FORMAT_VERSION) { + throw new IllegalStateException(String.format("Cannot set data for user because the format version of " + + "their user data (%s) is newer than the current format version (%s). " + + "Please ensure each server is running the latest version of HuskSync.", + snapshot.getFormatVersion(), CURRENT_FORMAT_VERSION)); + } + if (snapshot.getFormatVersion() < CURRENT_FORMAT_VERSION) { + if (plugin.getLegacyConverter().isPresent()) { + return plugin.getLegacyConverter().get().convert(data); + } + throw new IllegalStateException(String.format( + "No legacy converter to convert format version: %s", snapshot.getFormatVersion() + )); + } + if (!snapshot.getPlatformType().equalsIgnoreCase(plugin.getPlatformType())) { + throw new IllegalStateException(String.format("Cannot set data for user because the platform type of " + + "their user data (%s) is different to the server platform type (%s). " + + "Please ensure each server is running the same platform type.", + snapshot.getPlatformType(), plugin.getPlatformType())); + } + return snapshot; + } + + /** + * Return the ID of the snapshot + * + * @return The snapshot ID + * @since 3.0 + */ + @NotNull + public UUID getId() { + return id; + } + + /** + * Get the short display ID of the snapshot + * + * @return The short display ID + * @since 3.0 + */ + @NotNull + public String getShortId() { + return id.toString().substring(0, 8); + } + + /** + * Get whether the snapshot is pinned + * + * @return Whether the snapshot is pinned + * @since 3.0 + */ + public boolean isPinned() { + return pinned; + } + + /** + * Set whether the snapshot is pinned + * + * @param pinned Whether the snapshot is pinned + * @since 3.0 + */ + public void setPinned(boolean pinned) { + this.pinned = pinned; + } + + /** + * Get why the snapshot was created + * + * @return The {@link SaveCause data save cause} of the snapshot + * @since 3.0 + */ + @NotNull + public SaveCause getSaveCause() { + return saveCause; + } + + /** + * Set why the snapshot was created + * + * @param saveCause The {@link SaveCause data save cause} of the snapshot + * @since 3.0 + */ + public void setSaveCause(SaveCause saveCause) { + this.saveCause = saveCause; + } + + /** + * Get when the snapshot was created + * + * @return The {@link OffsetDateTime timestamp} of the snapshot + * @since 3.0 + */ + @NotNull + public OffsetDateTime getTimestamp() { + return timestamp; + } + + /** + * Get the Minecraft version of the server when the Snapshot was created + * + * @return The Minecraft version of the server when the Snapshot was created + * @since 3.0 + */ + @NotNull + public Version getMinecraftVersion() { + return Version.fromString(minecraftVersion); + } + + /** + * Get the platform type of the server when the Snapshot was created + * + * @return The platform type of the server when the Snapshot was created (e.g. {@code "bukkit"}) + * @since 3.0 + */ + @NotNull + public String getPlatformType() { + return platformType; + } + + /** + * Get the format version of the snapshot (indicating the version of HuskSync that created it) + *
    + *
  • 1: HuskSync v1.0+
  • + *
  • 2: HuskSync v1.5+
  • + *
  • 3: HuskSync v2.0+
  • + *
  • 4: HuskSync v3.0+
  • + *
+ * + * @return The format version of the snapshot + * @since 3.0 + */ + public int getFormatVersion() { + return formatVersion; + } + + /** + * A packed {@link DataSnapshot} that has not been deserialized. + * + * @since 3.0 + */ + public static class Packed extends DataSnapshot implements Adaptable { + + protected Packed(@NotNull UUID id, boolean pinned, @NotNull OffsetDateTime timestamp, + @NotNull SaveCause saveCause, @NotNull Map data, + @NotNull Version minecraftVersion, @NotNull String platformType, int formatVersion) { + super(id, pinned, timestamp, saveCause, data, minecraftVersion, platformType, formatVersion); + } + + @SuppressWarnings("unused") + private Packed() { + } + + @ApiStatus.Internal + public void edit(@NotNull HuskSync plugin, @NotNull Consumer editor) { + final Unpacked data = unpack(plugin); + editor.accept(data); + this.pinned = data.isPinned(); + this.saveCause = data.getSaveCause(); + this.data = data.serializeData(plugin); + } + + /** + * Create a copy of this snapshot at the current system timestamp with a new ID + * + * @return The copied snapshot (with a new ID, with a timestamp of the current system time) + */ + @NotNull + public Packed copy() { + return new Packed( + UUID.randomUUID(), pinned, OffsetDateTime.now(), saveCause, data, + getMinecraftVersion(), platformType, formatVersion + ); + } + + @NotNull + @ApiStatus.Internal + public byte[] asBytes(@NotNull HuskSync plugin) throws DataAdapter.AdaptionException { + return plugin.getDataAdapter().toBytes(this); + } + + @NotNull + @ApiStatus.Internal + public String asJson(@NotNull HuskSync plugin) throws DataAdapter.AdaptionException { + return plugin.getDataAdapter().toJson(this); + } + + @ApiStatus.Internal + public int getFileSize(@NotNull HuskSync plugin) { + return asBytes(plugin).length; + } + + @NotNull + public DataSnapshot.Unpacked unpack(@NotNull HuskSync plugin) { + return new Unpacked( + id, pinned, timestamp, saveCause, data, + getMinecraftVersion(), platformType, formatVersion, plugin + ); + } + + } + + /** + * An unpacked {@link DataSnapshot}. + * + * @since 3.0 + */ + public static class Unpacked extends DataSnapshot implements DataHolder { + + @Expose(serialize = false, deserialize = false) + private final Map deserialized; + + private Unpacked(@NotNull UUID id, boolean pinned, @NotNull OffsetDateTime timestamp, + @NotNull SaveCause saveCause, @NotNull Map data, + @NotNull Version minecraftVersion, @NotNull String platformType, int formatVersion, + @NotNull HuskSync plugin) { + super(id, pinned, timestamp, saveCause, data, minecraftVersion, platformType, formatVersion); + this.deserialized = deserializeData(plugin); + } + + private Unpacked(@NotNull UUID id, boolean pinned, @NotNull OffsetDateTime timestamp, + @NotNull SaveCause saveCause, @NotNull Map data, + @NotNull Version minecraftVersion, @NotNull String platformType, int formatVersion) { + super(id, pinned, timestamp, saveCause, Map.of(), minecraftVersion, platformType, formatVersion); + this.deserialized = data; + } + + @NotNull + @ApiStatus.Internal + private Map deserializeData(@NotNull HuskSync plugin) { + return data.entrySet().stream() + .map((entry) -> plugin.getIdentifier(entry.getKey()).map(id -> Map.entry( + id, plugin.getSerializers().get(id).deserialize(entry.getValue()) + )).orElse(null)) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + @NotNull + @ApiStatus.Internal + private Map serializeData(@NotNull HuskSync plugin) { + return deserialized.entrySet().stream() + .map((entry) -> Map.entry(entry.getKey().toString(), + Objects.requireNonNull( + plugin.getSerializers().get(entry.getKey()), + String.format("No serializer found for %s", entry.getKey()) + ).serialize(entry.getValue()))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + /** + * Get the data the snapshot is holding + * + * @return The data map + * @since 3.0 + */ + @NotNull + public Map getData() { + return deserialized; + } + + /** + * Pack the {@link DataSnapshot} into a {@link DataSnapshot.Packed packed} snapshot + * + * @param plugin The HuskSync plugin instance + * @return The packed snapshot + * @since 3.0 + */ + @NotNull + @ApiStatus.Internal + public DataSnapshot.Packed pack(@NotNull HuskSync plugin) { + return new DataSnapshot.Packed( + id, pinned, timestamp, saveCause, serializeData(plugin), + getMinecraftVersion(), platformType, formatVersion + ); + } + + } + + /** + * A builder for {@link DataSnapshot}s. + * + * @since 3.0 + */ + @SuppressWarnings("unused") + public static class Builder { + + private final HuskSync plugin; + private SaveCause saveCause; + private boolean pinned; + private OffsetDateTime timestamp; + private final Map data; + + private Builder(@NotNull HuskSync plugin) { + this.plugin = plugin; + this.pinned = false; + this.data = new HashMap<>(); + this.timestamp = OffsetDateTime.now(); + } + + /** + * Set the cause of the data save + * + * @param saveCause The cause of the data save + * @return The builder + * @apiNote If the {@link SaveCause data save cause} specified is configured to auto-pin, then the value of + * {@link #pinned(boolean)} will be ignored + * @since 3.0 + */ + @NotNull + public Builder saveCause(@NotNull SaveCause saveCause) { + this.saveCause = saveCause; + return this; + } + + /** + * Set whether the data should be pinned + * + * @param pinned Whether the data should be pinned + * @return The builder + * @apiNote If the {@link SaveCause data save cause} specified is configured to auto-pin, this will be ignored + * @since 3.0 + */ + @NotNull + public Builder pinned(boolean pinned) { + this.pinned = pinned; + return this; + } + + /** + * Set the timestamp of the snapshot. + * By default, this is the current server time. + * The timestamp passed to this method cannot be in the future. + *

+ * Note that this will affect the rotation of data snapshots in the database if unpinned, + * as well as the order snapshots appear in the list. + * + * @param timestamp The timestamp + * @return The builder + * @throws IllegalArgumentException if the timestamp is in the future + * @since 3.0 + */ + @NotNull + public Builder timestamp(@NotNull OffsetDateTime timestamp) { + if (timestamp.isAfter(OffsetDateTime.now())) { + throw new IllegalArgumentException("Data snapshots cannot have a timestamp set in the future"); + } + this.timestamp = timestamp; + return this; + } + + /** + * Set the data for a given identifier + * + * @param identifier The identifier + * @param data The data + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder data(@NotNull Identifier identifier, @NotNull Data data) { + this.data.put(identifier, data); + return this; + } + + /** + * Set a map of data to the snapshot + * + * @param data The data + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder data(@NotNull Map data) { + this.data.putAll(data); + return this; + } + + /** + * Set the inventory contents of the snapshot + *

+ * Equivalent to {@code data(Identifier.INVENTORY, inventory)} + *

+ * + * @param inventory The inventory contents + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder inventory(@NotNull Data.Items.Inventory inventory) { + return data(Identifier.INVENTORY, inventory); + } + + /** + * Set the Ender Chest contents of the snapshot + *

+ * Equivalent to {@code data(Identifier.ENDER_CHEST, inventory)} + *

+ * + * @param enderChest The Ender Chest contents + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder enderChest(@NotNull Data.Items.EnderChest enderChest) { + return data(Identifier.ENDER_CHEST, enderChest); + } + + /** + * Set the potion effects of the snapshot + *

+ * Equivalent to {@code data(Identifier.POTION_EFFECTS, potionEffects)} + *

+ * + * @param potionEffects The potion effects + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder potionEffects(@NotNull Data.PotionEffects potionEffects) { + return data(Identifier.POTION_EFFECTS, potionEffects); + } + + /** + * Set the advancements of the snapshot + *

+ * Equivalent to {@code data(Identifier.ADVANCEMENTS, advancements)} + *

+ * + * @param advancements The advancements + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder advancements(@NotNull Data.Advancements advancements) { + return data(Identifier.ADVANCEMENTS, advancements); + } + + /** + * Set the location of the snapshot + *

+ * Equivalent to {@code data(Identifier.LOCATION, location)} + *

+ * + * @param location The location + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder location(@NotNull Data.Location location) { + return data(Identifier.LOCATION, location); + } + + /** + * Set the statistics of the snapshot + *

+ * Equivalent to {@code data(Identifier.STATISTICS, statistics)} + *

+ * + * @param statistics The statistics + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder statistics(@NotNull Data.Statistics statistics) { + return data(Identifier.STATISTICS, statistics); + } + + /** + * Set the health of the snapshot + *

+ * Equivalent to {@code data(Identifier.HEALTH, health)} + *

+ * + * @param health The health + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder health(@NotNull Data.Health health) { + return data(Identifier.HEALTH, health); + } + + /** + * Set the hunger of the snapshot + *

+ * Equivalent to {@code data(Identifier.HUNGER, hunger)} + *

+ * + * @param hunger The hunger + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder hunger(@NotNull Data.Hunger hunger) { + return data(Identifier.HUNGER, hunger); + } + + /** + * Set the experience of the snapshot + *

+ * Equivalent to {@code data(Identifier.EXPERIENCE, experience)} + *

+ * + * @param experience The experience + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder experience(@NotNull Data.Experience experience) { + return data(Identifier.EXPERIENCE, experience); + } + + /** + * Set the game mode of the snapshot + *

+ * Equivalent to {@code data(Identifier.GAME_MODE, gameMode)} + *

+ * + * @param gameMode The game mode + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder gameMode(@NotNull Data.GameMode gameMode) { + return data(Identifier.GAME_MODE, gameMode); + } + + /** + * Set the persistent data container of the snapshot + *

+ * Equivalent to {@code data(Identifier.PERSISTENT_DATA, persistentData)} + *

+ * + * @param persistentData The persistent data container data + * @return The builder + * @since 3.0 + */ + @NotNull + public Builder persistentData(@NotNull Data.PersistentData persistentData) { + return data(Identifier.PERSISTENT_DATA, persistentData); + } + + /** + * Build the {@link DataSnapshot} + * + * @return The {@link DataSnapshot.Unpacked snapshot} + * @throws IllegalStateException If no save cause is specified + * @since 3.0 + */ + @NotNull + public DataSnapshot.Unpacked build() throws IllegalStateException { + if (saveCause == null) { + throw new IllegalStateException("Cannot build DataSnapshot without a save cause"); + } + return new Unpacked( + UUID.randomUUID(), + pinned || plugin.getSettings().doAutoPin(saveCause), + timestamp, + saveCause, + data, + plugin.getMinecraftVersion(), + plugin.getPlatformType(), + DataSnapshot.CURRENT_FORMAT_VERSION + ); + } + + /** + * Build and pack the {@link DataSnapshot} + * + * @return The {@link DataSnapshot.Packed snapshot} + * @throws IllegalStateException If no save cause is specified + * @since 3.0 + */ + @NotNull + public DataSnapshot.Packed buildAndPack() throws IllegalStateException { + return build().pack(plugin); + } + + } + + /** + * Identifies the cause of a player data save. + * + * @implNote This enum is saved in the database. + *

+ * Cause names have a max length of 32 characters. + */ + public enum SaveCause { + + /** + * Indicates data saved when a player disconnected from the server (either to change servers, or to log off) + * + * @since 2.0 + */ + DISCONNECT, + /** + * Indicates data saved when the world saved + * + * @since 2.0 + */ + WORLD_SAVE, + /** + * Indicates data saved when the user died + * + * @since 2.1 + */ + DEATH, + /** + * Indicates data saved when the server shut down + * + * @since 2.0 + */ + SERVER_SHUTDOWN, + /** + * Indicates data was saved by editing inventory contents via the {@code /inventory} command + * + * @since 2.0 + */ + INVENTORY_COMMAND, + /** + * Indicates data was saved by editing Ender Chest contents via the {@code /enderchest} command + * + * @since 2.0 + */ + ENDERCHEST_COMMAND, + /** + * Indicates data was saved by restoring it from a previous version + * + * @since 2.0 + */ + BACKUP_RESTORE, + /** + * Indicates data was saved by an API call + * + * @since 2.0 + */ + API, + /** + * Indicates data was saved from being imported from MySQLPlayerDataBridge + * + * @since 2.0 + */ + MPDB_MIGRATION, + /** + * Indicates data was saved from being imported from a legacy version (v1.x -> v2.x) + * + * @since 2.0 + */ + LEGACY_MIGRATION, + /** + * Indicates data was saved from being imported from a legacy version (v2.x -> v3.x) + * + * @since 3.0 + */ + CONVERTED_FROM_V2; + + @NotNull + public String getDisplayName() { + return Locales.truncate(name().toLowerCase(Locale.ENGLISH) + .replaceAll("_", " "), 18); + } + + } + + /** + * Represents the cause of a player having their data updated. + */ + public enum UpdateCause { + /** + * Indicates the data was updated by a synchronization process + * + * @since 3.0 + */ + SYNCHRONIZED("synchronization_complete", "synchronization_failed"), + /** + * Indicates the data was updated by a user joining the server + * + * @since 3.0 + */ + NEW_USER("user_registration_complete", null), + /** + * Indicates the data was updated by a data update process (management command, API, etc.) + * + * @since 3.0 + */ + UPDATED("data_update_complete", "data_update_failed"); + + private final String completedLocale; + private final String failureLocale; + + UpdateCause(@Nullable String completedLocale, @Nullable String failureLocale) { + this.completedLocale = completedLocale; + this.failureLocale = failureLocale; + } + + public Optional getCompletedLocale(@NotNull HuskSync plugin) { + if (completedLocale != null) { + return plugin.getLocales().getLocale(completedLocale); + } + return Optional.empty(); + } + + public Optional getFailedLocale(@NotNull HuskSync plugin) { + if (failureLocale != null) { + return plugin.getLocales().getLocale(failureLocale); + } + return Optional.empty(); + } + + } +} diff --git a/common/src/main/java/net/william278/husksync/data/Identifier.java b/common/src/main/java/net/william278/husksync/data/Identifier.java new file mode 100644 index 00000000..1279cdd9 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/data/Identifier.java @@ -0,0 +1,177 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.data; + +import net.kyori.adventure.key.InvalidKeyException; +import net.kyori.adventure.key.Key; +import org.intellij.lang.annotations.Subst; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.stream.Stream; + +/** + * Identifiers of different types of {@link Data}s + */ +public class Identifier { + + public static Identifier INVENTORY = huskSync("inventory", true); + public static Identifier ENDER_CHEST = huskSync("ender_chest", true); + public static Identifier POTION_EFFECTS = huskSync("potion_effects", true); + public static Identifier ADVANCEMENTS = huskSync("advancements", true); + public static Identifier LOCATION = huskSync("location", false); + public static Identifier STATISTICS = huskSync("statistics", true); + public static Identifier HEALTH = huskSync("health", true); + public static Identifier HUNGER = huskSync("hunger", true); + public static Identifier EXPERIENCE = huskSync("experience", true); + public static Identifier GAME_MODE = huskSync("game_mode", true); + public static Identifier PERSISTENT_DATA = huskSync("persistent_data", true); + + private final Key key; + private final boolean configDefault; + + private Identifier(@NotNull Key key, boolean configDefault) { + this.key = key; + this.configDefault = configDefault; + } + + /** + * Create an identifier from a {@link Key} + * + * @param key the key + * @return the identifier + * @since 3.0 + */ + @NotNull + public static Identifier from(@NotNull Key key) { + if (key.namespace().equals("husksync")) { + throw new IllegalArgumentException("You cannot register a key with \"husksync\" as the namespace!"); + } + return new Identifier(key, true); + } + + /** + * Create an identifier from a namespace and value + * + * @param plugin the namespace + * @param name the value + * @return the identifier + * @since 3.0 + */ + @NotNull + public static Identifier from(@Subst("plugin") @NotNull String plugin, @Subst("null") @NotNull String name) { + return from(Key.key(plugin, name)); + } + + @NotNull + private static Identifier huskSync(@Subst("null") @NotNull String name, + boolean configDefault) throws InvalidKeyException { + return new Identifier(Key.key("husksync", name), configDefault); + } + + @NotNull + @SuppressWarnings("unused") + private static Identifier parse(@NotNull String key) throws InvalidKeyException { + return huskSync(key, true); + } + + public boolean isEnabledByDefault() { + return configDefault; + } + + @NotNull + private Map.Entry getConfigEntry() { + return Map.entry(getKeyValue(), configDefault); + } + + /** + * (Internal use only) - Get a map of the default config entries for all HuskSync identifiers + * + * @return a map of all the config entries + * @since 3.0 + */ + @NotNull + @ApiStatus.Internal + @SuppressWarnings("unchecked") + public static Map getConfigMap() { + return Map.ofEntries(Stream.of( + INVENTORY, ENDER_CHEST, POTION_EFFECTS, ADVANCEMENTS, LOCATION, + STATISTICS, HEALTH, HUNGER, EXPERIENCE, GAME_MODE, PERSISTENT_DATA + ) + .map(Identifier::getConfigEntry) + .toArray(Map.Entry[]::new)); + } + + /** + * Get the namespace of the identifier + * + * @return the namespace + */ + @NotNull + public String getKeyNamespace() { + return key.namespace(); + } + + /** + * Get the value of the identifier + * + * @return the value + */ + @NotNull + public String getKeyValue() { + return key.value(); + } + + /** + * Returns {@code true} if the identifier is a custom (non-HuskSync) identifier + * + * @return {@code false} if {@link #getKeyNamespace()} returns "husksync"; {@code true} otherwise + */ + public boolean isCustom() { + return !getKeyNamespace().equals("husksync"); + } + + /** + * Returns the identifier as a string (the key) + * + * @return the identifier as a string + */ + @NotNull + @Override + public String toString() { + return key.asString(); + } + + /** + * Returns {@code true} if the given object is an identifier with the same key as this identifier + * + * @param obj the object to compare + * @return {@code true} if the given object is an identifier with the same key as this identifier + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof Identifier other) { + return key.equals(other.key); + } + return false; + } + +} diff --git a/common/src/main/java/net/william278/husksync/data/ItemData.java b/common/src/main/java/net/william278/husksync/data/ItemData.java deleted file mode 100644 index 86dc014f..00000000 --- a/common/src/main/java/net/william278/husksync/data/ItemData.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import com.google.gson.annotations.SerializedName; -import org.jetbrains.annotations.NotNull; - -/** - * Stores information about the contents of a player's inventory or Ender Chest. - */ -public class ItemData { - - /** - * A Base-64 string of platform-serialized items - */ - @SerializedName("serialized_items") - public String serializedItems; - - /** - * Get an empty item data object, representing an empty inventory or Ender Chest - * - * @return an empty item data object - */ - @NotNull - public static ItemData empty() { - return new ItemData(""); - } - - public ItemData(@NotNull final String serializedItems) { - this.serializedItems = serializedItems; - } - - @SuppressWarnings("unused") - protected ItemData() { - } - - /** - * Check if the item data is empty - * - * @return {@code true} if the item data is empty; {@code false} otherwise - */ - public boolean isEmpty() { - return serializedItems.isEmpty(); - } - -} diff --git a/common/src/main/java/net/william278/husksync/data/JsonDataAdapter.java b/common/src/main/java/net/william278/husksync/data/JsonDataAdapter.java deleted file mode 100644 index 2162ca5e..00000000 --- a/common/src/main/java/net/william278/husksync/data/JsonDataAdapter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSyntaxException; -import org.jetbrains.annotations.NotNull; - -import java.nio.charset.StandardCharsets; - -public class JsonDataAdapter implements DataAdapter { - - @Override - public byte[] toBytes(@NotNull UserData data) throws DataAdaptionException { - return toJson(data, false).getBytes(StandardCharsets.UTF_8); - } - - @Override - public @NotNull String toJson(@NotNull UserData data, boolean pretty) throws DataAdaptionException { - return (pretty ? new GsonBuilder().setPrettyPrinting() : new GsonBuilder()).create().toJson(data); - } - - @Override - public @NotNull UserData fromBytes(byte[] data) throws DataAdaptionException { - try { - return new GsonBuilder().create().fromJson(new String(data, StandardCharsets.UTF_8), UserData.class); - } catch (JsonSyntaxException e) { - throw new DataAdaptionException("Failed to parse JSON data", e); - } - } -} diff --git a/common/src/main/java/net/william278/husksync/data/LocationData.java b/common/src/main/java/net/william278/husksync/data/LocationData.java deleted file mode 100644 index 0d263acd..00000000 --- a/common/src/main/java/net/william278/husksync/data/LocationData.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import com.google.gson.annotations.SerializedName; -import org.jetbrains.annotations.NotNull; - -import java.util.UUID; - -/** - * Stores information about a player's location - */ -public class LocationData { - - /** - * Name of the world on the server - */ - @SerializedName("world_name") - public String worldName; - /** - * Unique id of the world - */ - @SerializedName("world_uuid") - public UUID worldUuid; - /** - * The environment type of the world (one of "NORMAL", "NETHER", "THE_END") - */ - @SerializedName("world_environment") - public String worldEnvironment; - - /** - * The x coordinate of the location - */ - @SerializedName("x") - public double x; - /** - * The y coordinate of the location - */ - @SerializedName("y") - public double y; - /** - * The z coordinate of the location - */ - @SerializedName("z") - public double z; - - /** - * The location's facing yaw angle - */ - @SerializedName("yaw") - public float yaw; - /** - * The location's facing pitch angle - */ - @SerializedName("pitch") - public float pitch; - - public LocationData(@NotNull String worldName, @NotNull UUID worldUuid, - @NotNull String worldEnvironment, - double x, double y, double z, - float yaw, float pitch) { - this.worldName = worldName; - this.worldUuid = worldUuid; - this.worldEnvironment = worldEnvironment; - this.x = x; - this.y = y; - this.z = z; - this.yaw = yaw; - this.pitch = pitch; - } - - @SuppressWarnings("unused") - protected LocationData() { - } -} diff --git a/common/src/main/java/net/william278/husksync/data/PersistentDataContainerData.java b/common/src/main/java/net/william278/husksync/data/PersistentDataContainerData.java deleted file mode 100644 index 44c5784e..00000000 --- a/common/src/main/java/net/william278/husksync/data/PersistentDataContainerData.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import com.google.gson.annotations.SerializedName; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -/** - * Store's a user's persistent data container, holding a map of plugin-set persistent values - */ -public class PersistentDataContainerData { - - /** - * Map of namespaced key strings to a byte array representing the persistent data - */ - @SerializedName("persistent_data_map") - protected Map> persistentDataMap; - - public PersistentDataContainerData(@NotNull Map> persistentDataMap) { - this.persistentDataMap = persistentDataMap; - } - - @SuppressWarnings("unused") - protected PersistentDataContainerData() { - } - - public Optional getTagValue(@NotNull String tagName, @NotNull Class tagClass) { - if (!persistentDataMap.containsKey(tagName)) { - return Optional.empty(); - } - - // If the tag cannot be cast to the specified class, return an empty optional - final boolean canCast = tagClass.isAssignableFrom(persistentDataMap.get(tagName).value.getClass()); - if (!canCast) { - return Optional.empty(); - } - - return Optional.of(tagClass.cast(persistentDataMap.get(tagName).value)); - } - - public Optional getTagType(@NotNull String tagType) { - if (persistentDataMap.containsKey(tagType)) { - return PersistentDataTagType.getDataType(persistentDataMap.get(tagType).type); - } - return Optional.empty(); - } - - public Set getTags() { - return persistentDataMap.keySet(); - } - -} diff --git a/common/src/main/java/net/william278/husksync/data/PersistentDataTag.java b/common/src/main/java/net/william278/husksync/data/PersistentDataTag.java deleted file mode 100644 index 9601d6c6..00000000 --- a/common/src/main/java/net/william278/husksync/data/PersistentDataTag.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import org.jetbrains.annotations.NotNull; - -import java.util.Optional; - -/** - * Represents a persistent data tag set by a plugin. - */ -public class PersistentDataTag { - - /** - * The enumerated primitive data type name value of the tag - */ - protected String type; - - /** - * The value of the tag - */ - public T value; - - public PersistentDataTag(@NotNull PersistentDataTagType type, @NotNull T value) { - this.type = type.name(); - this.value = value; - } - - @SuppressWarnings("unused") - private PersistentDataTag() { - } - - public Optional getType() { - return PersistentDataTagType.getDataType(type); - } - -} diff --git a/common/src/main/java/net/william278/husksync/data/PersistentDataTagType.java b/common/src/main/java/net/william278/husksync/data/Serializer.java similarity index 57% rename from common/src/main/java/net/william278/husksync/data/PersistentDataTagType.java rename to common/src/main/java/net/william278/husksync/data/Serializer.java index 56300dd6..2da2b14e 100644 --- a/common/src/main/java/net/william278/husksync/data/PersistentDataTagType.java +++ b/common/src/main/java/net/william278/husksync/data/Serializer.java @@ -21,34 +21,24 @@ package net.william278.husksync.data; import org.jetbrains.annotations.NotNull; -import java.util.Optional; +public interface Serializer { -/** - * Represents the type of a {@link PersistentDataTag} - */ -public enum PersistentDataTagType { - - BYTE, - SHORT, - INTEGER, - LONG, - FLOAT, - DOUBLE, - STRING, - BYTE_ARRAY, - INTEGER_ARRAY, - LONG_ARRAY, - TAG_CONTAINER_ARRAY, - TAG_CONTAINER; - - - public static Optional getDataType(@NotNull String typeName) { - for (PersistentDataTagType type : values()) { - if (type.name().equalsIgnoreCase(typeName)) { - return Optional.of(type); - } + T deserialize(@NotNull String serialized) throws DeserializationException; + + @NotNull + String serialize(@NotNull T element) throws SerializationException; + + static final class DeserializationException extends IllegalStateException { + DeserializationException(@NotNull String message, @NotNull Throwable cause) { + super(message, cause); } - return Optional.empty(); } + static final class SerializationException extends IllegalStateException { + SerializationException(@NotNull String message, @NotNull Throwable cause) { + super(message, cause); + } + } + + } diff --git a/common/src/main/java/net/william278/husksync/data/StatisticsData.java b/common/src/main/java/net/william278/husksync/data/StatisticsData.java deleted file mode 100644 index 1486b0ab..00000000 --- a/common/src/main/java/net/william278/husksync/data/StatisticsData.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import com.google.gson.annotations.SerializedName; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -/** - * Stores information about a player's statistics - */ -public class StatisticsData { - - /** - * Map of generic statistic names to their values - */ - @SerializedName("untyped_statistics") - public Map untypedStatistics; - - /** - * Map of block type statistics to a map of material types to values - */ - @SerializedName("block_statistics") - public Map> blockStatistics; - - /** - * Map of item type statistics to a map of material types to values - */ - @SerializedName("item_statistics") - public Map> itemStatistics; - - /** - * Map of entity type statistics to a map of entity types to values - */ - @SerializedName("entity_statistics") - public Map> entityStatistics; - - public StatisticsData(@NotNull Map untypedStatistics, - @NotNull Map> blockStatistics, - @NotNull Map> itemStatistics, - @NotNull Map> entityStatistics) { - this.untypedStatistics = untypedStatistics; - this.blockStatistics = blockStatistics; - this.itemStatistics = itemStatistics; - this.entityStatistics = entityStatistics; - } - - @SuppressWarnings("unused") - protected StatisticsData() { - } - -} diff --git a/common/src/main/java/net/william278/husksync/data/StatusData.java b/common/src/main/java/net/william278/husksync/data/StatusData.java deleted file mode 100644 index b5e193be..00000000 --- a/common/src/main/java/net/william278/husksync/data/StatusData.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import com.google.gson.annotations.SerializedName; - -/** - * Stores status information about a player - */ -public class StatusData { - - /** - * The player's health points - */ - @SerializedName("health") - public double health; - - /** - * The player's maximum health points - */ - @SerializedName("max_health") - public double maxHealth; - - /** - * The player's health scaling factor - */ - @SerializedName("health_scale") - public double healthScale; - - /** - * The player's hunger points - */ - @SerializedName("hunger") - public int hunger; - - /** - * The player's saturation points - */ - @SerializedName("saturation") - public float saturation; - - /** - * The player's saturation exhaustion points - */ - @SerializedName("saturation_exhaustion") - public float saturationExhaustion; - - /** - * The player's currently selected item slot - */ - @SerializedName("selected_item_slot") - public int selectedItemSlot; - - /** - * The player's total experience points

- * (not to be confused with experience level - this is the "points" value shown on the death screen) - */ - @SerializedName("total_experience") - public int totalExperience; - - /** - * The player's experience level (shown on the exp bar) - */ - @SerializedName("experience_level") - public int expLevel; - - /** - * The player's progress to their next experience level - */ - @SerializedName("experience_progress") - public float expProgress; - - /** - * The player's game mode string (one of "SURVIVAL", "CREATIVE", "ADVENTURE", "SPECTATOR") - */ - @SerializedName("game_mode") - public String gameMode; - - /** - * If the player is currently flying - */ - @SerializedName("is_flying") - public boolean isFlying; - - public StatusData(final double health, final double maxHealth, final double healthScale, - final int hunger, final float saturation, final float saturationExhaustion, - final int selectedItemSlot, final int totalExperience, final int expLevel, - final float expProgress, final String gameMode, final boolean isFlying) { - this.health = health; - this.maxHealth = maxHealth; - this.healthScale = healthScale; - this.hunger = hunger; - this.saturation = saturation; - this.saturationExhaustion = saturationExhaustion; - this.selectedItemSlot = selectedItemSlot; - this.totalExperience = totalExperience; - this.expLevel = expLevel; - this.expProgress = expProgress; - this.gameMode = gameMode; - this.isFlying = isFlying; - } - - @SuppressWarnings("unused") - protected StatusData() { - } -} diff --git a/common/src/main/java/net/william278/husksync/data/StatusDataFlag.java b/common/src/main/java/net/william278/husksync/data/StatusDataFlag.java deleted file mode 100644 index 249b9fe1..00000000 --- a/common/src/main/java/net/william278/husksync/data/StatusDataFlag.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import net.william278.husksync.config.Settings; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.List; - -/** - * Flags for setting {@link StatusData}, indicating which elements should be synced - * - * @deprecated Use the more direct {@link Settings#getSynchronizationFeature(Settings.SynchronizationFeature)} instead - */ -@Deprecated(since = "2.1") -public enum StatusDataFlag { - - SET_HEALTH(Settings.SynchronizationFeature.HEALTH), - SET_MAX_HEALTH(Settings.SynchronizationFeature.MAX_HEALTH), - SET_HUNGER(Settings.SynchronizationFeature.HUNGER), - SET_EXPERIENCE(Settings.SynchronizationFeature.EXPERIENCE), - SET_GAME_MODE(Settings.SynchronizationFeature.GAME_MODE), - SET_FLYING(Settings.SynchronizationFeature.LOCATION), - SET_SELECTED_ITEM_SLOT(Settings.SynchronizationFeature.INVENTORIES); - - private final Settings.SynchronizationFeature feature; - - StatusDataFlag(@NotNull Settings.SynchronizationFeature feature) { - this.feature = feature; - } - - /** - * Returns all status data flags - * - * @return all status data flags as a list - * @deprecated Use {@link Settings#getSynchronizationFeature(Settings.SynchronizationFeature)} instead - */ - @NotNull - @Deprecated(since = "2.1") - @SuppressWarnings("unused") - public static List getAll() { - return Arrays.stream(StatusDataFlag.values()).toList(); - } - - /** - * Returns all status data flags that are enabled for setting as per the {@link Settings} - * - * @param settings the settings to use for determining which flags are enabled - * @return all status data flags that are enabled for setting - * @deprecated Use {@link Settings#getSynchronizationFeature(Settings.SynchronizationFeature)} instead - */ - @NotNull - @Deprecated(since = "2.1") - public static List getFromSettings(@NotNull Settings settings) { - return Arrays.stream(StatusDataFlag.values()).filter( - flag -> settings.getSynchronizationFeature(flag.feature)).toList(); - } - -} diff --git a/common/src/main/java/net/william278/husksync/data/UserData.java b/common/src/main/java/net/william278/husksync/data/UserData.java deleted file mode 100644 index ada18f4c..00000000 --- a/common/src/main/java/net/william278/husksync/data/UserData.java +++ /dev/null @@ -1,376 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import com.google.gson.annotations.SerializedName; -import net.william278.desertwell.util.Version; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Optional; - -/** - * Stores data about a user - */ -public class UserData { - - /** - * Indicates the version of the {@link UserData} format being used. - *

- * This value is to be incremented whenever the format changes. - */ - public static final int CURRENT_FORMAT_VERSION = 3; - - /** - * Stores the user's status data, including health, food, etc. - */ - @SerializedName("status") - @Nullable - protected StatusData statusData; - - /** - * Stores the user's inventory contents - */ - @SerializedName("inventory") - @Nullable - protected ItemData inventoryData; - - /** - * Stores the user's ender chest contents - */ - @SerializedName("ender_chest") - @Nullable - protected ItemData enderChestData; - - /** - * Store's the user's potion effects - */ - @SerializedName("potion_effects") - @Nullable - protected PotionEffectData potionEffectData; - - /** - * Stores the set of this user's advancements - */ - @SerializedName("advancements") - @Nullable - protected List advancementData; - - /** - * Stores the user's set of statistics - */ - @SerializedName("statistics") - @Nullable - protected StatisticsData statisticData; - - /** - * Store's the user's world location and coordinates - */ - @SerializedName("location") - @Nullable - protected LocationData locationData; - - /** - * Stores the user's serialized persistent data container, which contains metadata keys applied by other plugins - */ - @SerializedName("persistent_data_container") - @Nullable - protected PersistentDataContainerData persistentDataContainerData; - - /** - * Stores the version of Minecraft this data was generated in - */ - @SerializedName("minecraft_version") - @NotNull - protected String minecraftVersion; - - /** - * Stores the version of the data format being used - */ - @SerializedName("format_version") - protected int formatVersion = CURRENT_FORMAT_VERSION; - - /** - * Create a new {@link UserData} object with the provided data - * - * @param statusData the user's status data ({@link StatusData}) - * @param inventoryData the user's inventory data ({@link ItemData}) - * @param enderChestData the user's ender chest data ({@link ItemData}) - * @param potionEffectData the user's potion effect data ({@link PotionEffectData}) - * @param advancementData the user's advancement data ({@link AdvancementData}) - * @param statisticData the user's statistic data ({@link StatisticsData}) - * @param locationData the user's location data ({@link LocationData}) - * @param persistentDataContainerData the user's persistent data container data ({@link PersistentDataContainerData}) - * @param minecraftVersion the version of Minecraft this data was generated in (e.g. {@code "1.19.2"}) - * @deprecated see {@link #builder(String)} or {@link #builder(Version)} to create a {@link UserDataBuilder}, which - * you can use to {@link UserDataBuilder#build()} a {@link UserData} instance with - */ - @Deprecated(since = "2.1") - public UserData(@Nullable StatusData statusData, @Nullable ItemData inventoryData, - @Nullable ItemData enderChestData, @Nullable PotionEffectData potionEffectData, - @Nullable List advancementData, @Nullable StatisticsData statisticData, - @Nullable LocationData locationData, @Nullable PersistentDataContainerData persistentDataContainerData, - @NotNull String minecraftVersion) { - this.statusData = statusData; - this.inventoryData = inventoryData; - this.enderChestData = enderChestData; - this.potionEffectData = potionEffectData; - this.advancementData = advancementData; - this.statisticData = statisticData; - this.locationData = locationData; - this.persistentDataContainerData = persistentDataContainerData; - this.minecraftVersion = minecraftVersion; - } - - // Empty constructor to facilitate json serialization - @SuppressWarnings("unused") - protected UserData() { - } - - /** - * Gets the {@link StatusData} from this user data - * - * @return the {@link StatusData} of this user data - * @since 2.0 - * @deprecated Use {@link #getStatus()}, which returns an optional instead - */ - @Nullable - @Deprecated(since = "2.1") - public StatusData getStatusData() { - return statusData; - } - - /** - * Gets the {@link StatusData} from this user data - * - * @return an optional containing the {@link StatusData} if it is present in this user data - * @since 2.1 - */ - public Optional getStatus() { - return Optional.ofNullable(statusData); - } - - /** - * Gets the {@link ItemData} representing the player's inventory from this user data - * - * @return the inventory {@link ItemData} of this user data - * @since 2.0 - * @deprecated Use {@link #getInventory()}, which returns an optional instead - */ - @Nullable - @Deprecated(since = "2.1") - public ItemData getInventoryData() { - return inventoryData; - } - - /** - * Gets the {@link ItemData} representing the player's inventory from this user data - * - * @return an optional containing the inventory {@link ItemData} if it is present in this user data - * @since 2.1 - */ - public Optional getInventory() { - return Optional.ofNullable(inventoryData); - } - - /** - * Gets the {@link ItemData} representing the player's ender chest from this user data - * - * @return the ender chest {@link ItemData} of this user data - * @since 2.0 - * @deprecated Use {@link #getEnderChest()}, which returns an optional instead - */ - @Nullable - @Deprecated(since = "2.1") - public ItemData getEnderChestData() { - return enderChestData; - } - - /** - * Gets the {@link ItemData} representing the player's ender chest from this user data - * - * @return an optional containing the ender chest {@link ItemData} if it is present in this user data - * @since 2.1 - */ - public Optional getEnderChest() { - return Optional.ofNullable(enderChestData); - } - - /** - * Gets the {@link PotionEffectData} representing player status effects from this user data - * - * @return the {@link PotionEffectData} of this user data - * @since 2.0 - * @deprecated Use {@link #getPotionEffects()}, which returns an optional instead - */ - @Nullable - @Deprecated(since = "2.1") - public PotionEffectData getPotionEffectsData() { - return potionEffectData; - } - - /** - * Gets the {@link PotionEffectData} representing the player's potion effects from this user data - * - * @return an optional containing {@link PotionEffectData} if it is present in this user data - * @since 2.1 - */ - public Optional getPotionEffects() { - return Optional.ofNullable(potionEffectData); - } - - /** - * Gets the list of {@link AdvancementData} from this user data - * - * @return the {@link AdvancementData} of this user data - * @since 2.0 - * @deprecated Use {@link #getAdvancements()}, which returns an optional instead - */ - @Nullable - @Deprecated(since = "2.1") - public List getAdvancementData() { - return advancementData; - } - - /** - * Gets a list of {@link AdvancementData} representing the player's advancements from this user data - * - * @return an optional containing a {@link List} of {@link AdvancementData} if it is present in this user data - * @since 2.1 - */ - public Optional> getAdvancements() { - return Optional.ofNullable(advancementData); - } - - /** - * Gets the {@link StatisticsData} representing player statistics from this user data - * - * @return the {@link StatisticsData} of this user data - * @since 2.0 - * @deprecated Use {@link #getStatistics()}, which returns an optional instead - */ - @Nullable - @Deprecated(since = "2.1") - public StatisticsData getStatisticsData() { - return statisticData; - } - - /** - * Gets {@link StatisticsData} representing player statistics from this user data - * - * @return an optional containing player {@link StatisticsData} if it is present in this user data - * @since 2.1 - */ - public Optional getStatistics() { - return Optional.ofNullable(statisticData); - } - - /** - * Gets the {@link LocationData} representing the player location from this user data - * - * @return the inventory {@link LocationData} of this user data - * @since 2.0 - * @deprecated Use {@link #getLocation()}, which returns an optional instead - */ - @Nullable - @Deprecated(since = "2.1") - public LocationData getLocationData() { - return locationData; - } - - /** - * Gets {@link LocationData} representing the player location from this user data - * - * @return an optional containing player {@link LocationData} if it is present in this user data - * @since 2.1 - */ - public Optional getLocation() { - return Optional.ofNullable(locationData); - } - - /** - * Gets the {@link PersistentDataContainerData} from this user data - * - * @return the {@link PersistentDataContainerData} of this user data - * @since 2.0 - * @deprecated Use {@link #getPersistentDataContainer()}, which returns an optional instead - */ - @Nullable - @Deprecated(since = "2.1") - public PersistentDataContainerData getPersistentDataContainerData() { - return persistentDataContainerData; - } - - /** - * Gets {@link PersistentDataContainerData} from this user data - * - * @return an optional containing the player's {@link PersistentDataContainerData} if it is present in this user data - * @since 2.1 - */ - public Optional getPersistentDataContainer() { - return Optional.ofNullable(persistentDataContainerData); - } - - /** - * Get the version of Minecraft this data was generated in - * - * @return the version of Minecraft this data was generated in - */ - @NotNull - public String getMinecraftVersion() { - return minecraftVersion; - } - - /** - * Gets the version of the data format being used - * - * @return the version of the data format being used - */ - public int getFormatVersion() { - return formatVersion; - } - - /** - * Get a new {@link UserDataBuilder} for creating {@link UserData} - * - * @param minecraftVersion the version of Minecraft this data was generated in (e.g. {@code "1.19.2"}) - * @return a UserData {@link UserDataBuilder} instance - * @since 2.1 - */ - @NotNull - public static UserDataBuilder builder(@NotNull String minecraftVersion) { - return new UserDataBuilder(minecraftVersion); - } - - /** - * Get a new {@link UserDataBuilder} for creating {@link UserData} - * - * @param minecraftVersion a {@link Version} object, representing the Minecraft version this data was generated in - * @return a UserData {@link UserDataBuilder} instance - * @since 2.1 - */ - @NotNull - public static UserDataBuilder builder(@NotNull Version minecraftVersion) { - return builder(minecraftVersion.toStringWithoutMetadata()); - } - - -} diff --git a/common/src/main/java/net/william278/husksync/data/UserDataBuilder.java b/common/src/main/java/net/william278/husksync/data/UserDataBuilder.java deleted file mode 100644 index 6a1e998a..00000000 --- a/common/src/main/java/net/william278/husksync/data/UserDataBuilder.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * A builder utility for creating {@link UserData} instances - * - * @since 2.1 - */ -@SuppressWarnings("UnusedReturnValue") -public class UserDataBuilder { - - @NotNull - private final UserData userData; - - protected UserDataBuilder(@NotNull String minecraftVersion) { - this.userData = new UserData(); - this.userData.minecraftVersion = minecraftVersion; - } - - /** - * Set the {@link StatusData} to this {@link UserData} - * - * @param status the {@link StatusData} to set - * @return this {@link UserDataBuilder} - * @since 2.1 - */ - @NotNull - public UserDataBuilder setStatus(@NotNull StatusData status) { - this.userData.statusData = status; - return this; - } - - /** - * Set the inventory {@link ItemData} to this {@link UserData} - * - * @param inventoryData the inventory {@link ItemData} to set - * @return this {@link UserDataBuilder} - * @since 2.1 - */ - @NotNull - public UserDataBuilder setInventory(@Nullable ItemData inventoryData) { - this.userData.inventoryData = inventoryData; - return this; - } - - /** - * Set the ender chest {@link ItemData} to this {@link UserData} - * - * @param enderChestData the ender chest {@link ItemData} to set - * @return this {@link UserDataBuilder} - * @since 2.1 - */ - @NotNull - public UserDataBuilder setEnderChest(@Nullable ItemData enderChestData) { - this.userData.enderChestData = enderChestData; - return this; - } - - /** - * Set the {@link List} of {@link ItemData} to this {@link UserData} - * - * @param potionEffectData the {@link List} of {@link ItemData} to set - * @return this {@link UserDataBuilder} - * @since 2.1 - */ - @NotNull - public UserDataBuilder setPotionEffects(@Nullable PotionEffectData potionEffectData) { - this.userData.potionEffectData = potionEffectData; - return this; - } - - /** - * Set the {@link List} of {@link ItemData} to this {@link UserData} - * - * @param advancementData the {@link List} of {@link ItemData} to set - * @return this {@link UserDataBuilder} - * @since 2.1 - */ - @NotNull - public UserDataBuilder setAdvancements(@Nullable List advancementData) { - this.userData.advancementData = advancementData; - return this; - } - - /** - * Set the {@link StatisticsData} to this {@link UserData} - * - * @param statisticData the {@link StatisticsData} to set - * @return this {@link UserDataBuilder} - * @since 2.1 - */ - @NotNull - public UserDataBuilder setStatistics(@Nullable StatisticsData statisticData) { - this.userData.statisticData = statisticData; - return this; - } - - - /** - * Set the {@link LocationData} to this {@link UserData} - * - * @param locationData the {@link LocationData} to set - * @return this {@link UserDataBuilder} - * @since 2.1 - */ - @NotNull - public UserDataBuilder setLocation(@Nullable LocationData locationData) { - this.userData.locationData = locationData; - return this; - } - - /** - * Set the {@link PersistentDataContainerData} to this {@link UserData} - * - * @param persistentDataContainerData the {@link PersistentDataContainerData} to set - * @return this {@link UserDataBuilder} - * @since 2.1 - */ - @NotNull - public UserDataBuilder setPersistentDataContainer(@Nullable PersistentDataContainerData persistentDataContainerData) { - this.userData.persistentDataContainerData = persistentDataContainerData; - return this; - } - - /** - * Build and get the {@link UserData} instance - * - * @return the {@link UserData} instance - * @since 2.1 - */ - @NotNull - public UserData build() { - return this.userData; - } - -} diff --git a/common/src/main/java/net/william278/husksync/data/UserDataHolder.java b/common/src/main/java/net/william278/husksync/data/UserDataHolder.java new file mode 100644 index 00000000..e1a00d0f --- /dev/null +++ b/common/src/main/java/net/william278/husksync/data/UserDataHolder.java @@ -0,0 +1,167 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.data; + +import net.william278.desertwell.util.ThrowingConsumer; +import net.william278.husksync.HuskSync; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +/** + * A holder of data in the form of {@link Data}s, which can be synced + */ +public interface UserDataHolder extends DataHolder { + + /** + * Get the data that is enabled for syncing in the config + * + * @return the data that is enabled for syncing + * @since 3.0 + */ + @Override + @NotNull + default Map getData() { + return getPlugin().getRegisteredDataTypes().stream() + .filter(type -> type.isCustom() || getPlugin().getSettings().isSyncFeatureEnabled(type)) + .map(id -> Map.entry(id, getData(id))) + .filter(data -> data.getValue().isPresent()) + .collect(HashMap::new, (map, data) -> map.put(data.getKey(), data.getValue().get()), HashMap::putAll); + } + + /** + * Apply the data for the given {@link Identifier} to the holder. + *

+ * This will be performed synchronously on the main server thread; it will not happen instantly. + * + * @param identifier the {@link Identifier} to set the data for + * @param data the {@link Data} to set + * @since 3.0 + */ + @Override + default void setData(@NotNull Identifier identifier, @NotNull Data data) { + getPlugin().runSync(() -> data.apply(this, getPlugin())); + } + + /** + * Create a serialized data snapshot of this data owner + * + * @param saveCause the cause of the snapshot + * @return the snapshot + * @since 3.0 + */ + @NotNull + default DataSnapshot.Packed createSnapshot(@NotNull DataSnapshot.SaveCause saveCause) { + return DataSnapshot.builder(getPlugin()).data(this.getData()).saveCause(saveCause).buildAndPack(); + } + + /** + * Deserialize and apply a data snapshot to this data owner + *

+ * This method will deserialize the data on the current thread, then synchronously apply it on + * the main server thread. + *

+ * The {@code runAfter} callback function will be run after the snapshot has been applied. + * + * @param snapshot the snapshot to apply + * @param runAfter the function to run asynchronously after the snapshot has been applied + * @since 3.0 + */ + default void applySnapshot(@NotNull DataSnapshot.Packed snapshot, @NotNull ThrowingConsumer runAfter) { + final HuskSync plugin = getPlugin(); + final DataSnapshot.Unpacked unpacked = snapshot.unpack(plugin); + plugin.runSync(() -> { + unpacked.getData().forEach((type, data) -> { + if (plugin.getSettings().isSyncFeatureEnabled(type)) { + if (type.isCustom()) { + getCustomDataStore().put(type, data); + } + data.apply(this, plugin); + } + }); + plugin.runAsync(() -> runAfter.accept(this)); + }); + } + + @Override + default void setInventory(@NotNull Data.Items.Inventory inventory) { + this.setData(Identifier.INVENTORY, inventory); + } + + @Override + default void setEnderChest(@NotNull Data.Items.EnderChest enderChest) { + this.setData(Identifier.ENDER_CHEST, enderChest); + } + + @Override + default void setPotionEffects(@NotNull Data.PotionEffects potionEffects) { + this.setData(Identifier.POTION_EFFECTS, potionEffects); + } + + @Override + default void setAdvancements(@NotNull Data.Advancements advancements) { + this.setData(Identifier.ADVANCEMENTS, advancements); + } + + @Override + default void setLocation(@NotNull Data.Location location) { + this.setData(Identifier.LOCATION, location); + } + + @Override + default void setStatistics(@NotNull Data.Statistics statistics) { + this.setData(Identifier.STATISTICS, statistics); + } + + @Override + default void setHealth(@NotNull Data.Health health) { + this.setData(Identifier.HEALTH, health); + } + + @Override + default void setHunger(@NotNull Data.Hunger hunger) { + this.setData(Identifier.HUNGER, hunger); + } + + @Override + default void setExperience(@NotNull Data.Experience experience) { + this.setData(Identifier.EXPERIENCE, experience); + } + + @Override + default void setGameMode(@NotNull Data.GameMode gameMode) { + this.setData(Identifier.GAME_MODE, gameMode); + } + + @Override + default void setPersistentData(@NotNull Data.PersistentData persistentData) { + this.setData(Identifier.PERSISTENT_DATA, persistentData); + } + + @NotNull + Map getCustomDataStore(); + + @NotNull + @ApiStatus.Internal + HuskSync getPlugin(); + +} diff --git a/common/src/main/java/net/william278/husksync/data/UserDataSnapshot.java b/common/src/main/java/net/william278/husksync/data/UserDataSnapshot.java deleted file mode 100644 index c7d088f9..00000000 --- a/common/src/main/java/net/william278/husksync/data/UserDataSnapshot.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import net.william278.husksync.command.Permission; -import net.william278.husksync.config.Locales; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; -import org.jetbrains.annotations.NotNull; - -import java.text.SimpleDateFormat; -import java.util.*; - -/** - * Represents a uniquely versioned and timestamped snapshot of a user's data, including why it was saved. - * - * @param versionUUID The unique identifier for this user data version - * @param versionTimestamp An epoch milliseconds timestamp of when this data was created - * @param userData The {@link UserData} that has been versioned - * @param cause The {@link DataSaveCause} that caused this data to be saved - */ -public record UserDataSnapshot(@NotNull UUID versionUUID, @NotNull Date versionTimestamp, - @NotNull DataSaveCause cause, boolean pinned, - @NotNull UserData userData) implements Comparable { - - /** - * Version {@link UserData} into a {@link UserDataSnapshot}, assigning it a random {@link UUID} and the current timestamp {@link Date} - *

- * Note that this method will set {@code cause} to {@link DataSaveCause#API} - * - * @param userData The {@link UserData} to version - * @return A new {@link UserDataSnapshot} - * @implNote This isn't used to version data that is going to be set to a database to prevent UUID collisions.

- * Database implementations should instead use their own UUID generation functions. - */ - public static UserDataSnapshot create(@NotNull UserData userData) { - return new UserDataSnapshot(UUID.randomUUID(), new Date(), - DataSaveCause.API, false, userData); - } - - /** - * Display a menu in chat to an {@link OnlineUser} about this {@link UserDataSnapshot} for a {@link User dataOwner} - * - * @param user The {@link OnlineUser} to display the menu to - * @param dataOwner The {@link User} whose data this snapshot captures a state of - * @param locales The {@link Locales} to use for displaying the menu - */ - public void displayDataOverview(@NotNull OnlineUser user, @NotNull User dataOwner, @NotNull Locales locales) { - // Title message, timestamp, owner and cause. - locales.getLocale("data_manager_title", versionUUID().toString().split("-")[0], - versionUUID().toString(), dataOwner.username, dataOwner.uuid.toString()) - .ifPresent(user::sendMessage); - locales.getLocale("data_manager_timestamp", - new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss").format(versionTimestamp())) - .ifPresent(user::sendMessage); - if (pinned()) { - locales.getLocale("data_manager_pinned").ifPresent(user::sendMessage); - } - locales.getLocale("data_manager_cause", cause().name().toLowerCase(Locale.ENGLISH).replaceAll("_", " ")) - .ifPresent(user::sendMessage); - - // User status data, if present in the snapshot - userData().getStatus() - .flatMap(statusData -> locales.getLocale("data_manager_status", - Integer.toString((int) statusData.health), - Integer.toString((int) statusData.maxHealth), - Integer.toString(statusData.hunger), - Integer.toString(statusData.expLevel), - statusData.gameMode.toLowerCase(Locale.ENGLISH))) - .ifPresent(user::sendMessage); - - // Advancement and statistic data, if both are present in the snapshot - userData().getAdvancements() - .flatMap(advancementData -> userData().getStatistics() - .flatMap(statisticsData -> locales.getLocale("data_manager_advancements_statistics", - Integer.toString(advancementData.size()), - generateAdvancementPreview(advancementData, locales), - String.format("%.2f", (((statisticsData.untypedStatistics.getOrDefault( - "PLAY_ONE_MINUTE", 0)) / 20d) / 60d) / 60d)))) - .ifPresent(user::sendMessage); - - if (user.hasPermission(Permission.COMMAND_INVENTORY.node) - && user.hasPermission(Permission.COMMAND_ENDER_CHEST.node)) { - locales.getLocale("data_manager_item_buttons", dataOwner.username, versionUUID().toString()) - .ifPresent(user::sendMessage); - } - if (user.hasPermission(Permission.COMMAND_USER_DATA_MANAGE.node)) { - locales.getLocale("data_manager_management_buttons", dataOwner.username, versionUUID().toString()) - .ifPresent(user::sendMessage); - } - if (user.hasPermission(Permission.COMMAND_USER_DATA_DUMP.node)) { - locales.getLocale("data_manager_system_buttons", dataOwner.username, versionUUID().toString()) - .ifPresent(user::sendMessage); - } - } - - @NotNull - private String generateAdvancementPreview(@NotNull List advancementData, @NotNull Locales locales) { - final StringJoiner joiner = new StringJoiner("\n"); - final List advancementsToPreview = advancementData.stream().filter(dataItem -> - !dataItem.key.startsWith("minecraft:recipes/")).toList(); - final int PREVIEW_SIZE = 8; - for (int i = 0; i < advancementsToPreview.size(); i++) { - joiner.add(advancementsToPreview.get(i).key); - if (i >= PREVIEW_SIZE) { - break; - } - } - final int remainingAdvancements = advancementsToPreview.size() - PREVIEW_SIZE; - if (remainingAdvancements > 0) { - joiner.add(locales.getRawLocale("data_manager_advancements_preview_remaining", - Integer.toString(remainingAdvancements)).orElse("+" + remainingAdvancements + "…")); - } - return joiner.toString(); - } - - /** - * Compare UserData by creation timestamp - * - * @param other the other UserData to be compared - * @return the comparison result; the more recent UserData is greater than the less recent UserData - */ - @Override - public int compareTo(@NotNull UserDataSnapshot other) { - return Long.compare(this.versionTimestamp.getTime(), other.versionTimestamp.getTime()); - } - -} diff --git a/common/src/main/java/net/william278/husksync/database/Database.java b/common/src/main/java/net/william278/husksync/database/Database.java index c6cd47d4..b6dc6995 100644 --- a/common/src/main/java/net/william278/husksync/database/Database.java +++ b/common/src/main/java/net/william278/husksync/database/Database.java @@ -21,20 +21,20 @@ package net.william278.husksync.database; import net.william278.husksync.HuskSync; import net.william278.husksync.config.Settings; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.data.UserDataSnapshot; -import net.william278.husksync.migrator.Migrator; -import net.william278.husksync.player.User; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.data.DataSnapshot.SaveCause; +import net.william278.husksync.data.UserDataHolder; +import net.william278.husksync.user.User; +import org.jetbrains.annotations.Blocking; import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.UUID; -import java.util.concurrent.CompletableFuture; /** * An abstract representation of the plugin database, storing player data. @@ -57,17 +57,19 @@ public abstract class Database { * @throws IOException if the resource could not be read */ @SuppressWarnings("SameParameterValue") + @NotNull protected final String[] getSchemaStatements(@NotNull String schemaFileName) throws IOException { return formatStatementTables(new String(Objects.requireNonNull(plugin.getResource(schemaFileName)) .readAllBytes(), StandardCharsets.UTF_8)).split(";"); } /** - * Format all table name placeholder strings in a SQL statement + * Format all table name placeholder strings in an SQL statement * - * @param sql the SQL statement with un-formatted table name placeholders + * @param sql the SQL statement with unformatted table name placeholders * @return the formatted statement, with table placeholders replaced with the correct names */ + @NotNull protected final String formatStatementTables(@NotNull String sql) { return sql.replaceAll("%users_table%", plugin.getSettings().getTableName(Settings.TableName.USERS)) .replaceAll("%user_data_table%", plugin.getSettings().getTableName(Settings.TableName.USER_DATA)); @@ -75,57 +77,67 @@ public abstract class Database { /** * Initialize the database and ensure tables are present; create tables if they do not exist. + * + * @throws IllegalStateException if the database could not be initialized */ - public abstract void initialize(); + @Blocking + public abstract void initialize() throws IllegalStateException; /** * Ensure a {@link User} has an entry in the database and that their username is up-to-date * * @param user The {@link User} to ensure - * @return A future returning void when complete */ - public abstract CompletableFuture ensureUser(@NotNull User user); + @Blocking + public abstract void ensureUser(@NotNull User user); /** * Get a player by their Minecraft account {@link UUID} * * @param uuid Minecraft account {@link UUID} of the {@link User} to get - * @return A future returning an optional with the {@link User} present if they exist + * @return An optional with the {@link User} present if they exist */ - public abstract CompletableFuture> getUser(@NotNull UUID uuid); + @Blocking + public abstract Optional getUser(@NotNull UUID uuid); /** * Get a user by their username (case-insensitive) * * @param username Username of the {@link User} to get (case-insensitive) - * @return A future returning an optional with the {@link User} present if they exist + * @return An optional with the {@link User} present if they exist */ - public abstract CompletableFuture> getUserByName(@NotNull String username); + @Blocking + public abstract Optional getUserByName(@NotNull String username); + /** - * Get the current uniquely versioned user data for a given user, if it exists. + * Get the latest data snapshot for a user. * - * @param user the user to get data for - * @return an optional containing the {@link UserDataSnapshot}, if it exists, or an empty optional if it does not + * @param user The user to get data for + * @return an optional containing the {@link DataSnapshot}, if it exists, or an empty optional if it does not */ - public abstract CompletableFuture> getCurrentUserData(@NotNull User user); + @Blocking + public abstract Optional getLatestSnapshot(@NotNull User user); /** - * Get all {@link UserDataSnapshot} entries for a user from the database. + * Get all {@link DataSnapshot} entries for a user from the database. * * @param user The user to get data for - * @return A future returning a list of a user's {@link UserDataSnapshot} entries + * @return The list of a user's {@link DataSnapshot} entries */ - public abstract CompletableFuture> getUserData(@NotNull User user); + @Blocking + @NotNull + public abstract List getAllSnapshots(@NotNull User user); /** - * Gets a specific {@link UserDataSnapshot} entry for a user from the database, by its UUID. + * Gets a specific {@link DataSnapshot} entry for a user from the database, by its UUID. * * @param user The user to get data for - * @param versionUuid The UUID of the {@link UserDataSnapshot} entry to get - * @return A future returning an optional containing the {@link UserDataSnapshot}, if it exists, or an empty optional if it does not + * @param versionUuid The UUID of the {@link DataSnapshot} entry to get + * @return An optional containing the {@link DataSnapshot}, if it exists */ - public abstract CompletableFuture> getUserData(@NotNull User user, @NotNull UUID versionUuid); + @Blocking + public abstract Optional getSnapshot(@NotNull User user, @NotNull UUID versionUuid); /** * (Internal) Prune user data for a given user to the maximum value as configured. @@ -133,61 +145,131 @@ public abstract class Database { * @param user The user to prune data for * @implNote Data snapshots marked as {@code pinned} are exempt from rotation */ - protected abstract void rotateUserData(@NotNull User user); + @Blocking + protected abstract void rotateSnapshots(@NotNull User user); /** - * Deletes a specific {@link UserDataSnapshot} entry for a user from the database, by its UUID. + * Deletes a specific {@link DataSnapshot} entry for a user from the database, by its UUID. * * @param user The user to get data for - * @param versionUuid The UUID of the {@link UserDataSnapshot} entry to delete - * @return A future returning void when complete + * @param versionUuid The UUID of the {@link DataSnapshot} entry to delete */ - public abstract CompletableFuture deleteUserData(@NotNull User user, @NotNull UUID versionUuid); + @Blocking + public abstract boolean deleteSnapshot(@NotNull User user, @NotNull UUID versionUuid); /** - * Save user data to the database

+ * Save user data to the database + *

* This will remove the oldest data for the user if the amount of data exceeds the limit as configured * * @param user The user to add data for - * @param userData The {@link UserData} to set. The implementation should version it with a random UUID and the current timestamp during insertion. - * @return A future returning void when complete - * @see UserDataSnapshot#create(UserData) + * @param snapshot The {@link DataSnapshot} to set. + * The implementation should version it with a random UUID and the current timestamp during insertion. + * @see UserDataHolder#createSnapshot(SaveCause) */ - public abstract CompletableFuture setUserData(@NotNull User user, @NotNull UserData userData, @NotNull DataSaveCause dataSaveCause); + @Blocking + public void addSnapshot(@NotNull User user, @NotNull DataSnapshot.Packed snapshot) { + if (snapshot.getSaveCause() != SaveCause.SERVER_SHUTDOWN) { + plugin.fireEvent( + plugin.getDataSaveEvent(user, snapshot), + (event) -> this.addAndRotateSnapshot(user, snapshot) + ); + return; + } + + this.addAndRotateSnapshot(user, snapshot); + } /** - * Pin a saved {@link UserDataSnapshot} by given version UUID, setting it's {@code pinned} state to {@code true}. + * Internal - Save user data to the database. This will: + *
    + *
  1. Delete their most recent snapshot, if it was created before the backup frequency time
  2. + *
  3. Create the snapshot
  4. + *
  5. Rotate snapshot backups
  6. + *
* - * @param user The user to pin the data for - * @param versionUuid The UUID of the user's {@link UserDataSnapshot} entry to pin - * @return A future returning a boolean; {@code true} if the operation completed successfully, {@code false} if it failed - * @see UserDataSnapshot#pinned() + * @param user The user to add data for + * @param snapshot The {@link DataSnapshot} to set. + */ + @Blocking + private void addAndRotateSnapshot(@NotNull User user, @NotNull DataSnapshot.Packed snapshot) { + final int backupFrequency = plugin.getSettings().getBackupFrequency(); + if (!snapshot.isPinned() && backupFrequency > 0) { + this.rotateLatestSnapshot(user, snapshot.getTimestamp().minusHours(backupFrequency)); + } + this.createSnapshot(user, snapshot); + this.rotateSnapshots(user); + } + + /** + * Deletes the most recent data snapshot by the given {@link User user} + * The snapshot must have been created after {@link OffsetDateTime time} and NOT be pinned + * Facilities the backup frequency feature, reducing redundant snapshots from being saved longer than needed + * + * @param user The user to delete a snapshot for + * @param within The time to delete a snapshot after */ - public abstract CompletableFuture pinUserData(@NotNull User user, @NotNull UUID versionUuid); + @Blocking + protected abstract void rotateLatestSnapshot(@NotNull User user, @NotNull OffsetDateTime within); /** - * Unpin a saved {@link UserDataSnapshot} by given version UUID, setting it's {@code pinned} state to {@code false}. + * Internal - Create user data in the database + * + * @param user The user to add data for + * @param data The {@link DataSnapshot} to set. + */ + @Blocking + protected abstract void createSnapshot(@NotNull User user, @NotNull DataSnapshot.Packed data); + + /** + * Update a saved {@link DataSnapshot} by given version UUID + * + * @param user The user whose data snapshot + * @param snapshot The {@link DataSnapshot} to update + */ + @Blocking + public abstract void updateSnapshot(@NotNull User user, @NotNull DataSnapshot.Packed snapshot); + + /** + * Unpin a saved {@link DataSnapshot} by given version UUID, setting it's {@code pinned} state to {@code false}. * * @param user The user to unpin the data for - * @param versionUuid The UUID of the user's {@link UserDataSnapshot} entry to unpin - * @return A future returning a boolean; {@code true} if the operation completed successfully, {@code false} if it failed - * @see UserDataSnapshot#pinned() + * @param versionUuid The UUID of the user's {@link DataSnapshot} entry to unpin + * @see DataSnapshot#isPinned() */ - public abstract CompletableFuture unpinUserData(@NotNull User user, @NotNull UUID versionUuid); + @Blocking + public final void unpinSnapshot(@NotNull User user, @NotNull UUID versionUuid) { + this.getSnapshot(user, versionUuid).ifPresent(data -> { + data.edit(plugin, (snapshot) -> snapshot.setPinned(false)); + this.updateSnapshot(user, data); + }); + } /** - * Wipes all {@link UserData} entries from the database. - * This should never be used, except when preparing tables for migration. + * Pin a saved {@link DataSnapshot} by given version UUID, setting it's {@code pinned} state to {@code true}. * - * @return A future returning void when complete - * @see Migrator#start() + * @param user The user to pin the data for + * @param versionUuid The UUID of the user's {@link DataSnapshot} entry to pin + */ + @Blocking + public final void pinSnapshot(@NotNull User user, @NotNull UUID versionUuid) { + this.getSnapshot(user, versionUuid).ifPresent(data -> { + data.edit(plugin, (snapshot) -> snapshot.setPinned(true)); + this.updateSnapshot(user, data); + }); + } + + /** + * Wipes all {@link User} entries from the database. + * This should only be used when preparing tables for a data migration. */ - public abstract CompletableFuture wipeDatabase(); + @Blocking + public abstract void wipeDatabase(); /** * Close the database connection */ - public abstract void close(); + public abstract void terminate(); /** * Identifies types of databases diff --git a/common/src/main/java/net/william278/husksync/database/MySqlDatabase.java b/common/src/main/java/net/william278/husksync/database/MySqlDatabase.java index 987ba7fc..412756b8 100644 --- a/common/src/main/java/net/william278/husksync/database/MySqlDatabase.java +++ b/common/src/main/java/net/william278/husksync/database/MySqlDatabase.java @@ -21,20 +21,17 @@ package net.william278.husksync.database; import com.zaxxer.hikari.HikariDataSource; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.DataAdaptionException; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.data.UserDataSnapshot; -import net.william278.husksync.event.DataSaveEvent; -import net.william278.husksync.player.User; +import net.william278.husksync.adapter.DataAdapter; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.User; +import org.jetbrains.annotations.Blocking; import org.jetbrains.annotations.NotNull; import java.io.ByteArrayInputStream; import java.io.IOException; import java.sql.*; -import java.util.Date; +import java.time.OffsetDateTime; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.logging.Level; public class MySqlDatabase extends Database { @@ -46,8 +43,7 @@ public class MySqlDatabase extends Database { public MySqlDatabase(@NotNull HuskSync plugin) { super(plugin); - this.flavor = plugin.getSettings().getDatabaseType() == Type.MARIADB - ? "mariadb" : "mysql"; + this.flavor = plugin.getSettings().getDatabaseType().getProtocol(); this.driverClass = plugin.getSettings().getDatabaseType() == Type.MARIADB ? "org.mariadb.jdbc.Driver" : "com.mysql.cj.jdbc.Driver"; } @@ -58,10 +54,16 @@ public class MySqlDatabase extends Database { * @return The {@link Connection} to the MySQL database * @throws SQLException if the connection fails for some reason */ + @Blocking + @NotNull private Connection getConnection() throws SQLException { + if (dataSource == null) { + throw new IllegalStateException("The database has not been initialized"); + } return dataSource.getConnection(); } + @Blocking @Override public void initialize() throws IllegalStateException { // Initialize the Hikari pooled connection @@ -124,192 +126,175 @@ public class MySqlDatabase extends Database { } } + @Blocking @Override - public CompletableFuture ensureUser(@NotNull User user) { - return getUser(user.uuid).thenAccept(optionalUser -> - optionalUser.ifPresentOrElse(existingUser -> { - if (!existingUser.username.equals(user.username)) { - // Update a user's name if it has changed in the database - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - UPDATE `%users_table%` - SET `username`=? - WHERE `uuid`=?"""))) { + public void ensureUser(@NotNull User user) { + getUser(user.getUuid()).ifPresentOrElse( + existingUser -> { + if (!existingUser.getUsername().equals(user.getUsername())) { + // Update a user's name if it has changed in the database + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + UPDATE `%users_table%` + SET `username`=? + WHERE `uuid`=?"""))) { - statement.setString(1, user.username); - statement.setString(2, existingUser.uuid.toString()); - statement.executeUpdate(); - } - plugin.log(Level.INFO, "Updated " + user.username + "'s name in the database (" + existingUser.username + " -> " + user.username + ")"); - } catch (SQLException e) { - plugin.log(Level.SEVERE, "Failed to update a user's name on the database", e); - } + statement.setString(1, user.getUsername()); + statement.setString(2, existingUser.getUuid().toString()); + statement.executeUpdate(); } - }, - () -> { - // Insert new player data into the database - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - INSERT INTO `%users_table%` (`uuid`,`username`) - VALUES (?,?);"""))) { + plugin.log(Level.INFO, "Updated " + user.getUsername() + "'s name in the database (" + existingUser.getUsername() + " -> " + user.getUsername() + ")"); + } catch (SQLException e) { + plugin.log(Level.SEVERE, "Failed to update a user's name on the database", e); + } + } + }, + () -> { + // Insert new player data into the database + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + INSERT INTO `%users_table%` (`uuid`,`username`) + VALUES (?,?);"""))) { - statement.setString(1, user.uuid.toString()); - statement.setString(2, user.username); - statement.executeUpdate(); - } - } catch (SQLException e) { - plugin.log(Level.SEVERE, "Failed to insert a user into the database", e); - } - })); + statement.setString(1, user.getUuid().toString()); + statement.setString(2, user.getUsername()); + statement.executeUpdate(); + } + } catch (SQLException e) { + plugin.log(Level.SEVERE, "Failed to insert a user into the database", e); + } + } + ); } + @Blocking @Override - public CompletableFuture> getUser(@NotNull UUID uuid) { - return CompletableFuture.supplyAsync(() -> { - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - SELECT `uuid`, `username` - FROM `%users_table%` - WHERE `uuid`=?"""))) { + public Optional getUser(@NotNull UUID uuid) { + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + SELECT `uuid`, `username` + FROM `%users_table%` + WHERE `uuid`=?"""))) { - statement.setString(1, uuid.toString()); + statement.setString(1, uuid.toString()); - final ResultSet resultSet = statement.executeQuery(); - if (resultSet.next()) { - return Optional.of(new User(UUID.fromString(resultSet.getString("uuid")), - resultSet.getString("username"))); - } + final ResultSet resultSet = statement.executeQuery(); + if (resultSet.next()) { + return Optional.of(new User(UUID.fromString(resultSet.getString("uuid")), + resultSet.getString("username"))); } - } catch (SQLException e) { - plugin.log(Level.SEVERE, "Failed to fetch a user from uuid from the database", e); } - return Optional.empty(); - }); + } catch (SQLException e) { + plugin.log(Level.SEVERE, "Failed to fetch a user from uuid from the database", e); + } + return Optional.empty(); } + @Blocking @Override - public CompletableFuture> getUserByName(@NotNull String username) { - return CompletableFuture.supplyAsync(() -> { - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - SELECT `uuid`, `username` - FROM `%users_table%` - WHERE `username`=?"""))) { - statement.setString(1, username); + public Optional getUserByName(@NotNull String username) { + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + SELECT `uuid`, `username` + FROM `%users_table%` + WHERE `username`=?"""))) { + statement.setString(1, username); - final ResultSet resultSet = statement.executeQuery(); - if (resultSet.next()) { - return Optional.of(new User(UUID.fromString(resultSet.getString("uuid")), - resultSet.getString("username"))); - } + final ResultSet resultSet = statement.executeQuery(); + if (resultSet.next()) { + return Optional.of(new User(UUID.fromString(resultSet.getString("uuid")), + resultSet.getString("username"))); } - } catch (SQLException e) { - plugin.log(Level.SEVERE, "Failed to fetch a user by name from the database", e); } - return Optional.empty(); - }); + } catch (SQLException e) { + plugin.log(Level.SEVERE, "Failed to fetch a user by name from the database", e); + } + return Optional.empty(); } + @Blocking @Override - public CompletableFuture> getCurrentUserData(@NotNull User user) { - return CompletableFuture.supplyAsync(() -> { - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - SELECT `version_uuid`, `timestamp`, `save_cause`, `pinned`, `data` - FROM `%user_data_table%` - WHERE `player_uuid`=? - ORDER BY `timestamp` DESC - LIMIT 1;"""))) { - statement.setString(1, user.uuid.toString()); - final ResultSet resultSet = statement.executeQuery(); - if (resultSet.next()) { - final Blob blob = resultSet.getBlob("data"); - final byte[] dataByteArray = blob.getBytes(1, (int) blob.length()); - blob.free(); - return Optional.of(new UserDataSnapshot( - UUID.fromString(resultSet.getString("version_uuid")), - Date.from(resultSet.getTimestamp("timestamp").toInstant()), - DataSaveCause.getCauseByName(resultSet.getString("save_cause")), - resultSet.getBoolean("pinned"), - plugin.getDataAdapter().fromBytes(dataByteArray))); - } + public Optional getLatestSnapshot(@NotNull User user) { + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + SELECT `version_uuid`, `timestamp`, `save_cause`, `pinned`, `data` + FROM `%user_data_table%` + WHERE `player_uuid`=? + ORDER BY `timestamp` DESC + LIMIT 1;"""))) { + statement.setString(1, user.getUuid().toString()); + final ResultSet resultSet = statement.executeQuery(); + if (resultSet.next()) { + final Blob blob = resultSet.getBlob("data"); + final byte[] dataByteArray = blob.getBytes(1, (int) blob.length()); + blob.free(); + return Optional.of(DataSnapshot.deserialize(plugin, dataByteArray)); } - } catch (SQLException | DataAdaptionException e) { - plugin.log(Level.SEVERE, "Failed to fetch a user's current user data from the database", e); } - return Optional.empty(); - }); + } catch (SQLException | DataAdapter.AdaptionException e) { + plugin.log(Level.SEVERE, "Failed to fetch a user's current user data from the database", e); + } + return Optional.empty(); } + @Blocking @Override - public CompletableFuture> getUserData(@NotNull User user) { - return CompletableFuture.supplyAsync(() -> { - final List retrievedData = new ArrayList<>(); - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - SELECT `version_uuid`, `timestamp`, `save_cause`, `pinned`, `data` - FROM `%user_data_table%` - WHERE `player_uuid`=? - ORDER BY `timestamp` DESC;"""))) { - statement.setString(1, user.uuid.toString()); - final ResultSet resultSet = statement.executeQuery(); - while (resultSet.next()) { - final Blob blob = resultSet.getBlob("data"); - final byte[] dataByteArray = blob.getBytes(1, (int) blob.length()); - blob.free(); - final UserDataSnapshot data = new UserDataSnapshot( - UUID.fromString(resultSet.getString("version_uuid")), - Date.from(resultSet.getTimestamp("timestamp").toInstant()), - DataSaveCause.getCauseByName(resultSet.getString("save_cause")), - resultSet.getBoolean("pinned"), - plugin.getDataAdapter().fromBytes(dataByteArray)); - retrievedData.add(data); - } - return retrievedData; + @NotNull + public List getAllSnapshots(@NotNull User user) { + final List retrievedData = new ArrayList<>(); + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + SELECT `version_uuid`, `timestamp`, `save_cause`, `pinned`, `data` + FROM `%user_data_table%` + WHERE `player_uuid`=? + ORDER BY `timestamp` DESC;"""))) { + statement.setString(1, user.getUuid().toString()); + final ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + final Blob blob = resultSet.getBlob("data"); + final byte[] dataByteArray = blob.getBytes(1, (int) blob.length()); + blob.free(); + retrievedData.add(DataSnapshot.deserialize(plugin, dataByteArray)); } - } catch (SQLException | DataAdaptionException e) { - plugin.log(Level.SEVERE, "Failed to fetch a user's current user data from the database", e); + return retrievedData; } - return retrievedData; - }); + } catch (SQLException | DataAdapter.AdaptionException e) { + plugin.log(Level.SEVERE, "Failed to fetch a user's current user data from the database", e); + } + return retrievedData; } + @Blocking @Override - public CompletableFuture> getUserData(@NotNull User user, @NotNull UUID versionUuid) { - return CompletableFuture.supplyAsync(() -> { - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - SELECT `version_uuid`, `timestamp`, `save_cause`, `pinned`, `data` - FROM `%user_data_table%` - WHERE `player_uuid`=? AND `version_uuid`=? - ORDER BY `timestamp` DESC - LIMIT 1;"""))) { - statement.setString(1, user.uuid.toString()); - statement.setString(2, versionUuid.toString()); - final ResultSet resultSet = statement.executeQuery(); - if (resultSet.next()) { - final Blob blob = resultSet.getBlob("data"); - final byte[] dataByteArray = blob.getBytes(1, (int) blob.length()); - blob.free(); - return Optional.of(new UserDataSnapshot( - UUID.fromString(resultSet.getString("version_uuid")), - Date.from(resultSet.getTimestamp("timestamp").toInstant()), - DataSaveCause.getCauseByName(resultSet.getString("save_cause")), - resultSet.getBoolean("pinned"), - plugin.getDataAdapter().fromBytes(dataByteArray))); - } + public Optional getSnapshot(@NotNull User user, @NotNull UUID versionUuid) { + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + SELECT `version_uuid`, `timestamp`, `save_cause`, `pinned`, `data` + FROM `%user_data_table%` + WHERE `player_uuid`=? AND `version_uuid`=? + ORDER BY `timestamp` DESC + LIMIT 1;"""))) { + statement.setString(1, user.getUuid().toString()); + statement.setString(2, versionUuid.toString()); + final ResultSet resultSet = statement.executeQuery(); + if (resultSet.next()) { + final Blob blob = resultSet.getBlob("data"); + final byte[] dataByteArray = blob.getBytes(1, (int) blob.length()); + blob.free(); + return Optional.of(DataSnapshot.deserialize(plugin, dataByteArray)); } - } catch (SQLException | DataAdaptionException e) { - plugin.log(Level.SEVERE, "Failed to fetch specific user data by UUID from the database", e); } - return Optional.empty(); - }); + } catch (SQLException | DataAdapter.AdaptionException e) { + plugin.log(Level.SEVERE, "Failed to fetch specific user data by UUID from the database", e); + } + return Optional.empty(); } + @Blocking @Override - protected void rotateUserData(@NotNull User user) { - final List unpinnedUserData = getUserData(user).join().stream() - .filter(dataSnapshot -> !dataSnapshot.pinned()).toList(); + protected void rotateSnapshots(@NotNull User user) { + final List unpinnedUserData = getAllSnapshots(user).stream() + .filter(dataSnapshot -> !dataSnapshot.isPinned()).toList(); if (unpinnedUserData.size() > plugin.getSettings().getMaxUserDataSnapshots()) { try (Connection connection = getConnection()) { try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" @@ -319,7 +304,7 @@ public class MySqlDatabase extends Database { ORDER BY `timestamp` ASC LIMIT %entry_count%;""".replace("%entry_count%", Integer.toString(unpinnedUserData.size() - plugin.getSettings().getMaxUserDataSnapshots()))))) { - statement.setString(1, user.uuid.toString()); + statement.setString(1, user.getUuid().toString()); statement.executeUpdate(); } } catch (SQLException e) { @@ -328,105 +313,97 @@ public class MySqlDatabase extends Database { } } + @Blocking @Override - public CompletableFuture deleteUserData(@NotNull User user, @NotNull UUID versionUuid) { - return CompletableFuture.supplyAsync(() -> { - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - DELETE FROM `%user_data_table%` - WHERE `player_uuid`=? AND `version_uuid`=? - LIMIT 1;"""))) { - statement.setString(1, user.uuid.toString()); - statement.setString(2, versionUuid.toString()); - return statement.executeUpdate() > 0; - } - } catch (SQLException e) { - plugin.log(Level.SEVERE, "Failed to delete specific user data from the database", e); + public boolean deleteSnapshot(@NotNull User user, @NotNull UUID versionUuid) { + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + DELETE FROM `%user_data_table%` + WHERE `player_uuid`=? AND `version_uuid`=? + LIMIT 1;"""))) { + statement.setString(1, user.getUuid().toString()); + statement.setString(2, versionUuid.toString()); + return statement.executeUpdate() > 0; } - return false; - }); + } catch (SQLException e) { + plugin.log(Level.SEVERE, "Failed to delete specific user data from the database", e); + } + return false; } + @Blocking @Override - public CompletableFuture setUserData(@NotNull User user, @NotNull UserData userData, - @NotNull DataSaveCause saveCause) { - return CompletableFuture.runAsync(() -> { - final DataSaveEvent dataSaveEvent = (DataSaveEvent) plugin.getEventCannon().fireDataSaveEvent(user, - userData, saveCause).join(); - if (!dataSaveEvent.isCancelled()) { - final UserData finalData = dataSaveEvent.getUserData(); - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - INSERT INTO `%user_data_table%` - (`player_uuid`,`version_uuid`,`timestamp`,`save_cause`,`data`) - VALUES (?,UUID(),NOW(),?,?);"""))) { - statement.setString(1, user.uuid.toString()); - statement.setString(2, saveCause.name()); - statement.setBlob(3, new ByteArrayInputStream( - plugin.getDataAdapter().toBytes(finalData))); - statement.executeUpdate(); - } - } catch (SQLException | DataAdaptionException e) { - plugin.log(Level.SEVERE, "Failed to set user data in the database", e); - } + protected void rotateLatestSnapshot(@NotNull User user, @NotNull OffsetDateTime within) { + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + DELETE FROM `%user_data_table%` + WHERE `player_uuid`=? AND `timestamp`>? AND `pinned` IS FALSE + ORDER BY `timestamp` ASC + LIMIT 1;"""))) { + statement.setString(1, user.getUuid().toString()); + statement.setTimestamp(2, Timestamp.from(within.toInstant())); + statement.executeUpdate(); } - this.rotateUserData(user); - }); + } catch (SQLException e) { + plugin.log(Level.SEVERE, "Failed to delete a user's data from the database", e); + } } + @Blocking @Override - public CompletableFuture pinUserData(@NotNull User user, @NotNull UUID versionUuid) { - return CompletableFuture.runAsync(() -> { - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - UPDATE `%user_data_table%` - SET `pinned`=TRUE - WHERE `player_uuid`=? AND `version_uuid`=? - LIMIT 1;"""))) { - statement.setString(1, user.uuid.toString()); - statement.setString(2, versionUuid.toString()); - statement.executeUpdate(); - } - } catch (SQLException e) { - plugin.log(Level.SEVERE, "Failed to pin user data in the database", e); + protected void createSnapshot(@NotNull User user, @NotNull DataSnapshot.Packed data) { + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + INSERT INTO `%user_data_table%` + (`player_uuid`,`version_uuid`,`timestamp`,`save_cause`,`pinned`,`data`) + VALUES (?,?,?,?,?,?);"""))) { + statement.setString(1, user.getUuid().toString()); + statement.setString(2, data.getId().toString()); + statement.setTimestamp(3, Timestamp.from(data.getTimestamp().toInstant())); + statement.setString(4, data.getSaveCause().name()); + statement.setBoolean(5, data.isPinned()); + statement.setBlob(6, new ByteArrayInputStream(data.asBytes(plugin))); + statement.executeUpdate(); } - }); + } catch (SQLException | DataAdapter.AdaptionException e) { + plugin.log(Level.SEVERE, "Failed to set user data in the database", e); + } } + @Blocking @Override - public CompletableFuture unpinUserData(@NotNull User user, @NotNull UUID versionUuid) { - return CompletableFuture.runAsync(() -> { - try (Connection connection = getConnection()) { - try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" - UPDATE `%user_data_table%` - SET `pinned`=FALSE - WHERE `player_uuid`=? AND `version_uuid`=? - LIMIT 1;"""))) { - statement.setString(1, user.uuid.toString()); - statement.setString(2, versionUuid.toString()); - statement.executeUpdate(); - } - } catch (SQLException e) { - plugin.log(Level.SEVERE, "Failed to unpin user data in the database", e); + public void updateSnapshot(@NotNull User user, @NotNull DataSnapshot.Packed data) { + try (Connection connection = getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(formatStatementTables(""" + UPDATE `%user_data_table%` + SET `save_cause`=?,`pinned`=?,`data`=? + WHERE `player_uuid`=? AND `version_uuid`=? + LIMIT 1;"""))) { + statement.setString(1, data.getSaveCause().name()); + statement.setBoolean(2, data.isPinned()); + statement.setBlob(3, new ByteArrayInputStream(data.asBytes(plugin))); + statement.setString(4, user.getUuid().toString()); + statement.setString(5, data.getId().toString()); + statement.executeUpdate(); } - }); + } catch (SQLException e) { + plugin.log(Level.SEVERE, "Failed to pin user data in the database", e); + } } @Override - public CompletableFuture wipeDatabase() { - return CompletableFuture.runAsync(() -> { - try (Connection connection = getConnection()) { - try (Statement statement = connection.createStatement()) { - statement.executeUpdate(formatStatementTables("DELETE FROM `%user_data_table%`;")); - } - } catch (SQLException e) { - plugin.log(Level.SEVERE, "Failed to wipe the database", e); + public void wipeDatabase() { + try (Connection connection = getConnection()) { + try (Statement statement = connection.createStatement()) { + statement.executeUpdate(formatStatementTables("DELETE FROM `%user_data_table%`;")); } - }); + } catch (SQLException e) { + plugin.log(Level.SEVERE, "Failed to wipe the database", e); + } } @Override - public void close() { + public void terminate() { if (dataSource != null) { if (!dataSource.isClosed()) { dataSource.close(); diff --git a/common/src/main/java/net/william278/husksync/event/CancellableEvent.java b/common/src/main/java/net/william278/husksync/event/Cancellable.java similarity index 89% rename from common/src/main/java/net/william278/husksync/event/CancellableEvent.java rename to common/src/main/java/net/william278/husksync/event/Cancellable.java index 7dc7f79c..ef0becd5 100644 --- a/common/src/main/java/net/william278/husksync/event/CancellableEvent.java +++ b/common/src/main/java/net/william278/husksync/event/Cancellable.java @@ -19,9 +19,9 @@ package net.william278.husksync.event; -public interface CancellableEvent extends Event { +@SuppressWarnings("unused") +public interface Cancellable extends Event { - @SuppressWarnings("BooleanMethodIsAlwaysInverted") default boolean isCancelled() { return false; } diff --git a/common/src/main/java/net/william278/husksync/event/DataSaveEvent.java b/common/src/main/java/net/william278/husksync/event/DataSaveEvent.java index 7e9be813..567131f8 100644 --- a/common/src/main/java/net/william278/husksync/event/DataSaveEvent.java +++ b/common/src/main/java/net/william278/husksync/event/DataSaveEvent.java @@ -19,21 +19,34 @@ package net.william278.husksync.event; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.player.User; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.User; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -public interface DataSaveEvent extends CancellableEvent { +import java.util.function.Consumer; + +@SuppressWarnings("unused") +public interface DataSaveEvent extends Cancellable { + + @NotNull + User getUser(); @NotNull - UserData getUserData(); + DataSnapshot.Packed getData(); - void setUserData(@NotNull UserData userData); + default void editData(@NotNull Consumer editor) { + getData().edit(getPlugin(), editor); + } - @NotNull User getUser(); + @NotNull + default DataSnapshot.SaveCause getSaveCause() { + return getData().getSaveCause(); + } @NotNull - DataSaveCause getSaveCause(); + @ApiStatus.Internal + HuskSync getPlugin(); } diff --git a/common/src/main/java/net/william278/husksync/event/Event.java b/common/src/main/java/net/william278/husksync/event/Event.java index f7ec6eb2..698abea3 100644 --- a/common/src/main/java/net/william278/husksync/event/Event.java +++ b/common/src/main/java/net/william278/husksync/event/Event.java @@ -19,10 +19,6 @@ package net.william278.husksync.event; -import java.util.concurrent.CompletableFuture; - public interface Event { - CompletableFuture fire(); - } diff --git a/common/src/main/java/net/william278/husksync/event/EventCannon.java b/common/src/main/java/net/william278/husksync/event/EventCannon.java deleted file mode 100644 index ac4779d4..00000000 --- a/common/src/main/java/net/william278/husksync/event/EventCannon.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.event; - -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.UserData; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; - -/** - * Used to fire plugin {@link Event}s - */ -public abstract class EventCannon { - - protected EventCannon() { - } - - /** - * Fires a {@link PreSyncEvent} - * - * @param user The user to fire the event for - * @param userData The user data to fire the event with - * @return A future that will be completed when the event is fired - */ - public abstract CompletableFuture firePreSyncEvent(@NotNull OnlineUser user, @NotNull UserData userData); - - /** - * Fires a {@link DataSaveEvent} - * - * @param user The user to fire the event for - * @param userData The user data to fire the event with - * @return A future that will be completed when the event is fired - */ - public abstract CompletableFuture fireDataSaveEvent(@NotNull User user, @NotNull UserData userData, - - @NotNull DataSaveCause saveCause); - - /** - * Fires a {@link SyncCompleteEvent} - * - * @param user The user to fire the event for - */ - public abstract void fireSyncCompleteEvent(@NotNull OnlineUser user); - -} diff --git a/common/src/main/java/net/william278/husksync/event/EventDispatcher.java b/common/src/main/java/net/william278/husksync/event/EventDispatcher.java new file mode 100644 index 00000000..2b6c5f42 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/event/EventDispatcher.java @@ -0,0 +1,72 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.event; + +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.user.User; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * Used to fire plugin {@link Event}s + */ +public interface EventDispatcher { + + /** + * Fire an event synchronously, then run a callback asynchronously. + * + * @param event The event to fire + * @param callback The callback to run after the event has been fired + * @param The material of event to fire + */ + default void fireEvent(@NotNull T event, @Nullable Consumer callback) { + getPlugin().runSync(() -> { + if (!fireIsCancelled(event) && callback != null) { + getPlugin().runAsync(() -> callback.accept(event)); + } + }); + } + + /** + * Fire an event on this thread, and return whether the event was canceled. + * + * @param event The event to fire + * @param The material of event to fire + * @return Whether the event was canceled + */ + boolean fireIsCancelled(@NotNull T event); + + @NotNull + PreSyncEvent getPreSyncEvent(@NotNull OnlineUser user, @NotNull DataSnapshot.Packed userData); + + @NotNull + DataSaveEvent getDataSaveEvent(@NotNull User user, @NotNull DataSnapshot.Packed saveCause); + + @NotNull + SyncCompleteEvent getSyncCompleteEvent(@NotNull OnlineUser user); + + @NotNull + HuskSync getPlugin(); + +} diff --git a/common/src/main/java/net/william278/husksync/event/PlayerEvent.java b/common/src/main/java/net/william278/husksync/event/PlayerEvent.java index c381e479..8146a292 100644 --- a/common/src/main/java/net/william278/husksync/event/PlayerEvent.java +++ b/common/src/main/java/net/william278/husksync/event/PlayerEvent.java @@ -19,10 +19,12 @@ package net.william278.husksync.event; -import net.william278.husksync.player.OnlineUser; +import net.william278.husksync.user.OnlineUser; +import org.jetbrains.annotations.NotNull; public interface PlayerEvent extends Event { + @NotNull OnlineUser getUser(); } diff --git a/common/src/main/java/net/william278/husksync/event/PreSyncEvent.java b/common/src/main/java/net/william278/husksync/event/PreSyncEvent.java index e5e27fc2..c47352d5 100644 --- a/common/src/main/java/net/william278/husksync/event/PreSyncEvent.java +++ b/common/src/main/java/net/william278/husksync/event/PreSyncEvent.java @@ -19,14 +19,30 @@ package net.william278.husksync.event; -import net.william278.husksync.data.UserData; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.DataSnapshot; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -public interface PreSyncEvent extends CancellableEvent { +import java.util.function.Consumer; + +@SuppressWarnings("unused") +public interface PreSyncEvent extends PlayerEvent { @NotNull - UserData getUserData(); + DataSnapshot.Packed getData(); + + default void editData(@NotNull Consumer editor) { + getData().edit(getPlugin(), editor); + } - void setUserData(@NotNull UserData userData); + @NotNull + default DataSnapshot.SaveCause getSaveCause() { + return getData().getSaveCause(); + } + + @NotNull + @ApiStatus.Internal + HuskSync getPlugin(); } diff --git a/common/src/main/java/net/william278/husksync/hook/PlanDataExtension.java b/common/src/main/java/net/william278/husksync/hook/PlanDataExtension.java deleted file mode 100644 index 89b6a7db..00000000 --- a/common/src/main/java/net/william278/husksync/hook/PlanDataExtension.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.hook; - -import com.djrapitops.plan.extension.CallEvents; -import com.djrapitops.plan.extension.DataExtension; -import com.djrapitops.plan.extension.ElementOrder; -import com.djrapitops.plan.extension.FormatType; -import com.djrapitops.plan.extension.annotation.*; -import com.djrapitops.plan.extension.icon.Color; -import com.djrapitops.plan.extension.icon.Family; -import com.djrapitops.plan.extension.icon.Icon; -import com.djrapitops.plan.extension.table.Table; -import com.djrapitops.plan.extension.table.TableColumnFormat; -import net.william278.husksync.HuskSync; -import net.william278.husksync.data.UserDataSnapshot; -import net.william278.husksync.player.User; -import org.jetbrains.annotations.NotNull; - -import java.util.Date; -import java.util.Locale; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.regex.Pattern; - -@TabInfo( - tab = "Current Status", - iconName = "id-card", - iconFamily = Family.SOLID, - elementOrder = {ElementOrder.VALUES, ElementOrder.TABLE, ElementOrder.GRAPH} -) -@TabInfo( - tab = "Data Snapshots", - iconName = "clipboard-list", - iconFamily = Family.SOLID, - elementOrder = {ElementOrder.VALUES, ElementOrder.TABLE, ElementOrder.GRAPH} -) -@TabOrder({"Current Status", "Data Snapshots"}) -@PluginInfo( - name = "HuskSync", - iconName = "exchange-alt", - iconFamily = Family.SOLID, - color = Color.LIGHT_BLUE -) -@SuppressWarnings("unused") -public class PlanDataExtension implements DataExtension { - - private HuskSync plugin; - - private static final String UNKNOWN_STRING = "N/A"; - - private static final String PINNED_HTML_STRING = "📍 "; - - protected PlanDataExtension(@NotNull HuskSync plugin) { - this.plugin = plugin; - } - - protected PlanDataExtension() { - } - - @Override - public CallEvents[] callExtensionMethodsOn() { - return new CallEvents[]{ - CallEvents.PLAYER_JOIN, - CallEvents.PLAYER_LEAVE - }; - } - - private CompletableFuture> getCurrentUserData(@NotNull UUID uuid) { - return CompletableFuture.supplyAsync(() -> { - final Optional optionalUser = plugin.getDatabase().getUser(uuid).join(); - if (optionalUser.isPresent()) { - return plugin.getDatabase().getCurrentUserData(optionalUser.get()).join(); - } - return Optional.empty(); - }); - } - - @BooleanProvider( - text = "Has Synced", - description = "Whether this user has saved, synchronised data.", - iconName = "exchange-alt", - iconFamily = Family.SOLID, - conditionName = "hasSynced", - hidden = true - ) - @Tab("Current Status") - public boolean getUserHasSynced(@NotNull UUID uuid) { - return getCurrentUserData(uuid).join().isPresent(); - } - - @Conditional("hasSynced") - @NumberProvider( - text = "Sync Time", - description = "The last time the user had their data synced with the server.", - iconName = "clock", - iconFamily = Family.SOLID, - format = FormatType.DATE_SECOND, - priority = 6 - ) - @Tab("Current Status") - public long getCurrentDataTimestamp(@NotNull UUID uuid) { - return getCurrentUserData(uuid).join().map( - versionedUserData -> versionedUserData.versionTimestamp().getTime()) - .orElse(new Date().getTime()); - } - - @Conditional("hasSynced") - @StringProvider( - text = "Version ID", - description = "ID of the data version that the user is currently using.", - iconName = "bolt", - iconFamily = Family.SOLID, - priority = 5 - ) - @Tab("Current Status") - public String getCurrentDataId(@NotNull UUID uuid) { - return getCurrentUserData(uuid).join() - .map(versionedUserData -> versionedUserData.versionUUID().toString() - .split(Pattern.quote("-"))[0]) - .orElse(UNKNOWN_STRING); - } - - @Conditional("hasSynced") - @StringProvider( - text = "Health", - description = "The number of health points out of the max health points this player currently has.", - iconName = "heart", - iconFamily = Family.SOLID, - priority = 4 - ) - @Tab("Current Status") - public String getHealth(@NotNull UUID uuid) { - return getCurrentUserData(uuid).join() - .flatMap(versionedUserData -> versionedUserData.userData().getStatus()) - .map(statusData -> (int) statusData.health + "/" + (int) statusData.maxHealth) - .orElse(UNKNOWN_STRING); - } - - @Conditional("hasSynced") - @NumberProvider( - text = "Hunger", - description = "The number of hunger points this player currently has.", - iconName = "drumstick-bite", - iconFamily = Family.SOLID, - priority = 3 - ) - @Tab("Current Status") - public long getHunger(@NotNull UUID uuid) { - return getCurrentUserData(uuid).join() - .flatMap(versionedUserData -> versionedUserData.userData().getStatus()) - .map(statusData -> (long) statusData.hunger) - .orElse(0L); - } - - @Conditional("hasSynced") - @NumberProvider( - text = "Experience Level", - description = "The number of experience levels this player currently has.", - iconName = "hat-wizard", - iconFamily = Family.SOLID, - priority = 2 - ) - @Tab("Current Status") - public long getExperienceLevel(@NotNull UUID uuid) { - return getCurrentUserData(uuid).join() - .flatMap(versionedUserData -> versionedUserData.userData().getStatus()) - .map(statusData -> (long) statusData.expLevel) - .orElse(0L); - } - - @Conditional("hasSynced") - @StringProvider( - text = "Game Mode", - description = "The game mode this player is currently in.", - iconName = "gamepad", - iconFamily = Family.SOLID, - priority = 1 - ) - @Tab("Current Status") - public String getGameMode(@NotNull UUID uuid) { - return getCurrentUserData(uuid).join() - .flatMap(versionedUserData -> versionedUserData.userData().getStatus()) - .map(status -> status.gameMode) - .orElse(UNKNOWN_STRING); - } - - @Conditional("hasSynced") - @NumberProvider( - text = "Advancements", - description = "The number of advancements & recipes the player has progressed in.", - iconName = "award", - iconFamily = Family.SOLID - ) - @Tab("Current Status") - public long getAdvancementsCompleted(@NotNull UUID playerUUID) { - return getCurrentUserData(playerUUID).join() - .flatMap(versionedUserData -> versionedUserData.userData().getAdvancements()) - .map(advancementsData -> (long) advancementsData.size()) - .orElse(0L); - } - - @Conditional("hasSynced") - @TableProvider(tableColor = Color.LIGHT_BLUE) - @Tab("Data Snapshots") - public Table getDataSnapshots(@NotNull UUID playerUUID) { - final Table.Factory dataSnapshotsTable = Table.builder() - .columnOne("Time", new Icon(Family.SOLID, "clock", Color.NONE)) - .columnOneFormat(TableColumnFormat.DATE_SECOND) - .columnTwo("ID", new Icon(Family.SOLID, "bolt", Color.NONE)) - .columnThree("Cause", new Icon(Family.SOLID, "flag", Color.NONE)) - .columnFour("Pinned", new Icon(Family.SOLID, "thumbtack", Color.NONE)); - plugin.getDatabase().getUser(playerUUID).join().ifPresent(user -> - plugin.getDatabase().getUserData(user).join().forEach(versionedUserData -> dataSnapshotsTable.addRow( - versionedUserData.versionTimestamp().getTime(), - versionedUserData.versionUUID().toString().split("-")[0], - versionedUserData.cause().name().toLowerCase(Locale.ENGLISH).replaceAll("_", " "), - versionedUserData.pinned() ? PINNED_HTML_STRING + "Pinned" : "Unpinned" - ))); - return dataSnapshotsTable.build(); - } -} diff --git a/common/src/main/java/net/william278/husksync/hook/PlanHook.java b/common/src/main/java/net/william278/husksync/hook/PlanHook.java index b0786f59..6b2581c5 100644 --- a/common/src/main/java/net/william278/husksync/hook/PlanHook.java +++ b/common/src/main/java/net/william278/husksync/hook/PlanHook.java @@ -20,10 +20,22 @@ package net.william278.husksync.hook; import com.djrapitops.plan.capability.CapabilityService; -import com.djrapitops.plan.extension.ExtensionService; +import com.djrapitops.plan.extension.*; +import com.djrapitops.plan.extension.annotation.*; +import com.djrapitops.plan.extension.icon.Color; +import com.djrapitops.plan.extension.icon.Family; +import com.djrapitops.plan.extension.icon.Icon; +import com.djrapitops.plan.extension.table.Table; +import com.djrapitops.plan.extension.table.TableColumnFormat; import net.william278.husksync.HuskSync; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataHolder; +import net.william278.husksync.data.DataSnapshot; import org.jetbrains.annotations.NotNull; +import java.time.OffsetDateTime; +import java.util.Optional; +import java.util.UUID; import java.util.logging.Level; public class PlanHook { @@ -50,6 +62,7 @@ public class PlanHook { private void registerDataExtension() { try { ExtensionService.getInstance().register(new PlanDataExtension(plugin)); + plugin.log(Level.INFO, "Registered HuskSync Plan data extension"); } catch (IllegalStateException | IllegalArgumentException e) { plugin.log(Level.WARNING, "Failed to register Plan data extension: " + e.getMessage(), e); } @@ -64,4 +77,199 @@ public class PlanHook { }); } + @TabInfo( + tab = "Current Status", + iconName = "id-card", + iconFamily = Family.SOLID, + elementOrder = {ElementOrder.VALUES, ElementOrder.TABLE, ElementOrder.GRAPH} + ) + @TabInfo( + tab = "Data Snapshots", + iconName = "clipboard-list", + iconFamily = Family.SOLID, + elementOrder = {ElementOrder.VALUES, ElementOrder.TABLE, ElementOrder.GRAPH} + ) + @TabOrder({"Current Status", "Data Snapshots"}) + @PluginInfo( + name = "HuskSync", + iconName = "exchange-alt", + iconFamily = Family.SOLID, + color = Color.LIGHT_BLUE + ) + @SuppressWarnings("unused") + public static class PlanDataExtension implements DataExtension { + + private HuskSync plugin; + + private static final String UNKNOWN_STRING = "N/A"; + + private static final String PINNED_HTML_STRING = "📍 "; + + protected PlanDataExtension(@NotNull HuskSync plugin) { + this.plugin = plugin; + } + + protected PlanDataExtension() { + } + + @Override + public CallEvents[] callExtensionMethodsOn() { + return new CallEvents[]{ + CallEvents.PLAYER_JOIN, + CallEvents.PLAYER_LEAVE + }; + } + + // Get the user's latest data snapshot + private Optional getLatestSnapshot(@NotNull UUID uuid) { + return plugin.getDatabase().getUser(uuid) + .flatMap(user -> plugin.getDatabase().getLatestSnapshot(user)) + .map(snapshot -> snapshot.unpack(plugin)); + } + + @BooleanProvider( + text = "Has Synced", + description = "Whether this user has saved, synchronized data.", + iconName = "exchange-alt", + iconFamily = Family.SOLID, + conditionName = "hasSynced", + hidden = true + ) + @Tab("Current Status") + public boolean getUserHasSynced(@NotNull UUID uuid) { + return getLatestSnapshot(uuid).isPresent(); + } + + @Conditional("hasSynced") + @NumberProvider( + text = "Sync Time", + description = "The last time the user had their data synced with the server.", + iconName = "clock", + iconFamily = Family.SOLID, + format = FormatType.DATE_SECOND, + priority = 6 + ) + @Tab("Current Status") + public long getCurrentDataTimestamp(@NotNull UUID uuid) { + return getLatestSnapshot(uuid) + .map(DataSnapshot::getTimestamp) + .orElse(OffsetDateTime.now()) + .toEpochSecond(); + } + + @Conditional("hasSynced") + @StringProvider( + text = "Version ID", + description = "ID of the data version that the user is currently using.", + iconName = "bolt", + iconFamily = Family.SOLID, + priority = 5 + ) + @Tab("Current Status") + public String getCurrentDataId(@NotNull UUID uuid) { + return getLatestSnapshot(uuid) + .map(DataSnapshot::getShortId) + .orElse(UNKNOWN_STRING); + } + + @Conditional("hasSynced") + @StringProvider( + text = "Health", + description = "The number of health points out of the max health points this player currently has.", + iconName = "heart", + iconFamily = Family.SOLID, + priority = 4 + ) + @Tab("Current Status") + public String getHealth(@NotNull UUID uuid) { + return getLatestSnapshot(uuid) + .flatMap(DataHolder::getHealth) + .map(health -> String.format("%s / %s", health.getHealth(), health.getMaxHealth())) + .orElse(UNKNOWN_STRING); + } + + @Conditional("hasSynced") + @NumberProvider( + text = "Hunger", + description = "The number of hunger points this player currently has.", + iconName = "drumstick-bite", + iconFamily = Family.SOLID, + priority = 3 + ) + @Tab("Current Status") + public long getHunger(@NotNull UUID uuid) { + return getLatestSnapshot(uuid) + .flatMap(DataHolder::getHunger) + .map(Data.Hunger::getFoodLevel) + .orElse(20); + } + + @Conditional("hasSynced") + @NumberProvider( + text = "Experience Level", + description = "The number of experience levels this player currently has.", + iconName = "hat-wizard", + iconFamily = Family.SOLID, + priority = 2 + ) + @Tab("Current Status") + public long getExperienceLevel(@NotNull UUID uuid) { + return getLatestSnapshot(uuid) + .flatMap(DataHolder::getExperience) + .map(Data.Experience::getExpLevel) + .orElse(0); + } + + @Conditional("hasSynced") + @StringProvider( + text = "Game Mode", + description = "The game mode this player is currently in.", + iconName = "gamepad", + iconFamily = Family.SOLID, + priority = 1 + ) + @Tab("Current Status") + public String getGameMode(@NotNull UUID uuid) { + return getLatestSnapshot(uuid) + .flatMap(DataHolder::getGameMode) + .map(Data.GameMode::getGameMode) + .orElse(UNKNOWN_STRING); + } + + @Conditional("hasSynced") + @NumberProvider( + text = "Advancements", + description = "The number of advancements & recipes the player has progressed in.", + iconName = "award", + iconFamily = Family.SOLID + ) + @Tab("Current Status") + public long getAdvancementsCompleted(@NotNull UUID playerUUID) { + return getLatestSnapshot(playerUUID) + .flatMap(DataHolder::getAdvancements) + .map(Data.Advancements::getCompleted) + .stream().count(); + } + + @Conditional("hasSynced") + @TableProvider(tableColor = Color.LIGHT_BLUE) + @Tab("Data Snapshots") + public Table getDataSnapshots(@NotNull UUID playerUUID) { + final Table.Factory dataSnapshotsTable = Table.builder() + .columnOne("Time", new Icon(Family.SOLID, "clock", Color.NONE)) + .columnOneFormat(TableColumnFormat.DATE_SECOND) + .columnTwo("ID", new Icon(Family.SOLID, "bolt", Color.NONE)) + .columnThree("Cause", new Icon(Family.SOLID, "flag", Color.NONE)) + .columnFour("Pinned", new Icon(Family.SOLID, "thumbtack", Color.NONE)); + plugin.getDatabase().getUser(playerUUID).ifPresent(user -> + plugin.getDatabase().getAllSnapshots(user).forEach(snapshot -> dataSnapshotsTable.addRow( + snapshot.getTimestamp().toEpochSecond(), + snapshot.getShortId(), + snapshot.getSaveCause().getDisplayName(), + snapshot.isPinned() ? PINNED_HTML_STRING + "Pinned" : "Unpinned" + )) + ); + return dataSnapshotsTable.build(); + } + } } diff --git a/common/src/main/java/net/william278/husksync/listener/EventListener.java b/common/src/main/java/net/william278/husksync/listener/EventListener.java index 5dba45eb..695b4378 100644 --- a/common/src/main/java/net/william278/husksync/listener/EventListener.java +++ b/common/src/main/java/net/william278/husksync/listener/EventListener.java @@ -19,22 +19,16 @@ package net.william278.husksync.listener; -import de.themoep.minedown.adventure.MineDown; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.DataSaveCause; -import net.william278.husksync.data.ItemData; -import net.william278.husksync.player.OnlineUser; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.OnlineUser; +import net.william278.husksync.util.Task; import org.jetbrains.annotations.NotNull; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; /** @@ -42,13 +36,11 @@ import java.util.logging.Level; */ public abstract class EventListener { - /** - * The plugin instance - */ + // The plugin instance protected final HuskSync plugin; /** - * Set of UUIDs of "locked players", for which events will be cancelled. + * Set of UUIDs of "locked players", for which events will be canceled. *

* Players are locked while their items are being set (on join) or saved (on quit) */ @@ -66,7 +58,7 @@ public abstract class EventListener { } /** - * Handle a player joining the server (including players switching from another proxied server) + * Handle a player joining the server (including players switching from another server on the network) * * @param user The {@link OnlineUser} to handle */ @@ -74,92 +66,51 @@ public abstract class EventListener { if (user.isNpc()) { return; } + lockedPlayers.add(user.getUuid()); - lockedPlayers.add(user.uuid); - CompletableFuture.runAsync(() -> { - try { - // Hold reading data for the network latency threshold, to ensure the source server has set the redis key - Thread.sleep(Math.max(0, plugin.getSettings().getNetworkLatencyMilliseconds())); - } catch (InterruptedException e) { - plugin.log(Level.SEVERE, "An exception occurred handling a player join", e); - } finally { - plugin.getRedisManager().getUserServerSwitch(user).thenAccept(changingServers -> { - if (!changingServers) { - // Fetch from the database if the user isn't changing servers - setUserFromDatabase(user).thenAccept(succeeded -> handleSynchronisationCompletion(user, succeeded)); - } else { - final int TIME_OUT_MILLISECONDS = 3200; - CompletableFuture.runAsync(() -> { - final AtomicInteger currentMilliseconds = new AtomicInteger(0); - final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - - // Set the user as soon as the source server has set the data to redis - executor.scheduleAtFixedRate(() -> { - if (user.isOffline()) { - executor.shutdown(); - return; - } - if (disabling || currentMilliseconds.get() > TIME_OUT_MILLISECONDS) { - executor.shutdown(); - setUserFromDatabase(user).thenAccept( - succeeded -> handleSynchronisationCompletion(user, succeeded)); - return; - } - plugin.getRedisManager().getUserData(user).thenAccept(redisUserData -> - redisUserData.ifPresent(redisData -> { - user.setData(redisData, plugin) - .thenAccept(succeeded -> handleSynchronisationCompletion(user, succeeded)).join(); - executor.shutdown(); - })).join(); - currentMilliseconds.addAndGet(200); - }, 0, 200L, TimeUnit.MILLISECONDS); - }); - } - }); + plugin.runAsyncDelayed(() -> { + // Fetch from the database if the user isn't changing servers + if (!plugin.getRedisManager().getUserServerSwitch(user)) { + this.setUserFromDatabase(user); + return; } - }); + + // Set the user as soon as the source server has set the data to redis + final long MAX_ATTEMPTS = 16L; + final AtomicLong timesRun = new AtomicLong(0L); + final AtomicReference task = new AtomicReference<>(); + final Runnable runnable = () -> { + if (user.isOffline()) { + task.get().cancel(); + return; + } + if (disabling || timesRun.getAndIncrement() > MAX_ATTEMPTS) { + task.get().cancel(); + this.setUserFromDatabase(user); + return; + } + + plugin.getRedisManager().getUserData(user).ifPresent(redisData -> { + task.get().cancel(); + user.applySnapshot(redisData, DataSnapshot.UpdateCause.SYNCHRONIZED); + }); + }; + task.set(plugin.getRepeatingTask(runnable, 10)); + task.get().run(); + + }, Math.max(0, plugin.getSettings().getNetworkLatencyMilliseconds() / 50L)); } /** * Set a user's data from the database * * @param user The user to set the data for - * @return Whether the data was successfully set - */ - private CompletableFuture setUserFromDatabase(@NotNull OnlineUser user) { - return plugin.getDatabase().getCurrentUserData(user).thenApply(databaseUserData -> { - if (databaseUserData.isPresent()) { - return user.setData(databaseUserData.get().userData(), plugin).join(); - } - return true; - }); - } - - /** - * Handle a player's synchronization completion - * - * @param user The {@link OnlineUser} to handle - * @param succeeded Whether the synchronization succeeded */ - private void handleSynchronisationCompletion(@NotNull OnlineUser user, boolean succeeded) { - if (succeeded) { - switch (plugin.getSettings().getNotificationDisplaySlot()) { - case CHAT -> plugin.getLocales().getLocale("synchronisation_complete") - .ifPresent(user::sendMessage); - case ACTION_BAR -> plugin.getLocales().getLocale("synchronisation_complete") - .ifPresent(user::sendActionBar); - case TOAST -> plugin.getLocales().getLocale("synchronisation_complete") - .ifPresent(locale -> user.sendToast(locale, new MineDown(""), - "minecraft:bell", "TASK")); - } - plugin.getDatabase().ensureUser(user).join(); - lockedPlayers.remove(user.uuid); - plugin.getEventCannon().fireSyncCompleteEvent(user); - } else { - plugin.getLocales().getLocale("synchronisation_failed") - .ifPresent(user::sendMessage); - plugin.getDatabase().ensureUser(user).join(); - } + private void setUserFromDatabase(@NotNull OnlineUser user) { + plugin.getDatabase().getLatestSnapshot(user).ifPresentOrElse( + snapshot -> user.applySnapshot(snapshot, DataSnapshot.UpdateCause.SYNCHRONIZED), + () -> user.completeSync(true, DataSnapshot.UpdateCause.NEW_USER, plugin) + ); } /** @@ -168,28 +119,27 @@ public abstract class EventListener { * @param user The {@link OnlineUser} to handle */ protected final void handlePlayerQuit(@NotNull OnlineUser user) { - // Players quitting have their data manually saved by the plugin disable hook + // Players quitting have their data manually saved when the plugin is disabled if (disabling) { return; } + // Don't sync players awaiting synchronization - if (lockedPlayers.contains(user.uuid) || user.isNpc()) { + if (lockedPlayers.contains(user.getUuid()) || user.isNpc()) { return; } - // Handle asynchronous disconnection - lockedPlayers.add(user.uuid); - CompletableFuture.runAsync(() -> plugin.getRedisManager().setUserServerSwitch(user) - .thenRun(() -> user.getUserData(plugin).thenAccept( - optionalUserData -> optionalUserData.ifPresent(userData -> plugin.getRedisManager() - .setUserData(user, userData).thenRun(() -> plugin.getDatabase() - .setUserData(user, userData, DataSaveCause.DISCONNECT))))) - .exceptionally(throwable -> { - plugin.log(Level.SEVERE, - "An exception occurred handling a player disconnection"); - throwable.printStackTrace(); - return null; - }).join()); + // Handle disconnection + try { + lockedPlayers.add(user.getUuid()); + plugin.getRedisManager().setUserServerSwitch(user).thenRun(() -> { + final DataSnapshot.Packed data = user.createSnapshot(DataSnapshot.SaveCause.DISCONNECT); + plugin.getRedisManager().setUserData(user, data); + plugin.getDatabase().addSnapshot(user, data); + }); + } catch (Throwable e) { + plugin.log(Level.SEVERE, "An exception occurred handling a player disconnection", e); + } } /** @@ -202,10 +152,10 @@ public abstract class EventListener { return; } usersInWorld.stream() - .filter(user -> !lockedPlayers.contains(user.uuid) && !user.isNpc()) - .forEach(user -> user.getUserData(plugin) - .thenAccept(data -> data.ifPresent(userData -> plugin.getDatabase() - .setUserData(user, userData, DataSaveCause.WORLD_SAVE)))); + .filter(user -> !lockedPlayers.contains(user.getUuid()) && !user.isNpc()) + .forEach(user -> plugin.getDatabase().addSnapshot( + user, user.createSnapshot(DataSnapshot.SaveCause.WORLD_SAVE) + )); } /** @@ -214,24 +164,22 @@ public abstract class EventListener { * @param user The user who died * @param drops The items that this user would have dropped */ - protected void saveOnPlayerDeath(@NotNull OnlineUser user, @NotNull ItemData drops) { - if (disabling || !plugin.getSettings().doSaveOnDeath() || lockedPlayers.contains(user.uuid) || user.isNpc() - || (!plugin.getSettings().doSaveEmptyDropsOnDeath() && drops.isEmpty())) { + protected void saveOnPlayerDeath(@NotNull OnlineUser user, @NotNull Data.Items drops) { + if (disabling || !plugin.getSettings().doSaveOnDeath() || lockedPlayers.contains(user.getUuid()) || user.isNpc() + || (!plugin.getSettings().doSaveEmptyDropsOnDeath() && drops.isEmpty())) { return; } - user.getUserData(plugin) - .thenAccept(data -> data.ifPresent(userData -> { - userData.getInventory().orElse(ItemData.empty()).serializedItems = drops.serializedItems; - plugin.getDatabase().setUserData(user, userData, DataSaveCause.DEATH); - })); + final DataSnapshot.Packed snapshot = user.createSnapshot(DataSnapshot.SaveCause.DEATH); + snapshot.edit(plugin, (data -> data.getInventory().ifPresent(inventory -> inventory.setContents(drops)))); + plugin.getDatabase().addSnapshot(user, snapshot); } /** - * Determine whether a player event should be cancelled + * Determine whether a player event should be canceled * * @param userUuid The UUID of the user to check - * @return Whether the event should be cancelled + * @return Whether the event should be canceled */ protected final boolean cancelPlayerEvent(@NotNull UUID userUuid) { return disabling || lockedPlayers.contains(userUuid); @@ -245,21 +193,65 @@ public abstract class EventListener { // Save data for all online users plugin.getOnlineUsers().stream() - .filter(user -> !lockedPlayers.contains(user.uuid) && !user.isNpc()) + .filter(user -> !lockedPlayers.contains(user.getUuid()) && !user.isNpc()) .forEach(user -> { - lockedPlayers.add(user.uuid); - user.getUserData(plugin).join() - .ifPresent(userData -> plugin.getDatabase() - .setUserData(user, userData, DataSaveCause.SERVER_SHUTDOWN).join()); + lockedPlayers.add(user.getUuid()); + plugin.getDatabase().addSnapshot(user, user.createSnapshot(DataSnapshot.SaveCause.SERVER_SHUTDOWN)); }); // Close outstanding connections - plugin.getDatabase().close(); - plugin.getRedisManager().close(); + plugin.getDatabase().terminate(); + plugin.getRedisManager().terminate(); } public final Set getLockedPlayers() { return this.lockedPlayers; } + /** + * Represents priorities for events that HuskSync listens to + */ + public enum Priority { + /** + * Listens and processes the event execution last + */ + HIGHEST, + /** + * Listens in between {@link #HIGHEST} and {@link #LOWEST} priority marked + */ + NORMAL, + /** + * Listens and processes the event execution first + */ + LOWEST + } + + /** + * Represents events that HuskSync listens to, with a configurable priority listener + */ + public enum ListenerType { + JOIN_LISTENER(Priority.LOWEST), + QUIT_LISTENER(Priority.LOWEST), + DEATH_LISTENER(Priority.NORMAL); + + private final Priority defaultPriority; + + ListenerType(@NotNull EventListener.Priority defaultPriority) { + this.defaultPriority = defaultPriority; + } + + @NotNull + private Map.Entry toEntry() { + return Map.entry(name().toLowerCase(), defaultPriority.name()); + } + + + @SuppressWarnings("unchecked") + @NotNull + public static Map getDefaults() { + return Map.ofEntries(Arrays.stream(values()) + .map(ListenerType::toEntry) + .toArray(Map.Entry[]::new)); + } + } } diff --git a/common/src/main/java/net/william278/husksync/migrator/Migrator.java b/common/src/main/java/net/william278/husksync/migrator/Migrator.java index 1b12d007..c9389055 100644 --- a/common/src/main/java/net/william278/husksync/migrator/Migrator.java +++ b/common/src/main/java/net/william278/husksync/migrator/Migrator.java @@ -20,13 +20,12 @@ package net.william278.husksync.migrator; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.UserData; import org.jetbrains.annotations.NotNull; import java.util.concurrent.CompletableFuture; /** - * A migrator that migrates data from other data formats to HuskSync's {@link UserData} format + * A migrator that migrates data from other data formats to HuskSync's format */ public abstract class Migrator { diff --git a/common/src/main/java/net/william278/husksync/player/OnlineUser.java b/common/src/main/java/net/william278/husksync/player/OnlineUser.java deleted file mode 100644 index 1da48a20..00000000 --- a/common/src/main/java/net/william278/husksync/player/OnlineUser.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.player; - -import de.themoep.minedown.adventure.MineDown; -import de.themoep.minedown.adventure.MineDownParser; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.Component; -import net.william278.desertwell.util.Version; -import net.william278.husksync.HuskSync; -import net.william278.husksync.config.Settings; -import net.william278.husksync.data.*; -import net.william278.husksync.event.PreSyncEvent; -import org.jetbrains.annotations.NotNull; - -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Level; - -/** - * Represents a logged-in {@link User} - */ -public abstract class OnlineUser extends User { - - public OnlineUser(@NotNull UUID uuid, @NotNull String username) { - super(uuid, username); - } - - /** - * Get the player's {@link StatusData} - * - * @return the player's {@link StatusData} - */ - public abstract CompletableFuture getStatus(); - - /** - * Set the player's {@link StatusData} - * - * @param statusData the player's {@link StatusData} - * @param statusDataFlags the flags to use for setting the status data - * @return a future returning void when complete - * @deprecated Use {@link #setStatus(StatusData, Settings)} instead - */ - @Deprecated(since = "2.1") - public final CompletableFuture setStatus(@NotNull StatusData statusData, - @NotNull List statusDataFlags) { - final Settings settings = new Settings(); - settings.getSynchronizationFeatures().put(Settings.SynchronizationFeature.HEALTH.name().toLowerCase(Locale.ENGLISH), statusDataFlags.contains(StatusDataFlag.SET_HEALTH)); - settings.getSynchronizationFeatures().put(Settings.SynchronizationFeature.MAX_HEALTH.name().toLowerCase(Locale.ENGLISH), statusDataFlags.contains(StatusDataFlag.SET_MAX_HEALTH)); - settings.getSynchronizationFeatures().put(Settings.SynchronizationFeature.HUNGER.name().toLowerCase(Locale.ENGLISH), statusDataFlags.contains(StatusDataFlag.SET_HUNGER)); - settings.getSynchronizationFeatures().put(Settings.SynchronizationFeature.EXPERIENCE.name().toLowerCase(Locale.ENGLISH), statusDataFlags.contains(StatusDataFlag.SET_EXPERIENCE)); - settings.getSynchronizationFeatures().put(Settings.SynchronizationFeature.INVENTORIES.name().toLowerCase(Locale.ENGLISH), statusDataFlags.contains(StatusDataFlag.SET_SELECTED_ITEM_SLOT)); - settings.getSynchronizationFeatures().put(Settings.SynchronizationFeature.LOCATION.name().toLowerCase(Locale.ENGLISH), statusDataFlags.contains(StatusDataFlag.SET_GAME_MODE) || statusDataFlags.contains(StatusDataFlag.SET_FLYING)); - return setStatus(statusData, settings); - } - - /** - * Set the player's {@link StatusData} - * - * @param statusData the player's {@link StatusData} - * @param settings settings, containing information about which features should be synced - * @return a future returning void when complete - */ - public abstract CompletableFuture setStatus(@NotNull StatusData statusData, @NotNull Settings settings); - - /** - * Get the player's inventory {@link ItemData} contents - * - * @return The player's inventory {@link ItemData} contents - */ - public abstract CompletableFuture getInventory(); - - /** - * Set the player's {@link ItemData} - * - * @param itemData The player's {@link ItemData} - * @return a future returning void when complete - */ - public abstract CompletableFuture setInventory(@NotNull ItemData itemData); - - /** - * Get the player's ender chest {@link ItemData} contents - * - * @return The player's ender chest {@link ItemData} contents - */ - public abstract CompletableFuture getEnderChest(); - - /** - * Set the player's {@link ItemData} - * - * @param enderChestData The player's {@link ItemData} - * @return a future returning void when complete - */ - public abstract CompletableFuture setEnderChest(@NotNull ItemData enderChestData); - - - /** - * Get the player's {@link PotionEffectData} - * - * @return The player's {@link PotionEffectData} - */ - public abstract CompletableFuture getPotionEffects(); - - /** - * Set the player's {@link PotionEffectData} - * - * @param potionEffectData The player's {@link PotionEffectData} - * @return a future returning void when complete - */ - public abstract CompletableFuture setPotionEffects(@NotNull PotionEffectData potionEffectData); - - /** - * Get the player's set of {@link AdvancementData} - * - * @return the player's set of {@link AdvancementData} - */ - public abstract CompletableFuture> getAdvancements(); - - /** - * Set the player's {@link AdvancementData} - * - * @param advancementData List of the player's {@link AdvancementData} - * @return a future returning void when complete - */ - public abstract CompletableFuture setAdvancements(@NotNull List advancementData); - - /** - * Get the player's {@link StatisticsData} - * - * @return The player's {@link StatisticsData} - */ - public abstract CompletableFuture getStatistics(); - - /** - * Set the player's {@link StatisticsData} - * - * @param statisticsData The player's {@link StatisticsData} - * @return a future returning void when complete - */ - public abstract CompletableFuture setStatistics(@NotNull StatisticsData statisticsData); - - /** - * Get the player's {@link LocationData} - * - * @return the player's {@link LocationData} - */ - public abstract CompletableFuture getLocation(); - - /** - * Set the player's {@link LocationData} - * - * @param locationData the player's {@link LocationData} - * @return a future returning void when complete - */ - public abstract CompletableFuture setLocation(@NotNull LocationData locationData); - - /** - * Get the player's {@link PersistentDataContainerData} - * - * @return The player's {@link PersistentDataContainerData} when fetched - */ - public abstract CompletableFuture getPersistentDataContainer(); - - /** - * Set the player's {@link PersistentDataContainerData} - * - * @param persistentDataContainerData The player's {@link PersistentDataContainerData} to set - * @return A future returning void when complete - */ - public abstract CompletableFuture setPersistentDataContainer(@NotNull PersistentDataContainerData persistentDataContainerData); - - /** - * Indicates if the player has gone offline - * - * @return {@code true} if the player has left the server; {@code false} otherwise - */ - public abstract boolean isOffline(); - - /** - * Returns the implementing Minecraft server version - * - * @return The Minecraft server version - */ - @NotNull - public abstract Version getMinecraftVersion(); - - /** - * Get the player's adventure {@link Audience} - * - * @return the player's {@link Audience} - */ - @NotNull - public abstract Audience getAudience(); - - /** - * Send a message to this player - * - * @param component the {@link Component} message to send - */ - public void sendMessage(@NotNull Component component) { - getAudience().sendMessage(component); - } - - /** - * Dispatch a MineDown-formatted message to this player - * - * @param mineDown the parsed {@link MineDown} to send - */ - public void sendMessage(@NotNull MineDown mineDown) { - sendMessage(mineDown - .disable(MineDownParser.Option.SIMPLE_FORMATTING) - .replace().toComponent()); - } - - /** - * Dispatch a MineDown-formatted action bar message to this player - * - * @param mineDown the parsed {@link MineDown} to send - */ - public void sendActionBar(@NotNull MineDown mineDown) { - getAudience().sendActionBar(mineDown - .disable(MineDownParser.Option.SIMPLE_FORMATTING) - .replace().toComponent()); - } - - /** - * Dispatch a toast message to this player - * - * @param title the title of the toast - * @param description the description of the toast - * @param iconMaterial the namespace-keyed material to use as an icon of the toast - * @param backgroundType the background ("ToastType") of the toast - */ - public abstract void sendToast(@NotNull MineDown title, @NotNull MineDown description, - @NotNull String iconMaterial, @NotNull String backgroundType); - - /** - * Returns if the player has the permission node - * - * @param node The permission node string - * @return {@code true} if the player has permission node; {@code false} otherwise - */ - public abstract boolean hasPermission(@NotNull String node); - - /** - * Show a GUI chest menu to the player, containing the given {@link ItemData} - * - * @param itemData Item data to be shown in the GUI - * @param editable If the player should be able to remove, replace and move around the items - * @param minimumRows The minimum number of rows to show in the chest menu - * @param title The title of the chest menu, as a {@link MineDown} locale - * @return A future returning the {@link ItemData} in the chest menu when the player closes it - * @since 2.1 - */ - public abstract CompletableFuture> showMenu(@NotNull ItemData itemData, boolean editable, - int minimumRows, @NotNull MineDown title); - - /** - * Returns true if the player is dead - * - * @return true if the player is dead - */ - public abstract boolean isDead(); - - /** - * Apply {@link UserData} to a player, updating their inventory, status, statistics, etc. as per the config. - *

- * This will only set data that is enabled as per the enabled settings in the config file. - * Data present in the {@link UserData} object, but not enabled to be set in the config, will be ignored. - * - * @param plugin The plugin instance - * @return a future returning a boolean when complete; if the sync was successful, the future will return {@code true}. - */ - public final CompletableFuture setData(@NotNull UserData data, @NotNull HuskSync plugin) { - return CompletableFuture.supplyAsync(() -> { - // Prevent synchronising user data from newer versions of Minecraft - if (Version.fromString(data.getMinecraftVersion()).compareTo(plugin.getMinecraftVersion()) > 0) { - plugin.log(Level.SEVERE, "Cannot set data for " + username + - " because the Minecraft version of their user data (" + data.getMinecraftVersion() + - ") is newer than the server's Minecraft version (" + plugin.getMinecraftVersion() + ")."); - return false; - } - // Prevent synchronising user data from newer versions of the plugin - if (data.getFormatVersion() > UserData.CURRENT_FORMAT_VERSION) { - plugin.log(Level.SEVERE, "Cannot set data for " + username + - " because the format version of their user data (v" + data.getFormatVersion() + - ") is newer than the current format version (v" + UserData.CURRENT_FORMAT_VERSION + ")."); - return false; - } - - // Fire the PreSyncEvent - final PreSyncEvent preSyncEvent = (PreSyncEvent) plugin.getEventCannon().firePreSyncEvent(this, data).join(); - final UserData finalData = preSyncEvent.getUserData(); - final List> dataSetOperations = new ArrayList<>() {{ - if (!isOffline() && !preSyncEvent.isCancelled()) { - final Settings settings = plugin.getSettings(); - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.INVENTORIES)) { - finalData.getInventory().ifPresent(itemData -> add(setInventory(itemData))); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.ENDER_CHESTS)) { - finalData.getEnderChest().ifPresent(itemData -> add(setEnderChest(itemData))); - } - finalData.getStatus().ifPresent(statusData -> add(setStatus(statusData, settings))); - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.POTION_EFFECTS)) { - finalData.getPotionEffects().ifPresent(potionEffectData -> add(setPotionEffects(potionEffectData))); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.ADVANCEMENTS)) { - finalData.getAdvancements().ifPresent(advancementData -> add(setAdvancements(advancementData))); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.STATISTICS)) { - finalData.getStatistics().ifPresent(statisticData -> add(setStatistics(statisticData))); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.LOCATION)) { - finalData.getLocation().ifPresent(locationData -> add(setLocation(locationData))); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.PERSISTENT_DATA_CONTAINER)) { - finalData.getPersistentDataContainer().ifPresent(persistentDataContainerData -> - add(setPersistentDataContainer(persistentDataContainerData))); - } - } - }}; - // Apply operations in parallel, join when complete - return CompletableFuture.allOf(dataSetOperations.toArray(new CompletableFuture[0])).thenApply(unused -> true) - .exceptionally(exception -> { - // Handle synchronisation exceptions - plugin.log(Level.SEVERE, "Failed to set data for player " + username + " (" + exception.getMessage() + ")"); - exception.printStackTrace(); - return false; - }).join(); - }); - - } - - /** - * Get the player's current {@link UserData} in an {@link Optional}. - *

- * Since v2.1, this method will respect the data synchronisation settings; user data will only be as big as the - * enabled synchronisation values set in the config file - *

- * Also note that if the {@code SYNCHRONIZATION_SAVE_DEAD_PLAYER_INVENTORIES} ConfigOption has been set, - * the user's inventory will only be returned if the player is alive. - *

- * If the user data could not be returned due to an exception, the optional will return empty - * - * @param plugin The plugin instance - */ - public final CompletableFuture> getUserData(@NotNull HuskSync plugin) { - return CompletableFuture.supplyAsync(() -> { - final UserDataBuilder builder = UserData.builder(getMinecraftVersion()); - final List> dataGetOperations = new ArrayList<>() {{ - if (!isOffline()) { - final Settings settings = plugin.getSettings(); - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.INVENTORIES)) { - if (isDead() && settings.isSynchroniseDeadPlayersChangingServer()) { - plugin.debug("Player " + username + " is dead, so their inventory will be set to empty."); - add(CompletableFuture.runAsync(() -> builder.setInventory(ItemData.empty()))); - } else { - add(getInventory().thenAccept(builder::setInventory)); - } - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.ENDER_CHESTS)) { - add(getEnderChest().thenAccept(builder::setEnderChest)); - } - add(getStatus().thenAccept(builder::setStatus)); - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.POTION_EFFECTS)) { - add(getPotionEffects().thenAccept(builder::setPotionEffects)); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.ADVANCEMENTS)) { - add(getAdvancements().thenAccept(builder::setAdvancements)); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.STATISTICS)) { - add(getStatistics().thenAccept(builder::setStatistics)); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.LOCATION)) { - add(getLocation().thenAccept(builder::setLocation)); - } - if (settings.getSynchronizationFeature(Settings.SynchronizationFeature.PERSISTENT_DATA_CONTAINER)) { - add(getPersistentDataContainer().thenAccept(builder::setPersistentDataContainer)); - } - } - }}; - - // Apply operations in parallel, join when complete - CompletableFuture.allOf(dataGetOperations.toArray(new CompletableFuture[0])).join(); - return Optional.of(builder.build()); - }).exceptionally(exception -> { - plugin.log(Level.SEVERE, "Failed to get user data from online player " + username + " (" + exception.getMessage() + ")"); - exception.printStackTrace(); - return Optional.empty(); - }); - } - - /** - * Get if the player is locked - * - * @return the player's locked status - */ - public abstract boolean isLocked(); - - /** - * Get if the player is a NPC - * - * @return if the player is a NPC with metadata - */ - public abstract boolean isNpc(); -} diff --git a/common/src/main/java/net/william278/husksync/redis/RedisKeyType.java b/common/src/main/java/net/william278/husksync/redis/RedisKeyType.java index fc069cad..7ba8f9fb 100644 --- a/common/src/main/java/net/william278/husksync/redis/RedisKeyType.java +++ b/common/src/main/java/net/william278/husksync/redis/RedisKeyType.java @@ -28,14 +28,24 @@ public enum RedisKeyType { DATA_UPDATE(10), SERVER_SWITCH(10); - public final int timeToLive; + private final int timeToLive; RedisKeyType(int timeToLive) { this.timeToLive = timeToLive; } @NotNull - public String getKeyPrefix() { - return RedisManager.KEY_NAMESPACE.toLowerCase(Locale.ENGLISH) + ":" + RedisManager.clusterId.toLowerCase(Locale.ENGLISH) + ":" + name().toLowerCase(Locale.ENGLISH); + public String getKeyPrefix(@NotNull String clusterId) { + return String.format( + "%s:%s:%s", + RedisManager.KEY_NAMESPACE.toLowerCase(Locale.ENGLISH), + clusterId.toLowerCase(Locale.ENGLISH), + name().toLowerCase(Locale.ENGLISH) + ); } + + public int getTimeToLive() { + return timeToLive; + } + } diff --git a/common/src/main/java/net/william278/husksync/redis/RedisManager.java b/common/src/main/java/net/william278/husksync/redis/RedisManager.java index 990b554c..fe298a19 100644 --- a/common/src/main/java/net/william278/husksync/redis/RedisManager.java +++ b/common/src/main/java/net/william278/husksync/redis/RedisManager.java @@ -19,21 +19,24 @@ package net.william278.husksync.redis; -import de.themoep.minedown.adventure.MineDown; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.UserData; -import net.william278.husksync.player.User; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.User; +import org.jetbrains.annotations.Blocking; import org.jetbrains.annotations.NotNull; -import redis.clients.jedis.*; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; +import redis.clients.jedis.JedisPubSub; import redis.clients.jedis.exceptions.JedisException; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; /** * Manages the connection to the Redis server, handling the caching of user data @@ -41,146 +44,180 @@ import java.util.concurrent.CompletableFuture; public class RedisManager extends JedisPubSub { protected static final String KEY_NAMESPACE = "husksync:"; - protected static String clusterId = ""; + private final HuskSync plugin; - private final JedisPoolConfig jedisPoolConfig; - private final String redisHost; - private final int redisPort; - private final String redisPassword; - private final boolean redisUseSsl; + private final String clusterId; private JedisPool jedisPool; + private final Map>> pendingRequests; public RedisManager(@NotNull HuskSync plugin) { this.plugin = plugin; - clusterId = plugin.getSettings().getClusterId(); - - // Set redis credentials - this.redisHost = plugin.getSettings().getRedisHost(); - this.redisPort = plugin.getSettings().getRedisPort(); - this.redisPassword = plugin.getSettings().getRedisPassword(); - this.redisUseSsl = plugin.getSettings().isRedisUseSsl(); - - // Configure the jedis pool - this.jedisPoolConfig = new JedisPoolConfig(); - this.jedisPoolConfig.setMaxIdle(0); - this.jedisPoolConfig.setTestOnBorrow(true); - this.jedisPoolConfig.setTestOnReturn(true); + this.clusterId = plugin.getSettings().getClusterId(); + this.pendingRequests = new ConcurrentHashMap<>(); } /** * Initialize the redis connection pool - * - * @return a future returning void when complete */ - public boolean initialize() { - if (redisPassword.isBlank()) { - jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort, 0, redisUseSsl); - } else { - jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort, 0, redisPassword, redisUseSsl); - } + @Blocking + public void initialize() throws IllegalStateException { + final String password = plugin.getSettings().getRedisPassword(); + final String host = plugin.getSettings().getRedisHost(); + final int port = plugin.getSettings().getRedisPort(); + final boolean useSSL = plugin.getSettings().redisUseSsl(); + + // Create the jedis pool + final JedisPoolConfig config = new JedisPoolConfig(); + config.setMaxIdle(0); + config.setTestOnBorrow(true); + config.setTestOnReturn(true); + this.jedisPool = password.isEmpty() + ? new JedisPool(config, host, port, 0, useSSL) + : new JedisPool(config, host, port, 0, password, useSSL); + + // Ping the server to check the connection try { jedisPool.getResource().ping(); } catch (JedisException e) { - return false; + throw new IllegalStateException("Failed to establish connection with the Redis server. " + + "Please check the supplied credentials in the config file", e); } - CompletableFuture.runAsync(this::subscribe); - return true; + + // Subscribe using a thread (rather than a task) + new Thread(this::subscribe, "husksync:redis_subscriber").start(); } + @Blocking private void subscribe() { - try (final Jedis subscriber = redisPassword.isBlank() ? new Jedis(redisHost, redisPort, 0, redisUseSsl) : - new Jedis(redisHost, redisPort, DefaultJedisClientConfig.builder() - .password(redisPassword).timeoutMillis(0).ssl(redisUseSsl).build())) { - subscriber.connect(); - subscriber.subscribe(this, Arrays.stream(RedisMessageType.values()) - .map(RedisMessageType::getMessageChannel) - .toArray(String[]::new)); + try (Jedis jedis = jedisPool.getResource()) { + jedis.subscribe( + this, + Arrays.stream(RedisMessageType.values()) + .map(type -> type.getMessageChannel(clusterId)) + .toArray(String[]::new) + ); } } @Override public void onMessage(@NotNull String channel, @NotNull String message) { - final RedisMessageType messageType = RedisMessageType.getTypeFromChannel(channel).orElse(null); - if (messageType != RedisMessageType.UPDATE_USER_DATA) { + final RedisMessageType messageType = RedisMessageType.getTypeFromChannel(channel, clusterId).orElse(null); + if (messageType == null) { return; } - final RedisMessage redisMessage = RedisMessage.fromJson(message); - plugin.getOnlineUser(redisMessage.targetUserUuid).ifPresent(user -> { - final UserData userData = plugin.getDataAdapter().fromBytes(redisMessage.data); - user.setData(userData, plugin).thenAccept(succeeded -> { - if (succeeded) { - switch (plugin.getSettings().getNotificationDisplaySlot()) { - case CHAT -> plugin.getLocales().getLocale("data_update_complete") - .ifPresent(user::sendMessage); - case ACTION_BAR -> plugin.getLocales().getLocale("data_update_complete") - .ifPresent(user::sendActionBar); - case TOAST -> plugin.getLocales().getLocale("data_update_complete") - .ifPresent(locale -> user.sendToast(locale, new MineDown(""), - "minecraft:bell", "TASK")); - } - plugin.getEventCannon().fireSyncCompleteEvent(user); - } else { - plugin.getLocales().getLocale("data_update_failed") - .ifPresent(user::sendMessage); + final RedisMessage redisMessage = RedisMessage.fromJson(plugin, message); + switch (messageType) { + case UPDATE_USER_DATA -> plugin.getOnlineUser(redisMessage.getTargetUuid()).ifPresent( + user -> user.applySnapshot( + DataSnapshot.deserialize(plugin, redisMessage.getPayload()), + DataSnapshot.UpdateCause.UPDATED + ) + ); + case REQUEST_USER_DATA -> plugin.getOnlineUser(redisMessage.getTargetUuid()).ifPresent( + user -> RedisMessage.create( + UUID.fromString(new String(redisMessage.getPayload(), StandardCharsets.UTF_8)), + user.createSnapshot(DataSnapshot.SaveCause.INVENTORY_COMMAND).asBytes(plugin) + ).dispatch(plugin, RedisMessageType.RETURN_USER_DATA) + ); + case RETURN_USER_DATA -> { + final CompletableFuture> future = pendingRequests.get( + redisMessage.getTargetUuid() + ); + if (future != null) { + future.complete(Optional.of(DataSnapshot.deserialize(plugin, redisMessage.getPayload()))); + pendingRequests.remove(redisMessage.getTargetUuid()); } - }); - }); + } + } } + @Blocking protected void sendMessage(@NotNull String channel, @NotNull String message) { try (Jedis jedis = jedisPool.getResource()) { jedis.publish(channel, message); } } - public CompletableFuture sendUserDataUpdate(@NotNull User user, @NotNull UserData userData) { - return CompletableFuture.runAsync(() -> { - final RedisMessage redisMessage = new RedisMessage(user.uuid, plugin.getDataAdapter().toBytes(userData)); - redisMessage.dispatch(this, RedisMessageType.UPDATE_USER_DATA); + public void sendUserDataUpdate(@NotNull User user, @NotNull DataSnapshot.Packed data) { + plugin.runAsync(() -> { + final RedisMessage redisMessage = RedisMessage.create(user.getUuid(), data.asBytes(plugin)); + redisMessage.dispatch(plugin, RedisMessageType.UPDATE_USER_DATA); + }); + } + + public CompletableFuture> getUserData(@NotNull UUID requestId, @NotNull User user) { + return plugin.getOnlineUser(user.getUuid()) + .map(online -> CompletableFuture.completedFuture( + Optional.of(online.createSnapshot(DataSnapshot.SaveCause.API))) + ) + .orElse(this.requestData(requestId, user)); + } + + private CompletableFuture> requestData(@NotNull UUID requestId, @NotNull User user) { + final CompletableFuture> future = new CompletableFuture<>(); + pendingRequests.put(requestId, future); + plugin.runAsync(() -> { + final RedisMessage redisMessage = RedisMessage.create( + user.getUuid(), + requestId.toString().getBytes(StandardCharsets.UTF_8) + ); + redisMessage.dispatch(plugin, RedisMessageType.REQUEST_USER_DATA); }); + return future.orTimeout( + plugin.getSettings().getNetworkLatencyMilliseconds(), + TimeUnit.MILLISECONDS + ) + .exceptionally(throwable -> { + pendingRequests.remove(requestId); + return Optional.empty(); + }); } /** * Set a user's data to the Redis server * - * @param user the user to set data for - * @param userData the user's data to set - * @return a future returning void when complete + * @param user the user to set data for + * @param data the user's data to set */ - public CompletableFuture setUserData(@NotNull User user, @NotNull UserData userData) { - try { - return CompletableFuture.runAsync(() -> { - try (Jedis jedis = jedisPool.getResource()) { - // Set the user's data as a compressed byte array of the json using Snappy - jedis.setex(getKey(RedisKeyType.DATA_UPDATE, user.uuid), - RedisKeyType.DATA_UPDATE.timeToLive, - plugin.getDataAdapter().toBytes(userData)); - - // Debug logging - plugin.debug("[" + user.username + "] Set " + RedisKeyType.DATA_UPDATE.name() - + " key to redis at: " + - new SimpleDateFormat("mm:ss.SSS").format(new Date())); - } - }); - } catch (Exception e) { - e.printStackTrace(); - } - return null; + public void setUserData(@NotNull User user, @NotNull DataSnapshot.Packed data) { + plugin.runAsync(() -> { + try (Jedis jedis = jedisPool.getResource()) { + jedis.setex( + getKey(RedisKeyType.DATA_UPDATE, user.getUuid(), clusterId), + RedisKeyType.DATA_UPDATE.getTimeToLive(), + data.asBytes(plugin) + ); + plugin.debug(String.format("[%s] Set %s key to redis at: %s", user.getUsername(), + RedisKeyType.DATA_UPDATE.name(), new SimpleDateFormat("mm:ss.SSS").format(new Date()))); + } catch (Throwable e) { + plugin.log(Level.SEVERE, "An exception occurred setting a user's server switch", e); + } + }); } + /** + * Set a user's server switch to the Redis server + * + * @param user the user to set the server switch for + * @return a future returning void when complete + */ public CompletableFuture setUserServerSwitch(@NotNull User user) { - return CompletableFuture.runAsync(() -> { + final CompletableFuture future = new CompletableFuture<>(); + plugin.runAsync(() -> { try (Jedis jedis = jedisPool.getResource()) { - jedis.setex(getKey(RedisKeyType.SERVER_SWITCH, user.uuid), - RedisKeyType.SERVER_SWITCH.timeToLive, new byte[0]); - plugin.debug("[" + user.username + "] Set " + RedisKeyType.SERVER_SWITCH.name() - + " key to redis at: " + - new SimpleDateFormat("mm:ss.SSS").format(new Date())); - } catch (Exception e) { - e.printStackTrace(); + jedis.setex( + getKey(RedisKeyType.SERVER_SWITCH, user.getUuid(), clusterId), + RedisKeyType.SERVER_SWITCH.getTimeToLive(), new byte[0] + ); + future.complete(null); + plugin.debug(String.format("[%s] Set %s key to redis at: %s", user.getUsername(), + RedisKeyType.SERVER_SWITCH.name(), new SimpleDateFormat("mm:ss.SSS").format(new Date()))); + } catch (Throwable e) { + plugin.log(Level.SEVERE, "An exception occurred setting a user's server switch", e); } }); + return future; } /** @@ -189,68 +226,65 @@ public class RedisManager extends JedisPubSub { * @param user The user to fetch data for * @return The user's data, if it's present on the database. Otherwise, an empty optional. */ - public CompletableFuture> getUserData(@NotNull User user) { - return CompletableFuture.supplyAsync(() -> { - try (Jedis jedis = jedisPool.getResource()) { - final byte[] key = getKey(RedisKeyType.DATA_UPDATE, user.uuid); - final byte[] dataByteArray = jedis.get(key); - if (dataByteArray == null) { - plugin.debug("[" + user.username + "] Could not read " + - RedisKeyType.DATA_UPDATE.name() + " key from redis at: " + - new SimpleDateFormat("mm:ss.SSS").format(new Date())); - return Optional.empty(); - } - plugin.debug("[" + user.username + "] Successfully read " - + RedisKeyType.DATA_UPDATE.name() + " key from redis at: " + - new SimpleDateFormat("mm:ss.SSS").format(new Date())); - - // Consume the key (delete from redis) - jedis.del(key); - - // Use Snappy to decompress the json - return Optional.of(plugin.getDataAdapter().fromBytes(dataByteArray)); - } catch (Exception e) { - e.printStackTrace(); + public Optional getUserData(@NotNull User user) { + try (Jedis jedis = jedisPool.getResource()) { + final byte[] key = getKey(RedisKeyType.DATA_UPDATE, user.getUuid(), clusterId); + final byte[] dataByteArray = jedis.get(key); + if (dataByteArray == null) { + plugin.debug("[" + user.getUsername() + "] Could not read " + + RedisKeyType.DATA_UPDATE.name() + " key from redis at: " + + new SimpleDateFormat("mm:ss.SSS").format(new Date())); return Optional.empty(); } - }); - } + plugin.debug("[" + user.getUsername() + "] Successfully read " + + RedisKeyType.DATA_UPDATE.name() + " key from redis at: " + + new SimpleDateFormat("mm:ss.SSS").format(new Date())); - public CompletableFuture getUserServerSwitch(@NotNull User user) { - return CompletableFuture.supplyAsync(() -> { - try (Jedis jedis = jedisPool.getResource()) { - final byte[] key = getKey(RedisKeyType.SERVER_SWITCH, user.uuid); - final byte[] readData = jedis.get(key); - if (readData == null) { - plugin.debug("[" + user.username + "] Could not read " + - RedisKeyType.SERVER_SWITCH.name() + " key from redis at: " + - new SimpleDateFormat("mm:ss.SSS").format(new Date())); - return false; - } - plugin.debug("[" + user.username + "] Successfully read " - + RedisKeyType.SERVER_SWITCH.name() + " key from redis at: " + - new SimpleDateFormat("mm:ss.SSS").format(new Date())); + // Consume the key (delete from redis) + jedis.del(key); + + // Use Snappy to decompress the json + return Optional.of(DataSnapshot.deserialize(plugin, dataByteArray)); + } catch (Throwable e) { + plugin.log(Level.SEVERE, "An exception occurred fetching a user's data from redis", e); + return Optional.empty(); + } + } - // Consume the key (delete from redis) - jedis.del(key); - return true; - } catch (Exception e) { - e.printStackTrace(); + public boolean getUserServerSwitch(@NotNull User user) { + try (Jedis jedis = jedisPool.getResource()) { + final byte[] key = getKey(RedisKeyType.SERVER_SWITCH, user.getUuid(), clusterId); + final byte[] readData = jedis.get(key); + if (readData == null) { + plugin.debug("[" + user.getUsername() + "] Could not read " + + RedisKeyType.SERVER_SWITCH.name() + " key from redis at: " + + new SimpleDateFormat("mm:ss.SSS").format(new Date())); return false; } - }); + plugin.debug("[" + user.getUsername() + "] Successfully read " + + RedisKeyType.SERVER_SWITCH.name() + " key from redis at: " + + new SimpleDateFormat("mm:ss.SSS").format(new Date())); + + // Consume the key (delete from redis) + jedis.del(key); + return true; + } catch (Throwable e) { + plugin.log(Level.SEVERE, "An exception occurred fetching a user's server switch from redis", e); + return false; + } } - public void close() { + public void terminate() { if (jedisPool != null) { if (!jedisPool.isClosed()) { jedisPool.close(); } } + this.unsubscribe(); } - private static byte[] getKey(@NotNull RedisKeyType keyType, @NotNull UUID uuid) { - return (keyType.getKeyPrefix() + ":" + uuid).getBytes(StandardCharsets.UTF_8); + private static byte[] getKey(@NotNull RedisKeyType keyType, @NotNull UUID uuid, @NotNull String clusterId) { + return String.format("%s:%s", keyType.getKeyPrefix(clusterId), uuid).getBytes(StandardCharsets.UTF_8); } } diff --git a/common/src/main/java/net/william278/husksync/redis/RedisMessage.java b/common/src/main/java/net/william278/husksync/redis/RedisMessage.java index 54cccb6a..da9275e6 100644 --- a/common/src/main/java/net/william278/husksync/redis/RedisMessage.java +++ b/common/src/main/java/net/william278/husksync/redis/RedisMessage.java @@ -19,34 +19,62 @@ package net.william278.husksync.redis; -import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; +import com.google.gson.annotations.SerializedName; +import net.william278.husksync.HuskSync; +import net.william278.husksync.adapter.Adaptable; import org.jetbrains.annotations.NotNull; import java.util.UUID; -import java.util.concurrent.CompletableFuture; -public class RedisMessage { +public class RedisMessage implements Adaptable { - public UUID targetUserUuid; - public byte[] data; + @SerializedName("target_uuid") + private UUID targetUuid; + @SerializedName("payload") + private byte[] payload; - public RedisMessage(@NotNull UUID targetUserUuid, byte[] message) { - this.targetUserUuid = targetUserUuid; - this.data = message; + private RedisMessage(@NotNull UUID targetUuid, byte[] message) { + this.setTargetUuid(targetUuid); + this.setPayload(message); } + @SuppressWarnings("unused") public RedisMessage() { } - public void dispatch(@NotNull RedisManager redisManager, @NotNull RedisMessageType type) { - CompletableFuture.runAsync(() -> redisManager.sendMessage(type.getMessageChannel(), - new GsonBuilder().create().toJson(this))); + @NotNull + public static RedisMessage create(@NotNull UUID targetUuid, byte[] message) { + return new RedisMessage(targetUuid, message); + } + + @NotNull + public static RedisMessage fromJson(@NotNull HuskSync plugin, @NotNull String json) throws JsonSyntaxException { + return plugin.getGson().fromJson(json, RedisMessage.class); + } + + public void dispatch(@NotNull HuskSync plugin, @NotNull RedisMessageType type) { + plugin.runAsync(() -> plugin.getRedisManager().sendMessage( + type.getMessageChannel(plugin.getSettings().getClusterId()), + plugin.getGson().toJson(this) + )); } @NotNull - public static RedisMessage fromJson(@NotNull String json) throws JsonSyntaxException { - return new GsonBuilder().create().fromJson(json, RedisMessage.class); + public UUID getTargetUuid() { + return targetUuid; + } + + public void setTargetUuid(@NotNull UUID targetUuid) { + this.targetUuid = targetUuid; + } + + public byte[] getPayload() { + return payload; + } + + public void setPayload(byte[] payload) { + this.payload = payload; } } \ No newline at end of file diff --git a/common/src/main/java/net/william278/husksync/redis/RedisMessageType.java b/common/src/main/java/net/william278/husksync/redis/RedisMessageType.java index a8ba7b2e..7153aa3c 100644 --- a/common/src/main/java/net/william278/husksync/redis/RedisMessageType.java +++ b/common/src/main/java/net/william278/husksync/redis/RedisMessageType.java @@ -27,17 +27,24 @@ import java.util.Optional; public enum RedisMessageType { - UPDATE_USER_DATA; + UPDATE_USER_DATA, + REQUEST_USER_DATA, + RETURN_USER_DATA; @NotNull - public String getMessageChannel() { - return RedisManager.KEY_NAMESPACE.toLowerCase(Locale.ENGLISH) + ":" + RedisManager.clusterId.toLowerCase(Locale.ENGLISH) - + ":" + name().toLowerCase(Locale.ENGLISH); + public String getMessageChannel(@NotNull String clusterId) { + return String.format( + "%s:%s:%s", + RedisManager.KEY_NAMESPACE.toLowerCase(Locale.ENGLISH), + clusterId.toLowerCase(Locale.ENGLISH), + name().toLowerCase(Locale.ENGLISH) + ); } - public static Optional getTypeFromChannel(@NotNull String messageChannel) { - return Arrays.stream(values()).filter(messageType -> messageType.getMessageChannel() - .equalsIgnoreCase(messageChannel)).findFirst(); + public static Optional getTypeFromChannel(@NotNull String channel, @NotNull String clusterId) { + return Arrays.stream(values()) + .filter(messageType -> messageType.getMessageChannel(clusterId).equalsIgnoreCase(channel)) + .findFirst(); } } \ No newline at end of file diff --git a/common/src/main/java/net/william278/husksync/HuskSyncInitializationException.java b/common/src/main/java/net/william278/husksync/user/CommandUser.java similarity index 59% rename from common/src/main/java/net/william278/husksync/HuskSyncInitializationException.java rename to common/src/main/java/net/william278/husksync/user/CommandUser.java index de75a0e4..c4db8540 100644 --- a/common/src/main/java/net/william278/husksync/HuskSyncInitializationException.java +++ b/common/src/main/java/net/william278/husksync/user/CommandUser.java @@ -17,15 +17,26 @@ * limitations under the License. */ -package net.william278.husksync; +package net.william278.husksync.user; +import de.themoep.minedown.adventure.MineDown; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; import org.jetbrains.annotations.NotNull; -/** - * Indicates an exception occurred while initializing the HuskSync plugin - */ -public class HuskSyncInitializationException extends IllegalStateException { - public HuskSyncInitializationException(@NotNull String message) { - super(message); +public interface CommandUser { + + @NotNull + Audience getAudience(); + + boolean hasPermission(@NotNull String permission); + + default void sendMessage(@NotNull Component component) { + getAudience().sendMessage(component); } + + default void sendMessage(@NotNull MineDown mineDown) { + this.sendMessage(mineDown.toComponent()); + } + } diff --git a/common/src/main/java/net/william278/husksync/data/PotionEffectData.java b/common/src/main/java/net/william278/husksync/user/ConsoleUser.java similarity index 62% rename from common/src/main/java/net/william278/husksync/data/PotionEffectData.java rename to common/src/main/java/net/william278/husksync/user/ConsoleUser.java index afe1d599..fe89c93b 100644 --- a/common/src/main/java/net/william278/husksync/data/PotionEffectData.java +++ b/common/src/main/java/net/william278/husksync/user/ConsoleUser.java @@ -17,25 +17,28 @@ * limitations under the License. */ -package net.william278.husksync.data; +package net.william278.husksync.user; -import com.google.gson.annotations.SerializedName; +import net.kyori.adventure.audience.Audience; import org.jetbrains.annotations.NotNull; -/** - * Stores potion effect data - */ -public class PotionEffectData { +public final class ConsoleUser implements CommandUser { - @SerializedName("serialized_potion_effects") - public String serializedPotionEffects; + @NotNull + private final Audience audience; - public PotionEffectData(@NotNull final String serializedPotionEffects) { - this.serializedPotionEffects = serializedPotionEffects; + public ConsoleUser(@NotNull Audience console) { + this.audience = console; } - @SuppressWarnings("unused") - protected PotionEffectData() { + @Override + @NotNull + public Audience getAudience() { + return audience; } + @Override + public boolean hasPermission(@NotNull String permission) { + return true; + } } diff --git a/common/src/main/java/net/william278/husksync/user/OnlineUser.java b/common/src/main/java/net/william278/husksync/user/OnlineUser.java new file mode 100644 index 00000000..4f28de4c --- /dev/null +++ b/common/src/main/java/net/william278/husksync/user/OnlineUser.java @@ -0,0 +1,188 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.user; + +import de.themoep.minedown.adventure.MineDown; +import de.themoep.minedown.adventure.MineDownParser; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.data.Identifier; +import net.william278.husksync.data.UserDataHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +/** + * Represents a logged-in {@link User} + */ +public abstract class OnlineUser extends User implements CommandUser, UserDataHolder { + + public OnlineUser(@NotNull UUID uuid, @NotNull String username) { + super(uuid, username); + } + + /** + * Indicates if the player has gone offline + * + * @return {@code true} if the player has left the server; {@code false} otherwise + */ + public abstract boolean isOffline(); + + /** + * Get the player's adventure {@link Audience} + * + * @return the player's {@link Audience} + */ + @NotNull + public abstract Audience getAudience(); + + /** + * Send a message to this player + * + * @param component the {@link Component} message to send + */ + public void sendMessage(@NotNull Component component) { + getAudience().sendMessage(component); + } + + /** + * Dispatch a MineDown-formatted message to this player + * + * @param mineDown the parsed {@link MineDown} to send + */ + public void sendMessage(@NotNull MineDown mineDown) { + sendMessage(mineDown + .disable(MineDownParser.Option.SIMPLE_FORMATTING) + .replace().toComponent()); + } + + /** + * Dispatch a MineDown-formatted action bar message to this player + * + * @param mineDown the parsed {@link MineDown} to send + */ + public void sendActionBar(@NotNull MineDown mineDown) { + getAudience().sendActionBar(mineDown + .disable(MineDownParser.Option.SIMPLE_FORMATTING) + .replace().toComponent()); + } + + /** + * Dispatch a toast message to this player + * + * @param title the title of the toast + * @param description the description of the toast + * @param iconMaterial the namespace-keyed material to use as an hasIcon of the toast + * @param backgroundType the background ("ToastType") of the toast + */ + public abstract void sendToast(@NotNull MineDown title, @NotNull MineDown description, + @NotNull String iconMaterial, @NotNull String backgroundType); + + /** + * Show a GUI chest menu to the user + * + * @param items the items to fill the menu with + * @param title the title of the menu + * @param editable whether the menu is editable (items can be removed or added) + * @param size the size of the menu + * @param onClose the action to perform when the menu is closed + */ + public abstract void showGui(@NotNull Data.Items.Items items, @NotNull MineDown title, boolean editable, int size, + @NotNull Consumer onClose); + + /** + * Returns if the player has the permission node + * + * @param node The permission node string + * @return {@code true} if the player has permission node; {@code false} otherwise + */ + public abstract boolean hasPermission(@NotNull String node); + + + /** + * Set a player's status from a {@link DataSnapshot} + * + * @param snapshot The {@link DataSnapshot} to set the player's status from + */ + public void applySnapshot(@NotNull DataSnapshot.Packed snapshot, @NotNull DataSnapshot.UpdateCause cause) { + getPlugin().fireEvent(getPlugin().getPreSyncEvent(this, snapshot), (event) -> { + if (!isOffline()) { + UserDataHolder.super.applySnapshot( + event.getData(), (owner) -> completeSync(true, cause, getPlugin()) + ); + } + }); + } + + /** + * Handle a player's synchronization completion + * + * @param succeeded Whether the synchronization succeeded + * @param plugin The plugin instance + */ + public void completeSync(boolean succeeded, @NotNull DataSnapshot.UpdateCause cause, @NotNull HuskSync plugin) { + if (succeeded) { + switch (plugin.getSettings().getNotificationDisplaySlot()) { + case CHAT -> cause.getCompletedLocale(plugin).ifPresent(this::sendMessage); + case ACTION_BAR -> cause.getCompletedLocale(plugin).ifPresent(this::sendActionBar); + case TOAST -> cause.getCompletedLocale(plugin) + .ifPresent(locale -> this.sendToast( + locale, new MineDown(""), + "minecraft:bell", + "TASK" + )); + } + plugin.fireEvent( + plugin.getSyncCompleteEvent(this), + (event) -> plugin.getLockedPlayers().remove(getUuid()) + ); + } else { + cause.getFailedLocale(plugin).ifPresent(this::sendMessage); + } + + // Ensure the user is in the database + plugin.getDatabase().ensureUser(this); + } + + @NotNull + @Override + public Map getCustomDataStore() { + return getPlugin().getPlayerCustomDataStore(this); + } + + /** + * Get if the player is locked + * + * @return the player's locked status + */ + public abstract boolean isLocked(); + + /** + * Get if the player is a NPC + * + * @return if the player is a NPC with metadata + */ + public abstract boolean isNpc(); +} diff --git a/common/src/main/java/net/william278/husksync/player/User.java b/common/src/main/java/net/william278/husksync/user/User.java similarity index 72% rename from common/src/main/java/net/william278/husksync/player/User.java rename to common/src/main/java/net/william278/husksync/user/User.java index aea20411..19c4bbc1 100644 --- a/common/src/main/java/net/william278/husksync/player/User.java +++ b/common/src/main/java/net/william278/husksync/user/User.java @@ -17,37 +17,48 @@ * limitations under the License. */ -package net.william278.husksync.player; +package net.william278.husksync.user; import org.jetbrains.annotations.NotNull; import java.util.UUID; /** - * Represents a user who has their data synchronised by HuskSync + * Represents a user who has their data synchronized by HuskSync */ public class User { - /** - * The user's unique account ID - */ - public final UUID uuid; + private final UUID uuid; - /** - * The user's username - */ - public final String username; + private final String username; public User(@NotNull UUID uuid, @NotNull String username) { this.username = username; this.uuid = uuid; } + /** + * Get the user's unique account ID + */ + @NotNull + public UUID getUuid() { + return uuid; + } + + /** + * Get the user's username + */ + @NotNull + public String getUsername() { + return username; + } + @Override public boolean equals(Object object) { if (object instanceof User other) { - return this.uuid.equals(other.uuid); + return this.getUuid().equals(other.getUuid()); } return super.equals(object); } + } diff --git a/common/src/main/java/net/william278/husksync/util/DataDumper.java b/common/src/main/java/net/william278/husksync/util/DataDumper.java index 31975a98..44ee1092 100644 --- a/common/src/main/java/net/william278/husksync/util/DataDumper.java +++ b/common/src/main/java/net/william278/husksync/util/DataDumper.java @@ -22,8 +22,8 @@ package net.william278.husksync.util; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import net.william278.husksync.HuskSync; -import net.william278.husksync.data.UserDataSnapshot; -import net.william278.husksync.player.User; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.User; import org.jetbrains.annotations.NotNull; import java.io.*; @@ -31,38 +31,37 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; import java.util.Locale; import java.util.StringJoiner; import java.util.logging.Level; /** - * Utility class for dumping {@link UserDataSnapshot}s to a file or as a paste on the web + * Utility class for dumping {@link DataSnapshot}s to a file or as a paste on the web */ public class DataDumper { private static final String LOGS_SITE_ENDPOINT = "https://api.mclo.gs/1/log"; private final HuskSync plugin; - private final UserDataSnapshot dataSnapshot; + private final DataSnapshot.Packed snapshot; private final User user; - private DataDumper(@NotNull UserDataSnapshot dataSnapshot, - @NotNull User user, @NotNull HuskSync implementor) { - this.dataSnapshot = dataSnapshot; + private DataDumper(@NotNull DataSnapshot.Packed snapshot, @NotNull User user, @NotNull HuskSync implementor) { + this.snapshot = snapshot; this.user = user; this.plugin = implementor; } /** - * Create a {@link DataDumper} of the given {@link UserDataSnapshot} + * Create a {@link DataDumper} of the given {@link DataSnapshot} * - * @param dataSnapshot The {@link UserDataSnapshot} to dump + * @param dataSnapshot The {@link DataSnapshot} to dump * @param user The {@link User} whose data is being dumped * @param plugin The implementing {@link HuskSync} plugin - * @return A {@link DataDumper} for the given {@link UserDataSnapshot} + * @return A {@link DataDumper} for the given {@link DataSnapshot} */ - public static DataDumper create(@NotNull UserDataSnapshot dataSnapshot, + public static DataDumper create(@NotNull DataSnapshot.Packed dataSnapshot, @NotNull User user, @NotNull HuskSync plugin) { return new DataDumper(dataSnapshot, user, plugin); } @@ -75,7 +74,7 @@ public class DataDumper { @Override @NotNull public String toString() { - return plugin.getDataAdapter().toJson(dataSnapshot.userData(), true); + return snapshot.asJson(plugin); } @NotNull @@ -128,7 +127,7 @@ public class DataDumper { } /** - * Dump the {@link UserDataSnapshot} to a file and return the file name + * Dump the {@link DataSnapshot} to a file and return the file name * * @return the relative path of the file the data was dumped to */ @@ -182,11 +181,11 @@ public class DataDumper { @NotNull private String getFileName() { return new StringJoiner("_") - .add(user.username) - .add(new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(dataSnapshot.versionTimestamp())) - .add(dataSnapshot.cause().name().toLowerCase(Locale.ENGLISH)) - .add(dataSnapshot.versionUUID().toString().split("-")[0]) - + ".json"; + .add(user.getUsername()) + .add(snapshot.getTimestamp().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"))) + .add(snapshot.getSaveCause().name().toLowerCase(Locale.ENGLISH)) + .add(snapshot.getShortId()) + + ".json"; } } diff --git a/common/src/main/java/net/william278/husksync/util/DataSnapshotList.java b/common/src/main/java/net/william278/husksync/util/DataSnapshotList.java index 6af99bcf..aecc1706 100644 --- a/common/src/main/java/net/william278/husksync/util/DataSnapshotList.java +++ b/common/src/main/java/net/william278/husksync/util/DataSnapshotList.java @@ -19,19 +19,19 @@ package net.william278.husksync.util; -import net.william278.husksync.config.Locales; -import net.william278.husksync.data.UserDataSnapshot; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.player.User; +import net.william278.husksync.HuskSync; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.CommandUser; +import net.william278.husksync.user.User; import net.william278.paginedown.PaginatedList; import org.jetbrains.annotations.NotNull; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** - * Represents a chat-viewable paginated list of {@link UserDataSnapshot}s + * Represents a chat-viewable paginated list of {@link net.william278.husksync.data.DataSnapshot}s */ public class DataSnapshotList { @@ -41,46 +41,52 @@ public class DataSnapshotList { @NotNull private final PaginatedList paginatedList; - private DataSnapshotList(@NotNull List snapshots, @NotNull User dataOwner, - @NotNull Locales locales) { + private DataSnapshotList(@NotNull List snapshots, @NotNull User dataOwner, + @NotNull HuskSync plugin) { final AtomicInteger snapshotNumber = new AtomicInteger(1); this.paginatedList = PaginatedList.of(snapshots.stream() - .map(snapshot -> locales.getRawLocale("data_list_item", + .map(snapshot -> plugin.getLocales() + .getRawLocale("data_list_item", getNumberIcon(snapshotNumber.getAndIncrement()), - new SimpleDateFormat("MMM dd yyyy, HH:mm:ss.sss") - .format(snapshot.versionTimestamp()), - snapshot.versionUUID().toString().split("-")[0], - snapshot.versionUUID().toString(), - snapshot.cause().getDisplayName(), - dataOwner.username, - snapshot.pinned() ? "※" : " ") - .orElse("• " + snapshot.versionUUID())).toList(), - locales.getBaseChatList(6) - .setHeaderFormat(locales.getRawLocale("data_list_title", dataOwner.username, + dataOwner.getUsername(), + snapshot.getId().toString(), + snapshot.getShortId(), + snapshot.isPinned() ? "※" : " ", + snapshot.getTimestamp().format(DateTimeFormatter + .ofPattern("dd/MM/yyyy, HH:mm")), + snapshot.getTimestamp().format(DateTimeFormatter + .ofPattern("MMM dd yyyy, HH:mm:ss.SSS")), + snapshot.getSaveCause().getDisplayName(), + String.format("%.2fKiB", snapshot.getFileSize(plugin) / 1024f)) + .orElse("• " + snapshot.getId())).toList(), + plugin.getLocales().getBaseChatList(6) + .setHeaderFormat(plugin.getLocales() + .getRawLocale("data_list_title", dataOwner.getUsername(), "%first_item_on_page_index%", "%last_item_on_page_index%", "%total_items%") .orElse("")) - .setCommand("/husksync:userdata list " + dataOwner.username) + .setCommand("/husksync:userdata list " + dataOwner.getUsername()) .build()); } /** - * Create a new {@link DataSnapshotList} from a list of {@link UserDataSnapshot}s + * Create a new {@link DataSnapshotList} from a list of {@link DataSnapshot}s * - * @param snapshots The list of {@link UserDataSnapshot}s to display - * @param user The {@link User} who owns the {@link UserDataSnapshot}s - * @param locales The {@link Locales} instance - * @return A new {@link DataSnapshotList}, to be viewed with {@link #displayPage(OnlineUser, int)} + * @param snapshots The list of {@link DataSnapshot}s to display + * @param user The {@link User} who owns the {@link DataSnapshot}s + * @param plugin The instance of the plugin + * @return A new {@link DataSnapshotList}, to be viewed with {@link #displayPage(CommandUser, int)} */ - public static DataSnapshotList create(@NotNull List snapshots, @NotNull User user, - @NotNull Locales locales) { - return new DataSnapshotList(snapshots, user, locales); + @NotNull + public static DataSnapshotList create(@NotNull List snapshots, @NotNull User user, + @NotNull HuskSync plugin) { + return new DataSnapshotList(snapshots, user, plugin); } /** - * Get an icon for the given snapshot number, via {@link #CIRCLED_NUMBER_ICONS} + * Get an hasIcon for the given snapshot number, via {@link #CIRCLED_NUMBER_ICONS} * * @param number the snapshot number - * @return the icon for the given snapshot number + * @return the hasIcon for the given snapshot number */ private static String getNumberIcon(int number) { if (number < 1 || number > 20) { @@ -90,12 +96,12 @@ public class DataSnapshotList { } /** - * Display a page of the list of {@link UserDataSnapshot} to the user + * Display a page of the list of {@link DataSnapshot} to the user * * @param onlineUser The online user to display the message to * @param page The page number to display */ - public void displayPage(@NotNull OnlineUser onlineUser, int page) { + public void displayPage(@NotNull CommandUser onlineUser, int page) { onlineUser.sendMessage(paginatedList.getNearestValidPage(page)); } diff --git a/common/src/main/java/net/william278/husksync/util/DataSnapshotOverview.java b/common/src/main/java/net/william278/husksync/util/DataSnapshotOverview.java new file mode 100644 index 00000000..b82c520d --- /dev/null +++ b/common/src/main/java/net/william278/husksync/util/DataSnapshotOverview.java @@ -0,0 +1,135 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.util; + +import net.william278.husksync.HuskSync; +import net.william278.husksync.config.Locales; +import net.william278.husksync.data.Data; +import net.william278.husksync.data.DataSnapshot; +import net.william278.husksync.user.CommandUser; +import net.william278.husksync.user.User; +import org.jetbrains.annotations.NotNull; + +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.StringJoiner; + +public class DataSnapshotOverview { + + private final HuskSync plugin; + private final User dataOwner; + private final DataSnapshot.Unpacked snapshot; + private final long snapshotSize; + + private DataSnapshotOverview(@NotNull DataSnapshot.Unpacked snapshot, long snapshotSize, + @NotNull User dataOwner, @NotNull HuskSync plugin) { + this.snapshot = snapshot; + this.snapshotSize = snapshotSize; + this.dataOwner = dataOwner; + this.plugin = plugin; + } + + @NotNull + public static DataSnapshotOverview of(@NotNull DataSnapshot.Unpacked snapshot, long snapshotSize, + @NotNull User dataOwner, @NotNull HuskSync plugin) { + return new DataSnapshotOverview(snapshot, snapshotSize, dataOwner, plugin); + } + + public void show(@NotNull CommandUser user) { + // Title message, timestamp, owner and cause. + final Locales locales = plugin.getLocales(); + locales.getLocale("data_manager_title", snapshot.getShortId(), snapshot.getId().toString(), + dataOwner.getUsername(), dataOwner.getUuid().toString()) + .ifPresent(user::sendMessage); + locales.getLocale("data_manager_timestamp", + snapshot.getTimestamp().format(DateTimeFormatter.ofPattern("MMM dd yyyy, HH:mm:ss.SSS")), + snapshot.getTimestamp().toString()) + .ifPresent(user::sendMessage); + if (snapshot.isPinned()) { + locales.getLocale("data_manager_pinned") + .ifPresent(user::sendMessage); + } + locales.getLocale("data_manager_cause", snapshot.getSaveCause().getDisplayName()) + .ifPresent(user::sendMessage); + + // User status data, if present in the snapshot + final Optional health = snapshot.getHealth(); + final Optional food = snapshot.getHunger(); + final Optional experience = snapshot.getExperience(); + final Optional gameMode = snapshot.getGameMode(); + if (health.isPresent() && food.isPresent() && experience.isPresent() && gameMode.isPresent()) { + locales.getLocale("data_manager_status", + Integer.toString((int) health.get().getHealth()), + Integer.toString((int) health.get().getMaxHealth()), + Integer.toString(food.get().getFoodLevel()), + Integer.toString(experience.get().getExpLevel()), + gameMode.get().getGameMode().toLowerCase(Locale.ENGLISH)) + .ifPresent(user::sendMessage); + } + + // Snapshot size + locales.getLocale("data_manager_size", String.format("%.2fKiB", snapshotSize / 1024f)) + .ifPresent(user::sendMessage); + + // Advancement and statistic data, if both are present in the snapshot + snapshot.getAdvancements() + .flatMap(advancementData -> snapshot.getStatistics() + .flatMap(statisticsData -> locales.getLocale("data_manager_advancements_statistics", + Integer.toString(advancementData.getCompletedExcludingRecipes().size()), + generateAdvancementPreview(advancementData.getCompletedExcludingRecipes(), locales), + String.format("%.2f", (((statisticsData.getGenericStatistics().getOrDefault( + "minecraft:play_one_minute", 0)) / 20d) / 60d) / 60d)))) + .ifPresent(user::sendMessage); + + if (user.hasPermission("husksync.command.inventory.edit") + && user.hasPermission("husksync.command.enderchest.edit")) { + locales.getLocale("data_manager_item_buttons", dataOwner.getUsername(), snapshot.getId().toString()) + .ifPresent(user::sendMessage); + } + locales.getLocale("data_manager_management_buttons", dataOwner.getUsername(), snapshot.getId().toString()) + .ifPresent(user::sendMessage); + if (user.hasPermission("husksync.command.userdata.dump")) { + locales.getLocale("data_manager_system_buttons", dataOwner.getUsername(), snapshot.getId().toString()) + .ifPresent(user::sendMessage); + } + } + + @NotNull + private String generateAdvancementPreview(@NotNull List advancementData, @NotNull Locales locales) { + final StringJoiner joiner = new StringJoiner("\n"); + final int PREVIEW_SIZE = 8; + for (int i = 0; i < advancementData.size(); i++) { + joiner.add(advancementData.get(i).getKey()); + if (i >= PREVIEW_SIZE) { + break; + } + } + final int remaining = advancementData.size() - PREVIEW_SIZE; + if (remaining > 0) { + joiner.add(locales.getRawLocale("data_manager_advancements_preview_remaining", + Integer.toString(remaining)) + .orElse(String.format("+%s…", remaining))); + } + return joiner.toString(); + } + +} diff --git a/common/src/main/java/net/william278/husksync/data/DataSerializationException.java b/common/src/main/java/net/william278/husksync/util/LegacyConverter.java similarity index 62% rename from common/src/main/java/net/william278/husksync/data/DataSerializationException.java rename to common/src/main/java/net/william278/husksync/util/LegacyConverter.java index 75474d5a..9702a0bb 100644 --- a/common/src/main/java/net/william278/husksync/data/DataSerializationException.java +++ b/common/src/main/java/net/william278/husksync/util/LegacyConverter.java @@ -17,18 +17,22 @@ * limitations under the License. */ -package net.william278.husksync.data; +package net.william278.husksync.util; +import net.william278.husksync.HuskSync; +import net.william278.husksync.adapter.DataAdapter; +import net.william278.husksync.data.DataSnapshot; import org.jetbrains.annotations.NotNull; -/** - * Indicates an error occurred during Base-64 serialization and deserialization of data. - *

- * For example, an exception deserializing {@link ItemData} item stack or {@link PotionEffectData} potion effect arrays - */ -public class DataSerializationException extends RuntimeException { - protected DataSerializationException(@NotNull String message, @NotNull Throwable cause) { - super(message, cause); +public abstract class LegacyConverter { + + protected final HuskSync plugin; + + protected LegacyConverter(@NotNull HuskSync plugin) { + this.plugin = plugin; } + @NotNull + public abstract DataSnapshot.Packed convert(@NotNull byte[] data) throws DataAdapter.AdaptionException; + } diff --git a/common/src/main/java/net/william278/husksync/util/Task.java b/common/src/main/java/net/william278/husksync/util/Task.java new file mode 100644 index 00000000..6daf6905 --- /dev/null +++ b/common/src/main/java/net/william278/husksync/util/Task.java @@ -0,0 +1,144 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.util; + +import net.william278.husksync.HuskSync; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +public interface Task extends Runnable { + + abstract class Base implements Task { + + protected final HuskSync plugin; + protected final Runnable runnable; + protected boolean cancelled = false; + + protected Base(@NotNull HuskSync plugin, @NotNull Runnable runnable) { + this.plugin = plugin; + this.runnable = runnable; + } + + public void cancel() { + cancelled = true; + } + + @NotNull + @Override + public HuskSync getPlugin() { + return plugin; + } + + } + + abstract class Async extends Base { + + protected long delayTicks; + + protected Async(@NotNull HuskSync plugin, @NotNull Runnable runnable, long delayTicks) { + super(plugin, runnable); + this.delayTicks = delayTicks; + } + + } + + abstract class Sync extends Base { + + protected long delayTicks; + + protected Sync(@NotNull HuskSync plugin, @NotNull Runnable runnable, long delayTicks) { + super(plugin, runnable); + this.delayTicks = delayTicks; + } + + } + + abstract class Repeating extends Base { + + protected final long repeatingTicks; + + protected Repeating(@NotNull HuskSync plugin, @NotNull Runnable runnable, long repeatingTicks) { + super(plugin, runnable); + this.repeatingTicks = repeatingTicks; + } + + } + + @SuppressWarnings("UnusedReturnValue") + interface Supplier { + + @NotNull + Task.Sync getSyncTask(@NotNull Runnable runnable, long delayTicks); + + @NotNull + Task.Async getAsyncTask(@NotNull Runnable runnable, long delayTicks); + + @NotNull + Task.Repeating getRepeatingTask(@NotNull Runnable runnable, long repeatingTicks); + + @NotNull + default Task.Sync runSyncDelayed(@NotNull Runnable runnable, long delayTicks) { + final Task.Sync task = getSyncTask(runnable, delayTicks); + task.run(); + return task; + } + + default Task.Async runAsyncDelayed(@NotNull Runnable runnable, long delayTicks) { + final Task.Async task = getAsyncTask(runnable, delayTicks); + task.run(); + return task; + } + + @NotNull + default Task.Sync runSync(@NotNull Runnable runnable) { + return runSyncDelayed(runnable, 0); + } + + @NotNull + default Task.Async runAsync(@NotNull Runnable runnable) { + final Task.Async task = getAsyncTask(runnable, 0); + task.run(); + return task; + } + + default CompletableFuture supplyAsync(@NotNull java.util.function.Supplier supplier) { + final CompletableFuture future = new CompletableFuture<>(); + runAsync(() -> { + try { + future.complete(supplier.get()); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }); + return future; + } + + void cancelTasks(); + + @NotNull + HuskSync getPlugin(); + + } + + @NotNull + HuskSync getPlugin(); + +} \ No newline at end of file diff --git a/common/src/main/resources/database/mysql_schema.sql b/common/src/main/resources/database/mysql_schema.sql index 3da68c3f..efef8797 100644 --- a/common/src/main/resources/database/mysql_schema.sql +++ b/common/src/main/resources/database/mysql_schema.sql @@ -1,3 +1,9 @@ +# Set the storage engine +SET DEFAULT_STORAGE_ENGINE = INNODB; + +# Enable foreign key constraints +SET FOREIGN_KEY_CHECKS = 1; + # Create the users table if it does not exist CREATE TABLE IF NOT EXISTS `%users_table%` ( @@ -5,7 +11,8 @@ CREATE TABLE IF NOT EXISTS `%users_table%` `username` varchar(16) NOT NULL, PRIMARY KEY (`uuid`) -); +) CHARACTER SET utf8 + COLLATE utf8_unicode_ci; # Create the user data table if it does not exist CREATE TABLE IF NOT EXISTS `%user_data_table%` @@ -18,4 +25,5 @@ CREATE TABLE IF NOT EXISTS `%user_data_table%` `data` longblob NOT NULL, PRIMARY KEY (`version_uuid`, `player_uuid`), FOREIGN KEY (`player_uuid`) REFERENCES `%users_table%` (`uuid`) ON DELETE CASCADE -); \ No newline at end of file +) CHARACTER SET utf8 + COLLATE utf8_unicode_ci; \ No newline at end of file diff --git a/common/src/main/resources/locales/bg-bg.yml b/common/src/main/resources/locales/bg-bg.yml index 162547f0..4bc4b394 100644 --- a/common/src/main/resources/locales/bg-bg.yml +++ b/common/src/main/resources/locales/bg-bg.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵ Данните синхронизирани!](#00fb9a)' -synchronisation_failed: '[⏵ Провалихме се да синхронизираме Вашите данни! Моля свържете се с администратор.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| Презаредихме конфигурацията и файловете със съобщения.](#00fb9a)' -error_invalid_syntax: '[Грешка:](#ff3300) [Неправилен синтаксис. Използвайте: %1%](#ff7e5e)' -error_invalid_player: '[Грешка:](#ff3300) [Не можахме да открием играч с това име.](#ff7e5e)' -error_no_permission: '[Грешка:](#ff3300) [Нямате право да използвате тази команда](#ff7e5e)' -error_console_command_only: '[Грешка:](#ff3300) [Тази команда може да бъде използвана единствено през конзолата](#ff7e5e)' -error_in_game_command_only: 'Грешка: Тази команда може да бъде използвана само от играта.' -error_no_data_to_display: '[Грешка:](#ff3300) [Не можахме да открием никакви данни за потребителя, които да покажем.](#ff7e5e)' -error_invalid_version_uuid: '[Грешка:](#ff3300) [Не можахме да открием никакви потребителски данни за тази версия на това UUID.](#ff7e5e)' +synchronization_complete: '[⏵ Данните синхронизирани!](#00fb9a)' +synchronization_failed: '[⏵ Провалихме се да синхронизираме Вашите данни! Моля свържете се с администратор.](#ff7e5e)' inventory_viewer_menu_title: '&0Инвентара на %1%' ender_chest_viewer_menu_title: '&0Ендър Сандъка на %1%' inventory_viewer_opened: '[Преглеждане снапшота на](#00fb9a) [%1%](#00fb9a bold) [ инвентар от ⌚ %2%](#00fb9a)' ender_chest_viewer_opened: '[Преглеждане снапшота на](#00fb9a) [%1%](#00fb9a bold) [ Ендър Сандък от ⌚ %2%](#00fb9a)' data_update_complete: '[🔔 Вашите данни бяха обновени!](#00fb9a)' data_update_failed: '[🔔 Провалихме се да обновим Вашите данни! Моля свържете се с администратор.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[Преглеждане потребителският снапшот](#00fb9a) [%1%](#00fb9a show_text=&7Версия на UUID:\n&8%2%) [за](#00fb9a) [%3%](#00fb9a bold show_text=&7UUID на Играча:\n&8%4%)[:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7Клеймо на Версията:\n&8Когато данните са били запазени)' data_manager_pinned: '[※ Закачен снапшот](#d8ff2b show_text=&7Закачен:\n&8Снапшота на този потребител няма да бъде автоматично завъртан.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Причина на Запазване:\n&8Какво е накарало данните да бъдат запазени)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Точки кръв) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Точки глад) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7Ниво опит) [🏹 %5%](dark_aqua show_text=&7Режим на игра)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Причина на Запазване:\n&8Какво е накарало данните да бъдат запазени)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Точки кръв) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Точки глад) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7Ниво опит) [🏹 %5%](dark_aqua show_text=&7Режим на игра)' data_manager_advancements_statistics: '[⭐ Напредъци: %1%](color=#ffc43b-#f5c962 show_text=&7Напредъци, в които имате прогрес:\n&8%2%) [⌛ Изиграно Време: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7Изиграно време в играта\n&8⚠ Базирано на статистики от играта)\n' data_manager_item_buttons: '[View:](gray) [[🪣 Инвентар…]](color=#a17b5f-#f5b98c show_text=&7Натиснете, за да прегледате run_command=/inventory %1% %2%) [[⌀ Ендър Сандък…]](#b649c4-#d254ff show_text=&7Натиснете, за да проверите run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Управление:](gray) [[❌ Изтрий…]](#ff3300 show_text=&7Натиснете, за да изтриете този снапшот от потребителски данни.\n&8Това няма да засегне текущите данни на потребителя.\n&#ff3300&⚠ Това не може да бъде отменено! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ Възстанови…]](#00fb9a show_text=&7Натиснете, за да възстановите тези потребителски данни.\n&8Това ще зададе данните на потребителя на този снапшот.\n&#ff3300&⚠ Текущите данни на %1% ще бъдат пренаписани! suggest_command=/husksync:userdata restore %1% %2%) [[※ Закачи/Откачи…]](#d8ff2b show_text=&7Натиснете, за да закачите или откачите този снапшот с потребителски данни\n&8Закачените снапшоти няма да бъдат автоматично завъртани run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[System:](gray) [[⏷ File Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to a file.\n&8Data dumps can be found in ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ Web Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to the mc-logs service\n&8You will be provided with a URL containing the data. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7и още %1%…' +data_manager_advancements_preview_remaining: 'и още %1%…' data_list_title: '[Лист от](#00fb9a) [снапшоти на данните на потребителя](#00fb9a) [%1%](#00fb9a bold show_text=&7UUID: %2%)\n' -data_list_item: '[%1%](gray show_text=&7Снапшот с данни %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7Закачен:\n&8Закачените снапшоти няма да бъдат автоматично завъртани. run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Клеймо на Версията:&7\n&8Когато данните са били запазени run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Версия на UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Причина на Запазване:\n&8Какво е накарало данните да бъдат запазени run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ Успешно изтрихме снапшота с потребителски данни](#00fb9a) [%1%](#00fb9a show_text=&7Версия на UUID:\n&8%2%) [за](#00fb9a) [%3%.](#00fb9a show_text=&7UUID на Играча:\n&8%4%)' data_restored: '[⏪ Успешно възстановихме](#00fb9a) [текущите потребителски данни за](#00fb9a) [%1%](#00fb9a show_text=&7UUID на Играча:\n&8%2%) [от снапшот](#00fb9a) [%3%.](#00fb9a show_text=&7Версия на UUID:\n&8%4%)' data_pinned: '[※ Успешно закачихме снапшота с потребителски данни](#00fb9a) [%1%](#00fb9a show_text=&7Версия на UUID:\n&8%2%) [за](#00fb9a) [%3%.](#00fb9a show_text=&7UUID на Играча:\n&8%4%)' @@ -38,4 +32,18 @@ list_page_jumpers: '(%1%)' list_page_jumper_button: '[%1%](show_text=&7Jump to page %1% run_command=%2% %1%)' list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' -list_page_jumper_group_separator: '…' \ No newline at end of file +list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| You are running the latest version of HuskSync (v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| A new version of HuskSync is available: v%1% (running: v%2%).](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| Презаредихме конфигурацията и файловете със съобщения.](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: '[Грешка:](#ff3300) [Неправилен синтаксис. Използвайте:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[Грешка:](#ff3300) [Не можахме да открием играч с това име.](#ff7e5e)' +error_no_permission: '[Грешка:](#ff3300) [Нямате право да използвате тази команда](#ff7e5e)' +error_console_command_only: '[Грешка:](#ff3300) [Тази команда може да бъде използвана единствено през конзолата](#ff7e5e)' +error_in_game_command_only: 'Грешка: Тази команда може да бъде използвана само от играта.' +error_no_data_to_display: '[Грешка:](#ff3300) [Не можахме да открием никакви данни за потребителя, които да покажем.](#ff7e5e)' +error_invalid_version_uuid: '[Грешка:](#ff3300) [Не можахме да открием никакви потребителски данни за тази версия на това UUID.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/de-de.yml b/common/src/main/resources/locales/de-de.yml index 0703c1a4..c642af66 100644 --- a/common/src/main/resources/locales/de-de.yml +++ b/common/src/main/resources/locales/de-de.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵ Daten synchronisiert!](#00fb9a)' -synchronisation_failed: '[⏵ Ein Fehler ist beim Synchronisieren deiner Daten aufgetreten! Bitte kontaktiere einen Administrator.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| Die Konfigurations- und Sprachdateien wurden neu geladen.](#00fb9a)' -error_invalid_syntax: '[Fehler:](#ff3300) [Falsche Syntax. Nutze: %1%](#ff7e5e)' -error_invalid_player: '[Fehler:](#ff3300) [Es konnte kein Spieler mit diesem Namen gefunden werden.](#ff7e5e)' -error_no_permission: '[Fehler:](#ff3300) [Du hast nicht die benötigten Berechtigungen um diesen Befehl auszuführen](#ff7e5e)' -error_console_command_only: '[Fehler:](#ff3300) [Dieser Befehl kann nur über die Konsole ausgeführt werden.](#ff7e5e)' -error_in_game_command_only: 'Fehler: Dieser Befehl kann nur im Spiel genutzt werden.' -error_no_data_to_display: '[Fehler:](#ff3300) [Es konnten keine Nutzerdaten zum Anzeigen gefunden werden.](#ff7e5e)' -error_invalid_version_uuid: '[Fehler:](#ff3300) [Es konnten keine Nutzerdaten für diese Versions-UUID gefunden werden.](#ff7e5e)' +synchronization_complete: '[⏵ Daten synchronisiert!](#00fb9a)' +synchronization_failed: '[⏵ Ein Fehler ist beim Synchronisieren deiner Daten aufgetreten! Bitte kontaktiere einen Administrator.](#ff7e5e)' inventory_viewer_menu_title: '&0Inventar von %1%' ender_chest_viewer_menu_title: '&0Endertruhe von %1%' inventory_viewer_opened: '[Du siehst den Schnappschuss des Inventares von](#00fb9a) [%1%](#00fb9a bold) [von ⌚ %2%](#00fb9a)' ender_chest_viewer_opened: '[Du siehst den Schnappschuss der Endertruhe von](#00fb9a) [%1%](#00fb9a bold) [von ⌚ %2%](#00fb9a)' data_update_complete: '[🔔 Deine Daten wurden aktualisiert!](#00fb9a)' data_update_failed: '[🔔 Ein Fehler ist beim Aktualisieren deiner Daten aufgetreten! Bitte kontaktiere einen Administrator.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[Du siehst den Nutzerdaten-Schnappschuss](#00fb9a) [%1%](#00fb9a show_text=&7Versions-UUID:\n&8%2%) [für %3%](#00fb9a bold show_text=&7Spieler-UUID:\n&8%4%)[:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7Versions-Zeitstempel:\n&8Zeitpunkt der Speicherung der Daten)' data_manager_pinned: '[※ Schnappschuss angeheftet](#d8ff2b show_text=&7Angeheftet:\n&8Dieser Nutzerdaten-Schnappschuss wird nicht automatisch rotiert.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Speicherungsgrund:\n&8Der Grund für das Speichern der Daten)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Lebenspunkte) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hungerpunkte) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP-Level) [🏹 %5%](dark_aqua show_text=&7Spielmodus)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Speicherungsgrund:\n&8Der Grund für das Speichern der Daten)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Lebenspunkte) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hungerpunkte) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP-Level) [🏹 %5%](dark_aqua show_text=&7Spielmodus)' data_manager_advancements_statistics: '[⭐ Erfolge: %1%](color=#ffc43b-#f5c962 show_text=&7Erfolge in denen du Fortschritt gemacht hast:\n&8%2%) [⌛ Spielzeit: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7Deine verbrachte Zeit im Spiel\n&8⚠ Basierend auf Spielstatistiken)\n' data_manager_item_buttons: '[Sehen:](gray) [[🪣 Inventar…]](color=#a17b5f-#f5b98c show_text=&7Klicke zum Ansehen run_command=/inventory %1% %2%) [[⌀ Endertruhe…]](#b649c4-#d254ff show_text=&7Klicke zum Ansehen run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Verwalten:](gray) [[❌ Löschen…]](#ff3300 show_text=&7Klicke, um diesen Nutzerdaten-Schnappschuss zu löschen.\n&8Dies betrifft nicht die aktuellen Nutzerdaten.\n&#ff3300&⚠ Dieser Schritt kann nicht rückgängig gemacht werden! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ Wiederherstellen…]](#00fb9a show_text=&7Klicke, um die Nutzerdaten wiederherzustellen.\n&8Dies wird die Nutzerdaten auf den Stand des Schnappschusses setzen.\n&#ff3300&⚠ Die aktuellen Nutzerdaten von %1% werden überschrieben! suggest_command=/husksync:userdata restore %1% %2%) [[※ Anheften/Loslösen…]](#d8ff2b show_text=&7Klicke, um diesen Nutzerdaten-Schnappschuss anzuheften oder loszulösen\n&8Angeheftete Nutzerdaten-Schnappschüsse werden nicht automatisch rotiert run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[System:](gray) [[⏷ Daten-Dump…]](dark_gray show_text=&7Klicke, um diesen rohen Nutzerdaten-Schnappschuss in eine Datei zu speichern.\n&8Daten-Dumps können unter ~/plugins/HuskSync/dumps/ gefunden werden. run_command=/husksync:userdata dump %1% %2% file) [[☂ Web-Dump…]](dark_gray show_text=&7Klicke, um diesen rohen Nutzerdaten-Schnappschuss auf den mc-logs Service hochzuladen.\n&8Du erhältst dann eine URL, die die Daten enthält. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7und %1% weitere…' +data_manager_advancements_preview_remaining: 'und %1% weitere…' data_list_title: '[Nutzerdaten-Schnappschüsse von %1%:](#00fb9a) [(%2%-%3% von](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7Daten-Schnappschuss %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7Angeheftet:\n&8Angeheftete Schnappschüsse werden nicht automatisch rotiert. run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Versions-Zeitstempel:&7\n&8Zeitpunkt der Speicherung der Daten run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Versions-UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Speicherungsgrund:\n&8Der Grund für das Speichern der Daten run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ Nutzerdaten-Schnappschuss erfolgreich gelöscht](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [für](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' data_restored: '[⏪ Erfgreich wiederhergestellt](#00fb9a) [Aktuelle Nutzerdaten des Schnappschusses von %1%](#00fb9a show_text=&7Spieler-UUID:\n&8%2%) [%3%.](#00fb9a show_text=&7Versions-UUID:\n&8%4%)' data_pinned: '[※ Nutzerdaten-Schnappschuss erfolgreich angepinnt](#00fb9a) [%1%](#00fb9a show_text=&7Versions-UUID:\n&8%2%) [für](#00fb9a) [%3%.](#00fb9a show_text=&7Spieler-UUID:\n&8%4%)' @@ -39,3 +33,17 @@ list_page_jumper_button: '[%1%](show_text=&7Springe zu Seite %1% run_command=%2% list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' list_page_jumper_group_separator: '…' +reload_complete: '[HuskSync](#00fb9a bold) [| Die Konfigurations- und Sprachdateien wurden neu geladen.](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +up_to_date: '[HuskSync](#00fb9a bold) [| You are running the latest version of HuskSync (v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| A new version of HuskSync is available: v%1% (running: v%2%).](#ff7e5e)' +error_invalid_syntax: '[Fehler:](#ff3300) [Falsche Syntax. Nutze:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[Fehler:](#ff3300) [Es konnte kein Spieler mit diesem Namen gefunden werden.](#ff7e5e)' +error_no_permission: '[Fehler:](#ff3300) [Du hast nicht die benötigten Berechtigungen um diesen Befehl auszuführen](#ff7e5e)' +error_console_command_only: '[Fehler:](#ff3300) [Dieser Befehl kann nur über die Konsole ausgeführt werden.](#ff7e5e)' +error_in_game_command_only: 'Fehler: Dieser Befehl kann nur im Spiel genutzt werden.' +error_no_data_to_display: '[Fehler:](#ff3300) [Es konnten keine Nutzerdaten zum Anzeigen gefunden werden.](#ff7e5e)' +error_invalid_version_uuid: '[Fehler:](#ff3300) [Es konnten keine Nutzerdaten für diese Versions-UUID gefunden werden.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/en-gb.yml b/common/src/main/resources/locales/en-gb.yml index bb2453b9..9b21a1bd 100644 --- a/common/src/main/resources/locales/en-gb.yml +++ b/common/src/main/resources/locales/en-gb.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵ Data synchronised!](#00fb9a)' -synchronisation_failed: '[⏵ Failed to synchronise your data! Please contact an administrator.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| Reloaded config and message files.](#00fb9a)' -error_invalid_syntax: '[Error:](#ff3300) [Incorrect syntax. Usage: %1%](#ff7e5e)' -error_invalid_player: '[Error:](#ff3300) [Could not find a player by that name.](#ff7e5e)' -error_no_permission: '[Error:](#ff3300) [You do not have permission to execute this command](#ff7e5e)' -error_console_command_only: '[Error:](#ff3300) [That command can only be run through console](#ff7e5e)' -error_in_game_command_only: 'Error: That command can only be used in-game.' -error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to display.](#ff7e5e)' -error_invalid_version_uuid: '[Error:](#ff3300) [Could not find any user data for that version UUID.](#ff7e5e)' +synchronization_complete: '[⏵ Data synchronized!](#00fb9a)' +synchronization_failed: '[⏵ Failed to synchronize your data! Please contact an administrator.](#ff7e5e)' inventory_viewer_menu_title: '&0%1%''s Inventory' ender_chest_viewer_menu_title: '&0%1%''s Ender Chest' inventory_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold)[''s inventory as of ⌚ %2%](#00fb9a)' ender_chest_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold)[''s Ender Chest as of ⌚ %2%](#00fb9a)' data_update_complete: '[🔔 Your data has been updated!](#00fb9a)' data_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[Viewing user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7Version timestamp:\n&8When the data was saved)' data_manager_pinned: '[※ Snapshot pinned](#d8ff2b show_text=&7Pinned:\n&8This user data snapshot won''t be automatically rotated.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Health points) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hunger points) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Health points) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hunger points) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)' data_manager_advancements_statistics: '[⭐ Advancements: %1%](color=#ffc43b-#f5c962 show_text=&7Advancements you have progress in:\n&8%2%) [⌛ Play Time: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7In-game play time\n&8⚠ Based on in-game statistics)\n' data_manager_item_buttons: '[View:](gray) [[🪣 Inventory…]](color=#a17b5f-#f5b98c show_text=&7Click to view run_command=/inventory %1% %2%) [[⌀ Ender Chest…]](#b649c4-#d254ff show_text=&7Click to view run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Manage:](gray) [[❌ Delete…]](#ff3300 show_text=&7Click to delete this snapshot of user data.\n&8This will not affect the user''s current data.\n&#ff3300&⚠ This cannot be undone! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ Restore…]](#00fb9a show_text=&7Click to restore this user data.\n&8This will set the user''s data to this snapshot.\n&#ff3300&⚠ %1%''s current data will be overwritten! suggest_command=/husksync:userdata restore %1% %2%) [[※ Pin/Unpin…]](#d8ff2b show_text=&7Click to pin or unpin this user data snapshot\n&8Pinned snapshots won''t be automatically rotated run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[System:](gray) [[⏷ File Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to a file.\n&8Data dumps can be found in ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ Web Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to the mc-logs service\n&8You will be provided with a URL containing the data. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7and %1% more…' +data_manager_advancements_preview_remaining: 'and %1% more…' data_list_title: '[%1%''s user data snapshots:](#00fb9a) [(%2%-%3% of](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7Data snapshot %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Version UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ Successfully deleted user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' data_restored: '[⏪ Successfully restored](#00fb9a) [%1%](#00fb9a show_text=&7Player UUID:\n&8%2%)[''s current user data from snapshot](#00fb9a) [%3%.](#00fb9a show_text=&7Version UUID:\n&8%4%)' data_pinned: '[※ Successfully pinned user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' @@ -38,4 +32,18 @@ list_page_jumpers: '(%1%)' list_page_jumper_button: '[%1%](show_text=&7Jump to page %1% run_command=%2% %1%)' list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' -list_page_jumper_group_separator: '…' \ No newline at end of file +list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| You are running the latest version of HuskSync (v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| A new version of HuskSync is available: v%1% (running: v%2%).](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| Reloaded config and message files.](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: '[Error:](#ff3300) [Incorrect syntax. Usage:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[Error:](#ff3300) [Could not find a player by that name.](#ff7e5e)' +error_no_permission: '[Error:](#ff3300) [You do not have permission to execute this command](#ff7e5e)' +error_console_command_only: '[Error:](#ff3300) [That command can only be run through console](#ff7e5e)' +error_in_game_command_only: 'Error: That command can only be used in-game.' +error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to display.](#ff7e5e)' +error_invalid_version_uuid: '[Error:](#ff3300) [Could not find any user data for that version UUID.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/es-es.yml b/common/src/main/resources/locales/es-es.yml index 411eeac2..0d5e4db5 100644 --- a/common/src/main/resources/locales/es-es.yml +++ b/common/src/main/resources/locales/es-es.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵ ¡Datos sincronizados!](#00fb9a)' -synchronisation_failed: '[⏵ Fallo al sincronizar los datos, por favor, contacte con un administrador.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| Recargada la configuración y los archivos de lenguaje.](#00fb9a)' -error_invalid_syntax: '[Error:](#ff3300) [Sintanxis incorrecta. Usa: %1%](#ff7e5e)' -error_invalid_player: '[Error:](#ff3300) [No se ha podido encontrar un jugador con ese nombre.](#ff7e5e)' -error_no_permission: '[Error:](#ff3300) [No tienes permisos para ejecutar este comando.](#ff7e5e)' -error_console_command_only: '[Error:](#ff3300) [Este comando solo se puede ejecutar desde la consola.](#ff7e5e)' -error_in_game_command_only: 'Error: Ese comando solo se puede utilizar desde el juego.' -error_no_data_to_display: '[Error:](#ff3300) [No se ha podido encontrar informacion sobre el jugador.](#ff7e5e)' -error_invalid_version_uuid: '[Error:](#ff3300) [No se ha podido encontrar informacion sobre la UUID de ese jugador.](#ff7e5e)' +synchronization_complete: '[⏵ ¡Datos sincronizados!](#00fb9a)' +synchronization_failed: '[⏵ Fallo al sincronizar los datos, por favor, contacte con un administrador.](#ff7e5e)' inventory_viewer_menu_title: '&0%1% Inventario de:' ender_chest_viewer_menu_title: '&0%1% Enderchest de:' inventory_viewer_opened: '[Viendo una snapshot de](#00fb9a) [%1%](#00fb9a bold) [Inventario a partir de ⌚ %2%](#00fb9a)' ender_chest_viewer_opened: '[Viendo una snapshot de](#00fb9a) [%1%](#00fb9a bold) [Enderchest a partir de ⌚ %2%](#00fb9a)' data_update_complete: '[🔔 ¡Tus datos han sido actualizados!](#00fb9a)' data_update_failed: '[🔔 Error al actualizar tus datos, por favor, contacte con un administrador.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[Viendo una snapshot sobre la informacion del jugador](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7Version del registro:\n&8Cuando los datos se han guardado)' data_manager_pinned: '[※ Snapshot anclada](#d8ff2b show_text=&Anclado:\n&8La informacion de este jugador no se rotará automaticamente.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Motivo del guardado:\n&8Lo que ha causado que se guarde)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Puntos de vida) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Puntos de hambre) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7Nivel de exp) [🏹 %5%](dark_aqua show_text=&7Gamemode)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Motivo del guardado:\n&8Lo que ha causado que se guarde)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Puntos de vida) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Puntos de hambre) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7Nivel de exp) [🏹 %5%](dark_aqua show_text=&7Gamemode)' data_manager_advancements_statistics: '[⭐ Logros: %1%](color=#ffc43b-#f5c962 show_text=&7Logros que has conseguido:\n&8%2%) [⌛ Tiempo de juego: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7In-game play time\n&8⚠ Based on in-game statistics)\n' data_manager_item_buttons: '[View:](gray) [[🪣 Inventario…]](color=#a17b5f-#f5b98c show_text=&7Click para ver run_command=/inventory %1% %2%) [[⌀ Enderchest…]](#b649c4-#d254ff show_text=&7Click para ver run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Manage:](gray) [[❌ Borrar…]](#ff3300 show_text=&7Click para borrar la snapshot del usuario.\n&8Esto no afectará a la informacion actual del jugador.\n&#ff3300&⚠ ¡Esto no se puede deshacer! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ Restaurar…]](#00fb9a show_text=&7Click para restaurar la informacion de este usuario.\n&8Esto hará que la informacion actual cambie por esta snapshot.\n&#ff3300&⚠ %1% la informacion actual será sustituida! suggest_command=/husksync:userdata restore %1% %2%) [[※ Pin/Unpin…]](#d8ff2b show_text=&7Click para anclar/desanclar esta snapshot\n&8Las snapshot ancladas no seran rotadas automaticamente run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[System:](gray) [[⏷ File Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to a file.\n&8Data dumps can be found in ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ Web Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to the mc-logs service\n&8You will be provided with a URL containing the data. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7y %1% más…' +data_manager_advancements_preview_remaining: 'y %1% más…' data_list_title: '[%1%''s user data snapshots:](#00fb9a) [(%2%-%3% of](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7Informacion de la snapshot %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7Anclado:\n&8Las snapshot ancladas no serán rotadas automaticamente. run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Version Tiempo:&7\n&8When the data was saved run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Version UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Causa del guardado:\n&8Lo que sea que haya hecho que se guarde run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ Se ha eliminado correctamente la snapshot del usuario](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' data_restored: '[⏪ Restaurado correctamente](#00fb9a) [%1%](#00fb9a show_text=&7UUID del jugador:\n&8%2%)[Informacion actual de la snapshot del jugador](#00fb9a) [%3%.](#00fb9a show_text=&7Version UUID:\n&8%4%)' data_pinned: '[※ Se ha anclado perfectamente la snapshot del jugador](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7UUID del usuario:\n&8%4%)' @@ -38,4 +32,18 @@ list_page_jumpers: '(%1%)' list_page_jumper_button: '[%1%](show_text=&7Jump to page %1% run_command=%2% %1%)' list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' -list_page_jumper_group_separator: '…' \ No newline at end of file +list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| You are running the latest version of HuskSync (v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| A new version of HuskSync is available: v%1% (running: v%2%).](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| Recargada la configuración y los archivos de lenguaje.](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: '[Error:](#ff3300) [Sintanxis incorrecta. Usa:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[Error:](#ff3300) [No se ha podido encontrar un jugador con ese nombre.](#ff7e5e)' +error_no_permission: '[Error:](#ff3300) [No tienes permisos para ejecutar este comando.](#ff7e5e)' +error_console_command_only: '[Error:](#ff3300) [Este comando solo se puede ejecutar desde la consola.](#ff7e5e)' +error_in_game_command_only: 'Error: Ese comando solo se puede utilizar desde el juego.' +error_no_data_to_display: '[Error:](#ff3300) [No se ha podido encontrar informacion sobre el jugador.](#ff7e5e)' +error_invalid_version_uuid: '[Error:](#ff3300) [No se ha podido encontrar informacion sobre la UUID de ese jugador.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/it-it.yml b/common/src/main/resources/locales/it-it.yml index ad67efb3..ae656be3 100644 --- a/common/src/main/resources/locales/it-it.yml +++ b/common/src/main/resources/locales/it-it.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵ Dati sincronizzati!](#00fb9a)' -synchronisation_failed: '[⏵ Sincronizzazione fallita! Perfavore contatta un amministratore.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| Configurazione e messaggi ricaricati.](#00fb9a)' -error_invalid_syntax: '[Errore:](#ff3300) [Sintassi errata. Usa: %1%](#ff7e5e)' -error_invalid_player: '[Errore:](#ff3300) [Impossibile trovare un giocatore con questo nome.](#ff7e5e)' -error_no_permission: '[Errore:](#ff3300) [Non hai il permesso di usare questo comando](#ff7e5e)' -error_console_command_only: '[Errore:](#ff3300) [Questo comando può essere eseguito solo dalla](#ff7e5e)' -error_in_game_command_only: 'Errore: That command can only be used in-game.' -error_no_data_to_display: '[Errore:](#ff3300) [Impossibile trovare dati da visualizzare.](#ff7e5e)' -error_invalid_version_uuid: '[Errore:](#ff3300) [Impossibile trovare dati utente per questa versione di UUID.](#ff7e5e)' +synchronization_complete: '[⏵ Dati sincronizzati!](#00fb9a)' +synchronization_failed: '[⏵ Sincronizzazione fallita! Perfavore contatta un amministratore.](#ff7e5e)' inventory_viewer_menu_title: '&0Inventario di %1%' ender_chest_viewer_menu_title: '&0Enderchest di %1%' inventory_viewer_opened: '[Stai vedendo l''istantanea di](#00fb9a) [%1%](#00fb9a bold) [inventario del ⌚ %2%](#00fb9a)' ender_chest_viewer_opened: '[Stai vedendo l''istantanea di](#00fb9a) [%1%](#00fb9a bold) [Ender Chest del ⌚ %2%](#00fb9a)' data_update_complete: '[🔔 I tuoi dati sono stati aggiornati!](#00fb9a)' data_update_failed: '[🔔 Aggiornamento dei tuoi dati fallito! Perfavore contatta un amministratore.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[Stai vedendo l''istantanea](#00fb9a) [%1%](#00fb9a show_text=&7Versione di UUID:\n&8%2%) [di](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7:\n&8Quando i dati sono stati salvati)' data_manager_pinned: '[※ Istantanea fissata](#d8ff2b show_text=&7Pinned:\n&8Quest''istantanea non sarà cancellata automaticamente.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\n&8Cosa ha causato il salvataggio dei dati)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Vita) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Fame) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7Livello di XP) [🏹 %5%](dark_aqua show_text=&7Modalità di gioco)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\n&8Cosa ha causato il salvataggio dei dati)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Vita) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Fame) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7Livello di XP) [🏹 %5%](dark_aqua show_text=&7Modalità di gioco)' data_manager_advancements_statistics: '[⭐ Progressi: %1%](color=#ffc43b-#f5c962 show_text=&7Progressi compiuti in:\n&8%2%) [⌛ Tempo di gioco: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7Tempo di gioco\n&8⚠ Basato sulle statistiche di gioco)\n' data_manager_item_buttons: '[View:](gray) [[🪣 Inventario…]](color=#a17b5f-#f5b98c show_text=&7Clicca per visualizzare run_command=/inventory %1% %2%) [[⌀ Ender Chest…]](#b649c4-#d254ff show_text=&7Clicca per visualizzare run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Gestisci:](gray) [[❌ Cancella…]](#ff3300 show_text=&7Fare clic per eliminare questa istantanea.\n&8Questo non influisce sui dati attuali dell''utente.\n&#ff3300&⚠ Questo non può essere annullato! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ Ripristina…]](#00fb9a show_text=&7Clicca per ripristinare i dati dell''utente.\n&8I dati dell''utente saranno ripristinati a quest''istantanea.\n&#ff3300&⚠ I dati di %1% saranno sovrascritti! suggest_command=/husksync:userdata restore %1% %2%) [[※ fissa/sblocca...]](#d8ff2b show_text=&7Clicca per fissare o sbloccare quest''istantanea\n&8Le istantanee fissate non saranno cancellate automaticamente run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[Sistema:](gray) [[⏷ Dump del File…]](dark_gray show_text=&7Clicca per ottenere il dump dei dati del giocatore.\n&8I dati salvati sono posizioanti nella cartella ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ Dump su Web…]](dark_gray show_text=&7Clicca per ottenere il dump del file su mc-logs\n&8 Ti verrà consegnato l''url per visionare il dump. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7e %1% altro…' +data_manager_advancements_preview_remaining: 'e %1% altro…' data_list_title: '[Lista delle istantanee di %1%:](#00fb9a) [(%2%-%3% of](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7Istantanea dei dati %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7Fissato:\n&8Le istantanee fissate non saranno cancellate automaticamente. run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Timestamp della versione:&7\n&8Quando i dati sono stati salvati run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Versione di UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Causa del salvataggio:\n&8Cosa ha causato il salvataggio dei dati run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ Istantanea eliminata con successo](#00fb9a) [%1%](#00fb9a show_text=&7Versione di UUID:\n&8%2%) [per](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' data_restored: '[⏪ Ripristato con successo](#00fb9a) [Dati dall''istantanea di](#00fb9a)[%1%](#00fb9a show_text=&7Player UUID:\n&8%2%) [%3%.](#00fb9a show_text=&7Versione di UUID:\n&8%4%)' data_pinned: '[※ Instantanea fissata](#00fb9a) [%1%](#00fb9a show_text=&7Versione di UUID:\n&8%2%) [per](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' @@ -39,3 +33,17 @@ list_page_jumper_button: '[%1%](show_text=&7Vai alla pagina %1% run_command=%2% list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| Il plugin è all''ultima versione disponibile (v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| Disponibile una nuova versione: v%1% (running: v%2%).](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| Configurazione e messaggi ricaricati.](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: '[Errore:](#ff3300) [Sintassi errata. Usa:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[Errore:](#ff3300) [Impossibile trovare un giocatore con questo nome.](#ff7e5e)' +error_no_permission: '[Errore:](#ff3300) [Non hai il permesso di usare questo comando](#ff7e5e)' +error_console_command_only: '[Errore:](#ff3300) [Questo comando può essere eseguito solo dalla](#ff7e5e)' +error_in_game_command_only: 'Errore: That command can only be used in-game.' +error_no_data_to_display: '[Errore:](#ff3300) [Impossibile trovare dati da visualizzare.](#ff7e5e)' +error_invalid_version_uuid: '[Errore:](#ff3300) [Impossibile trovare dati utente per questa versione di UUID.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/ja-jp.yml b/common/src/main/resources/locales/ja-jp.yml index f0b51241..89704925 100644 --- a/common/src/main/resources/locales/ja-jp.yml +++ b/common/src/main/resources/locales/ja-jp.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵データが同期されました!](#00fb9a)' -synchronisation_failed: '[⏵ Failed to synchronise your data! Please contact an administrator.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| 設定ファイルとメッセージファイルを再読み込みしました。](#00fb9a)' -error_invalid_syntax: '[Error:](#ff3300) [構文が正しくありません。使用法: %1%](#ff7e5e)' -error_invalid_player: '[Error:](#ff3300) [そのプレイヤーは見つかりませんでした](#ff7e5e)' -error_no_permission: '[Error:](#ff3300) [このコマンドを実行する権限がありません](#ff7e5e)' -error_console_command_only: '[Error:](#ff3300) [そのコマンドは%1%コンソールからのみ実行できます](#ff7e5e)' -error_in_game_command_only: 'Error: That command can only be used in-game.' -error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to display.](#ff7e5e)' -error_invalid_version_uuid: '[Error:](#ff3300) [Could not find any user data for that version UUID.](#ff7e5e)' +synchronization_complete: '[⏵データが同期されました!](#00fb9a)' +synchronization_failed: '[⏵ Failed to synchronize your data! Please contact an administrator.](#ff7e5e)' inventory_viewer_menu_title: '&0%1%''s Inventory' ender_chest_viewer_menu_title: '&0%1%''s Ender Chest' inventory_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold)[''s inventory as of ⌚ %2%](#00fb9a)' ender_chest_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold)[''s Ender Chest as of ⌚ %2%](#00fb9a)' data_update_complete: '[🔔 Your data has been updated!](#00fb9a)' data_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[Viewing user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7Version timestamp:\n&8When the data was saved)' data_manager_pinned: '[※ Snapshot pinned](#d8ff2b show_text=&7Pinned:\n&8This user data snapshot won''t be automatically rotated.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Health points) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hunger points) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Health points) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hunger points) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)' data_manager_advancements_statistics: '[⭐ Advancements: %1%](color=#ffc43b-#f5c962 show_text=&7Advancements you have progress in:\n&8%2%) [⌛ Play Time: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7In-game play time\n&8⚠ Based on in-game statistics)\n' data_manager_item_buttons: '[View:](gray) [[🪣 Inventory…]](color=#a17b5f-#f5b98c show_text=&7Click to view run_command=/inventory %1% %2%) [[⌀ Ender Chest…]](#b649c4-#d254ff show_text=&7Click to view run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Manage:](gray) [[❌ Delete…]](#ff3300 show_text=&7Click to delete this snapshot of user data.\n&8This will not affect the user''s current data.\n&#ff3300&⚠ This cannot be undone! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ Restore…]](#00fb9a show_text=&7Click to restore this user data.\n&8This will set the user''s data to this snapshot.\n&#ff3300&⚠ %1%''s current data will be overwritten! suggest_command=/husksync:userdata restore %1% %2%) [[※ Pin/Unpin…]](#d8ff2b show_text=&7Click to pin or unpin this user data snapshot\n&8Pinned snapshots won''t be automatically rotated run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[System:](gray) [[⏷ File Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to a file.\n&8Data dumps can be found in ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ Web Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to the mc-logs service\n&8You will be provided with a URL containing the data. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7and %1% more…' +data_manager_advancements_preview_remaining: 'and %1% more…' data_list_title: '[%1%''s user data snapshots:](#00fb9a) [(%2%-%3% of](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7Data snapshot %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Version UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ Successfully deleted user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' data_restored: '[⏪ Successfully restored](#00fb9a) [%1%](#00fb9a show_text=&7Player UUID:\n&8%2%)[''s current user data from snapshot](#00fb9a) [%3%.](#00fb9a show_text=&7Version UUID:\n&8%4%)' data_pinned: '[※ Successfully pinned user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' @@ -38,4 +32,18 @@ list_page_jumpers: '(%1%)' list_page_jumper_button: '[%1%](show_text=&7Jump to page %1% run_command=%2% %1%)' list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' -list_page_jumper_group_separator: '…' \ No newline at end of file +list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| HuskSyncの最新バージョンを実行しています(v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| HuskSyncの最新バージョンが更新されています: v%1% (running: v%2%).](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| 設定ファイルとメッセージファイルを再読み込みしました。](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: '[Error:](#ff3300) [構文が正しくありません。使用法:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[Error:](#ff3300) [そのプレイヤーは見つかりませんでした](#ff7e5e)' +error_no_permission: '[Error:](#ff3300) [このコマンドを実行する権限がありません](#ff7e5e)' +error_console_command_only: '[Error:](#ff3300) [そのコマンドは%1%コンソールからのみ実行できます](#ff7e5e)' +error_in_game_command_only: 'Error: That command can only be used in-game.' +error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to display.](#ff7e5e)' +error_invalid_version_uuid: '[Error:](#ff3300) [Could not find any user data for that version UUID.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/pt-br.yml b/common/src/main/resources/locales/pt-br.yml index 296d7f6e..b029551c 100644 --- a/common/src/main/resources/locales/pt-br.yml +++ b/common/src/main/resources/locales/pt-br.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵ Dados sincronizados!](#00fb9a)' -synchronisation_failed: '[⏵ Falha na sincronização de seus dados! Por favor entre em contato com um administrador.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| Arquivos de configuração e mensagens recarregados.](#00fb9a)' -error_invalid_syntax: '[Error:](#ff3300) [Sintaxe incorreta. Utilize: %1%](#ff7e5e)' -error_invalid_player: '[Error:](#ff3300) [Não foi possível encontrar um jogador com esse nome.](#ff7e5e)' -error_no_permission: '[Error:](#ff3300) [Você não tem permissão para executar este comando](#ff7e5e)' -error_console_command_only: '[Error:](#ff3300) [Esse comando só pode ser executado através do console](#ff7e5e)' -error_in_game_command_only: 'Error: Esse comando só pode ser usado dentro do jogo.' -error_no_data_to_display: '[Error:](#ff3300) [Não encontramos nenhuma informação deste jogador para exibir.](#ff7e5e)' -error_invalid_version_uuid: '[Error:](#ff3300) [Não foi possível encontrar nenhuma informação deste jogador para essa versão UUID.](#ff7e5e)' +synchronization_complete: '[⏵ Dados sincronizados!](#00fb9a)' +synchronization_failed: '[⏵ Falha na sincronização de seus dados! Por favor entre em contato com um administrador.](#ff7e5e)' inventory_viewer_menu_title: '&0%1%''s Inventory' ender_chest_viewer_menu_title: '&0%1%''s Ender Chest' inventory_viewer_opened: '[Visualizando snapshot de](#00fb9a) [%1%](#00fb9a bold) [''s inventory a partir de ⌚ %2%](#00fb9a)' ender_chest_viewer_opened: '[Visualizando snapshot de](#00fb9a) [%1%](#00fb9a bold) [''s Ender Chest a partir de ⌚ %2%](#00fb9a)' data_update_complete: '[🔔 Seus dados foram atualizados!](#00fb9a)' data_update_failed: '[🔔 Falha na atualização de seus dados! Por favor entre em contato com um administrador.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[Visualizando snapshot dos dados do usuário](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7Version timestamp:\n&8Quando os dados foram salvos)' data_manager_pinned: '[※ Snapshot marcada](#d8ff2b show_text=&7Marcada:\n&8Essa snapshot de dados do usuário não será girada automaticamente.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Causa do salvamento:\n&8O motivo para que os dados fossem salvos)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Pontos de Vida) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Pontos de vida) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Causa do salvamento:\n&8O motivo para que os dados fossem salvos)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Pontos de Vida) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Pontos de vida) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)' data_manager_advancements_statistics: '[⭐ Progressos: %1%](color=#ffc43b-#f5c962 show_text=&7Progressos que você tem realizado em:\n&8%2%) [⌛ Tempo de jogo: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7Tempo de jogo dentro do jogo\n&8⚠ Com base em estatísticas dentro do jogo)\n' data_manager_item_buttons: '[View:](gray) [[🪣 Inventory…]](color=#a17b5f-#f5b98c show_text=&7Clique para ver run_command=/inventory %1% %2%) [[⌀ Ender Chest…]](#b649c4-#d254ff show_text=&7Clique para ver run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Gerenciar:](gray) [[❌ Deletar…]](#ff3300 show_text=&7Clique para deletar esta snapshot de dados do usuário\n&8Isto não afetará os dados atuais do usuário.\n&#ff3300&⚠ Isto não pode ser desfeito! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ Restaurar…]](#00fb9a show_text=&7Clique para restaurar estes dados do usuário.\n&8Isto substituirá os dados atuais do usuário para os da snapshot.\n&#ff3300&⚠ %1%''s os dados atuais serão substituídos! suggest_command=/husksync:userdata restore %1% %2%) [[※ Marcar/Desmarcar…]](#d8ff2b show_text=&7Clique para marcar ou desmarcar este snapshot de dados do usuário\n&8Snapshots marcadas não serão giradas automaticamente run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[System:](gray) [[⏷ File Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to a file.\n&8Data dumps can be found in ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ Web Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to the mc-logs service\n&8You will be provided with a URL containing the data. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7e %1% mais…' +data_manager_advancements_preview_remaining: 'e %1% mais…' data_list_title: '[%1%''s user data snapshots:](#00fb9a) [(%2%-%3% of](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7Snapshot data %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7Marcado:\n&8Snapshots marcadas não serão giradas automaticamente. run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8Quando os dados foram salvos run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Version UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Causa do salvamento:\n&8O motivo para que os dados fossem salvos run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ Snapshot de dados do usuário deletada com sucesso](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' data_restored: '[⏪ Restaurada com sucesso](#00fb9a) [%1%](#00fb9a show_text=&7Player UUID:\n&8%2%)[''s current user data from snapshot](#00fb9a) [%3%.](#00fb9a show_text=&7Version UUID:\n&8%4%)' data_pinned: '[※ Snapshot de dados do usuário marcada com sucesso](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' @@ -38,4 +32,18 @@ list_page_jumpers: '(%1%)' list_page_jumper_button: '[%1%](show_text=&7Jump to page %1% run_command=%2% %1%)' list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' -list_page_jumper_group_separator: '…' \ No newline at end of file +list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| You are running the latest version of HuskSync (v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| A new version of HuskSync is available: v%1% (running: v%2%).](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| Arquivos de configuração e mensagens recarregados.](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: '[Error:](#ff3300) [Sintaxe incorreta. Utilize:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[Error:](#ff3300) [Não foi possível encontrar um jogador com esse nome.](#ff7e5e)' +error_no_permission: '[Error:](#ff3300) [Você não tem permissão para executar este comando](#ff7e5e)' +error_console_command_only: '[Error:](#ff3300) [Esse comando só pode ser executado através do console](#ff7e5e)' +error_in_game_command_only: 'Error: Esse comando só pode ser usado dentro do jogo.' +error_no_data_to_display: '[Error:](#ff3300) [Não encontramos nenhuma informação deste jogador para exibir.](#ff7e5e)' +error_invalid_version_uuid: '[Error:](#ff3300) [Não foi possível encontrar nenhuma informação deste jogador para essa versão UUID.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/uk-ua.yml b/common/src/main/resources/locales/uk-ua.yml index 03f0d81c..c6438974 100644 --- a/common/src/main/resources/locales/uk-ua.yml +++ b/common/src/main/resources/locales/uk-ua.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵ Дані синхронізовано!](#00fb9a)' -synchronisation_failed: '[⏵ Failed to synchronise your data! Please contact an administrator.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| Перезавантажено конфіґ та файли повідомлень.](#00fb9a)' -error_invalid_syntax: '[Помилка:](#ff3300) [Неправильний синтакс. Використання: %1%](#ff7e5e)' -error_invalid_player: '[Помилка:](#ff3300) [Гравця не знайдено](#ff7e5e)' -error_no_permission: '[Помилка:](#ff3300) [Ввас немає дозволу на використання цієї команди](#ff7e5e)' -error_console_command_only: '[Помилка:](#ff3300) [Ця команда може бути використана лише з допомогою %1% консолі](#ff7e5e)' -error_in_game_command_only: 'Error: That command can only be used in-game.' -error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to display.](#ff7e5e)' -error_invalid_version_uuid: '[Error:](#ff3300) [Could not find any user data for that version UUID.](#ff7e5e)' +synchronization_complete: '[⏵ Дані синхронізовано!](#00fb9a)' +synchronization_failed: '[⏵ Failed to synchronize your data! Please contact an administrator.](#ff7e5e)' inventory_viewer_menu_title: '&0%1%''s Inventory' ender_chest_viewer_menu_title: '&0%1%''s Ender Chest' inventory_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold)[''s inventory as of ⌚ %2%](#00fb9a)' ender_chest_viewer_opened: '[Viewing snapshot of](#00fb9a) [%1%](#00fb9a bold)[''s Ender Chest as of ⌚ %2%](#00fb9a)' data_update_complete: '[🔔 Your data has been updated!](#00fb9a)' data_update_failed: '[🔔 Failed to update your data! Please contact an administrator.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[Viewing user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%](#00fb9a bold show_text=&7Player UUID:\n&8%4%)[:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7Version timestamp:\n&8When the data was saved)' data_manager_pinned: '[※ Snapshot pinned](#d8ff2b show_text=&7Pinned:\n&8This user data snapshot won''t be automatically rotated.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Health points) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hunger points) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7Health points) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7Hunger points) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7XP level) [🏹 %5%](dark_aqua show_text=&7Game mode)' data_manager_advancements_statistics: '[⭐ Advancements: %1%](color=#ffc43b-#f5c962 show_text=&7Advancements you have progress in:\n&8%2%) [⌛ Play Time: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7In-game play time\n&8⚠ Based on in-game statistics)\n' data_manager_item_buttons: '[View:](gray) [[🪣 Inventory…]](color=#a17b5f-#f5b98c show_text=&7Click to view run_command=/inventory %1% %2%) [[⌀ Ender Chest…]](#b649c4-#d254ff show_text=&7Click to view run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Manage:](gray) [[❌ Delete…]](#ff3300 show_text=&7Click to delete this snapshot of user data.\n&8This will not affect the user''s current data.\n&#ff3300&⚠ This cannot be undone! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ Restore…]](#00fb9a show_text=&7Click to restore this user data.\n&8This will set the user''s data to this snapshot.\n&#ff3300&⚠ %1%''s current data will be overwritten! suggest_command=/husksync:userdata restore %1% %2%) [[※ Pin/Unpin…]](#d8ff2b show_text=&7Click to pin or unpin this user data snapshot\n&8Pinned snapshots won''t be automatically rotated run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[System:](gray) [[⏷ File Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to a file.\n&8Data dumps can be found in ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ Web Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to the mc-logs service\n&8You will be provided with a URL containing the data. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7and %1% more…' +data_manager_advancements_preview_remaining: 'and %1% more…' data_list_title: '[%1%''s user data snapshots:](#00fb9a) [(%2%-%3% of](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7Data snapshot %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Version UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ Successfully deleted user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' data_restored: '[⏪ Successfully restored](#00fb9a) [%1%](#00fb9a show_text=&7Player UUID:\n&8%2%)[''s current user data from snapshot](#00fb9a) [%3%.](#00fb9a show_text=&7Version UUID:\n&8%4%)' data_pinned: '[※ Successfully pinned user data snapshot](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [for](#00fb9a) [%3%.](#00fb9a show_text=&7Player UUID:\n&8%4%)' @@ -38,4 +32,18 @@ list_page_jumpers: '(%1%)' list_page_jumper_button: '[%1%](show_text=&7Jump to page %1% run_command=%2% %1%)' list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' -list_page_jumper_group_separator: '…' \ No newline at end of file +list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| You are running the latest version of HuskSync (v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| A new version of HuskSync is available: v%1% (running: v%2%).](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| Перезавантажено конфіґ та файли повідомлень.](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: '[Помилка:](#ff3300) [Неправильний синтакс. Використання:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[Помилка:](#ff3300) [Гравця не знайдено](#ff7e5e)' +error_no_permission: '[Помилка:](#ff3300) [Ввас немає дозволу на використання цієї команди](#ff7e5e)' +error_console_command_only: '[Помилка:](#ff3300) [Ця команда може бути використана лише з допомогою %1% консолі](#ff7e5e)' +error_in_game_command_only: 'Error: That command can only be used in-game.' +error_no_data_to_display: '[Error:](#ff3300) [Could not find any user data to display.](#ff7e5e)' +error_invalid_version_uuid: '[Error:](#ff3300) [Could not find any user data for that version UUID.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/zh-cn.yml b/common/src/main/resources/locales/zh-cn.yml index 62fca778..61224f0e 100644 --- a/common/src/main/resources/locales/zh-cn.yml +++ b/common/src/main/resources/locales/zh-cn.yml @@ -1,31 +1,25 @@ -synchronisation_complete: '[⏵ 数据同步完成!](#00fb9a)' -synchronisation_failed: '[⏵ 无法同步数据! 请联系管理员.](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| 插件配置和语言文件已重载.](#00fb9a)' -error_invalid_syntax: ':](#ff3300) [格式错误, 使用方法: %1%](#ff7e5e)' -error_invalid_player: '[错误:](#ff3300) [无法找到目标玩家.](#ff7e5e)' -error_no_permission: '[错误:](#ff3300) [你没有执行此指令的权限](#ff7e5e)' -error_console_command_only: '[错误:](#ff3300) [该指令只能在控制台运行](#ff7e5e)' -error_in_game_command_only: 'Error: 该指令只能在游戏内运行.' -error_no_data_to_display: '[错误:](#ff3300) [无法找到用户数据显示.](#ff7e5e)' -error_invalid_version_uuid: '[错误:](#ff3300) [无法找到该备份的 UUID .](#ff7e5e)' +synchronization_complete: '[⏵ 数据同步完成!](#00fb9a)' +synchronization_failed: '[⏵ 无法同步数据! 请联系管理员.](#ff7e5e)' inventory_viewer_menu_title: '&0%1% 的背包' ender_chest_viewer_menu_title: '&0%1% 的末影箱' inventory_viewer_opened: '[正在查看玩家](#00fb9a) [%1%](#00fb9a bold) [于 ⌚ %2% 的背包备份](#00fb9a)' ender_chest_viewer_opened: '[正在查看玩家](#00fb9a) [%1%](#00fb9a bold) [于 ⌚ %2% 的末影箱备份](#00fb9a)' data_update_complete: '[🔔 你的用户数据已更新!](#00fb9a)' data_update_failed: '[🔔 无法更新你的用户数据! 请联系管理员.](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[正在查看玩家](#00fb9a) [%3%](#00fb9a bold show_text=&7玩家 UUID:\n&8%4%) [的数据备份](#00fb9a) [%1%](#00fb9a show_text=&7备份版本 UUID:\n&8%2%) [:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7备份时间:\n&7何时保存了此数据)' data_manager_pinned: '[※ 置顶备份](#d8ff2b show_text=&7置顶:\n&8此数据备份不会按照备份时间自动排序.)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7备份原因:\n&7为何保存了此数据)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7血量) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7饱食度) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7经验等级) [🏹 %5%](dark_aqua show_text=&7游戏模式)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7备份原因:\n&7为何保存了此数据)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7血量) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7饱食度) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7经验等级) [🏹 %5%](dark_aqua show_text=&7游戏模式)' data_manager_advancements_statistics: '[⭐ 成就: %1%](color=#ffc43b-#f5c962 show_text=&7%2%) [⌛ 游玩时间: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7⚠ 基于游戏内的统计)\n' data_manager_item_buttons: '[View:](gray) [[🪣 背包…]](color=#a17b5f-#f5b98c show_text=&7点击查看 run_command=/inventory %1% %2%) [[⌀ 末影箱…]](#b649c4-#d254ff show_text=&7点击查看 run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[Manage:](gray) [[❌ 删除…]](#ff3300 show_text=&7点击删除此数据备份.\n这不会影响玩家当前的数据.\n&#ff3300&⚠ 此操作不可撤销! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ 恢复…]](#00fb9a show_text=&7点击让玩家恢复到此数据备份.\n这将会使玩家的数据恢复到这个备份.\n&#ff3300&⚠ %1% 当前的用户数据会被备份数据所覆盖! suggest_command=/husksync:userdata restore %1% %2%) [[※ Pin/Unpin…]](#d8ff2b show_text=&7Click to pin or unpin this user data snapshot\n&8Pinned snapshots won''t be automatically rotated run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[System:](gray) [[⏷ File Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to a file.\n&8Data dumps can be found in ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ Web Dump…]](dark_gray show_text=&7Click to dump this raw user data snapshot to the mc-logs service\n&8You will be provided with a URL containing the data. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7还有 %1% …' +data_manager_advancements_preview_remaining: '还有 %1% …' data_list_title: '[%1%''s user data snapshots:](#00fb9a) [(%2%-%3% of](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7备份 %3% run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7备份时间&7\n&8何时保存了此数据 run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7备份版本 UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7备份原因\n&8为何保存了此数据 run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ 成功删除玩家](#00fb9a) [%3%](#00fb9a show_text=&7玩家 UUID:\n&7%4%) [的数据备份](#00fb9a) [%1%.](#00fb9a show_text=&7备份版本 UUID:\n&7%2%)' data_restored: '[⏪ 成功恢复玩家](#00fb9a) [%1%](#00fb9a show_text=&7玩家 UUID:\n&7%2%)[的数据备份](#00fb9a) [%3%.](#00fb9a show_text=&7备份版本 UUID:\n&7%4%)' data_pinned: '[※ 成功置顶玩家](#00fb9a) [%3%](#00fb9a show_text=&7玩家 UUID:\n&8%4%) [的数据备份](#00fb9a) [%1%.](#00fb9a show_text=&7备份版本 UUID:\n&8%2%)' @@ -38,4 +32,18 @@ list_page_jumpers: '(%1%)' list_page_jumper_button: '[%1%](show_text=&7Jump to page %1% run_command=%2% %1%)' list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' -list_page_jumper_group_separator: '…' \ No newline at end of file +list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| 你正在使用最新版本的HuskSync (v%1%)](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| 一个新版本的HuskSync已经可以更新: v%1% (当前: v%2%)](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| 插件配置和语言文件已重载.](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: ':](#ff3300) [格式错误, 使用方法:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[错误:](#ff3300) [无法找到目标玩家.](#ff7e5e)' +error_no_permission: '[错误:](#ff3300) [你没有执行此指令的权限](#ff7e5e)' +error_console_command_only: '[错误:](#ff3300) [该指令只能在控制台运行](#ff7e5e)' +error_in_game_command_only: 'Error: 该指令只能在游戏内运行.' +error_no_data_to_display: '[错误:](#ff3300) [无法找到用户数据显示.](#ff7e5e)' +error_invalid_version_uuid: '[错误:](#ff3300) [无法找到该备份的 UUID .](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/main/resources/locales/zh-tw.yml b/common/src/main/resources/locales/zh-tw.yml index 84544d31..64e96ff5 100644 --- a/common/src/main/resources/locales/zh-tw.yml +++ b/common/src/main/resources/locales/zh-tw.yml @@ -1,41 +1,49 @@ -synchronisation_complete: '[⏵資料已同步!](#00fb9a)' -synchronisation_failed: '[⏵ 無法同步您的資料! 請聯繫管理員](#ff7e5e)' -reload_complete: '[HuskSync](#00fb9a bold) [| 已重新載入配置和訊息文件](#00fb9a)' -error_invalid_syntax: '[錯誤:](#ff3300) [語法不正確,用法: %1%](#ff7e5e)' -error_invalid_player: '[錯誤:](#ff3300) [找不到這位玩家](#ff7e5e)' -error_no_permission: '[錯誤:](#ff3300) [您沒有權限執行這個指令](#ff7e5e)' -error_console_command_only: '[錯誤:](#ff3300) [該指令只能透過 控制台 執行](#ff7e5e)' -error_in_game_command_only: '[錯誤:](#ff3300) [該指令只能在遊戲內執行](#ff7e5e)' -error_no_data_to_display: '[錯誤:](#ff3300) [找不到任何可顯示的用戶資訊.](#ff7e5e)' -error_invalid_version_uuid: '[錯誤:](#ff3300) [找不到正確的 Version UUID.](#ff7e5e)' +synchronization_complete: '[⏵資料已同步!](#00fb9a)' +synchronization_failed: '[⏵ 無法同步您的資料! 請聯繫管理員](#ff7e5e)' inventory_viewer_menu_title: '&0%1% 的背包' ender_chest_viewer_menu_title: '&0%1% 的終界箱' inventory_viewer_opened: '[查看](#00fb9a) [%1%](#00fb9a bold) [於 ⌚ %2% 的背包快照資料](#00fb9a)' ender_chest_viewer_opened: '[查看](#00fb9a) [%1%](#00fb9a bold) [於 ⌚ %2% 的終界箱快照資料](#00fb9a)' data_update_complete: '[🔔 你的資料已更新!](#00fb9a)' data_update_failed: '[🔔 無法更新您的資料! 請聯繫管理員](#ff7e5e)' +user_registration_complete: '[⭐ User registration complete!](#00fb9a)' data_manager_title: '[查看](#00fb9a) [%3%](#00fb9a bold show_text=&7玩家 UUID:\n&8%4%) [的快照:](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [:](#00fb9a)' data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7快照時間:\n&8何時保存的資料)' data_manager_pinned: '[※ 被標記的快照](#d8ff2b show_text=&7標記:\n&8此快照資料不會自動輪換更新)' -data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7保存原因:\n&8保存此快照的原因)\n' -data_manager_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7血量) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7飽食度) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7經驗等級) [🏹 %5%](dark_aqua show_text=&7遊戲模式)' +data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7保存原因:\n&8保存此快照的原因)' +data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:\n&8Estimated file size of the snapshot (in KiB))\n' +data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7血量) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7飽食度) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7經驗等級) [🏹 %5%](dark_aqua show_text=&7遊戲模式)' data_manager_advancements_statistics: '[⭐ 成就: %1%](color=#ffc43b-#f5c962 show_text=&7已獲得的成就:\n&8%2%) [⌛ 遊戲時間: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7遊戲內的遊玩時間\n&8⚠ 根據遊戲內統計)\n' data_manager_item_buttons: '[查看:](gray) [[🪣 背包…]](color=#a17b5f-#f5b98c show_text=&7點擊查看 run_command=/inventory %1% %2%) [[⌀ 終界箱…]](#b649c4-#d254ff show_text=&7點擊查看 run_command=/enderchest %1% %2%)' data_manager_management_buttons: '[管理:](gray) [[❌ 刪除…]](#ff3300 show_text=&7點擊刪除這個快照\n&8這不會影像目前玩家的資料\n&#ff3300&⚠ 此操作不能取消! suggest_command=/husksync:userdata delete %1% %2%) [[⏪ 恢復…]](#00fb9a show_text=&7點擊將玩家資料覆蓋為此快照\n&8這將導致玩家的資料會被此快照覆蓋\n&#ff3300&⚠ %1% 當前的資料將被覆蓋! suggest_command=/husksync:userdata restore %1% %2%) [[※ 標記…]](#d8ff2b show_text=&7點擊切換標記狀態\n&8被標記的快照將不會自動輪換更新 run_command=/userdata pin %1% %2%)' data_manager_system_buttons: '[系統:](gray) [[⏷ 本地轉存…]](dark_gray show_text=&7點擊將此玩家資料快照轉存到本地文件中\n&8轉存的資料可以在以下路徑找到 ~/plugins/HuskSync/dumps/ run_command=/husksync:userdata dump %1% %2% file) [[☂ 雲端轉存…]](dark_gray show_text=&7點擊將此玩家資料快照轉存到 mc-logs 服務\n&8您將獲得一個包含資料的 URL. run_command=/husksync:userdata dump %1% %2% web)' -data_manager_advancements_preview_remaining: '&7還有 %1% …' +data_manager_advancements_preview_remaining: '還有 %1% …' data_list_title: '[%1% 的玩家資料快照:](#00fb9a) [(%2%-%3% 共](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n' -data_list_item: '[%1%](gray show_text=&7快照名稱: %3% run_command=/userdata view %6% %4%) [%7%](#d8ff2b show_text=&7標記:\n&8被標記的快照不會自動輪換更新 run_command=/userdata view %6% %4%) [%2%](color=#ffc43b-#f5c962 show_text=&7時間戳:&7\n&8資料保存時間 run_command=/userdata view %6% %4%) [⚡ %3%](color=#62a9f5-#7ab8fa show_text=&7Version UUID:&7\n&8%4% run_command=/userdata view %6% %4%) [⚑ %5%](#23a825-#36f539 show_text=&7保存原因:\n&8保存此快照的原因 run_command=/userdata view %6% %4%)' +data_list_item: '[%1%](gray show_text=&7User Data Snapshot for %2%&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7Version timestamp:&7\n&8When the data was saved\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7Save cause:\n&8What caused the data to be saved run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7Snapshot size:&7\n&8Estimated file size of the snapshot (in KiB) run_command=/userdata view %2% %3%)' data_deleted: '[❌ 成功刪除:](#00fb9a) [%3%](#00fb9a show_text=&7玩家 UUID:\n&8%4%) [的快照:](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%)' data_restored: '[⏪ 成功將玩家](#00fb9a) [%1%](#00fb9a show_text=&7玩家 UUID:\n&8%2%)[的資料恢復為 快照:](#00fb9a) [%3%.](#00fb9a show_text=&7Version UUID:\n&8%4%)' data_pinned: '[※ 成功標記](#00fb9a) [%3%](#00fb9a show_text=&7玩家 UUID:\n&8%4%) [的快照:](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%)' data_unpinned: '[※ 成功解除](#00fb9a) [%3%](#00fb9a show_text=&7玩家 UUID:\n&8%4%) [快照:](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [的標記](#00fb9a)' data_dumped: '[☂ 成功將 %2% 資料快照 %1% 儲存至:](#00fb9a) &7%3%' -list_footer: \n%1%[頁面](#00fb9a) [%2%](#00fb9a)/[%3%](#00fb9a)%4% %5% +list_footer: '\n%1%[頁面](#00fb9a) [%2%](#00fb9a)/[%3%](#00fb9a)%4% %5%' list_previous_page_button: '[◀](white show_text=&7查看上一頁 run_command=%2% %1%) ' list_next_page_button: ' [▶](white show_text=&7查看下一頁 run_command=%2% %1%)' -list_page_jumpers: (%1%) +list_page_jumpers: '(%1%)' list_page_jumper_button: '[%1%](show_text=&7跳至第 %1% 頁 run_command=%2% %1%)' list_page_jumper_current_page: '[%1%](#00fb9a)' list_page_jumper_separator: ' ' -list_page_jumper_group_separator: … +list_page_jumper_group_separator: '…' +up_to_date: '[HuskSync](#00fb9a bold) [| 您運行的是最新版本的 HuskSync (v%1%).](#00fb9a)' +update_available: '[HuskSync](#ff7e5e bold) [| 發現可用的新版本: v%1% (running: v%2%).](#ff7e5e)' +reload_complete: '[HuskSync](#00fb9a bold) [| 已重新載入配置和訊息文件](#00fb9a)\n[⚠ Ensure config files are up-to-date on all servers!](#00fb9a)\n[A restart is needed for config changes to take effect.](#00fb9a italic)' +error_invalid_syntax: '[錯誤:](#ff3300) [語法不正確,用法:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&Click to suggest suggest_command=%1%)' +error_invalid_player: '[錯誤:](#ff3300) [找不到這位玩家](#ff7e5e)' +error_no_permission: '[錯誤:](#ff3300) [您沒有權限執行這個指令](#ff7e5e)' +error_console_command_only: '[錯誤:](#ff3300) [該指令只能透過 控制台 執行](#ff7e5e)' +error_in_game_command_only: '[錯誤:](#ff3300) [該指令只能在遊戲內執行](#ff7e5e)' +error_no_data_to_display: '[錯誤:](#ff3300) [找不到任何可顯示的用戶資訊.](#ff7e5e)' +error_invalid_version_uuid: '[錯誤:](#ff3300) [找不到正確的 Version UUID.](#ff7e5e)' +husksync_command_description: 'Manage the HuskSync plugin' +userdata_command_description: 'View, manage & restore player userdata' +inventory_command_description: 'View & edit a player''s inventory' +enderchest_command_description: 'View & edit a player''s Ender Chest' \ No newline at end of file diff --git a/common/src/test/java/net/william278/husksync/DummyHuskSync.java b/common/src/test/java/net/william278/husksync/DummyHuskSync.java deleted file mode 100644 index 1a444e99..00000000 --- a/common/src/test/java/net/william278/husksync/DummyHuskSync.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync; - -import net.william278.desertwell.util.Version; -import net.william278.husksync.config.Locales; -import net.william278.husksync.config.Settings; -import net.william278.husksync.data.DataAdapter; -import net.william278.husksync.database.Database; -import net.william278.husksync.event.EventCannon; -import net.william278.husksync.migrator.Migrator; -import net.william278.husksync.player.OnlineUser; -import net.william278.husksync.redis.RedisManager; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.InputStream; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Level; - -public class DummyHuskSync implements HuskSync { - @Override - @NotNull - public Set getOnlineUsers() { - return Set.of(); - } - - @Override - @NotNull - public Optional getOnlineUser(@NotNull UUID uuid) { - return Optional.empty(); - } - - @Override - @NotNull - public Database getDatabase() { - throw new UnsupportedOperationException(); - } - - @Override - @NotNull - public RedisManager getRedisManager() { - throw new UnsupportedOperationException(); - } - - @Override - @NotNull - public DataAdapter getDataAdapter() { - throw new UnsupportedOperationException(); - } - - @Override - @NotNull - public EventCannon getEventCannon() { - throw new UnsupportedOperationException(); - } - - @Override - @NotNull - public List getAvailableMigrators() { - return List.of(); - } - - @Override - @NotNull - public Settings getSettings() { - return new Settings(); - } - - @Override - @NotNull - public Locales getLocales() { - return new Locales(); - } - - @Override - public InputStream getResource(@NotNull String name) { - throw new UnsupportedOperationException(); - } - - @Override - public void log(@NotNull Level level, @NotNull String message, @NotNull Throwable... throwable) { - System.out.println(message); - } - - @Override - @NotNull - public Version getPluginVersion() { - return Version.fromString("1.0.0"); - } - - @Override - @NotNull - public File getDataFolder() { - return new File("."); - } - - @Override - @NotNull - public Version getMinecraftVersion() { - return Version.fromString("1.16.2"); - } - - @Override - public CompletableFuture reload() { - return CompletableFuture.supplyAsync(() -> true); - } - - @Override - public Set getLockedPlayers() { - return Set.of(); - } -} diff --git a/common/src/test/java/net/william278/husksync/config/LocalesTests.java b/common/src/test/java/net/william278/husksync/config/LocalesTests.java new file mode 100644 index 00000000..cb5ab5ca --- /dev/null +++ b/common/src/test/java/net/william278/husksync/config/LocalesTests.java @@ -0,0 +1,81 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.config; + +import net.william278.annotaml.Annotaml; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; + +@DisplayName("Locales Tests") +public class LocalesTests { + + private Locales englishLocales; + + @BeforeEach + @DisplayName("Test Loading English Locales") + @Test + public void testLoadEnglishLocales() { + try (InputStream locales = LocalesTests.class.getClassLoader().getResourceAsStream("locales/en-gb.yml")) { + Assertions.assertNotNull(locales, "en-gb.yml is missing from the locales folder"); + englishLocales = Annotaml.create(Locales.class, locales).get(); + } catch (IOException | InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @ParameterizedTest(name = "{1} Locales") + @DisplayName("Test All Locale Keys Present") + @MethodSource("provideLocaleFiles") + public void testAllLocaleKeysPresent(@NotNull File file, @SuppressWarnings("unused") @NotNull String keyName) { + try { + final Set fileKeys = Annotaml.create(file, Locales.class).get().rawLocales.keySet(); + englishLocales.rawLocales.keySet() + .forEach(key -> Assertions.assertTrue(fileKeys.contains(key), + "Locale key " + key + " is missing from " + file.getName())); + } catch (IOException | InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @NotNull + private static Stream provideLocaleFiles() { + URL url = LocalesTests.class.getClassLoader().getResource("locales"); + Assertions.assertNotNull(url, "locales folder is missing"); + return Stream.of(Objects.requireNonNull(new File(url.getPath()) + .listFiles(file -> file.getName().endsWith("yml") && !file.getName().equals("en-gb.yml")))) + .map(file -> Arguments.of(file, file.getName().replace(".yml", ""))); + } + +} \ No newline at end of file diff --git a/common/src/test/java/net/william278/husksync/data/DataAdaptionTests.java b/common/src/test/java/net/william278/husksync/data/DataAdaptionTests.java deleted file mode 100644 index b4727a60..00000000 --- a/common/src/test/java/net/william278/husksync/data/DataAdaptionTests.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.data; - -import net.william278.husksync.DummyHuskSync; -import net.william278.husksync.player.DummyPlayer; -import net.william278.husksync.player.OnlineUser; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Tests for the data system {@link DataAdapter} - */ -public class DataAdaptionTests { - - @Test - public void testJsonDataAdapter() { - final OnlineUser dummyUser = DummyPlayer.create(); - dummyUser.getUserData(new DummyHuskSync()).join().ifPresent(dummyUserData -> { - final DataAdapter dataAdapter = new JsonDataAdapter(); - final byte[] data = dataAdapter.toBytes(dummyUserData); - final UserData deserializedUserData = dataAdapter.fromBytes(data); - - // Assert all deserialized data is equal to the original data - Assertions.assertTrue(dummyUserData.getInventory().isPresent()); - Assertions.assertTrue(deserializedUserData.getInventory().isPresent()); - Assertions.assertEquals(dummyUserData.getInventory().get().serializedItems, deserializedUserData.getInventory().get().serializedItems); - Assertions.assertEquals(dummyUserData.getFormatVersion(), deserializedUserData.getFormatVersion()); - }); - } - - @Test - public void testJsonFormat() { - final OnlineUser dummyUser = DummyPlayer.create(); - final String expectedJson = "{\"status\":{\"health\":20.0,\"max_health\":20.0,\"health_scale\":0.0,\"hunger\":20,\"saturation\":5.0,\"saturation_exhaustion\":5.0,\"selected_item_slot\":1,\"total_experience\":100,\"experience_level\":1,\"experience_progress\":1.0,\"game_mode\":\"SURVIVAL\",\"is_flying\":false},\"inventory\":{\"serialized_items\":\"\"},\"ender_chest\":{\"serialized_items\":\"\"},\"potion_effects\":{\"serialized_potion_effects\":\"\"},\"advancements\":[],\"statistics\":{\"untyped_statistics\":{},\"block_statistics\":{},\"item_statistics\":{},\"entity_statistics\":{}},\"minecraft_version\":\"1.19\",\"format_version\":3}"; - AtomicReference json = new AtomicReference<>(); - dummyUser.getUserData(new DummyHuskSync()).join().ifPresent(dummyUserData -> { - final DataAdapter dataAdapter = new JsonDataAdapter(); - final byte[] data = dataAdapter.toBytes(dummyUserData); - json.set(new String(data, StandardCharsets.UTF_8)); - }); - Assertions.assertEquals(expectedJson, json.get()); - } - - @Test - public void testCompressedDataAdapter() { - final OnlineUser dummyUser = DummyPlayer.create(); - dummyUser.getUserData(new DummyHuskSync()).join().ifPresent(dummyUserData -> { - final DataAdapter dataAdapter = new CompressedDataAdapter(); - final byte[] data = dataAdapter.toBytes(dummyUserData); - final UserData deserializedUserData = dataAdapter.fromBytes(data); - - // Assert all deserialized data is equal to the original data - Assertions.assertTrue(dummyUserData.getInventory().isPresent()); - Assertions.assertTrue(deserializedUserData.getInventory().isPresent()); - Assertions.assertEquals(dummyUserData.getInventory().get().serializedItems, deserializedUserData.getInventory().get().serializedItems); - Assertions.assertEquals(dummyUserData.getFormatVersion(), deserializedUserData.getFormatVersion()); - }); - } - - private String getTestSerializedPersistentDataContainer() { - final HashMap> persistentDataTest = new HashMap<>(); - persistentDataTest.put("husksync:byte_test", new PersistentDataTag<>(PersistentDataTagType.BYTE, 0x01)); - persistentDataTest.put("husksync:double_test", new PersistentDataTag<>(PersistentDataTagType.DOUBLE, 2d)); - persistentDataTest.put("husksync:string_test", new PersistentDataTag<>(PersistentDataTagType.STRING, "test")); - persistentDataTest.put("husksync:int_test", new PersistentDataTag<>(PersistentDataTagType.INTEGER, 3)); - persistentDataTest.put("husksync:long_test", new PersistentDataTag<>(PersistentDataTagType.LONG, 4L)); - persistentDataTest.put("husksync:float_test", new PersistentDataTag<>(PersistentDataTagType.FLOAT, 5f)); - persistentDataTest.put("husksync:short_test", new PersistentDataTag<>(PersistentDataTagType.SHORT, 6)); - final PersistentDataContainerData persistentDataContainerData = new PersistentDataContainerData(persistentDataTest); - - final DataAdapter dataAdapter = new JsonDataAdapter(); - UserData userData = new UserData(); - userData.persistentDataContainerData = persistentDataContainerData; - return dataAdapter.toJson(userData, false); - } - - @Test - public void testPersistentDataContainerSerialization() { - Assertions.assertEquals(getTestSerializedPersistentDataContainer(), "{\"persistent_data_container\":{\"persistent_data_map\":{\"husksync:int_test\":{\"type\":\"INTEGER\",\"value\":3},\"husksync:string_test\":{\"type\":\"STRING\",\"value\":\"test\"},\"husksync:long_test\":{\"type\":\"LONG\",\"value\":4},\"husksync:byte_test\":{\"type\":\"BYTE\",\"value\":1},\"husksync:short_test\":{\"type\":\"SHORT\",\"value\":6},\"husksync:double_test\":{\"type\":\"DOUBLE\",\"value\":2.0},\"husksync:float_test\":{\"type\":\"FLOAT\",\"value\":5.0}}},\"format_version\":3}"); - } - - -} diff --git a/common/src/test/java/net/william278/husksync/hook/PlanHookTests.java b/common/src/test/java/net/william278/husksync/hook/PlanDataExtensionTests.java similarity index 71% rename from common/src/test/java/net/william278/husksync/hook/PlanHookTests.java rename to common/src/test/java/net/william278/husksync/hook/PlanDataExtensionTests.java index df12b4f2..000e59a3 100644 --- a/common/src/test/java/net/william278/husksync/hook/PlanHookTests.java +++ b/common/src/test/java/net/william278/husksync/hook/PlanDataExtensionTests.java @@ -20,19 +20,16 @@ package net.william278.husksync.hook; import com.djrapitops.plan.extension.extractor.ExtensionExtractor; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -/** - * Tests for the {@link PlanHook} and {@link PlanDataExtension} implementation - */ -public class PlanHookTests { +@DisplayName("Plan Hook Tests") +public class PlanDataExtensionTests { - /** - * Throws IllegalArgumentException if there is an implementation error or warning. - */ @Test - public void testExtensionImplementationErrors() { - new ExtensionExtractor(new PlanDataExtension()).validateAnnotations(); + @DisplayName("Test Plan Hook Implementation") + public void testPlanHookImplementation() { + new ExtensionExtractor(new PlanHook.PlanDataExtension()).validateAnnotations(); } -} +} \ No newline at end of file diff --git a/common/src/test/java/net/william278/husksync/player/DummyPlayer.java b/common/src/test/java/net/william278/husksync/player/DummyPlayer.java deleted file mode 100644 index 3dd4378b..00000000 --- a/common/src/test/java/net/william278/husksync/player/DummyPlayer.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * This file is part of HuskSync, licensed under the Apache License 2.0. - * - * Copyright (c) William278 - * Copyright (c) contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.william278.husksync.player; - -import de.themoep.minedown.adventure.MineDown; -import net.kyori.adventure.audience.Audience; -import net.william278.desertwell.util.Version; -import net.william278.husksync.config.Settings; -import net.william278.husksync.data.*; -import org.jetbrains.annotations.NotNull; - -import java.util.*; -import java.util.concurrent.CompletableFuture; - -public class DummyPlayer extends OnlineUser { - - private DummyPlayer() { - super(UUID.fromString("00000000-0000-0000-0000-000000000000"), - "DummyPlayer"); - } - - public static DummyPlayer create() { - return new DummyPlayer(); - } - - @Override - public CompletableFuture getStatus() { - return CompletableFuture.supplyAsync(() -> new StatusData(20, 20, 0, - 20, 5, 5, 1, - 100, 1, 1f, "SURVIVAL", false)); - } - - @Override - public CompletableFuture setStatus(@NotNull StatusData statusData, @NotNull Settings settings) { - return CompletableFuture.runAsync(() -> { - // do nothing - }); - } - - @Override - public CompletableFuture getInventory() { - return CompletableFuture.supplyAsync(() -> new ItemData("")); - } - - @Override - public CompletableFuture setInventory(@NotNull ItemData itemData) { - return CompletableFuture.runAsync(() -> { - // do nothing - }); - } - - @Override - public CompletableFuture getEnderChest() { - return CompletableFuture.supplyAsync(() -> new ItemData("")); - } - - @Override - public CompletableFuture setEnderChest(@NotNull ItemData enderChestData) { - return CompletableFuture.runAsync(() -> { - // do nothing - }); - } - - @Override - public CompletableFuture getPotionEffects() { - return CompletableFuture.supplyAsync(() -> new PotionEffectData("")); - } - - @Override - public CompletableFuture setPotionEffects(@NotNull PotionEffectData potionEffectData) { - return CompletableFuture.runAsync(() -> { - // do nothing - }); - } - - @Override - public CompletableFuture> getAdvancements() { - return CompletableFuture.supplyAsync(ArrayList::new); - } - - @Override - public CompletableFuture setAdvancements(@NotNull List advancementData) { - return CompletableFuture.runAsync(() -> { - // do nothing - }); - } - - @Override - public CompletableFuture getStatistics() { - return CompletableFuture.supplyAsync(() -> new StatisticsData(new HashMap<>(), - new HashMap<>(), new HashMap<>(), new HashMap<>())); - } - - @Override - public CompletableFuture setStatistics(@NotNull StatisticsData statisticsData) { - return CompletableFuture.runAsync(() -> { - // do nothing - }); - } - - @Override - public CompletableFuture getLocation() { - return CompletableFuture.supplyAsync(() -> new LocationData("dummy_world", - UUID.fromString("00000000-0000-0000-0000-000000000000"), - "NORMAL", 0, 64, 0, 90f, 180f)); - } - - @Override - public CompletableFuture setLocation(@NotNull LocationData locationData) { - return CompletableFuture.runAsync(() -> { - // do nothing - }); - } - - @Override - public CompletableFuture getPersistentDataContainer() { - return CompletableFuture.supplyAsync(() -> new PersistentDataContainerData(new HashMap<>())); - } - - @Override - public CompletableFuture setPersistentDataContainer(@NotNull PersistentDataContainerData persistentDataContainerData) { - return CompletableFuture.runAsync(() -> { - // do nothing - }); - } - - @Override - public boolean isOffline() { - return false; - } - - @NotNull - @Override - public Version getMinecraftVersion() { - return Version.fromString("1.19-beta123456"); - } - - @Override - @NotNull - public Audience getAudience() { - return Audience.empty(); - } - - @Override - public void sendMessage(@NotNull MineDown mineDown) { - // do nothing - } - - @Override - public void sendActionBar(@NotNull MineDown mineDown) { - // do nothing - } - - @Override - public void sendToast(@NotNull MineDown title, @NotNull MineDown description, - @NotNull String iconMaterial, @NotNull String backgroundType) { - // do nothing - } - - @Override - public boolean hasPermission(@NotNull String node) { - return true; - } - - @Override - public CompletableFuture> showMenu(@NotNull ItemData itemData, boolean editable, - int minimumRows, @NotNull MineDown title) { - // do nothing - return CompletableFuture.completedFuture(Optional.empty()); - } - - - @Override - public boolean isDead() { - return false; - } - - @Override - public boolean isLocked() { - return false; - } - - @Override - public boolean isNpc() { - return false; - } - -} diff --git a/docs/API-Events.md b/docs/API-Events.md index b6605dad..edfecadf 100644 --- a/docs/API-Events.md +++ b/docs/API-Events.md @@ -1,12 +1,12 @@ -HuskSync provides three API events your plugin can listen to when certain parts of the data synchronisation process are performed. These events deal in HuskSync class types, so you may want to familiarize yourself with the [API basics](API) first. Two of the events can be cancelled (thus aborting the synchronisation process at certain stages) and some of the events expose methods letting you affect their outcome (such as modifying the data that is saved during the process). +HuskSync provides three API events your plugin can listen to when certain parts of the data synchronization process are performed. These events deal with HuskSync class types, so you may want to familiarize yourself with the [API basics](API) first. Two of the events can be cancelled (thus aborting the synchronization process at certain stages), and some events expose methods letting you affect their outcome (such as modifying the data that is saved during the process). -Consult the Javadocs for more information -- and don't forget to register your listener when listening for these event calls. Please note that carrying out expensive blocking operations during these events is strongly discouraged as this may affect plugin performance. +Consult the Javadocs for more information—and don't forget to register your listener when listening for these event calls. Please note that carrying out expensive blocking operations during these events is strongly discouraged as this may affect plugin performance. ## List of API Events | Bukkit Event class | Cancellable | Description | |---------------------------|:-----------:|---------------------------------------------------------------------------------------------| -| `BukkitDataSaveEvent` | ✅ | Called when player data snapshot is created, saved and cached due to a DataSaveCause | -| `BukkitPreSync` | ✅ | Called before a player has their data updated from the cache or database, just after login | -| `BukkitSyncCompleteEvent` | ❌ | Called once a player has completed their data synchronisation on login successfully† | +| `BukkitDataSaveEvent` | ✅ | Called when player data snapshot is created, saved and cached due to a DataSaveCause | +| `BukkitPreSyncEvent` | ✅ | Called before a player has their data updated from the cache or database, just after login | +| `BukkitSyncCompleteEvent` | ❌ | Called once a player has completed their data synchronization on login successfully† | -†This can also fire when a user's data is updated while the player is logged in; i.e. when an admin rolls back the user, updates their inventory or Ender Chest through the respective commands, or when an API call is made forcing the user to have their data updated. \ No newline at end of file +†This can also fire when a user's data is updated while the player is logged in; i.e., when an admin rolls back the user, updates their inventory or Ender Chest through the respective commands, or when an API call is made forcing the user to have their data updated. diff --git a/docs/UserData-API.md b/docs/API-v2.md similarity index 73% rename from docs/UserData-API.md rename to docs/API-v2.md index 5fc78400..ee41a19c 100644 --- a/docs/UserData-API.md +++ b/docs/API-v2.md @@ -1,69 +1,18 @@ -HuskSync provides an API for fetching and retrieving `UserData`; a snapshot of a user's synchronization. +> **Warning:** API v2 is no longer supported or compatible with HuskSync v3.0. See [[Data Snapshot API]] for the equivalent v3 API. 🚨 -This page assumes you've read the [[API]] introduction and have imported the HuskSync API into your repository. +HuskSync v2.0 provides an API for fetching and retrieving `UserData`; a snapshot of a user's synchronization. -## Table of contents -1. Creating a class to interface with the API -2. Checking if HuskSync is present and creating the hook -3. Getting an instance of the API -4. Getting a user by UUID -5. Getting a user's data -6. Getting a user's data -7. Getting a user's inventory contents -8. Updating a user's data +This page assumes you've read the general [[API]] introduction and imported HuskSync (v2.x) into your project, and added it as a dependency. -## 1. Creating a class to interface with the API -- Unless your plugin completely relies on HuskSync, you shouldn't put HuskSync API calls into your main class, otherwise if HuskSync is not installed you'll encounter `ClassNotFoundException`s +🚨 HuskSync API v2 only targets HuskSync v2.0-2.2.8. It is **not compatible with HuskSync v3.0+**. The equivalent API for HuskSync v3 is the [[Data Snapshot API]]. -```java -public class HuskSyncAPIHook { - - public HuskSyncAPIHook() { - // Ready to do stuff with the API - } - -} -``` -## 2. Checking if HuskSync is present and creating the hook -- Check to make sure the HuskSync plugin is present before instantiating the API hook class - -```java -public class MyPlugin extends JavaPlugin { - - public HuskSyncAPIHook huskSyncAPIHook; - - @Override - public void onEnable() { - if (Bukkit.getPluginManager().getPlugin("HuskSync") != null) { - this.huskSyncAPIHook = new HuskSyncAPIHook(); - } - } -} -``` +## Table of Contents +1. [Getting a user by UUID](#1-getting-a-user-by-uuid) +2. [Getting a user's data](#2-getting-a-users-data) +3. [Getting a user's inventory contents](#3-getting-a-users-inventory-contents) +4. [Updating a user's data](#4-updating-a-users-data) -## 3. Getting an instance of the API -- You can now get the API instance by calling `HuskSyncAPI#getInstance()` - -```java -import net.william278.husksync.api.HuskSyncAPI; - -public class HuskSyncAPIHook { - - private final HuskSyncAPI huskSyncAPI; - - public HuskSyncAPIHook() { - this.huskSyncAPI = HuskSyncAPI.getInstance(); - } - -} -``` - -## 4. CompletableFuture and Optional basics -- HuskSync's API methods return `CompletableFuture`s and `Optional`s. -- A `CompletableFuture` is an asynchronous callback mechanism. The method will be processed asynchronously and the data returned when it has been retrieved. While you can use `CompletableFuture#join()` to block the thread until the future has finished processing, it's smarter to use `CompletableFuture#thenAccept(data -> {})` to do what you want to do with the `data` you requested after it has asynchronously been retrieved, to prevent lag. -- An `Optional` is a null-safe representation of data, or no data. You can check if the Optional is empty via `Optional#isEmpty()` (which will be returned by the API if no data could be found for the call you made). If the optional does contain data, you can get it via `Optional#get()`. - -## 5. Getting a user by UUID +## 1. Getting a user by UUID - HuskSync has a `User` object, representing a user saved in the database. You can retrieve a user using `HuskSyncAPI#getUser(uuid)` - If you have an online `org.bukkit.Player` object, you can use `BukkitPlayer#adapt(player)` to get an `OnlineUser` (extends `User`), representing a logged-in user. @@ -75,7 +24,6 @@ public class HuskSyncAPIHook { public HuskSyncAPIHook() { this.huskSyncAPI = HuskSyncAPI.getInstance(); } - public void logUserName(UUID uuid) { // getUser() returns a CompletableFuture supplying an Optional @@ -87,14 +35,14 @@ public class HuskSyncAPIHook { return; } // The User object has two fields; uuid and username. - System.out.println("User name is: " + optionalUser.get().username); + System.out.println("User name is: %s", optionalUser.get().username); }); } } ``` -## 6. Getting a user's data +## 2. Getting a user's data - With a `User` object, we can now call `HuskSyncAPI#getUserData()` to fetch their latest data - The `UserData` object contains eight data "modules", each holding certain parts of information. - UserData does not have to contain any single data "module"; the modules contained in a given UserData object when user data is saved by the plugin are determined by the plugin config settings. @@ -130,7 +78,7 @@ public class HuskSyncAPIHook { Optional statusData = optionalUserData.get().getStatus(); // Print the health from the fields, if the user has a status object statusData.ifPresent(status -> { - System.out.println(user.username + "'s health: " + status.health + "/" + status.maxHealth); + System.out.println("%s's health: %d/%d", user.username, status.health, status.maxHealth); }); } }); @@ -139,7 +87,7 @@ public class HuskSyncAPIHook { } ``` -## 7. Getting a user's inventory contents +## 3. Getting a user's inventory contents - The API provides methods for deserialzing `ItemData` used to hold Base 64 serialized inventory and ender chest `ItemStack` array contents into actual `ItemStack` array data. - For deserialziing inventories, use `HuskSyncAPI#deserializeInventory(serializedItems)` - For deserialziing ender chests, use `HuskSyncAPI#deserializeItemStackArray(serializedItems)` @@ -212,7 +160,7 @@ private void printEnderChestItems(User user) { -## 8. Updating a user's data +## 4. Updating a user's data - You can use `HuskSyncAPI#setUserData(user, userData)` to set a user's modified data to the database. - If you need to modify user data every time it's updated, you may want to look at listening to one of HuskSync's provided events instead. - You can use `HuskSyncAPI#serializeItemStackArray(itemStack[])` to serialize an array of ItemStacks into Base 64. @@ -233,7 +181,7 @@ public class HuskSyncAPIHook { // This returns a CompletableFuture that will invoke #thenRun() when it has completed huskSyncAPI.setUserData(user, data).thenRun(() -> { - System.out.println("Healed " + user.username + "!"); + System.out.println("Healed %s!", user.username); }); } }); diff --git a/docs/API.md b/docs/API.md index ee31e87f..ef39ae8f 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,13 +1,14 @@ -The HuskSync API provides methods for retrieving and updating user data, as well as a number of events for tracking when user data is synced and saved. +The HuskSync API (v3) provides methods for retrieving and updating [data snapshots](Data-Snapshot-API), a number of [[API Events]] for tracking when user data is synced and saved, and infrastructure for registering serializers to [synchronise custom data types](Custom-Data-API). ## Compatibility [![Maven](https://repo.william278.net/api/badge/latest/releases/net/william278/husksync?color=00fb9a&name=Maven&prefix=v)](https://repo.william278.net/#/releases/net/william278/husksync/) The HuskSync API shares version numbering with the plugin itself for consistency and convenience. Please note minor and patch plugin releases may make API additions and deprecations, but will not introduce breaking changes without notice. -| API Version | HuskSync Versions | Supported | +| API Version | HuskSync Versions | Supported | |:-----------:|:--------------------:|:---------:| -| v2.x | _v2.0—Current_ | ✅ | +| v3.x | _v3.0—Current_ | ✅ | +| v2.x | _v2.0—v2.2.8_ | ❌ | | v1.x | _v1.0—v1.4.1_ | ❌️ |
@@ -16,10 +17,15 @@ The HuskSync API shares version numbering with the plugin itself for consistency HuskSync versions prior to `v2.2.5` are distributed on [JitPack](https://jitpack.io/#/net/william278/HuskSync), and you will need to use the `https://jitpack.io` repository instead.
-## Table of contents -1. Adding the API to your project -2. Adding HuskSync as a dependency -3. Next steps +## Table of Contents +1. [API Introduction](#api-introduction) + 1. [Setup with Maven](#11-setup-with-maven) + 2. [Setup with Gradle](#12-setup-with-gradle) +2. [Creating a class to interface with the API](#3-creating-a-class-to-interface-with-the-api) +3. [Checking if HuskSync is present and creating the hook](#4-checking-if-husksync-is-present-and-creating-the-hook) +4. [Getting an instance of the API](#5-getting-an-instance-of-the-api) +5. [CompletableFuture and Optional basics](#6-completablefuture-and-optional-basics) +6. [Next steps](#7-next-steps) ## API Introduction ### 1.1 Setup with Maven @@ -80,7 +86,59 @@ softdepend: # Or, use 'depend' here - HuskSync ``` -### 3. Next steps +## 3. Creating a class to interface with the API +- Unless your plugin completely relies on HuskSync, you shouldn't put HuskSync API calls into your main class, otherwise if HuskSync is not installed you'll encounter `ClassNotFoundException`s + +```java +public class HuskSyncAPIHook { + + public HuskSyncAPIHook() { + // Ready to do stuff with the API + } + +} +``` +## 4. Checking if HuskSync is present and creating the hook +- Check to make sure the HuskSync plugin is present before instantiating the API hook class + +```java +public class MyPlugin extends JavaPlugin { + + public HuskSyncAPIHook huskSyncAPIHook; + + @Override + public void onEnable() { + if (Bukkit.getPluginManager().getPlugin("HuskSync") != null) { + this.huskSyncAPIHook = new HuskSyncAPIHook(); + } + } +} +``` + +## 5. Getting an instance of the API +- You can now get the API instance by calling `HuskSyncAPI#getInstance()` + +```java +import net.william278.husksync.api.BukkitHuskSyncAPI; + +public class HuskSyncAPIHook { + + private final HuskSyncAPI huskSyncAPI; + + public HuskSyncAPIHook() { + this.huskSyncAPI = HuskSyncAPI.getInstance(); + } + +} +``` + +## 6. CompletableFuture and Optional basics +- HuskSync's API methods often deal with `CompletableFuture`s and `Optional`s. +- A `CompletableFuture` is an asynchronous callback mechanism. The method will be processed asynchronously and the data returned when it has been retrieved. While you can use `CompletableFuture#join()` to block the thread until the future has finished processing, it's smarter to use `CompletableFuture#thenAccept(data -> {})` to do what you want to do with the `data` you requested after it has asynchronously been retrieved, to prevent lag. +- An `Optional` is a null-safe representation of data, or no data. You can check if the Optional is empty via `Optional#isEmpty()` (which will be returned by the API if no data could be found for the call you made). If the optional does contain data, you can get it via `Optional#get(). + +### 7. Next steps Now that you've got everything ready, you can start doing stuff with the HuskSync API! -- [[UserData API]] — Get data snapshots and update current user data +- [[Data Snapshot API]] — Get, edit, create & delete data snapshots and update players +- [[Custom Data API]] — Register custom data types to sync your plugin's data with HuskSync - [[API Events]] — Listen to, cancel and modify the result of data synchronization events \ No newline at end of file diff --git a/docs/Commands.md b/docs/Commands.md index c5ab087b..cbab7b47 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -1,17 +1,97 @@ -This page contains a table of HuskSync commands and their required permission nodes. +This page contains a table of HuskSync commands and their required permission nodes. You can also use wildcard patterns for each command, such as `husksync.command..*` to grant access to all sub-commands. -| Command | Description | Permission | -|-----------------------------------------------|--------------------------------------|--------------------------------------| -| `/husksync` | Use `/husksync` subcommands | `husksync.command.husksync` | -| `/husksync info` | View plugin information | `husksync.command.husksync info` | -| `/husksync reload` | Reload config & message files | `husksync.command.husksync.reload` | -| `/husksync update` | Check if an update is available | `husksync.command.husksync.update` | -| `/husksync migrate [args]` | Migrate user data | _Console-only_ | -| `/userdata view [version_uuid]` | View a snapshot of user data | `husksync.command.userdata` | -| `/userdata restore ` | Restore a snapshot of user data | `husksync.command.userdata.manage` | -| `/userdata delete ` | Delete a snapshot of user data | `husksync.command.userdata.manage` | -| `/userdata pin ` | Pin a snapshot of user data | `husksync.command.userdata.manage` | -| `/inventory [version_uuid]` | View a user's inventory contents | `husksync.command.inventory`† | -| `/enderchest [version_uuid]` | View a user's ender chest contents | `husksync.command.enderchest`†| - -† The respective `husksync.command.inventory.edit` and `husksync.command.enderchest.edit` permission node is required to be able to edit a user's inventory/ender chest using the interface. \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CommandDescriptionPermission
/husksync/husksyncView & manage plugin system informationhusksync.command.husksync
/husksync aboutView information about the pluginhusksync.command.husksync.about
/husksync reloadReload the plugin configurationhusksync.command.husksync.reload
/husksync migrateMigrate data from other plugins/legacy versions(Console-only)
/husksync updateCheck for plugin updateshusksync.command.husksync.update
/userdata/userdataView & manage user data snapshotshusksync.command.userdata
/userdata listView a list of a player's data snapshotshusksync.command.userdata.list
/userdata viewView a player's user data snapshothusksync.command.userdata.view
/userdata restoreRestore a data snapshot for a userhusksync.command.userdata.restore
/userdata deleteDelete user data snapshotshusksync.command.userdata.delete
/userdata pinPin and unpin a user data snapshotshusksync.command.userdata.pin
/userdata dumpDump a user data snapshothusksync.command.userdata.dump
/inventoryView the inventory of a user/a data snapshothusksync.command.inventory
Edit the contents of a user's current inventoryhusksync.command.inventory.edit
/enderchestView the Ender Chest of a user/a data snapshothusksync.command.enderchest
Edit the contents of a user's current Ender Chesthusksync.command.enderchest.edit
\ No newline at end of file diff --git a/docs/Config-File.md b/docs/Config-File.md index 9e57b9ea..f19284db 100644 --- a/docs/Config-File.md +++ b/docs/Config-File.md @@ -10,65 +10,98 @@ This page contains the configuration file reference for HuskSync. The config fil # ┃ Developed by William278 ┃ # ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ # ┣╸ Information: https://william278.net/project/husksync +# ┣╸ Config Help: https://william278.net/docs/husksync/config-file/ # ┗╸ Documentation: https://william278.net/docs/husksync +# Locale of the default language file to use. Docs: https://william278.net/docs/huskhomes/translations language: en-gb +# Whether to automatically check for plugin updates on startup check_for_updates: true +# Specify a common ID for grouping servers running HuskSync. Don't modify this unless you know what you're doing! cluster_id: '' +# Enable development debug logging debug_logging: false +# Whether to provide modern, rich TAB suggestions for commands (if available) +brigadier_tab_completion: false +# Whether to enable the Player Analytics hook. Docs: https://william278.net/docs/husksync/plan-hook +enable_plan_hook: true database: + # Type of database to use (MYSQL, MARIADB) + type: MYSQL credentials: - # Database connection settings + # Specify credentials here for your MYSQL or MARIADB database host: localhost port: 3306 database: HuskSync username: root password: pa55w0rd - parameters: ?autoReconnect=true&useSSL=false + parameters: ?autoReconnect=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8 connection_pool: - # MySQL connection pool properties + # MYSQL / MARIADB database Hikari connection pool properties. Don't modify this unless you know what you're doing! maximum_pool_size: 10 minimum_idle: 10 maximum_lifetime: 1800000 keepalive_time: 0 connection_timeout: 5000 + # Names of tables to use on your database. Don't modify this unless you know what you're doing! table_names: users: husksync_users user_data: husksync_user_data redis: credentials: - # Redis connection settings + # Specify the credentials of your Redis database here. Set "password" to '' if you don't have one host: localhost port: 6379 password: '' use_ssl: false synchronization: - # Synchronization settings - max_user_data_snapshots: 5 + # The number of data snapshot backups that should be kept at once per user + max_user_data_snapshots: 16 + # Number of hours between new snapshots being saved as backups (Use "0" to backup all snapshots) + snapshot_backup_frequency: 4 + # List of save cause IDs for which a snapshot will be automatically pinned (so it won't be rotated). Docs: https://william278.net/docs/husksync/data-rotation#save-causes + auto_pinned_save_causes: + - INVENTORY_COMMAND + - ENDERCHEST_COMMAND + - BACKUP_RESTORE + - CONVERTED_FROM_V2 + - LEGACY_MIGRATION + - MPDB_MIGRATION + # Whether to create a snapshot for users on a world when the server saves that world save_on_world_save: true + # Whether to create a snapshot for users when they die (containing their death drops) save_on_death: false + # Whether to save empty death drops for users when they die save_empty_drops_on_death: true + # Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing compress_data: true + # Where to display sync notifications (ACTION_BAR, CHAT, TOAST or NONE) notification_display_slot: ACTION_BAR - synchronise_dead_players_changing_server: true + # (Experimental) Persist Cartography Table locked maps to let them be viewed on any server + persist_locked_maps: false + # Whether dead players who log out and log in to a different server should have their items saved. You may need to modify this if you're using the keepInventory gamerule. + synchronize_dead_players_changing_server: true + # How long, in milliseconds, this server should wait for a response from the redis server before pulling data from the database instead (i.e., if the user did not change servers). network_latency_milliseconds: 500 + # Which data types to synchronize (Docs: https://william278.net/docs/husksync/sync-features) features: - health: true - statistics: true - persistent_data_container: false hunger: true - ender_chests: true - advancements: true - location: false + persistent_data: false + inventory: true game_mode: true - potion_effects: true - locked_maps: false - inventories: true - max_health: true + advancements: true experience: true - blacklisted_commands_while_locked: [] + ender_chest: true + potion_effects: true + location: false + statistics: true + health: true + # Commands which should be blocked before a player has finished syncing (Use * to block all commands) + blacklisted_commands_while_locked: + - '*' + # Event priorities for listeners (HIGHEST, NORMAL, LOWEST). Change if you encounter plugin conflicts event_priorities: - join_listener: LOWEST quit_listener: LOWEST + join_listener: LOWEST death_listener: NORMAL ``` diff --git a/docs/Custom-Data-API.md b/docs/Custom-Data-API.md new file mode 100644 index 00000000..d2e438ad --- /dev/null +++ b/docs/Custom-Data-API.md @@ -0,0 +1,131 @@ +HuskSync allows you to save and synchronize custom data through the existing versatile DataSnapshot format. This page assumes you've read the [[API]] introduction and are familiar with the aforementioned [[Data Snapshot API]]. + +To do this, you create and register an implementation of a platform `Data` class (e.g., `BukkitData`) and a corresponding `Serializer` class (e.g., `BukkitSerializer`). You can then apply your custom data type to a user using the `OnlineUser#setData(Identifier, Data)` method. + +> **Note:** Before you begin, consider if this is what you'd like to do. For simpler/smaller data sync tasks you may wish to consider using the PersistentDataContainer API format instead, which is a bit more portable if you decide to exit the HuskSync ecosystem. + +## Table of Contents +1. [Extending the BukkitData Class](#1-extending-the-bukkitdata-class) + 1. [Implementing Adaptable](#11-implementing-adaptable) +2. [Extending the BukkitSerializer Class](#2-extending-the-bukkitserializer-class) +3. [Identifiers and registering our Serializer](#3-identifiers--registering-our-serializer) +4. [Setting and Getting our Data to/from a User](#4-setting-and-getting-our-data-tofrom-a-user) + +## 1. Extending the BukkitData Class +* HuskSync provides a `Data` interface that you must implement that will represent your custom data. +* On the Bukkit platform, you should create a class that `extends` `BukkitData`. This class has method to implement: `#apply(BukkitUser, BukkitHuskSync)`, which will be called when the data needs to be applied to the player. +* You can use the `BukkitUser` class to get the `Player` object of the user. Avoid using the `BukkitHuskSync` class as this is for accessing plugin internals. + +
+Code Example — LoginParticleData class + +```java +// An example of a BukkitData class that you could use in a cosmetic plugin to store player particle data. +public class LoginParticleData extends BukkitData { + + private String particleId; + private int numberOfParticles; + + public LoginParticleData(String particleId, int numberOfParticles) { + this.particleId = particleId; + this.numberOfParticles = numberOfParticles; + } + + // This method is called whenever a user has their data applied. + // If you just want to use HuskSync to sync data used elsewhere, you don't have to do anything here, of course + @Override + public void apply(BukkitUser user, BukkitHuskSync plugin) { + final Player player = user.getPlayer(); + + // Let's use the Bukkit API to spawn some particles when a user's data is applied (e.g. when they login). + player.spawnParticle(Particle.valueOf(particleId), player.getLocation(), numberOfParticles); + } + +} +``` +
+ +### 1.1 Implementing Adaptable +* HuskSync provides the `Adaptable` marker interface to make it easier to Serialize and Deserialize your data using Gson (needed in the next step). +* I strongly advise implementing `Adaptable`. This requires a zero-arg constructor. Note that you _cannot_ serialize proprietary data types or `final` fields using `Adaptable`. + +
+Code Example — Adaptable LoginParticleData class + +```java +// We've implemented Adaptable here to make it easier to serialize and deserialize our data using Gson. +public class LoginParticleData extends BukkitData implements Adaptable { + + private String particleId; + private int numberOfParticles; + + public LoginParticleData(String particleId, int numberOfParticles) { + this.particleId = particleId; + this.numberOfParticles = numberOfParticles; + } + + @SuppressWarnings("unused") // Suppress compiler warnings + private LoginParticleData() { + // This is required for the Adaptable interface so that Gson can intantiate the class when deserializing. + } + + @Override + public void apply(BukkitUser user, BukkitHuskSync plugin) { + user.getPlayer().spawnParticle(Particle.valueOf(particleId), player.getLocation(), numberOfParticles); + } + +} +``` +
+ +## 2. Extending the BukkitSerializer Class +* To store your `Data`, you'll need to provide a `Serializer` class that will be used to serialize and deserialize your `Data` to and from a java `String` that can later be converted to a byte array and compressed/stored by HuskSync. + * For instance, you'd need a class like: `public class LoginParticleSerializer extends BukkitSerializer implements Serializer` to serialize the previous example. + * You'd then need to implement the `Serializer` interface, which has two methods: `#serialize(T)` and `#deserialize(String)`. +* If you made your class `Adaptable` as per above HuskSync also provides a `BukkitSerializer.Json` class which you can extend to create a simple serializer using Gson. + * This is the recommended way of creating a serializer, though, if you're dealing with NBT data, you may wish to implement a base Serializer with your own methods. + +```java +// An example of a BukkitSerializer class that you could use in a cosmetic plugin to store player particle data. +public class LoginParticleSerializer extends BukkitSerializer.Json implements Serializer { + + // We need to create a constructor that takes our instance of the API + public GameMode(@NotNull HuskSyncAPI api) { + super(api, LoginParticleData.class); // We pass the class type here so that Gson knows what class we're serializing + } + +} +``` + +## 3. Identifiers & registering our Serializer +* Now that we have our `Data` and `Serializer` classes, we need to register them with HuskSync. +* To do this, we register an `Identifier` with HuskSync. This is a unique identifier key for your data type. + * Use `Identifer#from(String, String)` or `Identifier#from(Key)` to create an identifier from a namespace-value pair or an adventure `Key` object. +* Make sure that the plugin you're writing registers the serializer on every server so that HuskSync will serialize the data. + +```java +// Create an identifier for our data (you may wish to store this somewhere where it can be accessed statically) +public static Identifier LOGIN_PARTICLES_ID = Identifier.from("myplugin", "login_particles"); + +// (...) + +// Register our serializer +huskSyncAPI.registerSerializer(LOGIN_PARTICLES_ID, new LoginParticleSerializer(HuskSyncAPI.getInstance())); +``` + +## 4. Setting and getting our Data to/from a User +* Now that we've registered our `Data` and `Serializer` classes, we can set our data to a user, applying it to them. +* To do this, we use the `OnlineUser#setData(Identifier, Data)` method. + * This method will apply the data to the user, and store the data to the plugin player custom data map, to allow the data to be retrieved later and be saved to snapshots. +* Snapshots created on servers where the data type is registered will now contain our data and synchronise between instances! + +```java +// Create an instance of our data +LoginParticleData loginParticleData = new LoginParticleData("FIREWORKS_SPARK", 10); + +// Set the data to a player +huskSyncAPI.getUser(player).setData(LOGIN_PARTICLES_ID, loginParticleData); + +// Get our data from a player +LoginParticleData loginParticleData = (LoginParticleData) huskSyncAPI.getUser(player).getData(LOGIN_PARTICLES_ID); +``` \ No newline at end of file diff --git a/docs/Data-Rotation.md b/docs/Data-Rotation.md index 274ea5be..1203f577 100644 --- a/docs/Data-Rotation.md +++ b/docs/Data-Rotation.md @@ -8,26 +8,29 @@ Each user data snapshot has: - a timestamp (when it was created) - a save cause (why it was created) - a flag to indicate if the snapshot has been pinned (preventing it from being rotated) +- a map of saved data -By default, HuskSync will store 5 user data snapshots about a user (including their latest snapshot). After that, when a new user snapshot is set, the oldest snapshot will automatically be deleted. You can change the number of snapshots to keep by changing the `max_user_data_snapshots` setting in the `config.yml` file (minimum 1). +By default, HuskSync will automatically replace the user's current snapshot in the database if it has been less than 4 hours since the last snapshot was created. This can be changed in the `config.yml` file by changing the `snapshot_backup_frequency` setting under `synchronization`. Setting this to "0" will save a new snapshot each time data is saved. -Pinned user data snapshots are exempt from being rotated and can only be deleted manually in-game. +HuskSync will keep the 16 most recent data snapshots for each user (including their current data). After that, when a new user snapshot is set, the oldest snapshot will automatically be deleted. You can change the number of snapshots to keep by changing the `max_user_data_snapshots` setting (minimum 1). + +Pinned user data snapshots are exempt from being replaced/rotated and can only be deleted manually in-game. ## Viewing user data -To view a list of a user's snapshots, use `/userdata list `. Their most recent snapshots will be listed from the database, from newest to oldest. You can click the buttons to navigate through their pages. +To view a list of a user's snapshots, use `/userdata list [username]`. Their most recent snapshots will be listed from the database, from newest to oldest. You can click the buttons to navigate through their pages. -[![Data snapshot list](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/data-snapshot-list.png)](#) +![Data snapshot list](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/data-snapshot-list.png) Snapshots marked with a star after the number have been pinned. Hover over it to view more information. -You can then click on the items in the list in chat to view an overview of each snapshot. Alternatively, to view a user's most recent data snapshot, use `/userdata view `. +You can then click on the items in the list in chat to view an overview of each snapshot. Alternatively, to view a user's most recent data snapshot, use `/userdata view [username]`. -[![Data snapshot viewer](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/data-snapshot-viewer.png)](#) +[Data snapshot viewer](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/data-snapshot-viewer.png) ## Managing user data You can use the "Manage" buttons to manage user data. These buttons will only appear if you have the userdata command manage permission. (See [[Commands]]) - Click on "Delete" to remove the data -- Click on "Restore" to restore the user data. If the user is online, their items and stats will be updated, otherwise they will be set to this data upon next login. +- Click on "Restore" to restore the user data. If the user is online, their items and stats will be updated, otherwise their data will be set to this snapshot upon their next login. - Click on "Pin" to pin the user data. An indicator will appear in the data viewer and list marking the snapshot as being pinned. ## Save causes @@ -39,7 +42,8 @@ Data save causes, marked with a 🚩 flag, indicate what caused the data to be s - **inventory command**: Indicates data was saved by editing inventory contents via the `/inventory` command - **enderchest command**: Indicates data was saved by editing Ender Chest contents via the `/enderchest` command - **backup restore**: Indicates data was saved by restoring it from a previous version -- **api**: Indicates data was saved by an [[API]] call +- **api**: Indicates data was saved by a call to the HuskSync [[API]] - **mpdb migration**: Indicates data was saved from being imported from MySQLPlayerDataBridge (See [[MPDB Migration]]) - **legacy migration**: Indicates data was saved from being imported from a legacy version (v1.x - See [[Legacy Migration]]) -- **unknown**: Indicates data was saved by an unknown cause. \ No newline at end of file +- **converted from v2**: Indicates data was automatically converted from HuskSync v2.0's data format +- **unknown**: Indicates data was saved by an unknown saveCause. \ No newline at end of file diff --git a/docs/Data-Snapshot-API.md b/docs/Data-Snapshot-API.md new file mode 100644 index 00000000..9480d4c0 --- /dev/null +++ b/docs/Data-Snapshot-API.md @@ -0,0 +1,458 @@ +HuskSync v3.0 provides an API for getting, creating, editing and deleting `DataSnapshot`s; a snapshot of a user at a given moment in time. This page will walk you through how to manipulate delete snapshots using the HuskSync API. + +This page assumes you have read the general [[API]] introduction and that you have both imported HuskSync (v3.x) into your project and added it as a dependency. + +## Table of Contents +1. [Getting a User](#1-getting-a-user) +2. [Getting DataSnapshots for a User](#2-getting-datasnapshots-for-a-user) + 1. [Getting a User's current data](#21-getting-a-users-current-data) + 2. [Getting a User's latest saved DataSnapshot](#22-getting-a-users-latest-saved-datasnapshot) + 3. [Getting a list of a User's saved DataSnapshots](#23-getting-a-list-of-a-users-saved-datasnapshots) +3. [Packing and Unpacking DataSnapshots](#3-packing-and-unpacking-datasnapshots) +4. [Getting and setting data in a DataSnapshot](#4-getting-and-setting-data-in-a-datasnapshot) + 1. [Data Types](#41-data-types) + 2. [Editing Health, Hunger, Experience, and GameMode data](#42-editing-health-hunger-experience-and-gamemode-data) + 3. [Editing Inventory and Ender Chest data](#43-editing-inventory-and-ender-chest-data) + 4. [Editing Location data](#44-editing-location-data) + 5. [Editing Advancement data](#45-editing-advancement-data) +5. [Creating new DataSnapshots](#5-creating-new-datasnapshots) + 1. [Creating a new snapshot from a player's current data](#51-creating-a-new-snapshot-from-a-players-current-data) + 2. [Creating a new snapshot from scratch](#52-creating-a-new-snapshot-from-scratch) +6. [Deleting DataSnapshots](#6-deleting-datasnapshots) + +## 1. Getting a User +* HuskSync has a `User` object, representing a user saved in the database. You can retrieve a user using `HuskSyncAPI#getUser(uuid)` + +
+Code Example — Getting a user by UUID + +```java +// getUser() returns a CompletableFuture supplying an Optional +huskSyncAPI.getUser(uuid).thenAccept(optionalUser -> { + // Check if we found a user by that UUID either online or on the database + if (optionalUser.isEmpty()) { + // If we didn't, we'll log that they don't exist + System.out.println("User does not exist!"); + return; + } + + // The User object provides methods for getting a user's UUID and username + System.out.println("Found %s", optionalUser.get().getUsername()); +}); +``` +
+ +* If you have an online `org.bukkit.Player` object, you can use `BukkitPlayer#adapt(player)` to get an `OnlineUser` (extends `User`), representing a logged-in user. + +
+Code Example — Getting an online user + +```java +// Get an online user +OnlineUser user = huskSyncAPI.getUser(player); +System.out.println("Hello, %s!", user.getUsername()); +``` +
+ +## 2. Getting DataSnapshots for a User +### 2.1 Getting a User's current data +* HuskSync provides a method for getting the user's current data. `HuskSyncAPI#getCurrentData(User)` returns a `CompletableFuture` supplying an `Optional`. +* This method will get the user's current data if they are online on the network, or their last saved data if they are offline (or, an empty optional if they user has never logged on). + +
+Code Example — Getting a user's current DataSnapshot + +```java +// Get a user's current data +huskSyncAPI.getCurrentData(user).thenAccept(optionalSnapshot -> { + if (optionalSnapshot.isEmpty()) { + System.out.println("Couldn't get data for %s", user.getUsername()); + return; + } + + // Get the snapshot, which you can then do stuff with + DataSnapshot.Unpacked snapshot = optionalSnapshot.get(); +}); +``` +
+ +### 2.2 Getting a User's latest saved DataSnapshot +* Note that the snapshot returned by the previous method _is not necessarily saved in the database_. +* If you want to get the user's last saved snapshot, use `HuskSyncAPI#getLatestSnapshot(User)` instead: + +
+Code Example — Getting a user's latest saved DataSnapshot + +```java +// Get a user's latest saved snapshot +huskSyncAPI.getLatestSnapshot(user).thenAccept(optionalSnapshot -> { + if (optionalSnapshot.isEmpty()) { + System.out.println("%s has no saved snapshots!", user.getUsername()); + return; + } + + // Get the snapshot, which you can then do stuff with + DataSnapshot.Unpacked snapshot = optionalSnapshot.get(); +}); +``` +
+ +### 2.3 Getting a list of a User's saved DataSnapshots +* If you want to get a list of all of a user's saved snapshots, you can use `HuskSyncAPI#getSnapshots(User)`. This method returns a `CompletableFuture` supplying an `Optional>`. + +
+Code Example — Getting all of a user's saved DataSnapshots + +```java +// Get a user's saved snapshots +huskSyncAPI.getSnapshots(user).thenAccept(optionalSnapshots -> { + if (optionalSnapshots.isEmpty()) { + System.out.println("%s has no saved snapshots!", user.getUsername()); + return; + } + + // Get the list of snapshots, which you can then do stuff with + List snapshots = optionalSnapshots.get(); +}); +``` +
+ +## 3. Packing and Unpacking DataSnapshots +* HuskSync provides two types of `DataSnapshot` objects: `DataSnapshot.Packed` and `DataSnapshot.Unpacked`. + - `DataSnapshot.Packed` is a snapshot that has had its data serialized into a byte map. This snapshot is ready to be saved in the database or set to Redis. + - `DataSnapshot.Unpacked` is a snapshot that has been unpacked from a `DataSnapshot.Packed` object. You can get, set, and manipulate data from these snapshots. +* Most of the time, you won't need to worry about this, as HuskSync typically deals with `Unpacked` snapshots. However, if you need to convert between the two (e.g., if you wish to copy the snapshot), you can use the `HuskSyncAPI#packSnapshot(DataSnapshot.Unpacked)` and `HuskSyncAPI#unpackSnapshot(DataSnapshot.Packed)` methods. +* The editor method `HuskSyncAPI#editPackedSnapshot(DataSnapshot.Packed, Consumer)` additionally provides a utility for unpacking, editing, then repacking a packed `DataSnapshot` object. + +
+Code Example — Packing and unpacking snapshots + +```java +// Get a user's current data +huskSyncAPI.getCurrentData(user).thenAccept(optionalSnapshot -> { + if (optionalSnapshot.isEmpty()) { + System.out.println("User does not exist!"); + return; + } + + // Get the snapshot + DataSnapshot.Unpacked snapshot = optionalSnapshot.get(); + + // Pack the snapshot + DataSnapshot.Packed packedSnapshot = huskSyncAPI.packSnapshot(snapshot); + // You can call #copy() on a packed snapshot to make a copy of it, which you can then edit + + // Unpack the snapshot again + DataSnapshot.Unpacked unpackedSnapshot = huskSyncAPI.unpackSnapshot(packedSnapshot); +}); +``` +
+ +## 4. Getting and setting data in a DataSnapshot +* Data within `DataSnapshot`s is represented by `Data` objects of different types; `Data.Items.Inventory` represents Inventory data, `Data.Health` represents a user's current/max health, `Data.Hunger` represents a user's current/max hunger, and so on. +* On Bukkit servers, `BukkitData` classes implement `Data` classes and provide utilities for converting between `Bukkit` and `HuskSync` data types. +* `DataSnapshot.Unpacked` provides methods for getting and setting `Data` in the snapshot, such as `DataSnapshot.Unpacked#getInventory()` (which returns an `Optional`) and `DataSnapshot.Unpacked#setHealth(Data.Health)`. + +### 4.1 Data Types +| Identifier Key | Description | Get Method | Set Method | +|----------------------------|--------------------------------------|-----------------------|------------------------| +| `husksync:inventory` | User inventories & held item slot | `#getInventory` | `#setInventory` | +| `husksync:ender_chest` | User Ender Chests | `#getEnderChest` | `#setEnderChest` | +| `husksync:potion_effects` | User active potion effects | `#getPotionEffects` | `#setPotionEffects` | +| `husksync:advancements` | User advancements | `#getAdvancements` | `#setAdvancements` | +| `husksync:location` | User location | `#getLocation` | `#setLocation` | +| `husksync:statistics` | User statistics | `#getStatistics` | `#setStatistics` | +| `husksync:health` | User health | `#getHealth` | `#setHealth` | +| `husksync:hunger` | User hunger, saturation & exhaustion | `#getHunger` | `#setHunger` | +| `husksync:experience` | User level, experience, and score | `#getExperience` | `#setExperience` | +| `husksync:game_mode` | User game mode and flight status | `#getGameMode` | `#setGameMode` | +| `husksync:persistent_data` | User persistent data container | `#getPersistentData` | `#setPersistentData` | +| Custom types; `plugin:foo` | Any custom data | `#getData(Identifer)` | `#setData(Identifier)` | + +* Plugin developers may supply their own `Data` classes for synchronisation & saving by implementing the `Data` interface and registering a `Serializer<>` for their class to an `Identifier`. See the [[Custom Data API]] page for more information. +* You can only get data from snapshots where a serializer has been registered for it on this server and, in the case of the built-in data types, where the sync feature has been enabled in the [[Config File]]. If you try to get data from a snapshot where the data type is not supported, you will get an empty `Optional`. + +### 4.2 Editing Health, Hunger, Experience, and GameMode data +* `DataSnapshot.Unpacked#getHealth()` returns an `Optional`, which you can then use to get the player's current and max health. +* `DataSnapshot.Unpacked#setHealth(Data.Health)` sets the player's current and max health. You can create a `Health` instance to pass on the Bukkit platform through `BukkitData.Health.from(double, double, double)`. +* Similar methods exist for Hunger, Experience, and GameMode data types +* Once you've updated the data in the snapshot, you can save it to the database using `HuskSyncAPI#setCurrentData(user, userData)`. + +
+Code Example — Getting and setting a player's health + +```java +// Get a user's current data +huskSyncAPI.getCurrentData(user).thenAccept(optionalSnapshot -> { + if (optionalSnapshot.isEmpty()) { + System.out.println("User does not exist!"); + return; + } + + // Get the player's health and game mode from the snapshot + DataSnapshot.Unpacked snapshot = optionalSnapshot.get(); + Optional healthOptional = snapshot.getHealth(); + if (healthOptional.isEmpty()) { + System.out.println("User has no health data!"); + return; + } + Optional gameModeOptional = snapshot.getGameMode(); + if (gameModeOptional.isEmpty()) { + System.out.println("User has no game mode data!"); + return; + } + // getExperience() and getHunger() work similarly + + // Get the health data + Data.Health health = healthOptional.get(); + double currentHealth = health.getCurrentHealth(); // Current health + double maxHealth = health.getMaxHealth(); // Max health + double healthScale = health.getHealthScale(); // Health scale (e.g., 20 for 20 hearts) + snapshot.setHealth(BukkitData.Health.from(20, 20, 20)); + + // Get the game mode data + Data.GameMode gameMode = gameModeOptional.get(); + String gameModeName = gameMode.getGameModeName(); // Game mode name (e.g., "SURVIVAL") + boolean isFlying = gameMode.isFlying(); // Whether the player is *currently* flying + boolean canFly = gameMode.canFly(); // Whether the player *can* fly + snapshot.setGameMode(BukkitData.GameMode.from("SURVIVAL", false, false)); + + // Save the snapshot - This will update the player if online and save the snapshot to the database + huskSyncAPI.setCurrentData(user, snapshot); +}); +``` +
+ +* To make this code more concise, we can use the `HuskSyncAPI#editCurrentData()` method to get the user's current data and perform an operation in a `Consumer` class. +* The result of editing the `DataSnapshot` object in the `Consumer` is then automatically passed to `HuskSyncAPI#setCurrentData()` to save the snapshot to the database and update the user if they are online + +
+Code Example — Editing a player's health + +```java +// Edit a user's current data +huskSyncAPI.editCurrentData(user, snapshot -> { + // Get the player's health + Optional healthOptional = snapshot.getHealth(); + if (healthOptional.isEmpty()) { + System.out.println("User has no health data!"); + return; + } + + // Get the health data + Data.Health health = healthOptional.get(); + + // Get the player's current health + double currentHealth = health.getCurrentHealth(); + + // Get the player's max health + double maxHealth = health.getMaxHealth(); + + // Set the player's health + snapshot.setHealth(BukkitData.Health.from(20, 20, 20)); +}); +``` +
+ +### 4.3 Editing Inventory and Ender Chest data +* We can get a player's inventory using `DataSnapshot.Unpacked#getInventory()`, which returns an `Optional`. You can also get the player's Ender Chest inventory using `DataSnapshot.Unpacked#getEnderChest()`. +* `Data.Items.Inventory` provides methods for the player's inventory, armor, offhand, and ender chest items as platform-agnostic `Stack` objects, which lets you view basic Item information, but does not expose their full NBT data. +* On Bukkit, simply cast a `Data.Items.(Inventory/EnderChest)` to a `BukkitData.Items.(Inventory/EnderChest)` to get access to the Bukkit `ItemStack[]` contents of the player's items, allowing you to edit the contents. + +
+Code Example — Getting and setting a player's inventory or Ender Chest + +```java +// Get a user's current data +huskSyncAPI.getCurrentData(user).thenAccept(optionalSnapshot -> { + if (optionalSnapshot.isEmpty()) { + System.out.println("User does not exist!"); + return; + } + + // Get the snapshot + DataSnapshot.Unpacked snapshot = optionalSnapshot.get(); + + // Get the player's inventory + Optional inventoryOptional = snapshot.getInventory(); + if (inventoryOptional.isEmpty()) { + System.out.println("User has no inventory data!"); + return; + } + + // Get the inventory data + Data.Items.Inventory inventory = inventoryOptional.get(); + + // Get the player's inventory contents + ItemStack[] inventoryContents = ((BukkitData.Items.Inventory) inventory).getContents(); + + // Set the player's inventory contents + ((BukkitData.Items.Inventory) inventory).setContents(inventoryContents); + + // Save the snapshot - This will update the player if online and save the snapshot to the database + huskSyncAPI.setCurrentData(user, snapshot); +}); +``` +
+ +* There also exist utility methods for both getting and setting just the player's current inventory or Ender Chest contents, if all you need to do is just update the player's inventory/Ender Chest. +* The Inventory methods are `#getCurrentInventory`, `#setCurrentInventory`, and `#editCurrentInventory`. For Ender chests, these are `#getCurrentEnderChest`, `#setCurrentEnderChest`, and `#editCurrentEnderChest`. There's also `Contents` methods that just deal with ItemStacks[], if you prefer. + +
+Code Example — Editing a player inventory + +```java +// Edit a user's current inventory +huskSyncAPI.editCurrentInventory(user, inventory -> { + // Get the player's inventory contents + ItemStack[] inventoryContents = ((BukkitData.Items.Inventory) inventory).getContents(); + + // The array of ItemStacks is a copy of the player's inventory contents (in 1.20.1, this is an array of length 42) + inventoryContents[0] = new ItemStack(Material.DIAMOND_SWORD); + inventoryContents[1] = null; // null = an empty slot + + // Set the player's inventory contents + ((BukkitData.Items.Inventory) inventory).setContents(inventoryContents); +}); +``` +
+ +### 4.4 Editing Location data +* HuskSync's support for player Locations is intended for mirrored world instances (such as RPG servers), and so is disabled by default in the plugin config. +* We can get a player's location using `DataSnapshot.Unpacked#getLocation()`, which returns an `Optional`. +* `Data.Location` provides methods for getting and setting the player's location, pitch, and yaw. We can also use the aforementioned `BukkitData` classes to set this using a `org.bukkit.Location`, and speed things along using the `HuskSyncAPI#editCurrentData` method. + +
+Code Example — Editing a player's location + +```java +// Edit a user's current data +huskSyncAPI.editCurrentData(user, snapshot -> { + // Get the player's location + Optional locationOptional = snapshot.getLocation(); + if (locationOptional.isEmpty()) { + System.out.println("User has no location data!"); + return; + } + + // Get the location data + Data.Location location = locationOptional.get(); + + // Get the player's location + org.bukkit.Location bukkitLocation = ((BukkitData.Location) location).getLocation(); + + // Set the player's location + ((BukkitData.Location) location).setLocation(bukkitLocation); +}); +``` +
+ +### 4.5 Editing Advancement data +* Advancements can be retrieved using `DataSnapshot.Unpacked#getAdvancements()`, which returns an `Optional`. +* `Data.Advancements` provides a wrapper for a list of `Data.Advancements.Advancement` objects, representing a map of a player's completed criteria when progressing to complete an advancement. +* You can add and remove advancements from the list, and set the list of advancements using `Data.Advancements#setAdvancements(List)`. + +
+Code Example — Editing a player's advancements + +```java +// Edit a user's current data +huskSyncAPI.editCurrentData(user, snapshot -> { + // Get the player's advancements + Optional advancementsOptional = snapshot.getAdvancements(); + if (advancementsOptional.isEmpty()) { + System.out.println("User has no advancements data!"); + return; + } + + // Get the advancements data + Data.Advancements advancements = advancementsOptional.get(); + + // Get the player's advancements + List playerAdvancements = new ArrayList<>(advancements.getAdvancements()); + + // Advancement progress is represented by completed critera entries, mapped to when said criteria was completed + Map criteria = Map.of("criteria_item_1", new Date()); + + // Add an advancement to the player's advancements + playerAdvancements.add(Data.Advancements.Advancement.adapt("foo:bar/baz", criteria)); + + // Remove all "recipe" advancements from the player's advancements + playerAdvancements.removeIf(advancement -> advancement.getIdentifier().startsWith("minecraft:recipes/")); + + // Set the player's advancements + advancements.setAdvancements(playerAdvancements); +}); +``` +
+ +## 5. Creating new DataSnapshots +* HuskSync provides methods for creating new snapshots; either by capturing a player's current data or by creating a new snapshot from scratch using a `DataSnapshot.Builder`. + +### 5.1 Creating a new snapshot from a player's current data +* You can create a new snapshot from a player's current data using `HuskSyncAPI#createSnapshot(OnlineUser)`, which returns a `DataSnapshot.Packed` with a save cause of `SaveCause.API`. + +
+Code Example — Capturing a player's current data into a Snapshot + +```java +// Create a new snapshot from a player's current data +final DataSnapshot.Packed data = huskSyncAPI.createSnapshot(user); + +// editPackedSnapshot() provides a utility for unpacking, editing, then repacking a DataSnapshot object +final DataSnapshot.Packed edited = huskSyncAPI.editPackedSnapshot(data, (unpacked) -> { + unpacked.setHealth(BukkitData.Health.from(10, 20, 20)); // Example - sets the user's health to 10 (5 hearts) +}); + +// Save the snapshot - This will save the snapshot to the database +huskSyncAPI.addSnapshot(edited); +``` +
+ +### 5.2 Creating a new snapshot from scratch +* You can create a new snapshot from scratch using a `DataSnapshot.Builder`. This is useful if you want to create a custom snapshot with specific data and apply it to a user. +* Get a new `DataSnapshot.Builder` using `HuskSyncAPI#snapshotBuilder()`. + +
+Code Example — Creating a new snapshot from scratch + +```java +// Create a new snapshot from scratch +final DataSnapshot.Builder builder = huskSyncAPI.snapshotBuilder(); + +// Create an empty inventory with a diamond sword in the first slot +final BukkitData.Items.Inventory inventory = BukkitData.Items.Inventory.empty(); +inventory.setContents(new ItemStack[] { new ItemStack(Material.DIAMOND_SWORD) }); +inventory.setHeldItemSlot(0); // Set the player's held item slot to the first slot + +// Use the builder to create, then pack, a new snapshot +final DataSnapshot.Packed packed = builder + .saveCause(SaveCause.API) // This is the default save cause, but you can change it if you want + .setTimestamp(OffsetDateTime.now().minusDays(3)) // Set the timestamp to 3 days ago + .setInventory(inventory) // Set the player's inventory + .setHealth(BukkitData.Health.from(10, 20, 20)) // Set the player to having 5 hearts + .buildAndPack(); // You can also call just #build() to get a DataSnapshot.Unpacked + +// Save the snapshot - This will save the snapshot to the database for a User +huskSyncAPI.addSnapshot(user, packed); +``` +
+ +## 6. Deleting DataSnapshots +* You can delete a snapshot using `HuskSyncAPI#deleteSnapshot(User, UUID)`, which will delete a snapshot from the database by its UUID. +* This method returns a CompletableFuture which will resolve to `true` if there was a snapshot with that UUID to delete, or `false` if there was no snapshot with that UUID to delete. + +
+Code Example — Deleting a snapshot + +```java +// Delete a snapshot +huskSyncAPI.deleteSnapshot(user, uuid).thenAccept(success -> { + if (success) { + System.out.println("Deleted snapshot with UUID %s", uuid); + } else { + System.out.println("No snapshot with UUID %s to delete", uuid); + } +}); +``` +
\ No newline at end of file diff --git a/docs/Dumping-UserData.md b/docs/Dumping-UserData.md index 039eca46..03a1a494 100644 --- a/docs/Dumping-UserData.md +++ b/docs/Dumping-UserData.md @@ -3,322 +3,43 @@ It's possible to dump user data snapshots to `json` objects as of HuskSync v2.1, This can be useful in debugging synchronization problems or for manually inspecting data. ## How-to guide -1. Grant yourself the special `husksync.command.userdata.dump` permission node. This is not set by default, even for operators. +1. Ensure you have the `husksync.command.userdata.dump` permission node. This is not set by default, even for operators. 2. Use the `/userdata list ` command to view a list of user data entries for a user. 3. Click on one of the user data entries for your chosen user. The data snapshot preview menu should appear, along with two new buttons at the bottom. -[![Data dumping buttons](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/data-dumping.png)](#) +![Data dumping buttons](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/data-dumping.png) ### Dumping to a file After clicking the "File Dump..." button (equivalent to `/userdata dump file`), a dump of this user data entry will be output in `~/plugins/HuskSync/dumps/`. -The name of the generated .json file will match the following format: `___.json` +The name of the generated .json file will match the following format: `___.json`
Example output file: William278_2022-10-12_21-46-37_disconnect_f7719f5c.json ```json { - "status": { - "health": 20.0, - "max_health": 20.0, - "health_scale": 0.0, - "hunger": 20, - "saturation": 0.0, - "saturation_exhaustion": 0.24399996, - "selected_item_slot": 1, - "total_experience": 0, - "experience_level": 0, - "experience_progress": 0.0, - "game_mode": "CREATIVE", - "is_flying": true - }, - "inventory": { - "serialized_items": "rO0ABXcEAAAAKXBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBzcgAXamF2YS51dGlsLkxp\r\nbmtlZEhhc2hNYXA0wE5cEGzA+wIAAVoAC2FjY2Vzc09yZGVyeHIAEWphdmEudXRpbC5IYXNoTWFw\r\nBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAADHcIAAAAEAAAAAJ0\r\nAAF2c3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcu\r\nTnVtYmVyhqyVHQuU4IsCAAB4cAAADDB0AAR0eXBldAASTEVBVEhFUl9DSEVTVFBMQVRFeABwc3EA\r\nfgAAP0AAAAAAAAx3CAAAABAAAAADcQB+AANzcQB+AAQAAAwwcQB+AAd0AAdCRURST0NLdAAGYW1v\r\ndW50c3EAfgAEAAAAQHgAcHBwcHBwcA\u003d\u003d\r\n" - }, - "ender_chest": { - "serialized_items": "rO0ABXcEAAAAG3NyABdqYXZhLnV0aWwuTGlua2VkSGFzaE1hcDTATlwQbMD7AgABWgALYWNjZXNz\r\nT3JkZXJ4cgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJl\r\nc2hvbGR4cD9AAAAAAAAMdwgAAAAQAAAAA3QAAXZzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GH\r\nOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAMMHQABHR5cGV0\r\nAA1TUFJVQ0VfUExBTktTdAAGYW1vdW50c3EAfgAEAAAAQHgAc3EAfgAAP0AAAAAAAAx3CAAAABAA\r\nAAADcQB+AANzcQB+AAQAAAwwcQB+AAd0AAdCRURST0NLcQB+AAlxAH4ACngAc3EAfgAAP0AAAAAA\r\nAAx3CAAAABAAAAADcQB+AANzcQB+AAQAAAwwcQB+AAdxAH4ADXEAfgAJcQB+AAp4AHNxAH4AAD9A\r\nAAAAAAAMdwgAAAAQAAAAA3EAfgADc3EAfgAEAAAMMHEAfgAHcQB+AA1xAH4ACXEAfgAKeABzcQB+\r\nAAA/QAAAAAAADHcIAAAAEAAAAANxAH4AA3NxAH4ABAAADDBxAH4AB3EAfgANcQB+AAlxAH4ACngA\r\nc3EAfgAAP0AAAAAAAAx3CAAAABAAAAADcQB+AANzcQB+AAQAAAwwcQB+AAdxAH4ADXEAfgAJcQB+\r\nAAp4AHNxAH4AAD9AAAAAAAAMdwgAAAAQAAAAA3EAfgADc3EAfgAEAAAMMHEAfgAHcQB+AA1xAH4A\r\nCXEAfgAKeABzcQB+AAA/QAAAAAAADHcIAAAAEAAAAANxAH4AA3NxAH4ABAAADDBxAH4AB3EAfgAN\r\ncQB+AAlxAH4ACngAc3EAfgAAP0AAAAAAAAx3CAAAABAAAAADcQB+AANzcQB+AAQAAAwwcQB+AAdx\r\nAH4ADXEAfgAJcQB+AAp4AHNxAH4AAD9AAAAAAAAMdwgAAAAQAAAAA3EAfgADc3EAfgAEAAAMMHEA\r\nfgAHcQB+AA1xAH4ACXEAfgAKeABzcQB+AAA/QAAAAAAADHcIAAAAEAAAAANxAH4AA3NxAH4ABAAA\r\nDDBxAH4AB3EAfgANcQB+AAlxAH4ACngAc3EAfgAAP0AAAAAAAAx3CAAAABAAAAADcQB+AANzcQB+\r\nAAQAAAwwcQB+AAdxAH4ADXEAfgAJcQB+AAp4AHNxAH4AAD9AAAAAAAAMdwgAAAAQAAAAA3EAfgAD\r\nc3EAfgAEAAAMMHEAfgAHcQB+AA1xAH4ACXEAfgAKeABzcQB+AAA/QAAAAAAADHcIAAAAEAAAAANx\r\nAH4AA3NxAH4ABAAADDBxAH4AB3EAfgANcQB+AAlxAH4ACngAc3EAfgAAP0AAAAAAAAx3CAAAABAA\r\nAAADcQB+AANzcQB+AAQAAAwwcQB+AAdxAH4ADXEAfgAJcQB+AAp4AHNxAH4AAD9AAAAAAAAMdwgA\r\nAAAQAAAAA3EAfgADc3EAfgAEAAAMMHEAfgAHcQB+AA1xAH4ACXEAfgAKeABzcQB+AAA/QAAAAAAA\r\nDHcIAAAAEAAAAANxAH4AA3NxAH4ABAAADDBxAH4AB3EAfgANcQB+AAlxAH4ACngAc3EAfgAAP0AA\r\nAAAAAAx3CAAAABAAAAADcQB+AANzcQB+AAQAAAwwcQB+AAdxAH4ADXEAfgAJcQB+AAp4AHNxAH4A\r\nAD9AAAAAAAAMdwgAAAAQAAAAA3EAfgADc3EAfgAEAAAMMHEAfgAHcQB+AA1xAH4ACXEAfgAKeABz\r\ncQB+AAA/QAAAAAAADHcIAAAAEAAAAANxAH4AA3NxAH4ABAAADDBxAH4AB3EAfgANcQB+AAlxAH4A\r\nCngAc3EAfgAAP0AAAAAAAAx3CAAAABAAAAADcQB+AANzcQB+AAQAAAwwcQB+AAdxAH4ADXEAfgAJ\r\ncQB+AAp4AHNxAH4AAD9AAAAAAAAMdwgAAAAQAAAAA3EAfgADc3EAfgAEAAAMMHEAfgAHcQB+AA1x\r\nAH4ACXEAfgAKeABzcQB+AAA/QAAAAAAADHcIAAAAEAAAAANxAH4AA3NxAH4ABAAADDBxAH4AB3EA\r\nfgANcQB+AAlxAH4ACngAc3EAfgAAP0AAAAAAAAx3CAAAABAAAAADcQB+AANzcQB+AAQAAAwwcQB+\r\nAAdxAH4ACHEAfgAJcQB+AAp4AHNxAH4AAD9AAAAAAAAMdwgAAAAQAAAAA3EAfgADc3EAfgAEAAAM\r\nMHEAfgAHcQB+AAhxAH4ACXEAfgAKeABzcQB+AAA/QAAAAAAADHcIAAAAEAAAAANxAH4AA3NxAH4A\r\nBAAADDBxAH4AB3EAfgAIcQB+AAlxAH4ACngAc3EAfgAAP0AAAAAAAAx3CAAAABAAAAADcQB+AANz\r\ncQB+AAQAAAwwcQB+AAdxAH4ACHEAfgAJcQB+AAp4AA\u003d\u003d\r\n" - }, - "potion_effects": { - "serialized_potion_effects": "" - }, - "advancements": [ - { - "key": "minecraft:recipes/transportation/mangrove_boat", - "completed_criteria": { - "in_water": "Oct 11, 2022, 10:07:07 PM" - } - }, - { - "key": "minecraft:recipes/redstone/spruce_button", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/misc/iron_nugget_from_smelting", - "completed_criteria": { - "has_chainmail_leggings": "Oct 12, 2022, 5:43:37 PM" - } - }, - { - "key": "minecraft:recipes/redstone/spruce_pressure_plate", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/redstone/warped_pressure_plate", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - }, - { - "key": "minecraft:recipes/decorations/spruce_sign", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/redstone/spruce_trapdoor", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/building_blocks/warped_slab", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - }, - { - "key": "minecraft:recipes/redstone/spruce_door", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/redstone/spruce_fence_gate", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/decorations/crafting_table", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/decorations/chest", - "completed_criteria": { - "has_lots_of_items": "Oct 12, 2022, 5:43:42 PM" - } - }, - { - "key": "minecraft:story/shiny_gear", - "completed_criteria": { - "diamond_boots": "Oct 12, 2022, 5:43:36 PM" - } - }, - { - "key": "minecraft:recipes/misc/stick", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/redstone/warped_fence_gate", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - }, - { - "key": "minecraft:recipes/transportation/acacia_boat", - "completed_criteria": { - "in_water": "Oct 11, 2022, 10:07:07 PM" - } - }, - { - "key": "minecraft:recipes/misc/iron_nugget_from_blasting", - "completed_criteria": { - "has_chainmail_leggings": "Oct 12, 2022, 5:43:37 PM" - } - }, - { - "key": "minecraft:recipes/decorations/warped_fence", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - }, - { - "key": "minecraft:adventure/adventuring_time", - "completed_criteria": { - "minecraft:beach": "Oct 12, 2022, 5:10:27 PM", - "minecraft:old_growth_pine_taiga": "Oct 12, 2022, 9:32:20 PM", - "minecraft:dark_forest": "Oct 11, 2022, 9:24:06 PM", - "minecraft:forest": "Oct 11, 2022, 10:06:58 PM", - "minecraft:taiga": "Oct 12, 2022, 8:58:59 PM", - "minecraft:river": "Oct 11, 2022, 10:07:07 PM", - "minecraft:stony_shore": "Oct 11, 2022, 9:23:59 PM", - "minecraft:snowy_plains": "Oct 11, 2022, 10:08:53 PM", - "minecraft:snowy_taiga": "Oct 12, 2022, 3:38:05 PM", - "minecraft:frozen_river": "Oct 11, 2022, 10:09:54 PM", - "minecraft:windswept_gravelly_hills": "Oct 12, 2022, 3:14:39 PM", - "minecraft:old_growth_spruce_taiga": "Oct 12, 2022, 9:42:12 PM", - "minecraft:snowy_beach": "Oct 11, 2022, 10:08:40 PM", - "minecraft:plains": "Oct 11, 2022, 10:07:07 PM" - } - }, - { - "key": "minecraft:recipes/decorations/barrel", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/transportation/spruce_boat", - "completed_criteria": { - "in_water": "Oct 11, 2022, 10:07:07 PM" - } - }, - { - "key": "minecraft:recipes/redstone/redstone_from_smelting_redstone_ore", - "completed_criteria": { - "has_redstone_ore": "Oct 11, 2022, 10:21:34 PM" - } - }, - { - "key": "minecraft:recipes/transportation/birch_boat", - "completed_criteria": { - "in_water": "Oct 11, 2022, 10:07:07 PM" - } - }, - { - "key": "minecraft:recipes/decorations/spruce_fence", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/building_blocks/spruce_stairs", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/transportation/oak_boat", - "completed_criteria": { - "in_water": "Oct 11, 2022, 10:07:07 PM" - } - }, - { - "key": "minecraft:recipes/redstone/redstone_from_blasting_redstone_ore", - "completed_criteria": { - "has_redstone_ore": "Oct 11, 2022, 10:21:34 PM" - } - }, - { - "key": "minecraft:recipes/redstone/warped_button", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - }, - { - "key": "minecraft:recipes/building_blocks/warped_stairs", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - }, - { - "key": "minecraft:recipes/redstone/warped_trapdoor", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - }, - { - "key": "minecraft:recipes/building_blocks/spruce_slab", - "completed_criteria": { - "has_planks": "Oct 11, 2022, 9:25:12 PM" - } - }, - { - "key": "minecraft:recipes/decorations/warped_sign", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - }, - { - "key": "minecraft:recipes/transportation/jungle_boat", - "completed_criteria": { - "in_water": "Oct 11, 2022, 10:07:07 PM" - } - }, - { - "key": "minecraft:recipes/transportation/dark_oak_boat", - "completed_criteria": { - "in_water": "Oct 11, 2022, 10:07:07 PM" - } - }, - { - "key": "minecraft:recipes/redstone/warped_door", - "completed_criteria": { - "has_planks": "Oct 12, 2022, 5:43:22 PM" - } - } - ], - "statistics": { - "untyped_statistics": { - "LEAVE_GAME": 16, - "TOTAL_WORLD_TIME": 282633, - "CROUCH_ONE_CM": 43, - "WALK_UNDER_WATER_ONE_CM": 113, - "DEATHS": 4, - "WALK_ONE_CM": 7313, - "JUMP": 866, - "SPRINT_ONE_CM": 63807, - "DROP_COUNT": 9, - "WALK_ON_WATER_ONE_CM": 331, - "TIME_SINCE_DEATH": 282357, - "SNEAK_TIME": 95, - "FLY_ONE_CM": 584296, - "ENDERCHEST_OPENED": 2, - "PLAY_ONE_MINUTE": 282633, - "TIME_SINCE_REST": 282377 - }, - "block_statistics": {}, - "item_statistics": { - "PICKUP": { - "SUGAR_CANE": 2 - }, - "DROP": { - "SPRUCE_PLANKS": 70, - "TURTLE_HELMET": 1, - "DIAMOND_BOOTS": 1, - "BEDROCK": 1, - "CHAINMAIL_LEGGINGS": 1, - "MANGROVE_PROPAGULE": 1, - "LEATHER_CHESTPLATE": 1 - }, - "USE_ITEM": { - "TURTLE_HELMET": 1, - "DIAMOND_BOOTS": 1, - "GRASS_BLOCK": 5, - "ENDER_CHEST": 1, - "CHAINMAIL_LEGGINGS": 1, - "LEATHER_CHESTPLATE": 1 - } - }, - "entity_statistics": {} - }, - "persistent_data_container": { - "persistent_data_map": {} - }, - "minecraft_version": "1.19.2", - "format_version": 3 + "id": "209a56fd-efd0-4354-8f7c-e09f6d0673d8", + "pinned": false, + "timestamp": "2023-09-15T17:27:08.6768038+01:00", + "save_cause": "DISCONNECT", + "minecraft_version": "1.20.1", + "platform_type": "bukkit", + "format_version": 4, + "data": { + "husksync:statistics": "{\"generic\":{\"minecraft:fly_one_cm\":26261,\"minecraft:jump\":23,\"minecraft:leave_game\":3,\"minecraft:play_one_minute\":1904,\"minecraft:sneak_time\":7,\"minecraft:sprint_one_cm\":1849,\"minecraft:time_since_death\":1904,\"minecraft:time_since_rest\":1904,\"minecraft:total_world_time\":1904,\"minecraft:walk_one_cm\":414},\"blocks\":{},\"items\":{},\"entities\":{}}", + "husksync:experience": "{\"total_experience\":0,\"exp_level\":0,\"exp_progress\":0.0}", + "husksync:game_mode": "{\"game_mode\":\"CREATIVE\",\"allow_flight\":true,\"is_flying\":true}", + "husksync:advancements": "[{\"key\":\"minecraft:recipes/decorations/crafting_table\",\"completed_criteria\":{\"unlock_right_away\":1694795225426}},{\"key\":\"minecraft:adventure/adventuring_time\",\"completed_criteria\":{\"minecraft:old_growth_birch_forest\":1694795225478}}]", + "husksync:inventory": "{held_item_slot:0,items:{size:41}}", + "husksync:ender_chest": "{size:27}", + "husksync:potion_effects": "[]", + "husksync:hunger": "{\"food_level\":20,\"saturation\":5.0,\"exhaustion\":0.449}", + "husksync:health": "{\"health\":20.0,\"max_health\":20.0,\"health_scale\":20.0}" + } } ```
### Dumping to the web -The Web Dump... button (equivalent to `/userdata dump web`) will dump user data snapshot json data to the https://mclo.gs service and provide you with a link to the uploaded file. Note that the web dumping service may not work if your user data snapshot exceeds 10MB in file size. +The \[Web Dump...\] button (equivalent to `/userdata dump web`) will dump user data snapshot json data to the https://mclo.gs service and provide you with a link to the uploaded file. Note that the web dumping service may not work if your user data snapshot exceeds 10MB in file size. diff --git a/docs/FAQs.md b/docs/FAQs.md index 05a4f4cc..3c42df19 100644 --- a/docs/FAQs.md +++ b/docs/FAQs.md @@ -17,9 +17,9 @@ Modded items are not supported.
- Are MMOItems / SlimeFun items supported? + Are MMOItems / SlimeFun / ItemsAdder items supported? -No. MMOItems and SlimeFun are not compatible with HuskSync due to the way they inject data directly into item NBT rather than the Spigot API's plugin-agnostic PersistentDataContainer. +These plugins, which provide custom items, should be supported as of HuskSync v3.x; but do note we cannot guarantee compatibility with all methods of injecting custom data to create custom items. Be sure to test thoroughly before deploying on production!
@@ -35,9 +35,9 @@ HuskSync requires Redis to operate (for reasons demonstrated below). Redis is an ![System diagram](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/system-diagram.png) -HuskSync makes use of both MySQL and Redis for optimal data synchronisation. +HuskSync makes use of both MySQL and Redis for optimal data synchronization. -When a user changes servers, in addition to data being saved to MySQL, it is also cached via the Redis server with a temproary expiry key. When changing servers, the receiving server detects the key and sets the user data from Redis. When a player rejoins the network, the system fetches the last-saved data snapshot from the MySQL Database. +When a user changes servers, in addition to data being saved to MySQL, it is also cached via the Redis server with a temporary expiry key. When changing servers, the receiving server detects the key and sets the user data from Redis. When a player rejoins the network, the system fetches the last-saved data snapshot from the MySQL Database. This approach is able to dramatically improve both synchronization performance and reliability. A few other techniques are used to optimize this process, such as compressing the serialized user data json using Snappy. diff --git a/docs/Home.md b/docs/Home.md index 0c26ae7c..750a473a 100644 --- a/docs/Home.md +++ b/docs/Home.md @@ -1,5 +1,5 @@ # [![HuskSync banner](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/banner.png)](https://github.com/WiIIiam278/HuskSync) -Welcome! This is the plugin documentation for HuskSync v2.x+. Please click through to the topic you'd like to read about. +Welcome! This is the plugin documentation for HuskSync v3.x+. Please click through to the topic you'd like to read about. ## Guides * 📚 [[Setup]] @@ -18,14 +18,16 @@ Welcome! This is the plugin documentation for HuskSync v2.x+. Please click throu * ☂️ [[Dumping UserData]] * 📋 [[Event Priorities]] * ⚔️ [[Keep Inventory]] -* 📦 [[API]] - * 📝 [[UserData API]] +* 📦 [[API]] v3 + * 📝 [[Snapshot API]] + * 📝 [[Custom Data API]] * ❗ [[API Events]] +* 🕸️ [[API v2]] _(Legacy)_ ## Links * 💻 [GitHub](https://github.com/WiIIiam278/HuskSync) -* 📂 [Buy HuskSync](https://www.spigotmc.org/resources/husksync.97144/) - * 🛒 [Spigot](https://www.spigotmc.org/resources/husksync.97144/) +* 📂 [Buy HuskSync](https://william278.net/project/husksync/) + * 🚰 [Spigot](https://www.spigotmc.org/resources/husksync.97144/) * 🛒 [Polymart](https://polymart.org/resource/husksync.1634) - * 🛒 [Craftaro](https://craftaro.com/marketplace/product/husksync.758) + * ⚒️ [Craftaro](https://craftaro.com/marketplace/product/husksync.758) * 💬 [Discord Support](https://discord.gg/tVYhJfyDWG) \ No newline at end of file diff --git a/docs/Keep-Inventory.md b/docs/Keep-Inventory.md index 7cb54c38..9d6da1ae 100644 --- a/docs/Keep-Inventory.md +++ b/docs/Keep-Inventory.md @@ -1,4 +1,4 @@ -If your server uses the `keepInventory` gamerule, where players keep the contents of their inventory after dying, HuskSync's built-in snapshot-on-death and dead-player synchronisation features can cause a conflict leading to synchronisation issues. +If your server uses the `keepInventory` gamerule, where players keep the contents of their inventory after dying, HuskSync's built-in snapshot-on-death and dead-player synchronization features can saveCause a conflict leading to synchronization issues. To solve this issue, you will need to adjust three settings in your `config.yml` file, as described below. @@ -8,7 +8,7 @@ HuskSync has some special handling when players die, to account for scenarios wh * **Snapshot creation on death**—HuskSync can create a special snapshot for backup purposes when a player dies, formed by taking their drops and setting this to their inventory. When `keepInventory` is enabled, the player drops are empty, so this creates an inaccurate snapshot. This option is disabled by default. ## How can this be fixed? -You will need to set the `synchronization.save_on_death` (which controls making snapshots on death), `save_empty_drops_on_death` (which controls whether snapshots of players who have no items to drop should be created), and `synchronization.synchronise_dead_players_changing_server` (which controls whether to sync dead players when they change servers) options to `false` in `config.yml`. +You will need to set the `synchronization.save_on_death` (which controls making snapshots on death), `save_empty_drops_on_death` (which controls whether snapshots of players who have no items to drop should be created), and `synchronization.synchronize_dead_players_changing_server` (which controls whether to sync dead players when they change servers) options to `false` in `config.yml`.
Example in config.yml @@ -19,7 +19,7 @@ You will need to set the `synchronization.save_on_death` (which controls making save_on_death: false # <-- Set this to false save_empty_drops_on_death: false # <-- Set this to false # ... - synchronise_dead_players_changing_server: false # <-- Set this to false + synchronize_dead_players_changing_server: false # <-- Set this to false ```
diff --git a/docs/Legacy-Migration.md b/docs/Legacy-Migration.md index be00f3cf..46284065 100644 --- a/docs/Legacy-Migration.md +++ b/docs/Legacy-Migration.md @@ -1,15 +1,15 @@ -This guide will walk you through how to upgrade from HuskSync v1.4.x to HuskSync 2.x. +This guide will walk you through how to upgrade from HuskSync v1.4.x to HuskSync v2.x or v3.x. Data from HuskSync v2.x will automatically be imported into HuskSync v3.x. ## Requirements - MySQL Database with HuskSync v1.4.x data - - Migration from SQLite is not supported, as HuskSync v2.x requires a MySQL database and does not support SQLite. Appologies for the inconvenience. + - Migration from SQLite is not supported, as HuskSync v2.x requires a MySQL database and does not support SQLite. Apologies for the inconvenience. - If you're running v1.3.x or older, follow the update instructions to 1.4.x first before updating to 2.x. ## Migration Instructions ### 1. Uninstall HuskSync v1.x from all servers - Switch off all servers and your proxy -- Delete the jarfile from your `~/plugins/` folders on your Spigot servers -- Also delete the jarfile from your `~/plugins/` folders on your Proxy. HuskSync v2.x no longer requires a proxy plugin. +- Delete the .jar file from your `~/plugins/` folders on your Spigot servers +- Also delete the .jar file from your `~/plugins/` folders on your Proxy. HuskSync v2.x no longer requires a proxy plugin. - Delete (or make a copy and delete) all HuskSync config data folders (`~/plugins/HuskSync/`). HuskSync 2.x has a new config and messages file. ### 2. Install HuskSync v2.x on all Spigot servers @@ -26,5 +26,5 @@ This guide will walk you through how to upgrade from HuskSync v1.4.x to HuskSync - Run `husksync migrate legacy start` to begin the migration process. This may take some time, depending on the amount of data you're migrating. ### 5. Ensure the migration was successful -- HuskSync will notify in console when migration is complete. Verify that the migration went OK by logging in and using the `/userdata list ` command to see if the data was imported with the `legacy migration` cause. +- HuskSync will notify in console when migration is complete. Verify that the migration went OK by logging in and using the `/userdata list ` command to see if the data was imported with the `legacy migration` saveCause. - You can delete the old tables in the database if you want. Be careful to make sure you delete the right ones. By default the *new* table names are `husksync_users` and `husksync_user_data` and the *old* ones were `husksync_players` and `husksync_data`, but you may have changed these. \ No newline at end of file diff --git a/docs/MPDB-Migration.md b/docs/MPDB-Migration.md index fb499d89..3f7991fb 100644 --- a/docs/MPDB-Migration.md +++ b/docs/MPDB-Migration.md @@ -24,5 +24,5 @@ This guide will walk you through how to migrate from MySQLPlayerDataBridge (MPDB - Start your Spigot servers again. ### 5. Ensure the migration was successful -- Verify that the migration was successful by logging in and using the `/userdata list ` command to see if the data was imported with the `mpdb_migration` cause. +- Verify that the migration was successful by logging in and using the `/userdata list ` command to see if the data was imported with the `mpdb_migration` saveCause. - You can delete the old tables in the database if you want. Be careful to make sure you delete the correct ones. \ No newline at end of file diff --git a/docs/Plan-Hook.md b/docs/Plan-Hook.md index 85d702d8..5a2f84d6 100644 --- a/docs/Plan-Hook.md +++ b/docs/Plan-Hook.md @@ -1,6 +1,6 @@ HuskSync supports displaying information about user data on your [Player Analytics](https://github.com/plan-player-analytics/Plan) (Plan) web panel. -[![Plan hook screenshots](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/plan-hook.png)](#) +![Plan hook screenshots](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/plan-hook.png) ## Requirements - HuskSync v2.0+ diff --git a/docs/Setup.md b/docs/Setup.md index ffbe7439..61292721 100644 --- a/docs/Setup.md +++ b/docs/Setup.md @@ -11,15 +11,15 @@ This will walk you through installing HuskSync on your network of Spigot servers - You do not need to install HuskSync as a proxy plugin. ### 2. Restart servers - Start, then stop every server to let HuskSync generate the [[config file]]. -- HuskSync will throw an error in console and disable itself as it is unable to connect to the database. You haven't set the credentials yet, so this is expected. +- HuskSync will throw an error in the console and disable itself as it is unable to connect to the database. You haven't set the credentials yet, so this is expected. - Advanced users: If you'd prefer, you can just create one config.yml file and create symbolic links in each `/plugins/HuskSync/` folder to it to make updating it easier. -### 3. Enter MySQL & Redis database credentails +### 3. Enter MySQL & Redis database credentials - Navigate to the HuskSync config file on each server (`~/plugins/HuskSync/config.yml`) - Under `credentials` in the `database` section, enter the credentials of your MySQL Database. You shouldn't touch the `connection_pool` properties. -- Under `credentials` in the `redis` section, enter the credentails of your Redis Database. If your Redis server doesn't have a password, leave the password blank as it is. +- Under `credentials` in the `redis` section, enter the credentials of your Redis Database. If your Redis server doesn't have a password, leave the password blank as it is. - Unless you want to have multiple clusters of servers within your network, each with separate user data, do not change the value of `cluster_id`. ### 4. Start every server again -- Provided your MySQL and Redis credentials were correct, synchronisation should begin as soon as you start your servers again. +- Provided your MySQL and Redis credentials were correct, synchronization should begin as soon as you start your servers again. - If you need to import data from HuskSync v1.x or MySQLPlayerDataBridge, please see the guides below: - [[Legacy Migration]] - [[MPDB Migration]] \ No newline at end of file diff --git a/docs/Sync-Features.md b/docs/Sync-Features.md index d8634749..f1dcabe1 100644 --- a/docs/Sync-Features.md +++ b/docs/Sync-Features.md @@ -1,6 +1,6 @@ This page contains a list of the features HuskSync is and isn't able to syncrhonise on your server. -You can customise how much data HuskSync saves about a player by [turning each synchronisation feature on or off](#toggling-sync-features). When a synchronisation feature is turned off, HuskSync won't touch that part of a player's profile; in other words, the data they will inherit when changing servers will be read from their player data file on the local server. +You can customise how much data HuskSync saves about a player by [turning each synchronization feature on or off](#toggling-sync-features). When a synchronization feature is turned off, HuskSync won't touch that part of a player's profile; in other words, the data they will inherit when changing servers will be read from their player data file on the local server. ## Feature table ✅—Supported  ❌—Unsupported  ⚠️—Experimental @@ -18,7 +18,7 @@ You can customise how much data HuskSync saves about a player by [turning each s | Game modes | Player's current game mode | ✅ | | Statistics | Player's in-game stats (ESC -> Statistics) | ✅ | | Location | Player's current coordinate positon and world† | ✅ | -| Persistent Data Container | Custom plugin persistent data key map | ⚠️ | +| Persistent Data Container | Custom plugin persistent data key map | ✅️ | | Locked maps | Maps/treasure maps locked in a cartography table | ⚠️ | | Unlocked maps | Regular, unlocked maps/treasure maps ([why?](#map-syncing)) | ❌ | | Economy balances | Vault economy balance. ([why?](#economy-syncing)) | ❌ | @@ -27,48 +27,38 @@ What about modded items? Or custom item plugins such as MMOItems or SlimeFun? Th *Purpur's custom ender chest resizing feature is also supported. -†This is intended for servers that have mirrorred worlds across instances (such as RPG servers). With this option enabled, players will be placed at the same coordinates when changing servers. - -### PersistentDataContainer tags -The player [PersistentDataContainer](https://blog.jeff-media.com/persistent-data-container-the-better-alternative-to-nbt-tags/) is a part of the Spigot API that enables plugins to set custom data tags to players, entities & items and have them persist. HuskSync will synchronise this data cross-server. Plugins that use legacy or proprietary forms of saving data, such as by modifying NBT directly, may not correctly synchronise. - -### Custom enchantments -Plugins that add custom enchantments by registering them to ItemStacks through setting them via the [EnchantmentStorageMeta](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/inventory/meta/EnchantmentStorageMeta.html) will work, but note that the plugin _must_ be lower on the load order than HuskSync; in other words, HuskSync should be on the plugin's `loadbefore:`. This is because Spigot's item serialization API requires that the plugin that registered the enchantment be online to serialize it due to how it reads from the enchantment registry and so if the plugin does not load before (and thus does not shut down after) HuskSync, it won't be able to serialize the custom enchantments in the event of a server shutdown with players online. +†This is intended for servers that have mirrored worlds across instances (such as RPG servers). With this option enabled, players will be placed at the same coordinates when changing servers. ### Map syncing -Map items are a special case, as their data is not stored in the item itself, but rather in the game world files. In addition to this, their data is dynamic and changes based on the updating of the world, something which can't be tracked across multiple instances. As a result, it's not possible to sync unlocked map items. - -However, experimental support for synchronising locked map items—that is, maps that have been locked in a cartography table—is currently available in development builds. This works by serializing its' map canvas pixel grid to the map item's persistent data container. +Map items are a special case, as their data is not stored in the item itself, but rather in the game world files. In addition to this, their data is dynamic and changes based on the updating of the world, something that can't be tracked across multiple instances. As a result, it's not possible to sync unlocked map items. Locked maps, however, are supported. This works by saving the pixel canvas grid to the map NBT itself, and generating virtual maps on the other servers. ### Economy syncing -Although it's a common request, HuskSync doesn't synchronise economy data for a number of reasons! +Although it's a common request, HuskSync doesn't synchronize economy data for a number of reasons! -I strongly recommend making use of economy plugins that have cross-server economy balance synchronisation built-in, of which there are a multitude of options available. Please see our [[FAQs]] section for more details on this decision. +I strongly recommend making use of economy plugins that have cross-server economy balance synchronization built-in, of which there are a multitude of options available. Please see our [[FAQs]] section for more details on this decision. ## Toggling Sync Features -All synchronization features, except location and locked map synchronising, are enabled by default. To toggle a feature, navigate to the `features:` section in the `synchronisation:` part of your `config.yml` file, and change the option to `true`/`false` respectively. +All synchronization features, except location and locked map synchronising, are enabled by default. To toggle a feature, navigate to the `features:` section in the `synchronization:` part of your `config.yml` file, and change the option to `true`/`false` respectively.
- Example in config.yml +Example in config.yml - ```yaml - synchronization: - # ... - features: - inventories: true - ender_chests: true - health: true - max_health: true - hunger: true - experience: true - potion_effects: true - advancements: true - game_mode: true - statistics: true - persistent_data_container: false - locked_maps: true - location: false - #... - ``` +```yaml +synchronization: + # ... + features: + health: true + statistics: true + location: false + potion_effects: true + ender_chest: true + experience: true + advancements: true + game_mode: true + inventory: true + persistent_data: true + hunger: true + #... +```
\ No newline at end of file diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md index f297f6fb..284f0eae 100644 --- a/docs/Troubleshooting.md +++ b/docs/Troubleshooting.md @@ -9,13 +9,13 @@ This is most frequently caused by running a cracked "offline mode" network of se ### Cannot set data with newer Minecraft version than the server This is caused when you attempt to downgrade user data from a newer version of Minecraft to an older one, or when your Spigot servers are running mismatched Minecraft versions. -HuskSync will identify this and safely prevent the synchronisation from occuring. Your Spigot servers must be running the same version of both Minecraft and HuskSync. +HuskSync will identify this and safely prevent the synchronization from occuring. Your Spigot servers must be running the same version of both Minecraft and HuskSync. -### User data failing to synchronise +### User data failing to synchronize This can occur due to misaligned timings between your Spigot servers and your Redis server. HuskSync has a built in way of tuning this. Try continously increasing the `network_latency_milliseconds` option in your config to a higher value. -### Synchronisation issues with Keep Inventory enabled -On servers that use Keep Inventory move (where players keep their items when they die), you can run into synchronisation issues. See [[Keep Inventory]] for details on why this happens and how to resolve it. +### Synchronization issues with Keep Inventory enabled +On servers that use Keep Inventory move (where players keep their items when they die), you can run into synchronization issues. See [[Keep Inventory]] for details on why this happens and how to resolve it. ### Exceptions when compressing data via Snappy (lightweight Linux distros) Some lightweight Linux distros such as Alpine Linux (used on Pterodactyl) might not have the dependencies needed for the [Snappy](https://github.com/xerial/snappy-java) compressor. It's possible to disable data compression by changing `compress_data` to false in your config. Note that after changing this setting you will need to reset your database. Alternatively, find the right libraries for your distro! diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md index ad197f43..504c74be 100644 --- a/docs/_Sidebar.md +++ b/docs/_Sidebar.md @@ -15,14 +15,16 @@ * ☂️ [[Dumping UserData]] * 📋 [[Event Priorities]] * ⚔️ [[Keep Inventory]] -* 📦 [[API]] - * 📝 [[UserData API]] +* 📦 [[API]] v3 + * 📝 [[Snapshot API]] + * 📝 [[Custom Data API]] * ❗ [[API Events]] +* 🕸️ [[API v2]] _(Legacy)_ ## Links * 💻 [GitHub](https://github.com/WiIIiam278/HuskSync) -* 📂 [Buy HuskSync](https://www.spigotmc.org/resources/husksync.97144/) - * 🛒 [Spigot](https://www.spigotmc.org/resources/husksync.97144/) +* 📂 [Buy HuskSync](https://william278.net/project/husksync/) + * 🚰 [Spigot](https://www.spigotmc.org/resources/husksync.97144/) * 🛒 [Polymart](https://polymart.org/resource/husksync.1634) - * 🛒 [Craftaro](https://craftaro.com/marketplace/product/husksync.758) + * ⚒️ [Craftaro](https://craftaro.com/marketplace/product/husksync.758) * 💬 [Discord Support](https://discord.gg/tVYhJfyDWG) \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 5f84c4de..adf307dd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,12 +3,11 @@ org.gradle.jvmargs='-Dfile.encoding=UTF-8' org.gradle.daemon=true javaVersion=16 -plugin_version=2.2.8 +plugin_version=3.0 plugin_archive=husksync plugin_description=A modern, cross-server player data synchronization system -jedis_version=4.3.2 +jedis_version=5.0.0 mysql_driver_version=8.1.0 -mariadb_driver_version=3.1.4 -snappy_version=1.1.9.1 -commons_text_version=1.10.0 \ No newline at end of file +mariadb_driver_version=3.2.0 +snappy_version=1.1.10.3 \ No newline at end of file diff --git a/images/data-dumping.png b/images/data-dumping.png index 9f3fb79b92c221041c9b19b30b3f268f75dff036..208dc6305675cbec6f69e333eb95a139c25f8a67 100644 GIT binary patch literal 310680 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�@ZIeJs0C&QgpXiYFSXK0`33AXQ-NQ7 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

fN5T4_qO_(^ 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

H6s@`<@ZLhJ;cmkWMOY(64!9g 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

i2w9Pp~ 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

A#hzSLM5pe?{lp$Cl~%vc!v}Sr!Yt&%<3j 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 z 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

65y~ytnHnWL z!W8z#yFoY0kS3|SP01-m6xPZw#|1(pAPwju2UK3v2R5{)+`z}n7E*Lpl_>^AD5k=LwI0 zT&a)JM_3Rar7Gky75Kqb*ZJ|wW0!d63xkY`={bKlSZ{LLSU&d?XX`I5I)tX25X*-!VsJ>u-Q_BJV< zx15(AzR}$|K z+0yR)r>_RwdFKG|WJ%*2=e@A+e((0oSCm`~cKJK!{e}PSj;FuWE)ekDxBUgG;M<^h zUtac(zXr4J&gTm9Q7*hm?p}I~us9XO0r9Vc}2^G_;z;#(DH=e(-F|Sh_Pox<`R~^p zIDl83{6632xnDaCKU&*|+b-`!Dr8sP&QJU~dF?L++0~zYC{Mvhj^?&ir-v-l( zjo?5ncsXQ1D`#&j8_%!0&-s2?o|ZP*uAX(f|JS#T#2bGQGI!O*e?01l_gAj}pX-04 z#U8>DoOaj;`?mg{8-Bg;JD;21JR-<(|NGj9`DM9Y;=iwZSmpXrAZ1q%KH=KRHvd^8 z)B2qwD;fj%og+U}x⋙v6-@(K8=t4h0j<2At-$Dx0l?vp$ChvxGkI=gC1p(p2w?lts+w`h{tJhv;8=YyL^ZZVyYSWuRRMsvis{7hVro*%!5( z)y%m7rnQM(7OZyLZtTynw4?bISM*d=gS|gC_C-plgv*Z!8j}yM)#GOKbw{K{13bat zKBat(Jx5F=NVMm4zgC(hjC>8B9+$l#I@R`kr^+8_AO%fsC-;MEb|{y@O6Yki*Edom&- z+M%C^k(^;9CB~dG-p@@DM{n8p=+QfN`K=kbF-~?)VM4^c{tIs$#j8uxCLFt{90^g{ zc}oYh^|lzc)*EijklBIwc51p;R+5g(>r90kv<)(2KhOp5;Lz`D7dYRu7A}s~J`7ri z59PpQf%{bAqfGL_>+b<7_7+Z5Yo$b~jman&1#RFBtuRZ>n{tecQg+stuSrrPQ3@F0 z;tfh92H389Aale?#K5%Km6-ju>jpora zC0Bf3ahm0AofIFs>~d(WVT?h#P2*!fyP`+p)Uy-+$C@uWS@L`N`aYb{LTdEmjeWg+ z1Nh;Ay)c=R{wj}>8<-c}K=87vXHX;FO1c3up6Q!|{ zXIM@fP8o3(W2cjbX>G6_e?rKD^`aNO$S*(f36J-E$TkxH^iS{c%a8kmKd2-hC!83z zz3kHO0|+0Gs&Aca|MWwitZ|X7j9B@&bW)%9mjCLz$$$UV)BJL^91FPp5y9X8 zz3Zx_0)_U6JE_3oz?;tuGLHv7?+v~n;9ZVAs&d=^edV9{ z@qg`2q0c)%^`%hgjd8i;ZGY*P@9@;WwFHHLdmML+U;n*#{gq$7{gYo}rC_YJ1OO23 zdAlI*`O*)5;-z9luxWTpWBa9JL;qjC{0g7`HC+lt{g~81IpV7Xk#O%C_Q=WtqcS+$ zKZ8sp{57n9AjyTWDTPvCeVC0=NpUMCR#89K`yTNPet9XM9wBR~3y59ZW5 zcx+k|`5J@$gybZ@e5v`4U;dB#e!?$5`g0GiY+vX{-w9X(unyd;egLI466d*+#6jx7 zt5BZ>D`fWDz55z$?^7u4IiIg7iYoBx`vl3>hpzi=zbs`}AGr23{|^1%%Yr=hwfB8r z-~NB|h!6SY|GqY4Ed1nU)maK(ci$k>`oMLMtZefeWjU5RkDvH{=<^Nt3vJ#v0XbG1 z)XB8Yy?-cn$xuif`+uggjg(#e>(B4wmp^%_&|L|<<(EI_mtQL6SW(!P8mpv*!2k zeq;}cv#mf#w=D-dP$UqN6Ss?sNI)7u1a$NgG;Dd|?deia8s6S*Y*qsqh&b99hUuYs z_RI%Lm3}t%C|w<5FC>29`XzEd?GWmk_!=XlP5_Enlscq>Wbg$2$S%=w`cwzJ_AC`@ z)pen2cZ>FJR<|xly*1pq@j>lHWm5a`2(MMU4G@B}Yml$!NLP}^(@ri8aqxsyH|}gp zg5lqj^14ja9g!gNwN=P@89!Qz)!fE}kR=j2)zC@* z)7_(WHsPKwWIF?FQN#xCQFg!{L%QVTsKj~q0i`vxR?yotvi)2F-VPw!pCjFoG~ds4 z0b_$=DEBY<_Z5?R}nK4dV|3s`A* zgSHJgn^aTE-?W9-%f?}7vD@Agk}PRkYsTFt`G!HdEc-5QW4$i&Ky0>^&NiD0d1HTO zV~dPU&8reEGKpDvRNggEj_9bw);_WE8?cfst%DRnwV2r8m=O`u1caCnPVo!CXM2-| ztXX%zYuI zg;U4L%Eb!wEH-!FvfVf^PVzB!%<#}6W&{0HfMm!&lV0i26WhvOOS?XEB^Unh@++%) zERYPq$+g{VlPa|Z!r#1y)cw_aPiB;~Zw4X(X+Y}gdSu4U*Z}|mr$6N>Aa|3#<&P;YPEglV;klPC zkh(FC$ya*m_1E>R%Qy1EKund_mvs*dWdN>JP8*9~K)^5xftKyBq{0Nedq4?5zUDkU88wc_SlQ&-cAK{_hsJ0%I_krv?Ip@dfXa5=2CWb+J(OYe!%av^Dch`SG3fs<|mKCkBElr`+VDisnkGQG$`z{Xn z5BTH{!~5_zgc3)}t{!xJC@lDaYftmbb(yjxenZHyPHXY%`oyJSzrQJ7;m`i;ABa|= zqX(ZD-kDN%C8b%i&9v~0i+)@DR$Y{^a9xBn>#^dxJVwZ|9@|1Wb;Wg|A1S-~OCiUq zyQ5|MI@E1D4cV1MlkH;o9ai`j5#Un8lNOFj#Z$}*-HI4V=@n+rh7w(tM^%i4RoEbd z4iwl0vY`k{X~0AR5>bOZ&uxYpr92VQNwhh(5& zuT*VXm?5l!A>$wFHj*;}#zO|Gf>g@a$QenMf2$l^`*E=hsddnN2|BSe(Ym8UR-qZV z$NUhSaa!L_^=$+2DQ#+_z&0Capz7CWKd3|nBB9_jK~;>dXN}2i5O^YpM0Yi78oo7p zI~quBC3ns)#l}6~t17icAd`-UUUDBa_l!}Oe06ocr%c!0ANi^!Ha?Yc0|6oTQS_6A z?CBueuY$-FM@3>n8}MX;pKHZlW8%6mV$3F-W1o`O1)^)E+uzPZ$gxz_vuDV1o<9BP zMB|F}{k4{vzyBKE2OI9YKm;r)Wxp*Lm~wf-5fQOyX!>@F`4_3SvOoCSLnz6B30)bd z24~k5b|ZTX_5%|bt`Jo8a42LTq@p9^G6R~HNny4kA^~Xt0q&!qki&iqHP4i@)h*lm z8NA|G$*?q{wG)1}U?pW0Og&7%_RK_hmnKk|*0N_G5VH||ptp}0ATH5lXi&+BXk*;8 zXk)s0aW;jTU!--&yX2XluUfCBdynzqo4hU^bO4i0(?Av|Cs)S($JsrEFg;|581#*jjW~^Dy=nP>FVALzUJmbov$=rOL(7iS6^&I}d8?rR%)t zsgw3LOxoy zcS^qp$BJ??QvxZ4uCQ^Gc1n*0jzW(FqyY*d|1<0OTxJCYRR}f*fMaiWTxCBe9xpOb z{pd2=cgqjuIp>@+?C@LR_!g2dmkp5qYb!Lzy+@e1q4t1^EY{E%ST`O zjL`l$Z}hPpzj&KlRrdMJ*Zd-7hNjRwgIG9bX2=hY(pJ zr4sFrSt;w?AtGd}nQh|;MfZS>0pe%JWX4I)9Pto?s|PzTL!zb^yRYKfhVEWYO0)qG zL%MXb^Nzpy$p-+iANTh^`2T#{M}O|Y{<*v3wmbXvGCS7$9u(UD)~6rn(i{VK+#cGO zUxCX12P?lw-6R(V3sC&NMg*+DNK4Q+D;}BR}bv|3efd ztb>$Y4T?Yd%x?_6t;FB9$b$8jUkNg;zilDM+AQqtZU}{Opd37jvDVFj2BU$1qGZEO z8rxT4#dhwSxl!Sf;N&>uJLNsN$r3-lKy8wxCF}ha1Ch3n$#OtxB%Ks_*5D!E!iWT< z0siJELaMoNjB~Kja2Y@N12bQl57^ZqrXQ3gXNd}iL%kkzybNC{WeXk>LZP=rg|wvv zZ0zp>9A8ialTjg9y}Q5bD^~}Zh$RQ!AS@Lr?D;w?gy7#Agw&-r>rp>rivzAzd1vfl zD&I;2%p8vsQce@RG4&_n*v?M;IN#TJdvN9LCMzgs!r`>Ng=;hbI2J=GK&{wxQ5;vn z8K*eSHV8;k8|1-v?q*;6*Ozew4EB3+a4G%n zZFWX^)u@;~N*B=v1VYz&Q|<5Y1R|(S>LD|h%1nOz3i$uo`|o&LlB+%x|E}up9ZtA8 zPPmhUMq!juKtd*%D1pGn2F)muZDW4MIKBrm*w{Q{i~~FnRzLxa1DY90U;*NRBoGoK z6lR2GG&#@Qx#8Rscj&HKzdu&3s_Ne1>~rpnbZ6$Q&pmhd?p)SF{j6kXjjF zWdD>UcG@UP9NnQHL@IKX4eitbJIoAr&Vv&N=E*$D)17tz$c$v24Yqt>Mn&7(7@k_d zLx}^}QfGQ3JmFa87^(0y}6D#kzaz1$>EEc&eF}Y5^$oS~@UXxpf3q4Qy~=Cjhn*Np{vU2?l3yDdWXe0C}I2 z$+USp*fLD34lL4lr+Gabl3}9Y(+U!o%=x0^Cg$ZUDR)m18*PkY%D} zOXruG{AIanZ@6*2Lo1(0<$9sMRDe<0Dw<&tf?1YoQnDfo zBORCN``~nKClXEBlv}#Wp(wIodUdeV-BSB@=-ei|lc@2m$Z<4>QsFO8)?{j4R>tOD|6<^Jsa>#`(tUuM1{5@1G$GR!Y}j zcOBRR2B}9T;&1)dZ;!3#ZEt(qruC;$v#z^Nqm(GtuYIl2wATLf>%MtxxgYw4_Y30> z!kd5oJzxg1uED$iaZEn=rk{T=D2HtNo>2;pvJRjec=ta^%KyT9K^cK7hbzvH(LyAo zDgn6w6_Zl{2b2@YrO~(;|NCctsIJcS^z%OyBgTBs&%R^ROyfa zlm9ApSjI>HV@wn%=cS(KUL4J?zIgv5;u}yoyy_=@Iaq&v;=lZ(q(M`g3jp|r|La#a zFEoaxjoIk@M|kl+`1heLpGlGuzUasPz4%^bgy;S6zk{tL-^DGz@h>)Q|Fu8%3sBRf z7hJM=^s3Y}NuqOUxLMVTL9{F$aHPH|7r)_O1!wt}UVhQo`v2F@y>;yQ$8Y%gaD4c0 z{of&o1sZvtp{hj7 z!M_%M82PK#pS)Pg6me=Iutt?qt>M!@- zz4SkiZS&v$i*E{GWKxpB-+jfOZ2Ii4|HNycCLXET)t84~jG)8RC8+@F;KOedX((o; zUwqkbjJ@xq-QYuy|E*2iyj8mC_-o~!hVUO>9wS_Bl?_Uh5B~DYV-&1e>iOV=M1)^S zO3kQ#<&}RLjwiMMcOQRE02Lp*JMJTY`_P07wn)GI=-1%hWtsbFlEGQ}^XDfdBAkUL zB`dt(K#XdbCMA6Pt3MZx|8;WyZP(lyj(_$`aqgtF)iOVH^ChCG0OL1b`ta1}Xc7|z z|5MdTFaXOgt|}~oCN<#&;`*1)+?qd{=XKOCBv!@Yyi!316~k*g{Ca3DD9eQZcm{(H zU5NH4 z(@oWY#IFakz^BRfHf^&v$(vR1UG=RubBaO+lN-?}0Kt?gZ#Sj$F|Wm06C*fllOdpD zG*^qD<*^RN(Ab2MWC(6(!Bg@UO(I)~(>!@lKtyn*n4sCpftbX+O2;uX991atjt{$A z!SPVc!l(_VflOs%LN?-ZP$Da`=&0|_xbh;anOe+D69!V%ueP4=My0E@>M4TI#{GDV zR{L_xy;;E#QO!sJYxN0)}YUYuuFSmS;P+9$ViLexZa+cBF)j~B8Tl0}k zU(F*LjgY8892g5-bW|Gx60J#CjHa|Hoc8`GQ}ZlnWr>~m)Hg=aw}GGw<#?dcezBc4w%D)A7ut@$Ie;k)a2lOSC)Ehp^w>}CzO^Kk>eDeTr$b8G7CRIz zOZpB&0z>v@ecmL=6y^zIG64;(oaCV>Nc^l4QlA$E&ExzO+|W(UuQH9YTyl!I(kJNi z%(wGe5tAiO<;I}hUIa6vv>VV6yap{;3<3}dzAE0-s@AsT9jpHcF!D%KDZHQNtKP!< z*9&AE*Uyfd&ypKvLM>kVF^g0A4j=O5(~ddRQj+<7Nns889Ix$$^0I#KS~Y|W(Ou}2I6~05p5@`(YZ>E z#a_P{|Cc3yx&JEwwBG&hci%Ivz90GfKT@kGCD*X`P0b~UfGaMGk*^-S_ueon)d@*; zb?lw2F1hToQ2w5~BvO_QHiANzUm5G1h3>xd&M2YgyxVvF!|#vvPq_At|MorJCjhwoNW9mbk323R zI2mFpMO2fryDElo($JbqloxbM6n1JuLhaRh$Uey4XZ^t#q zV&cCqJ@BZ{^WmA^T%6)HbSn{X_2H;G|MH2)$BIl{CCCwl$ z&w;_SkH-5hKeQsBgI;)?rCb=*JyiyPaqP0#54S$>sDCDT?!9IXtE~Y5VX|H6@PbRD z>C`O`Jqk6jbv~IM8N#&}Y~KDaJS0gE6+AG2qMPFdNrJ-9-v1DY2-U!fzYU3#Ie=(( zqsjLi#NSfT)*Vek`27`JM;DIQg0@FN){yen1$1Z{{Wb9KcI1 zjn{tqj{60O=tT3rFE4%8#j&1y9{?P{Lx-1LbIGRd{M7CD*ODBD+#Qg0PyIeL_e_y@ zF)TNN85J2qMr~Lp?=l4y6sKA+;{t%Htb#vC2;c2BL3-Z7;p(~PY})=Wt=xjVoxwS- zMZ5aqna?9{XRxKivv*y)X+3wkFTs^AMDtP~qiSH$S}5vVN#X;tztu&?sg#qX4-H`- zww8!CrPo|`Ivl5o1z&UNsd2??)GR+vP-YjK@o4do``1@d=$I37~lRZ><%Ju zXtdV>CWA0E3_xu?RWjkPbCrY1qfdY?AQD|@#zr)>K;g7s_!2czZ5T8q>IyWn7NELh z%{)D}j~eG}X@lod_}|dDp*It0j*n(Lmj@f+9{S6kN)qEOx5n8Cp=KI$20ge9pExho zj)doM-Y>&Pee$7+XCXWAk(!u8e`<(bCAJJ}o%lQWO#(oOjOHqan)248t4-Go#WMb= zsfi;343FeG;UNP#fQ@W5yHZAj}00IJzvw_^vC2;e}?!Bps?%(O}o zE7uR_O=iUGiZ#-Ujt8#!YXy+uG}uELjwTUmB#d%4V}|goFtDW?G1n8P^(`zbEFd>H z#Cs~{a-UNmo)a@kY47Pu`lE)n0KftJcC2i+Oiwhx*r9Wu=JNvURarYn8W3^D`5VB8 zV^C%!T3r@}i0VU!v`((?zb@oV8lMA1wsFtz(CB_2LXtZRT`;1*n*(KM#pXQaX$OEz zAsvVsfz5fF!IX(_Q4WxSF{!4ZzRQGM4^T!{%@F`m`BS5OJf?9R>{g#6Fv4dy(wh^7 znUT#;U<#guSrx+U&O+M16S_{#Cxj_NEj+3Ed}s~;06_|x6=ut?W27rQFfv|(uVzLg zcIKXfKS{7VOVP^Y6`2(@E8bD_5^u@{=51vRpX9GXg_vF$lfhLboGr1^l73SyQoVul z%$gj}ATrOCn^Aw3JW-+hy6j*!KdIn2oyY9jqv3O-Bf8oS>xQLaXW6&84!&mTLk85h zq}hK2?{m=r4y^<*mH^s-Ydo(F3HWr8@_#7}rH)yJ55(fU8BB;MI+BMv7%1{Chzth9 zwQ!z5D61awtR*H7`tCKOdj?d)$|sGaFh@fO-XM02nvc+fW_F)AlhH`TL6vmQx;BYc zDk-1Jj`YxDPc_-xp{>&-fUyHSp4rrV{p^r1Gqcq}1TSo3Z?f9ZX81X-g0OM?MH+pp z9v-}5^TG9IIqP7U5n^2h&92Yaw6k99m|$Uw3Dyt)=nq9L2Lyo36)m5+m*LnU*Klfy zUq`9|X~wg63QF{;t<4Nfa#+ zx9Vi2e2(7tNZVGsID%rnXIUmgd(FK5(xsqWdR{VQ`Sht0|O9x~sluIf4emzh67F!CXt9p{^F!(6td1GD`;XEH}YaEw-6z zfQlJ-$t4#~eJ@S=%)JlB>xYc2n*|LUSsyqeWxksLE)K=8F@^_D#$F7c&0*e#wV|p5 zuyW|5Qe_#OwOUggiW>P!HA9&}ZrUil#J?_NNu-1xz-fqGtt0LK@Lt%jJ$l>Zx5`#Q za9|2Gqf|dCgmGdLDW`_Ru8qCqJ39nWt6I>Y`DylbGGF6doqe84AP3-EF1%>uw{fI7 zK%NXf<%tf_Jr3M%7eG8y`LZ1+^g2Ddv5xhsMCtc}upTBkJxVyq_YwFV1sT!WLj{fD zdzQ{w)#S!~8Z15_3>6*&5nA|lBenL>wl#;l*PN;rM1*Y)^F<2)W5ZS;$bK{I?U-Qg zP=m4}LzcWMlgoey9IOWsIWiC#ICfz$8X|qu9&pq*<8bVOO63!Mfh7DafEx1=!G|B| zDKG)m67Hl72&<&s1C&YNBmJ%nKrM}GKwZR1n-j(Rkh4O-Xc^3hrE-8cVU96BWc%W zeUkjHS=NQ&mPJ^dZ=<=Af5#lPH+Aq4nMd}%ASn+e3}WD3L*%WIW@S{ zl7a{_(uXPl04M;Xyk!7GC^stPoh--=?9c`$>c*6sncN^cFcSf`Z=o8Yam-vz=*RW_ zPJYv9cXg0wnNf6FFkrAxwo74%NDWn4h5Hg>V!;4BSsf@-&?TS4VJ~s!lvWWNP$o9f z*1DQ+h%uw!1Aq?|ZIKtbpCXhz6HwVQ9olu!k7RBqJe*4$O>OCd#*1{`D3J7Km?lRJ zSf+vwovStAp$qH`Yny_Pbp8Ls#~#GrJTe}*9$T>6wUC^N&X&h-f{SM=Xn3M%2YieY zBVvspNTWFAnpO^MIm~|v5$E44D_e5E1fr0Wh%U&CBNU9P8!qiSD|m4DA4r&B!mTfq_f5{to5hWE6@~Vs_ve zL(jv70qQs2lB4~3UGiN!@H7fA;>YMVRaXqACCIl)0ZF`nsx?utlP@I0W1NIjvmaN9n!p$_QjUh~Bp;1PF@x%Z z1Mo12fRTW#08(%P0L5H1_nFjIS2=NXCLczaxfTg3@;4OQO#oZfV$^{Zb4;EX?C)#u zPWw-}*ysaeJm9jW^HOBr#zfmgNuOyy$eUuYt#?Da?A^AOI?3v7fJ(!hwPRJ4|II)k)lb{wg#yPz6H-9sfzwV9K0T_oh(n*xSX+V5X0`ezh zYNM@JYB|qzj5?n;%B7HmP^%|fn9Wg~t%Dtk*-GAy*`U)L7aH|J>efx2U`rcvb_h73 zzzj&;QF5tTj$j&NIe-I`6Ye>2GJUZ4d`TCm#U{$Qj-=n$x@m0V&8ZSMyL=S>~wUkcK}y17Oj+8GqSk%u8AOJ z?#nrd)_87@ov35o5hq>EwaLJ%H zNiGTxVpKKHmVNXi8DpmHL-H~s%L%sckg2bTXCiO@^8IxU1;u$N!(KPB`o@$7UQ)Snl5Xc&V-v@0bIy&Hgpml_6N3q}Bx zVLW6}>!6?gQ@^}v``d?qB7R}b%M-z;&Utpa-bQd91sMQ4i5kZYP#)W?_TT^lxEu*( zt$>?={$u}n(>4QQ>i_^|;qM1P=`4`sA@g<1*!sgqAE;L_W)FNK!G{Vo#(|9g`tg4j zj(_~s|IZV4&m98(^Pm3HP0PIQ1^?kI(30)ZzrD4!X_#Z>GvKzA6uap&aE`g$b9*HKSmI}wsX7UmZTIn zFKISqL|)bOReL7UIR!w@IpVmvsXct#G$$e>GbC}wiQqVz889>YjYtk50+MI^DL95V zq_zZPM5vq#Oi2JA;4q*W>2@zisZ~H~B_Q{Y$Eg+|U(8|GD!5Wq|J-+=wrBV>WNQtr zc;Rv$a}jV;+5n2a6aKlfLcoeEU1CPTFnK0Xh)RpRlSc`+aDG_m{gVC_C!%dsVzq8qfV^!+juKjAgI+s>ZMP&^ z$zmJaE+nGJo;d)3>Ez&U3&Wv9wto(~{cxuMbw#CZ0bzFM+cJLjz3u6O9q`W&Neg@J z0=CzdHUgrtT|EB%ReF#z<2z@QrWjn?|8!e*NE%}NhJ1#A!;KPR*n0AT;Y zH^%!_4!qn8S{qvJgDVHl2yT4{3`)7oI$&)O&G1&`8X8t$f1dg!P*xygLYVF>y*DLO z{%j4|JqR> z4-y zlh!t;jA4-WCzQ3!)XiKSkl}$$J)%_OeR^@HW*)Bwl7V&REXtvO*=soByVX7*Lm?!r zOYG9CUIh?^C``3y^pUsNYX?AHYOC!^A}C2juLPNHLe3D*%y&`d8P>aPkn4cDEx2|8 zYUgkZ9Z+sCzjrq{BWx_R!EFHqoEud0!VdF%8z?fcAz=4B967j70km@%2Hc)GI07!7 zlluTbIoHAR1i(0nM%mu+)O_?`+G6>w5>NO%7l=KOtDT!v76A6mZ|^=^Dm{JMt$zA- zo8HHcIX5d=09fvUn1RXy>s|u8F#weoydfZq1|{6uaEzJVc!osRBKn4Bf!Bwi%EI+M zVB09cY(c{c=ncmLhIA=YzY*Y>11_F!)?CLoo@Nj96(Yxg8<}4uro%zpn)veh5^10p zW|n<_jNofKlxKC}b8a$ZjYPW&IzlTOyq9whF3SL0B?8!I?ikqtAX8|e=)f34WgQF= z$QW2#2LNw>*So^;54`2A-WeTu=eyrMw$7`PB!G9_c?S$D;4mOEAh?>{bti8HM=T;j zWi5b4J`eVpH5(I_lg+CRLb$e{^1!Pweb`SPFsK!y0Rw5toZ&<1x~z+4+VSAbeMc(EgzfZcOIM);eD+ZeVAY_wbWvT4D!bJ&G8ILlD& z?#{IMF@Q6hmYPiIjCuGh>e-_Xf}3xH7rUT^HZa%1OZT_2GT*^Qw~dWXf#ro! z$@Nz0PtLlA9onHCdQ!-n-KmCZ(n^-@Dj%Pr+W+Q1O=(f|OSISeC^kwgEv*CV0|7j1 zeLN@6QS^o=Hil@g4eH4iuQ)8GcD)kAGaG2F54QJ=Phr~8UVQaQ16wrrc`?C;X#X{< zK@#Xh1JxL_JyYb`y#O#f?-bw2{gIX-0wqB=l#I8A83x|XKbtqxr)P+Ea~$mekf}sq zSHW?NedVSk^K;yc89kje`)?XqMj%5ftyk$kCH!(-{U74;CyuXaxk=9bL;!V+_m2Qr z_n1P>c{td!JH+H(X(StFmb?qWp)-bsO?yE!3Ndu8K4VrGA3o1(TR2I`<{wiOM9JcU z46K0te|kM`;S?KOYAK0teQfYw?c9X+>pZh@E` zfN}1V2J>ioO0d@~c-dwx1TT#^p`RUx&+w7;j09c@>9QK_R4O$pqjDsP%NtQ{Ih)>-c_p|PY#9ix8sXMZ*vzxzG!3CGvJK^AZ_2Jd~}`^MJKIiSWs?|IjI z#+FIxjn`j?2tFbpdEfirzoqB8{<=5F_3aQt6+C1(17wA0C*J$c@olcv^A?HdmF88D z6OhOhhVb5ZZC+2aPIf+VpPE@=w)VW~hu$bANc$In{R`lI^WeSn_`V0-M;1Zstd@Lp!uXJM?s=;X)h3h4$tJr%-!UfXK>`U17g? z)D|=(_b#x!_g;OUJVWJnjdR}C2(SpJRYDDcw?=^{DvHL!h)`9>$ z_hpeyPOp9O{9VBZ603#7YKyVfVyw0qt1XAM7O>{e4IlYWKr!mX{XQg;w<}(@im4(-qm z?aeyEXf5~AUhbiNrk~ih zB-eh09DFwm640xjxl-;Yi>}>&006@>qjU~~%3{5&eB{t^77<$~x7mx`CJ9htz?c#3 z&NGR20LT=Qq%j1SgiRYXqfkvGKd7b()p<0`>=vjQ-D)e>Id$A(plD?%H!2|C8fcJA z!!eG2dM-GQdm0$VO55Q~TfoC|%i&DhVWr~%MT@cCVpKQ(40!(n(1_ggOQ?qu9ZzGj zweQdl?a&VG&{Lj<^KA_0+gLeo&-8-L?KFA=<-ZQ>QLe#8nNeD*EiXGJ*|H`_hEKm7{IzG4dgr(Xa|5yp(cXXNKBLH zO>cc;IKJ%S%j(yStKWl%&Wk_6_;K)ww`yr|9v>qW}N9Te)jGE5jbxT zc>e-k^LM@zXW9;{ZQ%Qs?*b0*0_JB_-S0cJd6^x0S`nSukOjYAf_f!d2FRB;00uTH z29`w)pAiGS5;Q22YkSy}`QQmdixbPDzIOm6`_E+`n8 zzt@)&KBViME^D&j6KXt15J%4fY8P2@s8B!)%AIJr=(_ zwhYX*fFhIdwEh}i=)^jY`1Kg?^ak3e*U>q>fzHV_bWd%deQF)ulWXWGSXr&l@g49HX_m-W zlgf-n#2PJA^MQpf6*Lo2oFxj@)h`B=J-+o*6_^R8Vg2%)myKtiXQ}^|UW|tNg2lTx zE&p_-9RMXc`G$@od{IM5=WGNHdJmzW-jmK05e>x03F*4 z9NGn3xDThUz7*BL1yuXGs17Zl+Bb*l;5^>6kYo#e^$&-`|1Y&?++TNm+@W)f)&`); z0;_$Xa+q7|0gjO^Z(zf+B(Y;)@7f0782L&Mj}IWp>MDzTy$7-`B(I~50Wh?i~ePSK{{NI8HVkfs8PeFX~2M@R#dxPR*O~WBuwR-`}Zq37F8F ziI*+JYfn#5rd>D}ulw>^tf4*OzDInz3<7}Fvu8fW)i5H@8}WWbSOWGY3c#@od#{wg zDfg^>_X!NgwJVxldqk85d#EjH2zhjZ1?j1Ee}aL}KNv4ui6D;%fb*uWUwg&4rx^`I zF(xoY?fjQw5NH}$@SF!@i<0YxGXpGi8clnkWVDxIC|22a_@djc2M4 z7o&9pAt>C)`NMhrynY7$JB`4SPSmjm%H!7!0;5wD=nW@0DF(?O<4B_1XqiSCP}rP9 zls(_5+V`ZsO&1tNAt~U{XC;h2lJh=d2NxqqX!vYNFpC&XkPLwjcxG@C&`4D@dY+Tt z^`|_B3deBZH7*RC>G|d-FQumX2Jo6FvBc*dsQ)&ulb&;aY{RGSj+&#FToUT1FFz)L zX08R^J1@ucZ2>U5y8>vgJR;w_Ezqe|pwj{t+u#fKiAHO&1C$P!ZwYwX(*?RMscVOx zRI;rc8%K9xm(LO1k-4knQpIEDhK7K~f1Z$8PIGK=JW27coFNT_< zjgtb~G*eGW!T>vLG0DQr#N{*70Ug)@AXCX%2O=QPWRtAyXl~Awm>DgTVQ4Mxy5}wc zjBX=)W|J&C7(@8=cf4cM_M}MpiYu=i`K>a*@WMT)jx3-&vWUkQD)4!G!RPG(pTAc& zt+^Kd8P?*3&;Qm<@4G`=pp_o5HV_k>wSj05)&|($@58JM7%*#nWa|U@TkRuT>A|cI zkgfNTtx1{Bo*IG&6^MX#&5?+b{}ET$2?-g`pSKcj8Nfs9@j8oqELh%`F#mbNi|xiehOD?PtIi{mzB@>3?6B$grwz|kUJ|JDO8)RTTva<8;!4rDGIAFoV^ z!gxU|Ue`(P`*2Bt(LUDVaP2=k9FJ29ZD{bR$BOuj4^}3*&ZoSjXxha7!qkUr0d zopx(%I{-)w{N$HQ+OZ9tR3kwY&8Ntlex}-7N=&aP1x^H}M&x^KZ`QC7OB-lV=QBcQ z`I8s!jm&vF*@ApAO{WyXc7O15;b-?_e8 zpMOa209x(G{`#8B5-{fLF(hVb9*oevCnP!Pd`r&n>Hv$9j|klsuzL=CY@cX-<_aLo z1mMiKKntCat7M0^PUY?n%H18TUVdPD!T0wmzJlBCUB=v_D*{#?UBUb#D=@>S zf+j`A;lF%tG*5f<(4*lvHL3dNNts``HJWMuv*#QMHT~1)h-RG`IC`@}l{khs#bw8ar{s_SrK z&SCj=*I;;b5#{;2@wS((;pDu-Qis9c`KGNsx=FEN?*)RR(k%soV##s9r^MG zvXvelIn@U(_dqK>Z0I#>{fSjy)AbDP7zUljoadoLIs*ZQ8=xbV(yDf@$;tZ9!-Wm- zrIp;U^jRgT;n#Ft5!=$Uz`Ggau!kX`qFz4>jqG)Co z+G8UW?odKUcgx>%fjh_i+&;CA?xQQ1dt?Q351+x@!^@a^Xc_YlpF#Jr)lI_`KN&Ph zb1{q3K~0*PCP-G#hss9pQhB~gL5Suo+p0;3$|1TYN6%KF&a$dP0zq8|(b~FJu^N_f z9nm~(&tQ|QChY)_Db&hylvM==qsTH46N)q)c!M%B$b1}HmBVVX!AV2_%9bDaUW;*J z&f&2IheziujxWgZ@p*?+a}2B1z3Q7n9m|+CGS}0es9z#m?!%p21(r5IOB=AKR)N#& zprv)-^g6J#4lHd5XjtCx$GwmVeiB_a&wmL`bg8&?B#e1ZZ|B}o|Spc}ST|$%GcatKQx9ja4*M6<12@2*C0CIIF zmPwi9v^7_C>er|3OY2VC9>7I%F9U*ZQS%(>NfJrX#Y8 z1dcedQ3=%x*AAI5+905wdk4TJiLy0)*TED4?AN2%I@V}-e(aM$@Yzt%VM3zR?Nm-D5GUs$&VRX>oC(BRr0whWWU&D&ZBTydz;IsTprkinHl z>WsJ+o@<3elamK;p*NF`ZS-BO&icI+fDk+rL?q!gFFPn@9oK+Q07o_O0k5%1&ILe` zeD5Sc2FY7Ix~G24xX+X*{8xY6{R`3#K)^yWSPhZ*iS{X zUH_#Q$LF}`g!stp>HybXC?ICOE!tu|zh_SV_RfKJ&w=*MgZIu!ey3+R4ffAtuzwzB zo^y2MH?j`h$5t`-kN}hU2bQq#;2HUR;LMELlhOTeGgdhO05snHOm`c%szz{8|0Qdb zk$Ih3VTR$S3oz>I@Ypug%sAtPq~HTS!E>HXt!FxMZ5i63NIL*z8abeo%VuMporw08 zglUvN%M!+StV;+1<&j1Fz5n{_cx1ui;YEixJbW|wqW$3W_loWB4k0_!L$=gIcBY5n zBd0;9)_{`&BLcMvnetv=Y`mGLgw<;@oD_H|f35ftDC1rC3n2YhtM3PQ zi}{d2WYP_Q-(8CLNN;`p{#gId9CYED|8&v>!77^f_2TDdC};8ut1|Njb%y_RS&ck4 z`SMyU)h1lgj$q@TJXF7?@z^7jY8);}fJ~S-+WJ?QEWC1_{fUDSRd3@XE+VOd>J`#b!zy5HekH?|UL z@yG}s+do<#1N=|FHGmQNPk-20tNb9nV2`xTv6!p*d(Csg{2ksE+uw>lH5mXHlib$- zkeHmIav}gay$)~-1s;AQWe zjEj8>a=d>*?(q!CGR>L6#`(LkasKX+-^ejK$5%1`z>)_fOIWz)G#2hVg}KL8K!M+n zeWh#9W@MY%$PqF%v#Xza_P{TFgi}YNY1U6Z`#dpyV#a^EZ9bg;iD&hL0H^!l{&3!b z5hWi0AcEqlb9f3dfHqO^83crXQ{1raQA8?waxmVMe+P&}+5sR_$Yd?B6Gz1&pRKEy zfnMfq8`}na=^^~Z(IFmL6rgeMZ+{<#7wv`X7WjoUx5b1|w@(+M${}0Y5J0iiLw0&2 zfQ$Hj11E034|HlBbb1{Zo_Br#3=cl|V7Mo7XC{Fe~ z2NS596-7oatqi!VCAZ1^sf^^>x|vXH%2n;CT}S~-2IUc=v=u?KCJf_xH3WHvffE_L zO7#sqbFSUw4>r2>wp`qb-&1B@H7P_520ppAd2-x&_3r@cOmZvBJ-{Ix%B#>Pt+ADl zz1`@!gtt79OyAVEC0s}1|DsgPc;9L5Q43Ca8~VRgobqUtHbi&3Ai(Ca8=%R>StkvO zQHz3=0vTo)4^#jd*M?23o21`OD`EciA=1x;TqU`G`M6(3R1x&R)yWE8QYex#9#67wEoj7&BH?BT_@;kS}|A!8_U$aBM$<#w7J~xoCe}U^+#e8JPq^{Jc)j>w3WK!gwJ9IB0pe zUdNRl5IHB{D|EI#Hp5<`S{vs9ofOE(fVE#P+8;qmy9oEnjc80*`%nWJ9Nq2jTL(1( z$T*Jgj)k!#5Db9zeu=$4d^_Afjwg@0@ay`#I(JGu)ezviOaZ`q*2{Jp2KaNlVx+e*ifJDej&WsY6igTz13>)erELWBr_{tLME3|~8De!8?<<1n1fckbJ}+_TPNnp{ z`J`-ea3}!?DHDDmj{syGb3O~dPJ|HQ3aB&59b?e5B}&KGlaDX6RWcNr?uF#pvkC2= z&!(4|mEw3~7?_$YG2P^Jyp0e`1FUzXF1iJ(-k3-!EX*!};GAn{l+yc9@I^Dmge0N0 zdDzxixeYKq@^EtByq!V8iU19Hm}qq+^|{0@J!t9DydZ($W6^Tt6gUUU2zFrobqq2F zwsOb{0o^vOCjk_uNS=Oo;yj&z9alOy$H;OMo~asGsas9beE+g#VOaHLCH1fs@TL5` ztS1go;KQ6azjNIOq*XVm(ta2@Hx8JPGID+%E4ZtHnxw8vqe&PU3WJYyQiD85@t{ES zsxa4c>0aeEIMzi|G-ed0A0De;4MU&e(u1*lCy(vFaG%`EIb!5!HJ zcVH3j=x*@A1-Ju?PYdmeZRc3I`VdyGuJa|Pv{<<36z1LpIAeFVjbD3b@}bYx_}SQU!)p}UcVQZt0Z70=I2E6nF0|2c+PX46M#nUHBCf> z&wt_bK@0Is-}pCSj0sGWF(&-!cl|BPGW?JK`8xol4R3nmn?l)lz5AVh1C9%oQGSA= zoxTZT^5_hHdD{gI#cv!-eIcrF{EGWCX-{r&QOgGK@z(o%b%+`S0`PfLc&3H%Hy%VV z`?~A0DgcM8J7p+;`=9{9fU?4$^Ii_t)}_{vwQgUAz!d($6)ET$j%Z*2;K03c9KVEO zl#+`di07BCjOT0EZo+=Nct;V&!@)b_MeA2aruxViqq_U(Ejdh9fbs$-u3i~ee{B14RL4~|qVC|{_u*IN|Iyblx_S3W*114>1?fT>(a29GfC*VQ( z-D+Tww=$TV>R>=Al`{X)PliJm<(p_7_=f;|Zla`38j+9;p?%>`hPl~)?!~c~5e-eb zUZHitKN88hb*NraPw=W{SZo=#bioe>%^tnuBPYTl>*SZ_HA-40fT2> z81B`+pzqqHpKK^Un|dG<$D-6zJT0U@b`Qt>_Q*ceB^OlO(*ayI)Q8GaU7#% z7%+a~nwTi?zuXq>S^vS+@%;Mvqb5HG^`<(0=Lz*C&d00LTQAIQRzU%0qB3 zJci**E(D%?4DQ)S@lWQHFt)hhtJcPC(Xc{(as$QjRb-E^p?}X~pof+~kFB75-~{mS z67c9UF2Cr~5sgL4Iy7-n^~Ec9rKC%sBwt%qGqf%%SEK8y~AiF3|wU5dD)5avt0u*_ zGxLKbGf@p1)BkusAiu&9fW>wZOcinIApsbbi{PfR5sX-l=dHtBk^APdXr?@1>EszW zk;W^)!M=qMETCWjkFSCsUj=S`1R7$s_o52}$l3e(hvC`<_<}uHe#Iq{*!RGqn0+1E z1sq%y4Nhv3c#hKwI`|YF!>4d8AhS7?xEhb+#7{ng#akc6u3H`jv#i}jswJ7eX;>yW zHFpX)x<0`j_x%@tgnk&3CFfPirf9=pYe|l(zJ+OtGjZd_a8+#UmMAcw z9Hj8nFp1rm*Jqa>+%`i>GJwiiz<5AODPJ}@2*CiVKvloCF^4Awt>fxRZ#mZNYD|*? zfcI2%TV8vy_5PRnz}~!H`n8yg$t0^@C7{AZr*R@i*|Q?qHx$gcOl|^0rhX;HUu#PV zx>0z>KQM6H=vxijt7+|>jbo39U@Hd==+z9sQ1vR9oM20bJj)_js@*_14V`lepiC~> zOJ^B&DE<<8H%EPj)q2+p5aivva{9Ps>%dOIRXQ*x)SXZe$S}_q(l+6s%Z)M$hJyc? z07@53u@HkK?COSzLs=o~u&n@4T=(|PClR(d0ua5oXXf(O9I9cjZgQsJh1vVm`1hc| z4ic_9tf>HqG7xjXe+0rptB59AR~}BZ9ua83dQf6r?fZPIh(P0#0|BtixAIVDR4lRh z0r~4YdG7h|2=18y?4S3V6o(?qz@-K5Jp~+I0PcJ|0c^=;4G{1~23kK)X=4`BX_kAbGF>6PO+bo`uZ zE*q7aUoitPaa{-dSDv0rKR1a)>bySLN7hm`N;JLN{^npy6&Q(-k*6fGekKx~OKIRI zMktzZx;r-j8#mmj+lITy9B-LQYcv%7jK83pTsXEvygD=s7 zfX;?&w$JOvdwsEAgiB*nMZ~MpBmH4Dm&I^bxHDyc68e2IjW4sHPX3JZtP!XBkzmLf#c- zbojzcHf_K8i@U@(BL(XIow~{)Yx_j8ee2uGK?CC|=lxXxTRPaGLop{~&Dug5cfsT)07hmYD+F}q-WP}&X!RImGOWJrqHyi5Pu>$C0zng60;gX# zp$*Ag+WqPKY62UjrI%b33h%r5K`&&Ys8LqX<2A*`3yTKU;zbu7NG#8y*5V_(Owbzzc2I3-`et+Xr{?0l16&vH#BJxCyxF4>5oH{aF0O<5>92!#pe)gdFglk;^R11$js%tl5a)IqCMhM|%i+6YG4VWdbxde@ z_boYK0Y}bjLbW`HJRk$EgNCZCkmVVk|I)b5f9}&2*gB9gc)`n}T>r2Be1I&^;j9&* zsODqxK-#gxi(b*j%^%-*JAh&GHvrK0pS>}E>F?=vC4kER+2qgpKkzxk^goj{AcRW} zAaudRhGGdt~O#-mu&mkLqnwO<1&9?(95qk=gNb1GxNI(KbMr{@%(S(eI z$Td;&s%;2Ni+@+04Tj0v9xO&CQ&q%3y0`PlZ|enP7kA*wp)AynHxmSn62k)``N9lv z=_FJu2}6h0W|fRo3BMa8CRz3MP^Iv!JIpqP0{Pm@=NX7^|(AfhL(8 zrDkB0Ou{%}Lf98{*40*OW(K+0z;bAi2QsLpX$xnPnhA$@&=8*|7GT{Jg?GCc6_jgb`wO^BG9 z!O6jF{ZOkT^PRE{qAY5zU?@D2sfAASA8s_V5Fjj?Y0twAHdIY9;bzHU@|>Iw-{4c@ zK^rp)-5(%Y%**n#cR>ZzX^u+Z*tvNhWaJ&<;Q?Kj{|p~ z0NwpKaQEZD-6zmlDQiq_jloZSEgCBPrYTg)ys6d$0LTx1GK5yERV$wrabg>PFb;r> zv@1EcfB*im=1~CZW>ScNfUP(or@kc007%n>W8=z=KKmx5QD2(o5!Jv7Gp6{2WJ7ip zBlBijb|_L2LfkRMKWOv&28O2D9)dS}@b;`O<+61{B2b=#Czs67t{=~r1j|Eg z`0U=>$yFK5aWaM-NlO)T?7 z(X=tFW`twOGeom)UMhoN>%#akA(4%YKW2b~iG(unvPP&$k}Dm^M6lv2$#Vl{P-akW zl;K)s>NC%{yV33*+F{B+<}3t;~lh&Ivs|>5h}sYM_qSS=e#`;wyg**dM4z-ZiBwi= zASVaO=}sQAUQ2!x`Ejl<`%uq{ue=Hc&@o9F7r=t^>ziW+<|5FTE2WHMcwo{1Ako$f z0Hak#Kod>D5=~3`3BWA%fTah(fAv6QqqXWiUAT+)!(M&}?y4hjmmh??@-W`n%$&lRU6n?tU)5`=)SD-)rryV@+ z!tX$ly#cxT764y8{ba8M?syEi{ZY`D9tCcH6u9jX@VzHN-p=0dlaUhXkT80YkyXiK zm|Qf5(XCBH_Suaao&+jwr^F$c5W`>sa6^%9s)#IvdL$BYLvl~uuma=c)zOz*0RWCqzUp;UjTMd+Ljg3$3YfVKPJ6q&6Z*_AClvZ(ZZ#{39=&5bTpo) zHVMMH^k8eG?=(E)z}4>C)OJYQ<3?UD7oRPCAETNNMw(bJ%#YeVVw;p5MQ-ZDSmzu7 zS6M&grJt>}Xqg-?LzJvLh8o_icXLFBb4v0OSPRhtq77b-MK+8M$E6X2YH7j2KO10flsf1dO`>H8UHmK8q{ zuHOu-4A)8!A(*9U;DEpc1%VC#eIH4GXI>~!Y`E!bcKC~fREK@mmgIwW*c*Rw`Z!vH zuV%66U~Sm<{eZLt-~~ZC4!+^)3#Znv#3NrunN61z3|a+$P63D(VV9Ii>Z^kU@x@b+ zsozyYqQJt9{LV4|kJqH6$LVh=2yrT1PtK{f#`y(F%ZEob2KLxqxGN8VuQ&{QIp{!i`=z9XrVdh!uK7&p(?-VMWnu-tz*?8#b)V_~$- zC?Ly>LC-}Ao^uZD#M}y;XhV`s#N?R>eEhpInF;qz!~4PuXUoB0#{}ysOtKc9_|LCG zw|FxQeK&}9eMMVPIRP5CKIDPMBfys)5eKw1B9td%2*{#Yk{E_0+I2+A!?dTo~Xb5rzwmNbmKQ(%gFM`h=q5TP+-nIGnj4?Sx$8gigGjw z^WJ3aM^FNi^AjilPcXoK{G0lv%s@6j>eTBjdsD3xaKr|)&q6P@!aOnz<2y?qve`g1 zes2g9e7_Kc*=2u@*?}$4&I&LK;E)iiCWPy)`l6A@iVUu@0(1)sOes4KlHybwp}t>r zpoOqmleeE?AVkCp=?5IPr} z2Pq*}kOz+1&tXWAuGN@4o*AeHm8|7O0#X?@bJFyfJ%gksW~qr9GZZoj6R%Fv{$+_ox*jPi^efka zWv#iCv`=4e%6yM3Pov+MEo`#s>$7x*z(&RxbSQ)YB%){+?*JHK9#iRT>HrfcjNAstZKpBhP~c2TOu!pLuw8PMGHA=L~M zoZdcP^mz-C?6&IEuH{BRNElZbDHDGnkY}XBPri^XZRA$`6`iaF#|~VOm<_3fzA&hI zWdJ0a#4u}R0uBi1nl^fF5PgwI7*`$N%yDxJQu~a+CBw034ULcXR_k}46T|qV*N$BX zC=k~v4&y=+4f=Uwv|p%};T^0}M_C`TLVnjVrmzgruh7jERSl3z#j@WtI zB#5t=hZzt82Zs3Gw{ z11!N&jmZM|kjBM(5Cf~uMv1h^!Cnv}Z!8|Qvts1FZ+ZcW zTaRP@U4MnS4}BRl6z#(4>VE9YFA|^+V5NKjtyT+dcNk59PbbT<)*m2!*$Ne8y&1nD zG|j4<6Cb6aUmN7L8xcs67tnx0CUxgxV4wtb2-waHCfij%{pqP_f+cVF4}NkEFT3;~ zqR9Rshz>t#jjEhzGXC-&&}Z)leeOZqdYUs0DkLzzZHIe z<6Ex}(tq`*u%(qO!a$f%>Ts$XC+Tmx;Sfg63iRQ$>8U6xr8>tpmeg6?1z;6{pMnOR z`<$92_>;DjP58UMC_ynrp@xdjeWH#Xb2m*(06>}Yq#{gAN?Hs0|D@?i&cr{ZyKX_AIkbiHWS z6#+IB_*@q|Q=<~oF z1PDY_lhy|lEl;lEV3zgz*KIyWZu8g8 zDLsS{&P)UgUh5me*CI0Num8^P-n9KUe)xv4E(9Tq*Bp^IHJoLw_`r=H2>nQgQ1#_~ z=AA6G6OjF&DUb@!kVlOXQGL$daMK6EJC+>`}R=&(;xmn;W|y?W=t05{fauS*Y-DQf9a8LdTk0n^0{5G z8!Kq%1zvIa5xA>guvz!l$bIQ^v1{sGR6AEYW}s(jL;KD0Os~CqPp@B zs^=a>^@0mgz3@WVD-Q$tm^JhXB6DIL^Y8d8%)jfiSX#Lods`P{h4054Ux?M}0WY9n z%+rOw?+D-%u-0L9qc?VK*5sD0yr^xu3Zf;!P)*O!_g zc73<-b(1luhQl2btaF@XO?ttx41e&G-;ag%zXj2GPxMXl$Jfxl^-*-b@CZ)-!CwKN zdqCoI1IWlbXcLD>EW38?ssRlJ8+xpNMNuHnbLBz9fE39V*UeG98j}K>k@>Ttq<>%)OM!NF|1wQJN%CHB?%+np&|wKdZ@z zXS|aBRsRq8Hiu_G(j9S|1|Vh()1lbrq|)bRrfN00at)0gH|*hsA!#WO-w>%GJb~ZRn5Off%>+doe?DLdXIXy%J@qC1LCy_Ku^de8pL{3Ek=mql2nm? zrqNY+q(MTqw4sDv*DYECIsjP1frH80h4?cO1^Z-`V5eqtIyZDJ$qEyIh4n%e1&u)p zkI2lYb9ffYe5Pg! z%a*R$%@Zj^1M@y#qS^J1>t^}P)$ zXMXQy@Q}bM?so9s>+5Pe%L2cm>u9|ULq>QUv5pDOi8;5cY`7+40`d&T2hOR=5?M=u zht#F~fZQ{#J)}vD7~rPk`ZI{0DgcB47<}p9T#5_#y%V{4)e~0pnT=}U&+pH>fB69B zZhjE0hn9mjW9g1N!2ohHaK=x%bTNcPd`baEQ53b~6oh117VUqtCPVG*hEwK`lf-SF zkqx%RE~>5>0GA9?$YP|Fs^UQeS0z3Q{qYQ13gsNXm%|wXEGn?r)Aj}#E222-v-}jAZIGfQpQ!7H< zCqjP|h6_=PWm9H^V;ul?4|Bk$i!h#B^mj@A2hPl${i2n%$3!9;#drX`ld+Bs4?=_b z*(BF#*j`S}OB(NX%&XQLIv*`2L?;Uibkf(`U_8{xR_fzqtcL$aA3BW724hDwl29s+ zHSw!SzjNR=8k!zurV$P8^yjLwp`YO|?-nhox0?YQK8AiKj0cCgmdw3`T;)JH{JarO zVMZndQUEpHabSYH-#{K;@~n)v01NH@u9J1gPuL2Sdph)^p{4Pu`W?$sN zzw_b51NismV3Jr-o{cMI>QM_nJX8Bs0j#(t2yr#dO1ImE zb1wWb3*awqeh}?X-w$TS>Ut0Eg%`rT`U>!?u7G>l#Xxt9@!Q9cJF)=xYi|NR`8R-n z@J_5f`~b*EL^}9B4}Cu(yfiSxNgs>ghLfw5tgDcbfn`RaW}P0KStlB2Tgp7B218_d z9^OT!DFYbDGL0~*t@1v$)z)%pJ)P)W2O!G!X1M>~e=`m)z8^%p&#Fdd;7gCL;}5>L zjNiZI3_f+w#`%|D@nY3tn7O$K7BX3cbyzAR`#s}P!t8;_uKE4Y8~U~;q!tc zpEAa2$XFu6r59fsj_-T$-ry8WIqDMdBo~KD?^I(EIz~4d1sVP~_3dD8FofRLU+VQX z%HDZWm`G_yldin%%5Z$=J$E$BaGD3Py1L>yd7Yx0ft_7j}RdkqUaAF4P0lhJBL+@=Mhwx3_-#VmgkeP1B75S1Xv#kfQ^AoZBhVm1q37Yz=1`eM@h(F zz=Q6_JDoIs_U(yderfe|(E2vbpETms?(Uwk^?cWN#PT1w@dJ`yrQ({&S zxk;oUnboW@rNtt~TUjkvYWoB*I_DN!aSL58&jj;NxdD)y43&+c;GN(50_#Q;hP`Qz z$uY4v)=y`a!!g?uFxkl3m3J3md#kY=r&Eey+6!=l^{^ij7%#r$2y6p@%(4!o<8%Gi z&j%2oCRV-+YTzK8L%Q^OfE9*g9W-cJJvZt6X7{XLm+Woc!7;vS{~IYd@E1{98~k1f zNO*S!Ie=-@7sSB(l^6iQmqdQ21e7d2z8W0iEAIJQFb*9$6hX<#3h3s0VE*!M(0}+S z(8}OmdNJHLUjzQuXM?XiI}7^q6~}--`R8c==)2MV*ct}KL$J0ALYaYm6m7~-4$A

v-_x00g|}-f(MzBqDExxXr;A)YSG0`OJz`Yx2yZa~Xgr2b<&J zU;4Y)H~$XER&}c^dbh>O(Y}7Jyw?SQs&t%JV!h>xzlVpE&Ql z^Fp~0>e2D03HwGq2|g<^WYaXV0vVqGEM>xUe^pI^L?qH*AZA11QP!5~fQ!H+x8{lfMyt%i^ekvD$8aOb3LjMXRC_N? z@S$sqhOsq?1`kF86$Hs$%fzT=5nCmnvOQOQ3oLB@s3B}^&%$(k&EP#S!%$QaN;{~bee@0~L?bUZYX&%lQvhGTJ_%QnCg}^cc|nl}3$ZE=JV3acM|wmo+EwJp$OWKbjQXsI zMkE4~VOY23=jUOqg|#;3`eFugCe|8%b`Q*--3|Qoha_3zH(vwy?au+f@-m;8a*MRP zi^2PT1o_|lFtY!19BsNVEaV-NONeYl-YkGL57-pkYM<#?9}*(dVNCK~8fei|Gqk!2 zVuLn+%tbT$K0ht#Tm>KzeBAugFUQ`w?SYSnm-_hMpE-$l{@HQdd3*x`I4X$Vc<7IZ z`}XY%rcoB9xVaxXbSP*^w53@~9MC5Lj__c~_n3V*GBi3qvqZ}fCBk78 z2dO<76N2$*GA=mwo3_86W7x_RfYf*-gb?B8Df8{USH_(vRTCPodqDwMFpEDaPWHvmx~fn5k^m9MiRmM#@(M z8$g9*mKQLZrFQ3X6gGtbK2l!*UBI`;L)NJYK3GBNn6hI`uEPAz2zI?nDoa3@ZvUMA z;;&5^o}>x7A-1{&S~f#z7-qmIjgwHbg#eYJlcO4_>YgI@@c%{skves_g$?f4%;zX0 zF<&wSSIQjB+Zjrq)ts%YCt4=eN(K$aCge&7E;)n&c4ZvIWB{)FaRQWRI) zBF-^DOt4km?5jy)CPKkKsO9Hx)}8}=M5?-hpqTR1d<4ts`98v>@vg}^MzygFfKX}# zEdP@oY^c1=pOd3@Ucf#9k%N+m&9F{)dTpVy?z--v{`cNBn8 zFI590zFnhjpm6_s{gl-2%AvKG0dHm3NF1Yj8N8R5YpB^nX`9+~_8{)~l%g#bXZ zEQ6YC5$9lbqIHpp3UkjX;MYD5^J^am4lcsI{#v*bIl)x;s#P z_F;6g^QAp0PY}B}2q3lpHS%M9TW|qj$2X({g2Q`?<d4zcvs&!}u#WM^x1GkX|LLRn$QMt8xk8K%(2N`~05Cjw@F3dlb`5;g0Z5%u z|5yL+ZGI3F-u^4UQOoW<&h+XnKl~xN6&pX~f+GYcg7oLKE_x!h{Ki_(N0B$vvejvwMY?33ujfAqmR2Vaw*B<-v%c%zh>7Nm6Jhi+($lacE2U9Ww8 zIQPMi+$7DI0>q-(oiHNmEIvy_pc_7PLrmlr8iHW1rrJGiAOj)i0kh_InB2BAYfGVR zK_J***mkvdhvT&0KJ*7Sg$LAURK`r{b>9--^#?z4Q~2$>UO)cXZ@TdYtrFk)T}eOR zc;lGOj%(4SKJ@z^gmDH{2E6uL#z+17y+8c02OAOiR1NUaEn0s36MA+Kz+lMt0_h`y zcbFzZxlxHJMn-^G)QM1o1ZcC3VExScQV35wiGpU*x74%}#;0;2auc&K^onCCH(sl% zH3=9bu18=?6JUmVgH|LF@L)OvzuY?m&Gn)4#@YIN`M`}IK;Aa6C1c<2XtKDpays-+ z2yg+NgR-rq=36&@=!W2b7a~_R0Y@_UB5yOfpR0k55e`X!UkYqS$nRrBjMski=IfZ6 zFD|aj_n_67KwtM=uN!;*V>f*WbrjARvPDgIKc(I=QL<}v?VjC}wGf_eSzeCqOxA(> zZoUN(1dOlavX?$D{C4N3ZwcqG{F-<^rQ1GrOAw%3^YU2ci=Vv3AJqZSb6*k5eBsY; zjnDPU=Z>xavwwDL1He%H&hUUE-avswQY4|s^)STrF$ zSOXk8Fsoy@w9An<=Svo4lky6+PD=J=PbSN}ABfI-{~o-Lh;}GJqGnm^O<0JguA5JH zI#&Tm2B3v^zU4bmWLM2}Rj;)8@1H)7|MW+X;LhV~5OAS@qvt<28s7&1%EN~b2k?

<4id6&q5#FwDf8p4p&!+VZxOViY9#y;Dm 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 diff --git a/images/data-snapshot-list.png b/images/data-snapshot-list.png index 9f47ac8136f5c7dd6c943e054e23f5228b8ce505..8516b5ad97c4bd70aa905af6c720ca4f59fff163 100644 GIT binary patch literal 592774 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%0AUag}u+*ua*Ro!aLcE{Cw?@i~*!Kg#$b zg*yN@unIix$?MwU&~YR%t9>6608WrQII^k^I(y$y(T)2{A|FkMrnYk0tGj2z^6ni4 zHK=MER}Z$s^4_Jx>NR)`-{B5Mq!V{y*Tcmp7sKTvb?mqV(M#MaX^^e-D^a^>FM#E} zjRPy?c8&ymB=%x^dog{Ss8GI(W|Z*@GIR}#Gj+(93aD-!K1P1TXIhEl{mY*zoT?lI z%13`p_JNIHcXYT?2d7T`O+>!D8*Lci-b zC!&A&*n59<^VY!E%>#a}e4Qr@@i}ZgKzMoZF=~XdJWDviMtJ-k0bz@>$;+$5ui89_ zwh#O|vbX$2b1WWrkIfg;KOM_+S~=0IMV3Dg@EuWm1LBv1>oK~&1;#dmAbNDX3HYy` zIJrKseo?r6b9;iOtgX)gvq7jswSQyzxc+Ircpv7o(%R>~0N2E%W#`pD>@gviyMMXc zaxInJkr%$5-VB$QzIuEZZO^&-CqB0&@7?g^gWN^#I;Ha-c+-D`59_7FJ-@hF{M>Uow*<9n4GXRb}Z95YPQ4@+O_b z3!r_Z?+zaOm*}SZCEZpAk==`z@MV$GO!@8QY(A#oez5E8i^!lUYFl;?pG?sHj28RU zvC2(9{10ic2_`O@7T4vExfAwNCbq95ya&$T`NcjnDZ=ZGrit(8L;RGCsDl%C$AL2N z!lemnSCssUiZfufHxwrR&#PF~-jrp1foe z_$A2$dcEz?bXb^4yBFAR(a)ET_ZDe{9W?N><|FXk*JW#C38B|P=yEwv{ozNsQOmEA zmb|eu^MrgowjdEU%|8B>S61%xVo*-Yo_%bVxTy`9$0R@6g#h{F?(4Jxex;9ZxGe&d zFME}SBlwNI?b}>pk;17gW9m@Z9OF~QL`4Z5_ftKzbI_t(dD3N~-}>o3PTCe&+t-`R zscY$f^NOQ9EztG9;|2Bom|A23Q@d2<5N-5G@RJzs3y=q8+y|4R^CvwN$)R(!M3Ch* zo~IC5v5zffT*-VW zf0InCAN*bEsq--u51&l^^cZP*x9;}Wb&=t<`nxTCl)FSV5B4?U2b+M8_#Wh?tBirE z6NWhOc>?X^ z(RpPTW!)Od=BD7wx>4`iTC8|6L<@{wFt%i;8#2N!7DBztsdohtzZDW87u>h^8L>)5za zN^J){1I2YY6y2}xvtHwGHvZ-(Pm$3dmY%smT4`8h0oa>wN}~8GBTsgbHG$$HXTBrj zSJWwRHc#9T*eGG?9gdFzO4)4I!zYh_GHkD;#ElB>da)Spoqf(>daUOq(Gw5?^kOW( z7|`mb0a7byi zI4&Wmqu0XP=ud`w5k>6Zrtpd))zBWT^wVdkgPlYamFp>0l0q;-~R5?OEgAQ=NC zHJFDXdC=lnKFA?D8~r6Bt6yFL$s%rdz_^$otvlVZz$W~fJ^7IMA{uAvk~&S!TXg%8 z%p;JF(QY{NV$07D?tr*+N4_tZw|SPV^=lo{S!v+Y?bm+}*y~i!^ho)-ZX^zD=Q#C+ zG{jG!!%t_~kInP?Eb4IC$Zdd}(l3pi>Bza0egb{R(BJX0YHsWU)MnVWDVu z1$6!_JbB2|jMSG*7<#bF#034469vV&^Jdj0$-(}CHc4A##C~)Wf5IR?gG%^g;iL4X zFxeZVkhT1f?1SI|z0On@P{t`uWk58%d2IWL1&{a_Rvmap7iiNz`{<|22K?$e zk56l&&etow$L~yv7IeCKxdGBtE?}hNJSSOsBV-|mfPdatrziMz>lc4PTc&;eLNy7A zH@=Q&$}ag+ZxoP+$2y|n@K15AEtsi*l1&_9g z=nW)4e!Vb~Z#CXkxzz4>k&U=jaKQ^6H3{isPfE7`NnIthJz&EvPr^hg@C3A9k3KDW zMD~rz)~?qV+ndV*Rs5jxWFp&o&Vq;Yo9SfUC-B6#eQ8U#U>|m!(>^BvYCx60iS)vf zY|r(%0e=cjXI%8SVRM}uwiQG^ID&a=5H+n%Gdd<&c)YiTJ$i)BlBvh&y2ZJR{BEo*Qwd& ztoz70$oFFia81ahcgA$+4_~w1;A`TyJSRG^(BmT~!;bw8+>`CFUVmhpCBOKr{XE@< zDMU8Z8P1D;Ci(FT%O-#NK9luaJ22xbT3Ds$RGr#b=BQ zI+hd1v29QCb3*pvgd@t1I7O&*#!}^AjH%6XB^%)e;6>&cd1KFZt&&~k`z^~;^+y!^ z77=7CI@sazPA__heDPwL$R^q*BS&KJkFxhU*?@eF<*7@^%jbb~b@})`2fiVLzwyFS zEo|B5`~>aN_6G2OtFt_51Z@`>-I1*VI@(-*Vn4Ip=6g8k%K9*WrE}{#Wyy^SB~NbN zcU@-THw!S#qtebqCy53SGYdcj;2V9h;ko<;Xt%vp$)AspKmN(^Se4P`!$&9&?*0$h za<^tOep&b_f;v zoC;iedOs^3MKS+FvVe zw@@QklcJReuMNXLtsm-I1#AHBy9CSo>tS_w=BDs@vJqa(Hx>9*5ryF(g+&}wcw z&%uqh;RVv(24fweJk*&N@j39AI}YPVRIer0+-ZtTbug3vXAAUD9n?DR;Lf&vaP&{# zV!Uo1wd)`m#Avijt(|zE@4pn3e0_nh*a9!F@N^ z0sM;W&KF;-J-P`r8~u8a^CErGBLQvyupnEvq3qHc#bx8RVXS49D#LnM1t$;3dg?5)ts5P zzieBf1DBt=M^~RHj@s@M=}CR7e1D1s*w~O4Vg%E1xh22i)$-Tz1ZQa7bl}O1@%R?- zQy#v1Km33$MgO`kve4$S*9&4?ye}Ox3F$tU{bd$Bx^_i6#GHQa3o#Le?bUV1Lzb2u zM~aERfLFnHFw>`XVDXsiNsWB5;qX)t51GH%ho4{}SCV>@9psXy%A1Git6wu_UQ{+F z#aQq#$BsvRF5RXOJ`ctPk3EFv?zcN{(d3)3#LXS$1(lEb>{n^&x}VmQEmLk5NWDlR z9Zq#@TJXS&dXlhtGrFv`I95-2Fy4>3YpDadg7^gZde@4C)n2NUs%Y&uXQ-@LLY z3m&F7>ZU0L`C$IE=t22Hr`ovw&B`-JcuY*fwBR9|n_Z#I(}G9j?YRc*ZafoAdI;Ly znp*6w7CaOh*qly`^m_iK`MC*XMhGIK_!|P{p3m*=FM3@6Xujlye7u(sUb7HkA8FaO zM2LY8sH3cksg zHaEXw)U{-tIV(?m+uvoO&Gw7EG4D(~)U2)FEOEj$9golj>ze*uBuaol`6#np!E~J^WjSO zY^0Nr0UD0ePVzQzy~JfGU-DK!#JlSB*ooM#YuDC3mwVh|8tT-8m&MBCj^abKHWzBp zFXeV5mb|tr^q1-foaopvvv7dk)d^MDK1LT=%%vlHa;{_QmBLO9s~a5KMK?OfVfzH< z+6^e6+^`!PBe0r&EXIZcJr0uhq8gi*#A2mRt>}3GuOjYVf6*f+dL zojEyIXGwjEla1_JA%m399v+l1P@L^ncH%P?f{}CW$O?6Qd;e$uCEMWc#nsuVI=tc2ZHswW4D0$P*fEIB$&Ydu z5begm9r2HJPWnVAp4od5T`q^SduPMxy$lrgCLI2ZBDO01dI0e3cKQ&~s?5VJAzmiC zL!s~mKN(mW=J(|hI&hv}*V$JJY?R3(>p$g4KSbO5y$CYth&`zzOwyO?(;&m}V!w`$ zt@Ez})FY^8vM`eY1b;~LGQs7iEw6C#A(Ot{FSwiXnV*R#$Hl)EJwm7Vb^YQ$Cv-U@ zXY!orJrC{!D0ts~1$h;H@3X=0R9#6{3EtGtGM@R+=b&G=VSlDz-vJ*LumQ@^A@$^D z**_~-Cdj+`tk{o@%nws1UcwO+v3RpY^2h1EtAoJ zM5X`he1955!@;|1Cp_Vi^f{f}kB6C8h^*%CUVk2#%t}2;{jlAc7J$##Tle1_+!s?i zPoyY{%R@KiiSqwQZQfIj9X=KxjFFiXTSr9 zZ-~4FdJ!ag&y8D1YYNkk*Y&vW(63iG7L+OFihm$5)`+e%0onOckICyga&9{BBkMJ~ z?q45=Ztl9qe>D%?2egjSqhf>hagDhig3i11Kz6DxwgtuYHnfS#n3Z;kz$BXO$aW!{ z^5j_EH7&hnyBs#qlT6s(e^MzjOTLO-Pk8usj@8yV6pL$Kqjvd`%3qVb>SNhgxL%>> z*i$cfEIc7zV@2mrIYhhYsTS=oc=$qsELu79qYR{@JoxG!*B~d^ijG;B;zW3v`5T{2 z5F?5jf7|e6HTI(Y@ho!gAWZF4D2w7Ao_=sfq)=NK<#EaJ&;-`QVrq0hn!iyu0~Hr$SOQc$Mm8#QfP%?o>s(PdLi zWb1UE7Mp*>oW-Pv(kBb5ce1#kkn0M{-~E~#x!f+h>;e7fIJyrb)F~&lfHU^6*0k!xldeltFYNV zk!)Lcv?<*_C7tb1{QzLSyqX#0qt6flkUDX<FbP;l(jQBHwp@l@F+gHU`NXpb)JX9Bzj9zIWgQ(TC`Lx9(Jc zk5c~fga(@O$}udiyomGe_m2JO`#YjVnMJPj28y)N9i9=rTan#C@y>F1?`!X6|9Lo| z-!J^e?|9LG&*Rv!>u>Wocgh&c>agtY3}>$=a~kiyQ_7vMVv3L91AkD@dQC_2r{6kG zZ=e6(=RG-|#%U~Q*-3X8x6<2ja_$ejTgd*C(>=LTSwv4dlL`3J!8&sY2jutpU;8bw znvO;*^xf|s_o3lejw9>&+uzBDUH4FRgZF7#SS5e{^WIKg-vZK@7g&&y{ym6LM0B@Y zJy6ngXrO~!I0n%2AjHCgZU%;9BPh^tzsQH+p?bo%Wx!U1n>aM}M@R6z@80x72la74 zes6t6{t9uZoZLYTuRs0L%iGJLeBb(ZI%ttY%5uC6^5JaIlXvfb|K`WsDaX_)3O+jY zk>Nu)+OE>?$b=5MoH~YJf6xcNlRrkt({%>BOq%Pu+nmsdKcCw2jR(lX@bNc}yrcd= zIo|y0Z+Yvyi=U5vc-#kZU;id;KSM zb}-&8@b*{#iNu0Wthy+?_p2GO%<=ZOslS4Kz`kuXpz;2%?|%^XnK)1mK9JvSncGb1 z==~!<*8lc*-gKwE?UFXz+p@>T2R}U0-yf-u&wcL;%B$L6;d;Gk9Q#3g%F*zEPhvRs zL;7!i>;AQRDjFVO(LV|LPIg1ObicS{^}(-y0cIyu83J^3U2!Mu%TB4Y0Mr@Lfv^m~_ti z^w|JkM;!>yldSFc-G(*TPr*O<;mtnVTVMI@*yE>Rw7n8w>GH#4KU)5+dc_40JMhim z96t@v=bpWkt}}qw{;W92^-wtu<;%zL!MyIaUTED+SmTLf%klPi_%Qn96Tq=)KmYx| z;O!L)Ba)||sByVk20EvG-iMBSJQ0M>%LmQ-XHJKR>QsCKsdk?H0PGXz!yg>*vj@;0 zubG|Z-sndPEU(v?o@Z4`(@69W;;b^pb z=I16o0he*q&CS&Fn+;iL@YAJ6#jLa(*_8B)jDqX7*D?)M@~S7471$rl zz~r>i8I-KRJT4Q^UR0Q2Zgc*xy#0iS4`jDIEmW9~hXT^fkI_ALGo6E0#vQ@*y0t=P zdy_=_C(Pq$%gwsJ#%er$SGHg#o4L&aF9?-QceyAJDtNVgJ!saNq&w6W;EI?L#kdNR`{O{WxH)Y4C@H#2L!t7o>kvy=u#@zPizNg{1 z=$?FZIkMIcEVcd%$bQm4wD1F6rxKU;J#CAwL$7>j`x5&klKL3FOV4b4Uaa_3=$IVG z+Y;e%*s-#R4%tezx4h###-aaqplokP?>4yd`w~^Laky+}PWDxS3Y1DDBQF~{2r3Y= zaAig^&ydSTa#NtvY_7OVLG+}fEV3x*GK=s#7Fbw;Rzu<6xDa>@&`aIzLkALF6<>k& zXAb%p_#;tD=0_oAfHbClf9wg4hq4}T2UDZ$&9JGicSY&}eJ8JUdn-?1NQ~c6|JMq|?ZEh{cOxtov!=vtn!fwcF zw0fap@p!o`?^na_Mx=h&pJZ)Yu${kv9oQaQH)%eG%}UJ^cN1wJdM{*G2Ox(1iW8pb zIot0z{MiLOR*-z6Yi%tn5Syd!U~`CXK^_ZkuZvhq;PakZw zg>)v-Up1gRbp$#b3;0Puek!of{vzPPw&XMFl5_Rb2_F%d{3G;n0+20`-nK}aAm1aJ zzMD#&aQg+(#rI|~L%Q4P*LEwJEme1yr}DiD#{wR^-n3ux6EnUO2|2*q?esytxw^my z)(r=vtp4o6lf(x6b~u1)!w$h#gYS6(e{c}eE$wAqCv#suqb3QC0Che6VGU{UXY~uN z+wQAF-bqYfD`5n_r@}KNdJxvY%tyZn&#t?(5Sym0M=v=yZ$Hf0=!1^W=MeH*g~f33 zXgyp$rae+V6{=JYEL`|5HYV#7zwaInPu$_ylQGn7XzF~$A@~kd$H(S~BfiTv@j*ctHD9|Y3|5vSA8FTOt5JRU_zA$MAHCw$q` zbjdPsd9Blwhdh~ZNcj{LPmiiad4B@R)}8HQ<%NOxn9%fMxni|`Z9lR>?2QTR7is%rqoU+CF*b+)$sM>=M$R9J zOjHSGLFr$B7he68kD1d>rH{~KkOuYoYP`cAdy&6WHZ~1sitZ^7V-D&R;}OXwS0qb( ze$^fLOTrgIYk!{7GVgE;IJNB6eWas7Irin$SgT$U{1k@zwA|&NCrwlah3>y}dD2%v zZp6t1?A$gJOTjildFe--=h$*i2kZYK#|h-E?7{3LjcsjD48DCZZyDVrncn(H2sO84!X zN1rPAZtIc}ekc8CQA1}Uf*sqR>1Wx=cKuQ7%CpPP6D&@kzm_rAp^F(qlPd}M_)E#W zzC9pb(nm$!zN~1`?UZ8L1Bu_0gq(*y{G^;=1iy3Gulf~c3fP@rt0uckm_6m8;POES zeU#h?UGB!beB)Cdl-+(n?cHAdw6`o^m=CsYV_MJTH$7S8KD>fcUXvq0SL2gKp72&2 zg~SCNKl;C3Z@RteIPhXSYJSEm3ie&tZKrR$n=O>}92$BU6$(qSxuPVUNY15~u{{^M zZa4QCvrs3)&rJ}sV+$^O(!}RWC(>!_V0@igJ$c{t8^m@fTgr!D&YTQ(lztQY0dbS} zXm{j+jESRT%Egmm4eNWy*#3#e|JWUMF8vu6tQ?<7b<-Y(Q}ubWI70n{G-V)=*Z-fp ze`~UAS+eu6mAUd#Rr`AO>285AfdC1h0h;Mwkd&E7h%!A&PZBSZVERKc;zfMY?-3=D zK%;SKfD(xAKE3Z%m6>a0YJ6k3N5ov2wRi4awNIbs$ee4=88gDe-NVDkY*#W$3p6(I=_$biJ@ouCkY2ebcgu5>Wd-cix>b+19!1UHZiFZ%KO3Q(M|D zu6doBwoAT)_o=SOm!b!JPC%}-BV|k2v94Q>rY}@J38zlWXRyFeoYMKK_x0(byc+hf z^LK5eXKavsOoQ+9dHYQIVIgjnKgW~mkKp_7|7`dD>p$DQzWI$8RL+=ak{|f~?Vs;n zU41dOXM=**X3?d9*RP*>hx~5|sK*7K)1L%S^r`@m?r?KZ#cGH7^I)f92gBgICY%3~ zu-{!vDru#R=h^S*wSE`CWAERb!I2{T)4p%AMOyz z89+}5*%D!Q@sV8BM{*q6+);6US)lUk(zHS6eeI7$*83YdE513R?fk{vZvRS+-%EH@ zUT5h5?XPr>Gp5mG!LoIU+rlaK(?~2_&%BqjOEi947?K;7^z| zkiEPQGKr!+12VUlKdqha4W!l-pS4#kU;Cv%dzdznys)KgKgFsXyX?oP`uIF_TKZ26 z+UrISu9Pof;KP8tH_FX@n)lQVO#^vef1XJs>p&a6qWPj;@OO8sL9^`6uNR@L?Nj1= z*l5qV84f2TMqA}Sq*6b^8h96&MA%O9(B}2T6&vl~0Dj+c ziL&w~2l8yYdk)~sgUw}2XhXD}ufnuNHp#Bd3=&R!Uq7)Abip6G(Xlj|aGkS3SG9G} z^WE$wnk}~Q7-_5LmD7S>iLI2Toi$RkmLE&1-7Nw8;j2IBe8Yb&e)wI zSo5^o#ETNJg=|?=q28ySobsMYN6IGU^z-422f9wAUi^GS!YT`REt`9cuG^(!>*y(j z;@xc)JG|f_Kj?|aqK^%*M_=oL#}?!^|0t)v5ycb6{PD(z`YS2M#s}NywJK{LC*F4A zar&7C>DrI;WQ3n4kq!7M4aJ)|X{&g#-)Y}|wGR`2F8A2B{RI4TESvYHtIk<`G{0L+ zIe_Dv*XDrV$&n{WwRv(^erGM$$R&Q17ip;HimW5)KqO5^*Zef5GlFCv0A0uSl+F{~ z(3X8O!Hy1y$I};C@Q~~*Y*ZYsd7emNCQIG%CSFuO(l)W+fo*l3%IiedEO@|Y`B>3d z!NlWS?AR`NxcyQ5w!6~>k5!Ke>oQB<-8>IqjS@Kq>t<~ z--I-#%_U{)uJiGNhswwL_ShnRqU8zo+GwAcH(AH8yBtDpOb5iXe@e9bheVtk+ zcsoj$_efIZ$dgxTlwC-5zi{?yMCP-$U-YO;@oq?t;#gE zC!Q=HG*Ak168~&>_f~zkn=E+bwULTrewMf-wcTm+!bQTP=WK~fHIH8a>6;X4j?L+f zx>B}cdJICfk#pyPf&PuNGD2celQ`cy>wF5=j? ztNgr3CcWIg`3rwI|8V;kl8XgO@mh6&ee6%Rr?i(|?D$Cg&)t6@Cur-UH_lThY4h^L zj5r{c_2H-H9Vt7m`DrFc$pyDpJb;1hg1@oDYiKEd*{kP&C3mRuixvF@^u#83_3De= ztCwHwKDz$3E<}*^QOq9&gZCQ1XVr1i{$0Qs9XK4doe##c8ubr@f;is1-QB(E!ibzd z7gQP?8%`^v{_=D+UK!RRje`#dnX>;(`v*i#1tmfv&5FE*onkF|062!UKa3^Y^Td=K z$^&MIZ({Q|BeZ`eJdx}LHqsq;_h&TvR9aPD77pCl{D3eg*k7n2zrfkWLAmq56Bc65 z$IvTzo&z_Ua!5F0R>6&NBev&m`!pVRI$>&xISsqhwb@<&6gCcO3BSZv@ei!oKij z*pY21Wgfdbdcfs7PY!JHc@L_;sFiOlxdAP^@Q2r=1D84efR2%UHFQItj+brD`J$`n zKlx!$%HWx}zh#oIXdjgyc|OqLR7dZEhCKf9eQ|arA`*jFhrRgh`S$#5n914@|M@By zdb3>%v%|ZE%Uor|(?ouvXz8?nIQ*Eh@fq=R>%a=QtTYIAePU~1n`K+Xf(AC1S4-gE z%L)BlkltHpCy(dh;su>n>`X8(;#D1E?3(_{{&Iex`sd=}io0|eNYtdk7$p4e0)4P` zd-YC@c3Hc;r=HrMFvw#9;X{G)q3`xwV3Yk9h{tv)+Qs(XuYBKynJe_ktnC!L$FIsB zo(%>ZOMSO*ekO>k&3EF9q2BWCu5A1rSm^LO^lv?3$Hb%CmG=N`$@w);+;TS`wxpbD z?+rchr!q-D2t7HWk-_Z@=n1JzAXFc)%TsXwLUgk>O5cn=S5L4PQKRyD0zE!q%S6hW zPG_`{_`p7All|N8odEft3%G%<`{7lmGO63VN=MiX@@ngTO8hAOq;*WCIA+YLbe)ak z_#rmmk=^B>jfs~`IKFUM#Xe@m!=mA?beS zr`ot{QswE1B=^^{S#QMG=0yega{1$fs!dhcb8-5e5opEkCjSqfIQc0^Il5ov^XCD1 zEE)XQ<~{?wNI#`*%ieG~fXdQ0IN*P5lhW75UefQdO=(QZ#F{^B|4g{9Y{m)XjZL)e zW!&{XNFJGZre36OJO=je{9S+eb_{L!Q|J<4@`tBNX1n4^P;FC=(>twe97)}CiXhg{ zoz_gGeVh2IOYH}WGo_7Q^rQdyz)qcd5})ld)&>px&*6J0KgChq>hb}YXZTiQqv!sEimW=Z6y1_M-V%b>Ev*58Vdc=1}e}l@JUUuv;n(b~P@yIWm zWgO)wEy?cMNB4rqX2bU>X49l?PWud?o~yCLvPEH)TSWBRe@Qj!h;2KIZDYYhTl5ou z$u=*jj42yW3}>!1F^RPYUneb({J^os!3n(W)T~uQ; z$0_|=YrG}GA4=yec4yl$nfL+AgWj+acz(!sicahF1?Q>10HP(U%L2N-;Bp2o9s+(i+lQKfDCp1m z?`(H>H(y((`-5nd%^6XSfUUtZIxFTXR_dxYk@M3<51~Wfj{GO*Y9s6D$AMf2{V=&C z!+(AA)$+Qq2pI)F7Z@@H5@)g++wTUDC2}3rfqi@Yvjjf__kJ=0`BY4o+|5)MekRItK(PtUcT?XExD`-zS#Z9Ry$ z96zAdC!u;r+qtg+*K^Sm5r-NCXW?NjmoDx6dD5e8*?CoK9_3B}F`N{q6 ziiK`$rR$aVvL7>t9zvO=c>bwWH zq6xk5FwqO8Po;+E9?1VZs6~};$M3Q+=uLjzAA>#vb@)%cOWzea6=&$o%GCAZ5?Qp% zB$GC1qN|~Y=;xquD2r{QjZqvgxGj2Ju}+Gp<+lBVpTNFAe2;#&+bqf><@_vAhDIhG z(MfJFVapR9Y~;H~|LCUDWCBll+76n|^N?4eARp;EEjD(@xZ$V5NoZd=pl|jQbWm{L zS?S@Xe>*(35#PdJSdOjtU+kr9gzzdq`~rVW_%Jc(i8@chJP&?4-?DYxsQje!Ob+E^ z`R|9+^R}h)6PsZIo9neHqW-gi_}5(RCp@B~#|s|z zeQcy7F*f0TccW;|7>3Wv)*f%NC-KPUKA&_q%T+OmqI_J&l>*!9w7`?dt}`8;{HL5c z=NOv3E&jC^JbF>B>j2l>W--sCEj*;`@Ga9$$Vc`BIsG7O%S*g&Q+*%m{!^Ih}to^lxFp|GkGfou=E^C4y5wntsS*T8!& zgXl%qcl4K_tBbuk;@ZApjXC!X)6PFU0OVSqF2e4%i*3=pQ@HJ=+>kkTsNFGT$ zPq6`)=Z?i3>iO(P&$bFWvft-^4F5m=&*n$r_*Tm)c-)79{=fQv{%{)sAsaIJ=KUyAwH|F6d%@c--oi~ol-DTi^chTJIa zf@2-4F#hx(Kj!Zb{@#D1Yf8MQL#;!}^l$&$=Y0(S5B^nNzvd5~sY9|qyW0Jm|L%Y1 zun&g!(BJR<3(7v7fp^#Akt_e0|;IsWc0FR~~-IN$Mo4mlRSt0MBQ+$;p_mB)SF<@gu>;)xFz zKNG+D+x;O$1|xDHd?5ed|5Jyp_~M^_8ky`su-~fo@_2l&#jj11ynpsjpZM72d*HAA z2mg2JS-IhqE~1k^{Tthl)q!7&zud7J(17Fox-ow^JM6ALPAA(pD=c>`pl|yhAK ziT`K+-TyJi9|(W&hvKD*h>7BhkL3UU-_QNX^R~_C58YEIXms5;1DmG;*Z>Rrs+TOV zL~E!#sccomrs3!_I>b#UifhC z^|kmYe?!OU-~RW%e7@@k?X8Q}|3LKr)W={y|9AiE()`3`fURRXXJ0<`LH75-56F>D z>%@jX`GD=f4rH+4MLW)D3uGJL{HuTH^A81oq+RHb=!38S-V;v%J+uA&^uOnwvN~AG ziw@$p~($>WdiK1uH%)2ZeNFRQfb+kEvWPqcaOgD3KRuDtI9KIRM~GeG;F&n7KGj!$ z__$C0`9Jxjj?g7coIl&|eDTM>S4TllxD8<%5!63vgJ++Nr-7maN7#*zR+|JZeCV9^ zMNCxxz3BASQ$9Z=e;lWz!E@WGAMhKH?Rxpu-+Qe4&(to%WV4z0eU|;yXVCuLrX^pq zzT%mr{Y^JgJl5HSZLIQ2TuL5ZvEqBVs!R~}H+Wba02lj@GC^11TLh!N*ltDbjJ}wB zLG{;o$^tq3{RbVlhz}3y@7oq)53b|B7>+z~Uv;5j|EtSA;pZnJO9#;vI*LuNAFT!% z7f-NY)4)%ScI(M{3rFJR#{pF?*43(U@wAlTX1q(g zGJHjN#704D7)rFx`PP!cH}bRKA$do37vguj=-v8lx*2<=3_EP*1}3k-^BQD%`mS^( zLH;uqrS#{yHU-B%I7&bDw0sF)%V;bT6;AEllk5gQO1z)QclqL1yZgKJXM%BHxUW;- z$xAOPYyf}cnRMjuISrpIZJ!Vy)EiJbo(df5LpJ&0eFbQDVH>6mPS8EC!|KZ;9f;2C zOJuM2cU!w_8}7EtP>}r^wn$p()n#H**tbdmed>JJo%$Z`&(wqxZB84TuB3`a{;-*iPKVHax%4a%9)-UXK9|2g+9$xh{Gq z*7R;*sQDOvCd_bv0%=k8MXgEM%}f1;4Cf8UUZlyj36YJ59G-X+S8q|rQ;)~7D_}u}G#sjafqO8h!@$qtAm3ChrnqND3 zzq<(UXXh#_UMt2oRCpCtH6W>&iSr!z5l3l)%D%t6O2eRYUU|fq+if?HV?`PqxzmZf zs;2%-A2isAl7 zR`r7Vq%yjQKY0p!-ytDg@i8zyuKf#CK^i9-Og7q;hr6eFc{fCXZzIw9=jklUSv=Dz zF4&;)4&*cej&ynvKWkXXpNBL9F`j9O;=lkqu_IYY#+mQg(0jY7G(jroAo)_gdc39hke(3=S` z{NW4L%jwI`>TdsO8_=fwVw=ueJaoT(*b0+{_yh!kuK^Z*xXXJ^b~6@;wAgX-jXmYH zGSs8iX-Qdl@I0I@v1Jd4L4It-m#%rf3HhyG?(pyUJl*jdZGRz=@_5>DXcfkRPAYU;ljGeGJ)+4Um)}X#-L_d zn=sPZ@VxO~8pZ@+T?FHf3agZYLGd-U7( zjqOp=lOE|o(+bGHpKkPghGaJH+L9xGqRBk-o_+d~{;rC`?jMwnMG`-SLR$(i3Zq}B z{^?(#%=G?I-Ua+Xk>`JDM+38E8UF}?j|?2xh`>itm`#G7&+ zSS!%EI{(K5eS@QpStK+yp_rn)Sv*piXQ4y;QC{?eDnIK5`n*XfKB(=lU#k|zl>y~7 zGJ;qADXe`1Tgnt5SV`|R%cdYdIn+<`3Fs9Y%xl&1gb|-JKt9uUtY^S?=?~`4cCSV7 zdpWlhgHVFM518oo2Zpu1c=@R)KXw4`ix*d)?Ot4eL}uEgRJM0Pq8-mwVa~pH0k}}q zS>Vp<^9Ks%=?-sK9?HiP?LUykDfVaAyGwN}F4YjQpPldD4V>MJABmI-tW83?BLeQ_ zSPwF=yZ0Rk{5F6+W4p3oSKw4+Z!A2xl06@Be=H`%p+q+dI^b9qN<1|K6y!IFEq$S% z1D*^xzs6}|WT~G|V}|pwdk@w~qwV2b&Wkb0^WDMoAw7EHL7j3>M)|uXk1-uw^wS*z z?)*td03E79`}VlI`%dKrucSe@`FA71=0@#Gn(%inw7*_#^sgW=$w=7SW28wy*Xe+q zN$w8~Y^HS#Q!Jo88}fs^``&{lIv9NKOLYV;?^WO0zfM2Pdyl7&r7>p1CZ-NZ$42?4 zLo%*a2g8T_iC-FEKWa_q#kA%m07xTFTqe!7cdYzUc=1Y&aWks@)w|a2KQ!9c6($b> zXWNj842UVY(y=z%Mt4^F+HV7vfq~7PJ6UZ9bV5~-`j?*5uSLUle^g4&%wAWjXs9ti~K1^>I&uHR|Gs0-R^nNZ+h=4^}m8ZSF{oM6b7Hw zFZ-Y<`@g;86(ZQ)hiPX#DAz#UZJ>?^escLlX6UpJeJ{9b7ft)iOmLr~`>mxOBd-I{ zS=;S9(mKs5=PyufhUoSHHFf9t_1}FA`MSu_G9hCoSlq^_zEdCF*CI3grgWD9An(q9 zWt|L388k!JcAI)WeHH^&=+ZBu9GNUxbaVo)cvHN2_RFJlarraocb_u(Gbsx{UM#E) zf3~O1ppM#?HHzofZ$rmv^RwB1*(TX^F8bXLWx(BIk&g5p5U;)iS$WQKeGCu4>F;tk ziYLG#i~BRfHxn*?DDPoMq1*9OzAbC)!u=xc-v<|0AIJVg%M+2+emsTfmkDb6Oh0`Q zIrhgvcAj`Trf=`9Wb|d^tajTQoXMwpvT^(sMsZT+@*|5cVw~X{A(>45T^m1R=j^pb z77OtMP^_}`Y)VgkscpNMDE+FRLH{}vKQ-awc(utU+m_hS(dx&o|3b7)eaj@d7d_5j zcuabHW?t;Ze2YeKT!*zYR)q|*^c2=Ws~d~NOP8oaV83vTj#m)B`)csi$a+VwQo_&XP z(V8KCUa6Gxz^~JitwvfVcgr3fMtnUCL zb1MH4r#M(`k2Z_T5`dYAVt-pbxSV+l3^x)V z$yYSguA=j?uW~r3AI=86*v7Xrs?4dQeCVIPUN5-ee`cEu+V;{Wwf(gnz>nn-Pi=ow z|IN!*hV%zh*2DhF2Vr~Gfv?s^`8a+2Pj8^KudMV-6v<3k5XgKvGKM2*m)8_3oC*JR z%!{7=bfXDrM<0}r;45vmgijDK11UTH@=uvX|6UN$o)5*d=z$M{9`a?;)rl)UIu6z5 z7sRHrI6q*9NZ4gldZuruU}U3Q8-0_97v8na_76SKH4Ew&?&=cjo#Q1T1|N1Yq{bu)C`xqHQ=FZfb5;6b)|MW>jK~yap z*QSyB=}?)7OE^8-y}9|?+lPh=^r4I!Wk0qmgKPJfw~}iPz<4y4g^;}}Iu+QDyFLL1 zPZ;vyRz`bwRDF2du>l!@B89|;X@wlh97d>v=Xo&E0z*$7VMUJYDV{3nnG zB`dJUH#Gd^RPR*jj!bN0=RZy6=U{)Wx*FXIz-*Iy;5IYne|V&I?XzB8V6MzI=0+#L&u3h2;sGn-uW7&4iCQ#jC`HnZzoTK zHmv|`K$E}h=_#9{oqU(AaSdL35WvRWH`oU6gmzum@oxntn1!X z*6Tq1gTeZvE~P6SU-a`4`=$J}_h1~mhHCzlQEkt~%8w|#qy2q0s88^xjc>UySbho& zX3x1%NXN}BcNxw~COYpB!*$UYiKBhl_lL%--}`*`^4A~lu0E3t=RYlvEO=z_jE1dc zkr)GGPx!Roq0Uz<*$J=C>doztu2bft-VRnWap6~uc)}p*VUNbalNemc@; zV50cr9KXZ%?{2?Rx!>##8oy!(?r(^P_WvBS(9z$N@SuMK(Y4-MKlkbbsxGO$?pN2m z4?GcJ-+~P@+4GJui1g`6!DV6Ox!^A1-jsnfPno3*_?wHq39}z@xpwD|{FoymR?d^v}FLta89#3Htj^3<0?u5?M9iALSulR%$I{obiCK|mlKGf!k zFZX>DpNU3v)%0Ai==&-kXg5eRp6*~iqRNpy_Q6wI@zIHsaW>(Uto|6~ALj$F?%k<1@x_>DV_oN|LvK;Vpe3d{63@>z(#|8UY>mf(Q0z zpH@g2w(O8pI_yvJJig=))>tG^c*i|^z}M{LuUP0+d6@mw3-ZMVt)Juf-kPtrzs_-N ziyyN8qd$k;IAkKWM+*2l@k6d})VrRaY9A8bZG#R;PSI2QA!sywHAnZ7M_D)<*HOjf zZ6=l<9*|dj^2R3Ssuj^TB3~#*B^O)9i|}oIiY@4&dge3Rrj*$9lXv+TZPbU@P3g{C z{1E?HY^a6*hc~VCLX{$9|EA50rq3vSXcAa3kTacKvuu2^0+GFsH1ryThn;K`gkinB^Yt88G@ zC*N!&8zA0uko+hdCD~(CRk;W)qVEd|AAI!c_jez?`2F3h>+O49KLju?8aY6PNkw{$ z!x@ht$q61+LD*zKcMo6h?#_6JvveRsKb$}DK4*hs#!tx<4|{cdp5H+|$PjMTpip>r zc%}K@6+G;!k+WfmJ6`RxmtkEhjPEIUp)7HKmx05P%PP`brux&&-eK~F=hVB z4jy>jo(+P#An=tm;(%l1C1Elp{9Hb!x6w&~7JoEq)p>IVf)wubK~I2j`Qx^&BlQj) z_2!7Z{T6{P)j=WGJhuDW0Uea+KA=O@?YP@=+V^+d4Vs0D)|0jGzegRA-vTI3-xbb4 z89P}zePBwcc(u@mVWqRhRcu5=ygAy3N7?w)+4}$)sW)^?B_p&;1Ui#$U#fre99+Io zJ4e4ubA3tIvOPzfVn3zkMCS4|_ z-vhF{>(8&e(Jo#8>Rmp9NsLUOkfyi22YT4Aws#CaTu*G*b)9zn7k~$}+RhG_atZPY zKc(YJg#+Sq)JMxxTd5qM)LVdb4AdE1YjZ!b%Le}+-IzW}v}F-FC)SO&;dNU_C!lQR z)_u-j9;yZU&BPj`c26kt8js8V_E5RAA{ka??KL934c5 z9W|59H{N=&3;OQ^77m#hux%@kcP&~{E?H;`GyK6rCGy5=M!bNb%{L#(#@(O621^v9 zGp19Mw7v5Z^p)vXy7FKPe==Z`K zXxp6#FIJ6xptyr4+X6mD@!fufzHj(&d$``M{Fjej?C1p#CK;bX{6*=8bB8gG%3_Bn z4AC)VSsQlOX;LrH??mh-`T;Bkv=8K(bz9j&Yo}5=F?RWsP0q9iI%+*By?His0W$T|9cw^gIAx*Fv+&ww>B(;G2cWO5 z>4_n4)Bc*yqZ|!n_c?a0t@CMMfBo7+%8CV#@k%vq)G;r3m<~XHS@2++dTiN<*L6T) zeZ4l8@FEZMxpFk- zV{F(UNou1{vh_m_)o)@zHIxOHUqS{i-Y}=xX15<|ofBoX^QO>g!J{WUDt}w{#RAcVt10LS)_E#^p@%nW7P2?XLu)lsv1KqGdvPyQaq?iuK?u(G7O! zEJSj#1KB`y8Cl8iRR7ecwJmIa7qBQi+d;N%zeAL)*DQ*{PHtkLPf1-cg8|2qBXuU> zls9Ue#|KI=o-*~^`5B|;aL1!y<%Ii)>mEE8IyLohN#qa+KkI<#yJ-|4g?f(4V zd;Af+f9HSrcXoGl5Y_SKF-~OtOCVu_T z<%H3f;DL@*;0|=DV*A|&I)>$_MEf^?=doUX{m0vnWK#;i`8$vE{m}URKau_2Q2O>HVve+x;6FvK)i>YIPjz1Ld}Z`fxq?^S{;aNB%JQ zy?_0Q%!S$}-Amo~JXIr{`x_+c9K5;TUB2A!?!GT4rFwe#QR?>Ldz|>~?(#)BPC4!K zech=%KK?}`QOCml8J*Cn>DB4}+rRb~b@XBIt3OgbFZ$iU|K{&}*gSskUwtCEIST!5 zV1O6G!BT$qYt=dX^S|+7pA!7lAAKT!c2vXoLi^kq^5qlq{_3BljJ&9sBmbUVbUD>t zY(}2aVO_U>?J{M@_gv~Qoq;rtJ@}y^wOy+o@-AF2^ziBuB_NJ@R+{^&bJIGYIM09w z@`W$|@WcA1|JlF#)sPEcx;`c3*BzlQW&c0^!Jj7Z1L1Sosd_4PR`PZoDc^uE?2f|3 z!|toU|JXNu_K)-Z0I=3CFeH+kPks3Heef9{hcD1!T#=5@l+lAxq4|N^Zj&3U-zaIG zl=pq`**{Uo_7dGfUAgeDY{_|@^!oDeF0YI#{OX_5UWPMw3?*N>e*qm-)2TrSozV96 zPkr$C_x?oma#>>%>B=`8XjgW4dHGWPwA%ep2wh*!OEg1bo}N;LRc+3nD&t zXNLpEWGQ#w^)EfHX#YnXzIzt`5isF*+Gk-B$$6IAIREnRe%L-a{hz0h@#W;_DWCPl zAOGG)$C(HZ&~V#Rqsw3ob;x4(t-pYNz?^4Eo4CE{zd{>MmqNO()Go~$4;|OrUFY*x=8(8X|nG!nfc(`RvIkOG)gNAvWVrQ zvVU$U+0;)1|Dc`p=>^@oyg#F_JSld$0`3my?Hv9XGs zQb?F5WXq=5XF@v*@i{NQ+x;5#yVu26CX`pK;}g&ehr@oG$BIWD+j3g{Lds-9T$jvU z)-5yAG{vCyqs$f3bz4D^zc)bLZ{NYq$FW`Fbv-dod_C=t0qLdh_ZX2eHrRQR26`Po z;rJrwTkXW~eT}94NXnTX{^-;fb>g;v^w53_taTc+F9P_fZogV5UGKX-MrR98Cpuck z1NI^G@Auf4_*CC==oc}>8?V1Q-Ybtf@7MfRcBTP*^DBLBlje3z0(jg$<6#Ss+x`t_e?yQzhQjetn8DsX}MN#wUT-|pVrK0R>k zMHYbaU1*S$LVS)xIB`ae3qIuSLP$R7;hYbV``aWJo@DQd_EUHPk%?e!Oept_52xTG z_?L3VOwa=wo4p^mDhDn(y8?b_w3G4xaqYM)umi?;v>~fZN|o`LkKwBvAI@YC=W0aQ z6pjJXxa=>tlVA<<=`Aax?@-JK22Tf!y2wO44v7hnJMqtUE4gkYk1q8_XXBma%VT@0 zTxWi&hd9}|qfWJ0CIfAeV3CFRWR4jzxy7S>y^7-!f70x(#Eq=67 ziMbs4Rf7AYY|<6G1FegrbinqZf&CtCE~KWiXVnKb)WLT33dhglS8M`Z*|$nh`>TT- zyLghW_`nvR-ukWxI=k9fKttcTu7>66mFlQ$aK{})vtzOCIDRNB`YK(1Xk`2yJF%@$ z7wsQ-R55o;v5_KHHdrpH$CszJcJ}aG@ZdBpJxrs#kbj4JeaO@7Hj+N4T zzc*P|!cTlGJ_+ANW6ZW~tUnB>pMFwFwm249XxQ206K=k{*}eVp!%rwGL;Xl*+7e_( z2iORkuCURe+}N3co*u)RE+0N77^TaS$oNItt>RrjYJccF;@he{ab2JM!qdu+WyjBy z4LaTUE133&#nlTQs({nfLLQJ2AQIN?d5;H6L?;^Ophmjuj5rX4&&Yc;xSmy6r_m+q8sI zuwTi_HOC1$#fJuMQC^!v9ne3%+4?X4@*{nm40aX2M6-{wpW?1pUL7O5w%uou1=trp z0T1Z0ld9VkGW2=EV1Mzk+lm*zdcV8Aqt*JuZpBxmMK3}C~8f!e+&uqV`H)x~u=WFaM2wN1b_l9X^v!_x&3*J*k3U=9~P25gw zJ%;P5`vUId6*#EvR43?4ay-`6Ps8-Dv_tbQefY7@Dp@QaanYsQDRlf89S^F!Zlj+r zI^1#hDDBIYZ-AjQOWz7Qe7l3~QXBQCpKu|k^$(u#gS>t%6FezLKjncQC<`ZKUr#c+ z?qPqux`^~#qweI-oLNWcCbV-5LMOh5<7~}OZ}SR2>7$ZIHteRJYU+># z3r?Y(_SO@x;=!(HFY@a9jA>Z-IC+&(O@fA$e(`0+&qQZLy6JbUCzm%T@qhd^koTQW z7%AFXW}!mbq$h4~9hO*ai`isY(*{evrq-|01GGauuIn-L=@UligEqU%dgYHYWwXoz z@tDBxCybDFmM9`&|Bo-7H>IQr4Hxwx!KjB3gxl9Yh(Ppxo z%TCy~W025GM$Re68Z+BBsIQM5w=K_pjw#9)eQ!Io&+t=5d3~8_v59X#W#rg8E!msT z)@48}%9ee}rfb*>baYZ>*ztMFD86VcV3d9NSoN&!9G=#vj2h7+^s>blcKW>pAGO4fkKxz8t)H&W7~lnfy)nOq;Jf1AGjhCr-%l<<+luFR#DYy}tP} z+wHu|_x0_Ua300)r1+D&xEgI-F|f1U>+k=3_xkm3b`LOYy_Z597lXi(I`KqzDk;1~sgH5kf4{qUkilaVau6v9oFf&HLRGr;!{;lgcTB=7 ztvB+00)BU)oS6q;3NHRX4034#&4~VCQ?uf2W4!n1<|L?auLg^mws5ygBYJU#a8!(Y^SP!@@pp z;g1cyQ3s{(E5(1{(O~RR9ZGE$LmTu#bgqHk9fN%A^|a&o;Sl{6&c%x-_&ziwT*){Z z68i}{D3Vnh3s=12k?rtS1C2NL-hXIZV;|CQcbwqmorn?2k;?vLW4rrI7`h{{s!2Me zY$-oK?y5l;Z6HZ#{O1CI%F&%E{i^en4k`nmWpWXHxQ_2VILE)aQ*C0fu6m9h*{H(> z*Gbq?UTnGJ;lt|>ZRI;rDn~OB-*EH#xV!m|&bDN=zxdFI28Ta#9>}+DTcmw_93Iel zVR9(+&?TLWc)|SrA`m;HoXs1)A#GCHCG?s)!u9S~^v9?JmqHGq;WYRmUUl^J4Fc~2 zI(GCqXnVwr27mC1y%HAv{*d25R-VdY!)}=9V2dvhsAHVb$s3))r}a<17gwrW=!KOP zYf1G<9alE%w0QbU!6xsrBik!{;dfMz<@?cBmm&*p9vrAI<%xxTmov0-CuoiY+s226 zv{r)-URQ_j@L~&B@JnY0wP|xubc(J&;SIZ`Ez4v8G~2fO)g9hk=I@3Fs*2a@^kh@h zp`N@4u0Gp)gWvew_}JT~DY!J%D?8_$Hw<=o;$gA7LUjUVF zHZaeBXl!enaT(7P^bdZxj<&!RpYygs+j-wu!Y_T~@2EWS8#Td5-L&q63nuiKtShpy zDfr5Q2R1OjO7a*z0UFf8V52aRbH2upN$E| z^`?aQ|FntO2t%G%_G@{SP~!ELc%;dOOc@izu2MHkV8zXAWadP<=Uz@6zQ-I&gWa-- z?8W0M+chqB=W^B7b$?u;Z-Q*-No_{jx4C7E1HEiuYYVxO{8s)dh3hCBmaZrht{_+Q zDqG+!1lUPO1FqvaR9~fY4<7d^*%HTg;e2Sf+IK0wje)cv(r8*4sC?=!R8xt zwM~D+*zH{l9_V(KbuV_XjW%(_4-d9M+Cr6Gwx_?{fDK{;Zojo{ZEAw@8m}_KClP1F z1t|+Qx95`Q)L&EH9fvLbyy_bvLtQaQU;W9J33=KM5|S--bs{!6^8vl+#_OaT$fQ7* ze`tvhZ;Yu-*?-AJzudStaabKNa#?wJ%+NU5CrQ(x+-$SKScWAFYcS;SrfqzFl{* z!92ki&U-@NjCcdwgq>IW1+;sSV)pL!_rL1fI_KT{){he(3CW|Nd9qf~s^w(N1Zm+^hK_?;_o8tmo^itUv@X-O# zXX90Fj*X0^bHg@3pIFo|v87Mfzh^80DH?O|J%0i%(EbsgY~$L@yRV_M@5&b~ZKCs! zf2W@H9Dq5d?zzm-?Lm2?4`tpN>cFou_l@_G&-NtRb@fMK#w6{_7r)xQx%+DO=JqS! zEiHE>g6F$eS6_JJ_~qs2yBBIK{e-|_aInFfH~m3t2jW24d*D=dnhjfwkFb5w=JlWCp^ke}LH2OC z`&LoV?Otk?j_@~1lfl!|6NT@G+(k|K#_sgX_kn;_sh$r0=Ly&b**jwE9XrgRs|P*E zYq@)KNj(OGiyjyyp3;$48$8^6b?fc@ko_f!gFS0Ci!2@*s9xIs#bX@SFIC`~>k_Wzq8%)9< zbs!U;g3i4VL|n2JVdBQ;C@wY@b_QBzHvak;K)1`3{@bvVib9!hQrLzkJb}E4LFUbX z&XE)Tu$juod6k}ff|1E}CK&nNsjutLlhXDn)i;tH=0{t6DD4mD$k%z!vS#z-qBceH zRpKUoBMTm5u|vG{Vn=Vp$4{>d9*s4x2IUdon$7iG@unT(6RJ!WnHp_#P1knl_BH&V zpU%;nd{_F{(P`%kS}On*v<-5>^hSBA@2@ej>#5uRT6B}&^`3GRl0$9Ssb~ZnjzFY%x?q7ucF5kZ-QOc)M`S#$Hl=jrr&mPF zwuP)^7cO^g_D8CBwpHsP@jPchUM?@5=+0ut>=UeZrM-FNxE9@Phuq|nHZA4j2m-oI zUw!S5Q|@d{4EntY(sqa+Xx$=7X~_HaDWmmfsE&sXdS5cd2Ky>I$zhpt-ir~S+eKd? zUD~B#UCwvlb`#M9EU%y`=JL#Be&GM=rew+ zbZ#4LyXi%@$4?n$Q@ycGVuySCBW&>ETJ7WTN!T8lk{>)Kt#zf-nbVKK44&=Y-hS^V zGpzUvDc*PZLpU48{O0YKySHz@a{QtA6TGK>-Tnc` zn1Rcc221NZ_E)&!xKu%Vqk>a09%CbeK_7j&9o zA{~M5G>okj{=h_?ZGZt5ci|FOGIe|QK_SkrYFnNVa(&eA#f!7u;Wc-W9(Q-&p6za5 zi%Z(8v^CPB>bW+`>goj!SWc7rYaQZj6$c$0x@2b_1~!+1$@vF_8xI?^HlA+#@L32v zxx++O^aYqKKFBxU`%bYu%HDdqd#!T5)1di~37iiJbj;>XrW>UbT^HP7$)50??(p2I z{Iu~+r+XHl4=UsK;gZXXBAvzy*wjlLcj*?@meX*aO6R-n+_A$J+K*R!!F>z!D1D6b zC*R~95Z+sd1)=g`ar-8GxIHak(?+=gUCqGAq zlr=hZnR-t-epsLz|C!IWj|Rs%?<1Eg_NNX17akR^HjOsH8@4d);lm@HH`P}!j>z`( zcf7+N(}uK;;O8-H>bBk3Y!+H28)b)qYfpa!aqLf}mmhj6=Wv(&TyGTj;^oEe@=Be` zOAU&&LGLdU-ByAz_;M#%^0^FaGK6#5V1Yg<bX$6rtV#dj8@SXh><8Ux zSj9kbvLywEn{R|zbeYWoLiweYj=$QL#jR$E5WGvVfm3)!PL9dCiGOUYGx z$@Ua%Pvq4_>G~Iaxvrk*tS59nENaY!erm%8$vYE=r!r13xq}Sxky-F?n*j}NJ+ZU) zpHdF3WZHaQG5*Svi&>x(NA?etCyHqWvDMwwvcnEzB5__9EqG^MLmPJR)Wl+M#P{9Q zeuYd;3OY|g{>}?DiWuKiHk5>dbVfaOSY)Ei1|5${Q|>O$bL>ZLNR9J4AJc?Cf~Y6n z3oiTKKpiXGK7eu&t~WFro?kbKeEM0^N5M4w(nSy`T@6Zd(jP_6kpT}9<)(z zGnA$mJle-iq|CCBf9jlXc&bG=(6&Ro=xC;!eqWr)*5Y>(cTRdML_FEQv-xUmwuNXZ zQ=0E;2r)UgulpA=nI zt%Ib&&dsZBUFBN#I7qtORdyUEU>t#IS1oOGs8}s8d&;sm`=c4J7d!y=&@>rGv+-0o zZJcj%6))5Se3BO@;koP!c+rJZ@)dc$V`RILEoLDdf6}%a9hme1yrH7?>$sw8 z?aHpE9hQ$*{;O69vp>QP@gtQ_wu%K0?24Du{)hW$<}sApCk>uz13i8cQx!tF%CEzp zj@L~QvlXUapA@b8vcrbuEFMjZbhhF28)tg1_FieUvx@l9mT@L?u8E&It|M){niZcU z=F2Bh@B6i7v~kK`I-wk#i_YQI3u(3&e0hk4M`!Fb*ofy-+3=r=llnHtr|9hN_Dk($ z1NU!sXBY8x!~>m2{DAzDY>SQh>k}%hrrCIu$HhYwd-u>CfPl(wW4F&EoQ7Gyo<*Y|u69>f)zQ#}tZu22 ztQEG%Q3=c&9l#Qd{NpHnLV_HF&VvH1CmU|1@N))F6^(CocoL`bAUlJy2k3^2I={bB zKDvH=@u`9;Pe7iP9v}y=7inN@!1B36G|Pcx)A=`%%Citdo5+Oi0v1aMI>*Qo6g8kb z1i3R0e)@)MdzG8=G~1{V@?Jm*_8&n^wC}-f zfv4!@{33%SUz1%N@6%z(9ruZE@YD;9tO*097lBbu;6$=*zDH6pE$?98@3FE`s<9#%$@o zsph{--MW3P4ui{va!wgRfeAcx+~u~JBoW5qtl~VJsd4ZVOM;l>5kmcl26s{B@#8f7 zj&Ag8g8KVCX;e5??%4N*Iwm~QX>M@b$W8jt#)q1}@=s2?d<_5ahCAyn{8Y>BYbG4A zjj|!(`V+|ot>r1Zn>SPG*Dv=vKklxtLz6N%Yx+Em1eE^v8y$;}>rXFq41MuYLQbC) z44VZ@JF@yB%hS;i9b4q}i=0}g&@B48j(+2S=-ki&5v?8&0m*C|uOR%mAMJGGoOa-8 zEHnh-dM`iOYD63wasV%vALCbQa)8AsMZk65zg1aQIo-TYyK}8_0k#eM(JD*v*LuE@ zKHd2*J^#B;S zYX^vGwx@M8r>7J943unx%8d5$&;R!0k5Yf}N9p9F^G-kNfd0sZ@2})oH068kuT`&( zzUd}hxPv}AC;HVcH$`w1x)IU1rW*Mm~Er}1=!Z)yY0TU+p}vQ{i2#P5X%CYb>X3M)cyCi30j4KdEdRU_?aOVeqlbYLzH23;o_ zr|t9>(ogw$CWhXLMK3KM7;Qw^(eS(0-LyeP%${fxW7B>ZixTNbjQlEm$&)aA`D(f> z0?~Fh@_i8y3yXgy<0LYF3UiqY<{Q7@vue*egW?_AAwGQt3 zkNjcf-8_uYVT*$7WXmx+t1(>VYai3>68R+mRp$0hV}W{rICZXFx9JUdHyxMF`R=0H z$A@|fI`lBz=ms0v$g%JMwmwc8sJL#|lz-b^*XdKA_!#)zE|=uR>-uPCyC~B}E_^Vr zvy7+K{^wJ^sZ%zuqnvAgh*wKZv@XdbWi)KEf&SJ$x*Sp82gdQCf*|InfJS9J-*Cy7ScCp!8G z3oZY-3cHl7hL1&*7)s2G1s06*#YLV}aoF9LMBiQSKhg1Dz=6*jXZIK40cKMvF4f?I zEUth!o`(CTHAzL1sSdNDYZtrgYwiX@=!f0StqQS{zqtBT@tL3~g|yUCtQ+WI@SWf4 zgdv_IjD|sc<8YiEDZnd1fE&JhIhZRsRi2V4YD@~7*^=Y>@?&)@ROm&YZ?sG(6>$YV zPz$HCLr*x{MhpIJ$NU&A8x^Du3+`O++c}Bq0~3$POIB)tADF-pbj&M?e29!VGDlQE zJ)MC5&-ng=Pek@(>GHLl)<-ege4Y0uCT5W*gNG!!|g1}=`}l%H)qp1 zEKpdR6UXCeEEUYiL)=oz(=UZL0DnwQFa}|a+s`{av0?NGyPChInn9O7kkAhM5hCYTO|WToynAi5h9oc@7cCaz+` z+EH&HTRw<#?Xuj<)+jrF)V@sIzR$KnGUd>dJkTsB@AWah(Nah~4SjI;Ml_`-CTTCL zj-ltbuggEKFt2C3moFp7QFd~B6P>)MGCF@TI|ZQY+U>V(2Qi?o1NONEQhlOtAZSx~~ z=LV7)zsWA~4SaPSPCltOENV`kh}VE}^RSYlF0{VZ8ymooISlB3>ecx#GC`lafKo?8 z$Mlr`g8qPTxOppESjvVnNR>AZcej!u%w_CO9l##0$7B+|c1)n@BJ~Ix>q*aSx?l#m zp1c9__-;uLw0V`|`R)#$h%!_~dR^{1#1mt%OcL^~_P*oY-)29{a~Ze`=@fUG;Jz1G zRsX;I!x~5|_|+ffhKk4NyqN0fg){Pnxm>p2EL+@j7nH6a?oJ0w=nq<3z6Kn;$VoZ% zdFA7u)&=#)aT>G<@{J1jUTwtjE|V#yWOmhG!d3{BpWpf%;%sfJ^~*jiRDL=)9ei!E z1A1`OU?K}Ua{g{-u+x+SgYm0Z=VP&>7w&SCiuhu2MN#)JKHA-U9lr4GgU8`N!kHMV z(}f|hu|-&)J_Eak-kQSx+DIq^uI_6LZ1mpf{L858w4dm>Qg_>JPGv?LUh0*Q+Un%) zTk0D+N<{m2?T79g=3$1lez6Zi&(-lGif`27hLA;0uG=2DMz*7$(J>0^siP#`u`hBadSsvBV+@vA7+qQ=eW&y4C zamxET`GovK?}e_D4e~rKOY-X6PHk~*`;Vi3YFnbMlR3Z>iv?bPcVxjo9kU7z+O`tE z31Z_qE**l_D?sntCvP5hm)F1YQNOYSdh1=h&zV$gAJzGyCnlv`&T0>Qhwhq;@^c3n zkY-CWlQ|&a_{7zoC@1@jCxM^ePAaZ3JGZS&3R}wB>5G2bOvm5&yrq0&7p7eME&b^~ z!Swfu52?SvZ~1oGns=^YKa_Q@;Y;Yhr=9X^u4$`pztNRh zXFSHMb5j?;&Xu2~u7cE2bfB1$ecGkM*a@j`Iw@U~zimcoS%`%PCODzrz5u`BCr@;h z8%+2I}#wr&4HL+#Z`y^K9=G0H?}e;23*E;94#rj1{c|Jk(T0=DQpM<$B1WO&-Q?s5~M z?1fYQ9xZs>uHzKNuCy~9a~Y?$H8JumtZk$O80FZAEvolbHpg3={G_XnZ9ZP)@+HyY zx=vc9gDLcsKQ?$5?e!m(9X*!?1x& z&RbUh+=Z6^@IU!4l}Q+Q`9d9a71moC8R5m%XSW5z);L}+oMxK)pEGKafzJidcbV1TaUiwg`FN<79j z`Di2ZHztHEb`@QY7Nf#|w;eA17Omc&I@j4@F5U3judID1v@;dnqJ*ceD)ak>q9(gK3nc?T#en$f+1@14W zZVzv7)vzg!^5PC}UN?17cZS2~-Oc^(>SLwFd=ALjlT8uk;^X?LXMy^`d0)T#4&7p- zqDLkyTzL?NKJY#m1NN0XiA7CNiQe#eN-$WaQIHM%Uqg4&PnEm0rQekE z(5?1odtEQJMIK#~{djV9^?fSOOwK?@N!0o1MzIItsOG5SzB6p?&@f@rzP7O$Fjrp4 zVO5ij+0=n2&2(fDB@<=u>(cKhWy^I9f6GFP7uP}A=Jg9Yh!$RPMC?TUEVS^gfVpoy znu)=C>u%F|E1fjlIZZSY>NqxWD*sH^k%Mkaa$VOp>9F~9Ob5MD|3c@q<2myQtcOBL z<6i^$blo{u+r`z*9lJu`feM@-?*a0OcvpgM2fI(>r&`2r=X6T17vqTFZ(S`ioDR|q zokFwA!xM~ZCpcqKgV_B_uZJT(39-ZzvSF{}vn-SXCLs7gVf&(W(kf5jEj%b+>z|;~ z89vs1nQDhGB**cA$J=$xqO@c_s9s;F&hfEC7D2)(%xMQ5=yq`mJWaBvZR2&Qcf<~D zK>NH7W+|`J{z?{0gRlPX_DKuytA8^45{7LLW`cVrf9iMuWm^8ki*G_}ETUiU?zjO5 z_%d~M5y(JSv;J%bi>-%3bc$YzCmp-pE!x0O7by&V09&ui10HqA%|^pM`F705Du?u^ zJFE0m0Z5v`XDB!qda<=6i1b zI9cp)q?uFfG<8)G2^jFxBl;t#%W2dV%bMd==F@U&eQq%FuYLQV1?wdK<+Zp_eq%B5 zVlUs&GGV{k!QbLe-_`YfuELdo+; z7iM(oYMo>U>&+!#w1G8vA3nP#E}*~q(8FQ5Q_=nRaO@kj1YX}@=#nS)xM@JJKPch0 zK1va*+#9Q}0Jc%nD_X0q8Qb)Z{0_K`%9h+0aa398$>i1A20r!+N`e1$oQn5|g)I-G zUn@LCuO~bDT4bCwHogZeIzwL`b8?)JCFx=dgXh3ES#%=pd$9x1C!%d+ab@=9WFt#G z#Ma)Wr|5ag?57o~t?lv1nik|v{&jLGlNu9qQgMuF#Ao{r=(V3{+W7qDGro7>U)#{x zNVhGU_{X8lM_6rLITDmqZ+2D``zQ;9ekhI$z8F%5E+a_k4 zn|SAE*BN`24$f5WBfla=Td`73KJNn8mVO9CTJHkBY}!u3vBf#xr8bB=`j<4V3xFKM zz6Er+UT>`a7_4n8Iy+6%i+?@IefpFU`E1(Blc$Wb7tInJn^k~hrH?3$S!V5t>Nq)I zA7OX`Q-8ROh218#RY~U+cW_ub-nLzd zJ+U5>W|o}<*zg5-(r8^&88=zBj(gIwF$l3loopoB?TL>=KXq>P1KaeQCvoMY=-ZE{jcOb*)9al1!k@Cx^6J&+ySFzY*puot zQOzsFUhw*>rBe-V?~}O=g~BR*dE$38z`D*PEXpNL`MuS+z}bBnbS1k|2TqZ^C_|oO z0b#8~U0%ZV;tW@~OwmcjMd5Z7WH0*g(G8G4cn*VHQ_!0?U+rGhqr!J`uo%|3gPObl zO4q~4=-@635)fgspGBuEw7|x6{A;J>UIscQX4pn$g7$1M+gWrjtFdQ*QOcv$SNHYg1hQ6v=@M?By*8b;5lvJ@|WA z$e%*3G7%0Ln4%u8oXMBiKUjw$rg@?gErR$h^>kxs0X{sgQ(G12vs#oXAC zPkin2qm<>{8`-kzxF_5dp$BbU)-PT#SjQ%gyF2NVkKr4$IVdFjR{nLM1uXQFrv^H2 z21`ELgsFvM*JlA`@h;4IP{8)r&XYjrvnOd9WbE!{kYBltlb(ec3W#10$hm)lopE`^{{kj!=MtG~P61r>bpPd~RU7>lTF zH%I-sUDF>6DGuYVJ?jB}c)ExigM7i)p_e{r;`aat_;)G0M(k0STezk=`x|18 z1A#I>?5KJG}PklE}IlosuGeMwB z`!ltH<$DYra)uf_fhGF3Xy4tddb&Jy0{Z%j^-f^=cBAiK^>XkE0}J}<@JBUhUtibZ z{{EvtX30S4~tU9)4*E|A7;So>DlSL*y@{ znz~G1Y?eir)1)H}EWEVs_4Pq%*aJRl+SfX12CVxhCULy;FQn*`toE^$QB-Ol4F537 zYyz&R!`lhPt*uC*bIwpzrE({g}HW3|PEw@>VH zJ+;Nvc0ua@B9~wtb{L{5&#$n#hc)Eh?V<7=Oc~7r!V)Z*< zYm13FeR%Tr`OrniWhpl)h{*bt3d)Yeid^IiETr`YdPH14lirGr|&&C{1Jfr^vIWrZm|(nCO}s*L+P9fj*v!AjA3u)dH|heqS#%pcPCE0ZfYf=HpU+e#(v258 zd^xgp9UWsU+iU2NWo}TN*!HW_W^VP&!t47zX;hLH7qQ1jPa3s7oC3Q!srSH(4*25g zyA6HT&hu~jvu(*o&6|ljpXe#s@+-!wD=26cP?-C%kM+&WSC<^H4H-55M5 z-XdS$IoE!mD;}>Cy1v%H+m1td+}6Nc`Hh7ZjDvKQH$2)9s?szhdiH$Ke-wy9C6E=O zFdH-{kaUCNE2h;>jERFgp4_Pc@{S33?==uwWCBNj)EO#Vz*(nKpK}MPjPTr(yg&s; zdhU)dA}qADLU=V&PztJ4YX`~>YB98kk#sGuoxP8xzjG!D?sxlM&^p1;5oz`Z@uqzZ zPJ2SsQoY>jc?-$4T=t}b5*>Yqz8uaKI?X`$@D@iG-g?3rnCH9IvB6vEp0xTsEobR171;PCfeOX<5h6OnN4mg+`~Fy-&>tmxmX#|l$HAIql3zvPb)}D9vd3NSkZeQ99awyGNGdb>`ivg2hcA+S@W7{{1(8)=E)C7M_E5q9kC@DeDE`q4*|Ml+XlGi&#h!sj`C%dvr+5V20pzI`eA$@bvi*vb8hV~i zX&XgG?;omB;)ydagoqY*V4E+cy-NCyAB3knFOW_iXn@v^w_jnSdPMy__uc#2l9Y@^ zpMeh@Z|XDG$yIfja5p9>MEQ1_fduqKDyONZGh+J;b0;~P|KaCO(5aEx%~36iQP$mu zb8+5Zs-uMssS*Bozq|WZ9YK+1!Ij09!_8dK3W_Ju;7K9QS!m&@m4@w5;7KDty`@uL zWdkz#Q1)QVPSCg`^`sL-8H8eC>C_|NT1KGr?|5zdTxp#8-1W{#Y_0En8Tys}*A8hf zqBTy-!F8;TJqazP=e$D&4hL^rU?!u!$w$+d@l%GF5ArIV>j>FGqiKnc&SB_bU~=GV zmG`i%s!J*mr|j6h(88-AY1f@h7qd<)9lN4W`H!?Ic8Y=``*niyEjh0|8mrzEmqiZR z>fFtQ-;1$!8G50`M?&SXubT;g7cr|-&i8^4jif9JGg-0M-%*XqMfZDz&ZFs`Uu9tI zJkBw&?cGbW#tugN=#Nmy!%DM6d_kU=q`sJX$PXqq^Yco4UT* z;R4^`Zhw_@BR?Z)30tWWx=!Fs|JAV+W2pzJck6k#A;IN~GxbA0kKL(WaJMcu8sQ)M zn^^QC-hRLG_88`qyjn-9=UI3Q{4v+MMtc@X8sfd!cBtZYpAE|eJSD;ayxXRpL})5g zM+xoMIgA^P1ZdeN8pCFQju-tqz4*uzZ%XGjGkNXKgIMG1sxUrFO3+x{IS@qI)D8>gs>ugy_2<_EQUFM5i zBDlG3==$*gLXIb2TN&{`b0H&>iLoQ!K*HWWRd!no7=TwRO`w0pTvTyUZ-^L+EcR>B zrOQdQ*M+dQyT%+tL?>e$j;~wxQ!Xfk1|gNo=Z`STC^}lpc)dXj``mD~=-KqEkJoL^ zM5kKHsj!yIQ~kXsztgbdq^wuH#lE^-XykbGn`Ey)G?@tcbury{>oV-V-P2DQExH-) z7TDUNC#Xb^t9|3hst4*nlZn1L#y$W_+@z?!MAv(T(0}8++Yopi{!Yk5KHxX~Qjf)@ z2lk}PmHN?U6}3%L_RupC{0=v|lD6WVLgj_;0i%8M&4#2Y`PPKaSm*lBjaG`ku_Jlj z@~M368T{DY(>%4erP1hE2)0S{dPNR)?0D7cW z%3jcw^3GgFQqtd}t;*uA19Yk}I8PcO`(S;_;J)}`drTZZUhL@W(K9lye*f`}1g#I4 zXxrsDe1iCidA`;uu#PEKjdy+Rxo0T?kK?jbbRzNmXb?cR8u8?3BX}8>1an8lrbu z492Br9ed8n#gGf5NGPv5G|CQPA>~G52N_+5yUe4vrckt%ZiI9{SpV1-o@kCih*iXk z4>v!`HvRulnel^eE4fY^G}}siH+}obsp$*5Av<(CsaYF*qWWGQ%&` z>AdNRA$eSw=l8qI^R-Z02+?`_m1zKXnwd=&7)xKX7^Fe?4PXARPMJAWzSq|utIqCs z$NO@~q7j2CVn*?W;tA(e+i|B(#a+v!e9IvFi55TMQDE}D3yuj28o0d*;{NP*cg|!F zB+$Dojzj&rSHC(B+N3ooQPJ6?EU z1$ZD@a=Hi@VCe6>2Ja7i9GY1|AXZrjFlthW!Ty+h5InJ{OP0HQRO=JOHtu&v-@Ti3 zOcWe%)J^D)lq>e6x$XS7G(cU5E9E2oP+@G3y17>w+lX& z1|Q)C+aed5yBD9=AUj!(ya5x{MrMY6=qGc?s|!m&mho*7 z3&4NUlD8+EeYw&|Z*`#S#DRv&q@DugZ6u=u+6yiGDp}%%e;`ZO)rIFG?WYQhZq7O3 zzZ&+UInnYY9GT88R0niARnl>EB)^V3i0xc!z`~@7xba7qMSam@BkhQ;SKD#(_HK9e zB63p3w|u*)fo+fcvWKSiTj2X3v)+^Il3rM^(Lv2%ek(V&Y@P}|83lTwqp|Aj5pQ+P z3&cwnJ#pGWr;9agMvB~TDHF9 z8*-imU2HyeD(Cz%f!6wGzZnQA9TNflEf(lmU;4*i<`rX=m*8)7k>l!fm%RIFOBO<5 zylosGnLAQ*eZ6xTar3cMPWVwhsD8+vy?nKA@(?Yz-CR=s=$fYxc>>q34_h9+I_(Iv z7}ASsUCwlZaf3XO0xoJ|(f(IhUxkHEr(Fds787=NR6Je6k8`66;I)Dc^H*iuPYZYZ z6Z>BDcWPh0n|R50H3qQg-pWh%0a0~5b{G)b6ClvxWTn@3H|!_ZXoGDto2-^}8y+~F zb++@~)P-IMaG0!Xu~&c|uRkgpvcZ16D>lIs-Jt!)&G%Ebl@BJwpxv-9sblQ<@~ZBb zE<0&@?q6!pU0`d!g5y<>-EK8HZtq)0=x_X>Xm|m;&9iu>_2ZvDC9k2qyHQ&x9qeDc z+`au;KA>nYIo^CY<*Iw?+ZbpIl)Wc2OAp=GBwowrc6TcaJdmO}gR!o+t1NSZIq5r} z#H~CV8ynH}Q~h~Rn7l#m(DPwX?b2yG0_ZzD%C8gmPByug-y=vT{R)d-p!at*jLQ3j zXAnE%K-U-DILV3qa2|H@i_bgtDZXpFg2rM;iAKF>9(qz{EXGut)YD0Go#+8mCLqGD z$J&NHRAviKZK}Wb2e^S}BX?g@*N8=lv~< zElxCT9nFx{2l2a3z{1m<=o1v7`D_ZKj%~1p5wm0Ki2O^g*6-;!5<84dl1{yZWl@Xv zbTf&I4yz2?MxL_w)i=A}%*W?E|^u|+eS%{6iu7isYg1<6Fu>J z(pMbcZV4GBqs=Tmaqc{z-}>decFvRWBG<)}%8#-nZkH)|{OTgvOXUZTy6ABC4HuvI zc%Gv2);@X&hA%5@<_shoew_)$EU-DyaaP^r>Fwm3NbodyS><;-LH_#hCyi`_zVp3g zsrb=fj!v;%jBUG~ys!1-F}7vfi+^B~(^3wn?ZC|cF*d%j+DkI9{~9@gNgu4`0w*)i zg#Y9xjZV&=gl(O@Htjckd|~C5vu-E5-F$pwK$mqxx?b9njZbwN?6LEVoc31^3$4w~ z0r1GpO9J+h_Hz0o>R-z}+RI0a9nhV+KK)R-C%22w>CZ?5PkpXE*UFYR?WF>GZW6## z%iX!o>~e%XzH{LX*ftXS*cN5WT(Tco^k4A?y>16|5WxD#VV4J5=v|x9`!%`pGPlf)}5KrXq`D6(GPx1K$c>n_7Y&bz4!)S@oi?X_7myn zcD>SdUGBNV=P$JUZ~m`hI)Wh}y1Mk_OBX^iPqUgZn2)ki8k6+9-Ca4}Foi+N(CV(J ztLyqk%l+(-y0S00I!~p&t&h;#=_xslL++fv*Fa8u>9FHm_D8h=g)=Spa#J4n^^^^jzd6l2ra4etmoLZK{NzziIbZL-;Aqg) zVP*2{;r>#NYBK4GGQoE;3*3FZuaCsHeU+kw><{0g10M=HARhYA8BeshDC_%1tf5qNrt0Ovs*zBixM1h;G|zmmfAc?zB=_P)ApAcjJ80;$ioeZ-59dUhQ{p zU#DKb@WN?)nloyig}XPj3DeI~$1YwS^9`KRC5=7b*)aiVU|&6vr(pU5=i{|<3A73; zpL^MFbPm5P1o%*ZCVJp?7uZwL_jTy$Ksz|0y+Ku{sz)d4EPm>|+BY(Bx5wu*2^`i{mrM7`>iir(RgHZ;wdTn;kv#JgejFxYPk!8d zH9MdHxmFDS0;CJdVlECunmh$CW$lmA4ou}L9)2C+G z0XZ0cLm0g4(i#pbwtqqE#ZXqWO)Rd;9^Lm)R8K0{&=jb1cXEqfm$7{d3z@VD))|cW zl3=RZCJ#BE@YM<;IqemE&CX^GltqIbb#gpGB0WPHALM~Q$J+QX{t6bXiRqg(48@Xw z?ni)ry0+lEzc`@1VG>(ycP~1q0?G%*meOXTrz~>pn+N=q>y)V&{?0|Qjqkg^$(`4& z&m@dikG?r4S6k2YXIQBAtHXpIFmoq7TP|h;J~de#`B*q-p&~=0#WZ6Q<2X_>=+lWy_=cAckmcbfLbT2I#F# z`qjAuFLe$dho4^UY%IPNW=RAao76UaD)O@T2|ojyg>>m;{XsvqRJPX2g7c_}~2!8)$^+Z>~x z(}_IW?ZU?oP9%zU`~6e9T=B@yENn1&GxS~+jQAX_eSlTJ+etLYooI5%3zYY%-%~$h zosZ4f!|LRfp;x-kk7iH_M>-BKlMsA_9GrVPdS?R-f!)(1!g?xpvh zNR+cog6B=@#;sbmnV|bWJ{bt<%)=WA&RL zhTl$J+q$*2$*s+1GBGr1m!mi0qYLyWEy?~?pR?M7^e>n@FAWwTIqpDPa5H$ngsf+w3}Cl2|bSM3H^b^7Gi@c@$y-=CGAgr)MoL`*vhcB zv1v0;{Zrd#@+KeO6lF5u_rNy|SGfppdvUtN%f8E|!|<8UTYQ6>ZMfRZRX?G;0R7NG z<^QCPk-qKSWuW>!YkR^6W0Q*3{S)UP{S6-9ft5Bf z=b4V{8`0+5WI~IZjQ9qiA)fsWtA?Vqt|E{84|6bsjq2ka{rf%+L!H*9nii7LxPj+|pL4DU@2syj6-KFxnJ$}Et-m?&MHWp9<<=gd) zges&f(IP%$@XLCtfOtV-s-ZlK)0^RMT4Gl&-m z5MRz_=}YwMvi7@ca)6QejjM7lw-i!%<+mq|4rgz7m%ER4ce{FR8hnUu8y~Nr;Dh?c zBHOlc1EJkmJL-I^#ZKgKxw}VZfxgw|!{?H(-_6`cwtqSGc7Kqw!+3RxiKL_S)6SOH zjexvf<3f#8_=NUh)A&S3d=wlVF=;z0prJi{_o?#2$)8^pAKLM5?7jmZKJO37i^

=ZG(bAwi;}1x^Vhu+FI`I{38pJd&eg_TL<#s60sL=bdKfF zvA8vIOFql5bi;g!z}*6hYBXF56Pfa*<*9#?0gP6;+kinaj62$rxpW_H|DKGayL8x# z@8x1ch|uD7=;K~oRvfdJDrKiSYx$TC(mp+UklDtxZ59S1AV=KyLJM8=HhKl!8UEiG z#dgdBf8?3yYRkB=KyomZeaTt{2~a>Ka|xXPcDB3fuKxL0^~^E&TpIPkxn1M%`Niz$ z#XB{5fDtNrIizip|L$NE{N@U(Kk9$>_|wOBPt^9EyjnUJMoy2SgtMZ;=dM=(<%$zJ zr4DsntWG6k`{IWJI*TIx@P(ylJ(}H-8`=+{Y3Q_eA*-Jvdp4RapSmwzAQ!mJlP7j( zC&#nJ-P75@1DWCC>7n@8okhy8Wf*u8SqA)Ndn};#9NwNk-33bPu}#dr^Ki$I|8^|Lion7I_5G#nFSrhg%%2XNx2mDqiTLJ~5g7;Q7xH-S@dIdet^yr&Tj>##UiUuEsnDFvv_wUYLZO74NYLG8hF9 z6c0}RR;NrFFj$(^v8&a3wvz3t94Q_0KzR6_Ewt{a?|1j^QQq#5-Mm;%+Q|uMvl#4f zXI^g3^@=?Dp`D*C8314f`Eqv1n<1j%R61g{I+;CYOD_D^VGMGhK5;t#|xV$$j zIo?i*jm5qEB1@?snb=cCeXqes`q}1;NtQMJ047Z7W8hDJ*vI?QPb_-lyJVZm1WO7- zIiu{Zz=H>BGj+rfVbe6lC3~X)rKWZwL!nD)%Q1jv`wL^6sU5*3XMD>4!0h z?tC(!l()S?i~0_(zr>cfQU?R%IxE?wd(qR1KTa}dnIO!B@A$>}6xj+7pmua5uJR@C zuAkIX7OW93=g|*LB%i)sahrB*LEeHq7$#hR^MNb+15(M4KWA95ttX66_46}iQ}v+U z;st|W-6vM!Pb`9-4Z5YC8lC)r+%RoE(Gh+@FL{-tOu7v4X=>oDd6LOJA zvD*JFW(eeYC@*Q3YG0c7Pm7M-eRQR1xiat6hcnHjg^fY^CQZ9rp?K@Mg8{+y6x2h? z;4-L((mDw%XB6K<*BDoq!7g1pfIL-QYo6``_0exo$n~~x&l;&i(4z~b*Lk#Vj2DA^ z^|z`mpModG^kY)n+c&C?u1-E}{pbi4Zx(gL*6^Dzx{W;dBm-%}2ijUrO^bN#Nf%;K zx}-z9imqimt7*1h#)sg!9T5;HeX(r!6?jp-{HL8xTbg_1KtDYrO!NZ?ZH)DH-+>7O z+b^3(sRN|%1VQ|dr_e&(kSl-OOP-^H+^v6*4%(NH;(Wr3bab(`i37d8 zHRcR0(8LZ)MUoHDa@~*N|FU28JAH&O`KU`-|kH7w1UtVV;cE$HYAN?X97e^&0r97sffgEnPEG*}< zkNv63#?HHc{cDzIDmi72e164yKU_~o{I&1?1$8#!-Cz5P`N67O6{zoh*}ML^k8g%u z@xABkShYfND$=6+BY#>A+XZ~y*L^A{@^>nEK|a6y-9MgtZ-T$}-M_HTM!fIq)rnR^ z*!G7fm_!0fZXp@qn=OEEjZpkO!=HwOhNk75d$ZX`f8g@R`akdMlQ*d|MG*fVc_-I0&?{<@DTDk1|kK`P%Ld|xgn_`F~HkvgLs@FltW-0P+L zS3dYZuCo#EQ@X%1PJ^rSpZdYeAKZWc*M8KEr3;aK3t#r0>!tgbKbQ{{PQeHA{juXQ z%hf5U3j@QU^!z366o%6}A;LiicZkOJwGDFR=_mf2^x6gdtgm}{h=>21_3N__y!(3j z{YxMGrFAyq^MCa}t~1Drf%4%W{F1se;tRhvI)abcwvqIK&-*DK-wc20gTJiKM*N&_ z__&X&&Ex~Wg1`T;h46*}4>FAL|KmS+`NRBQ@HIcI#~64q@xYgT-bd@~jqw-1_gB=} zh%fruf8chE)cqYW;m7~NSNb@`7kSZLCR{smuu0n;d;>DktG4 z9jyivD=fr_JyCI1nBkfMWu0bFj%|g;_7fp+c%3q63+8uZXR@WIc;d-QZkuNvpKNYD zJ6om9n^)6S>&OSb*-|#Buz*wDCO+cvt+LbMMcV~NWgi;Y%CtL^6yWed)rx!bSm{Zw za}k=Dcwuk`IofRUVesaQ^XGwpkv7DA9Pmh7T?dX{top~_N*%nm;j8>k%H){ZC(~`# z8sqja3Fn0^f^AFFRs#Zl&fB4pyVa>|CZCOPm_dGWXgTfpd!THrOO$Dsi%{YDAJ*s} z_jEzonqQPlg}-x`0deKA__*HZ&F+(W3yph@DP^lNZn^5MteT(ue#1b^;ldjpyv;#Ac)JAn%^uU8&@cW!rd!Jd|MY+PPwH&M3on1gY=3__ zTYFKDa#=FQR$>nyOQ-L_@HkNw8cZfNZP^Djvl z<-PNt;w?F;vhH+2{E?$R=NR4Pb2;d0S=;q7{D1Pbmu>Qc4@*Z2JxJJnSB}^ajV&2A zBB2cQ0Q@pIg#1{KQYNOZX!idgd0$A5W3PgKo^s^~Z}n91aGt(+;>YGoh><^uH5k$| zpNa-}T6Hhz@W>$YM%j(LVWsO~OXVEd7MtfBou?|p zrfIkqIQO7hg$1n-7}z(uJmj~>6Kt14k9AvwxM`cBb#CN%%9CJ9OHedcIIuN1R$x&C z=6^C-zn|;l9{*5{x@fZHBU#f7Uymj8iH6Qa02I80eSmqPA=iO@HL_ z$Km;)y~}=5cK1IgJbg3#+JFBq)!B&u^tX%Vj;na~jXOSu|6lyOm-`0~Kk-;Otuk}j zozK4UKmPA?J;5LUt<|SCkK_NryD!uH@a1FMFImJI{@s1Y)OZTM{yY9kosIa{@8E-l|CX1d?X&y=jThc9_S28SF*#~^7aVXbifAFub+P36pw5``9wUfW4?uJ%J+h0fAOJT3iV4!P?|_s&~c%lWx3S zKI(VpPhlM|@hcs4n7@Zr`e2yQ6WqrT9KUEA>TK@%e#&5ae;dQZO68G-tAP5Hx1PDE zObG`^+v9MQ7jG{?SNbuOV|2w(4}?Ltr{D}fA9x!2qEjg2Fe^#OAA=Ab}q z3@On>D6{d1S)aYxQpPOq;+Oav2;9t*4+xfyoIYciw+#N-kwye$exMG>A*(&~n|6vP zxF|nq5XfUOP9Dzo)^^(+T0JM-a;%uUILQM1rU8Q&Dy0?z3KW`b*YTZ~&7lN93c=s+ z$clN4@QYwSX&dHj_dt9~n2C}(LS@0icwwMSr$fecfx+)=DSZ^khSaHyDjWGju=ejs zZKwl^a~Qeh9bP%k+aeeoyh2Z>kZ?9$h*S>4gpOlYt7JQ%t^m_L`fmzXcIO)dU-U7- zf*Y;y`67gZF$P0b!;4 zbaLrU;DH8r;>DMmoVX286W3A|Di`m?zByMXM!G@u?lw5z;~Pqx#4Qd`;7nGftl^PA zeuXE${nho8RY=Tavsx+cN*=J~9!^S}w}UW#uM2l5Ca#U$n}UYWP8~n?pr7rJax?`x z)Nd3ub83L%<`8qt!*uq|@0~z)@jd>Y1!!B+rtD65m}CJQ`}{UQRur#S^=;|&}@uJVwFbRChRH6vbtAW)I};0uw*D^RvsH!l#Bw(!X+7Z3E{C z7Myhxnaus00()U~eCmmnIOzr*N4e=^nA)=61Jt|Vumf*zsb4TMnP6d`-je@asFJT^ zU)=^uGZFgSE2%imm4Blyn_!Ur=37NEfv?>rs|>6C?Lh`6Sa8UlKd4-jEPI|0fqFQA`*B`jHM9W}y8!RgFr1^SIUnRC&-0CeILBLZkUGsN z^oFK$*%h`SX-jIr*18tx{>E?47D|>TcQVPMvfMB@N12iwrwlTCusbyE-#@UMA2A8D z5p8XUJ7fNx9WSICR2`p)f9{)+M~*sFJQr7TRyOQ_*`j~^AS4rp%G*ZnOuCx4<|XoZ zv4EUlA05kf<_$VlLGsqz#6re067AU_8WHnTe~?yGL)-V|vEWOK{qBj}W$iIIyQjLrSLbA;_b-JhRwciB(m z$M$paiukN^Jun@f3}NgyX;8lKmA7Z2EB(-ZI1U~5$$#QLWjim)^O}hymF*CQ*i^2b zpuv6-pD1SB>iE%YeZt_T?#l+|jgQmS$?R128QX9Hw%%ZHhBs3v1GeDWNOqa9piSm2 zjXQT()x4OUN}x_wPiFhNzrQ?G*i4qJ)!$+Zt?PnGmKCeZmGWR;N}eA+dg$l$QIPMJ z18<|uJ!ONwlX!Vv%^vn4wy4fuH3)RN9`ZT&*5x2zpwgG zGN>%ft6zs)5eFi|+d50-7w2-ris#KD`SZ5UmR+^WlCf(8Igkxw`j>Z=PRn9J`5`Y2 zWTx#Lzdf=P-8wS4_G+aQ)uCS{_99T!}&%>P(QYjJVif27jod3$Rj_+&m;@sxK15H?_x)e;}Ure z8RSJiDacE}N9T%TT_Zb`y~;JTiZ1B_^g|Xz5MQw$8j-I5~J@(YwVWEInNn( zH*vy;v>DVtXf8iRSN}q{obnp#<1DN2n#myXoBZ@jakopw%gfdZ5c@_*}E$q;R^?1U^5l6)$imPvagjO;dc=Na{FIED?V z0KTN22ZXI!$UnjD1JBE^Cs~w+bt&>LIi^kYTO=gMJ?f`ucb{LOO_L)e9i^ta%$B^Z zC$LfYmP@Wc&UoHGB8r_0KdEPq8E<*cQT2*vTrbrBJ<3#-Rs{E7xVLb_S)_IEq% z%?|ESATT-UG&>s?J8BIN3@@4as{#Y$Z7Os{vMUT*4q%K>-b`4i17;^hw&gHgLsq{AB|csXPcANj4fGOpm7vpJMwH)g*az> zGNtD<8GPT*>?Uu{EDlfxY5=XMvTXxtPqBJTWrRNnTL%6VvGYOi))lILdHqn87^Pvw zfuh@+t&gKb5#rmxd+d`gtF*lB3Y`fGK>6dlHtJwZJIHT0yoaM-%imKu!FxJ67?T*B zDt{|l=#}3Z7>~ls`9*9E{wnLceO&=$Uvfn`JDT{ZBrwsz@sEp4civ?nSeLjIe1u1K$iH;CD!Uy#rJSC7)g=wE zUG(mBMe`IMl#%h_eOsvmgJF0xxRY8x>xR025kotIk6V^4SRYHKWN1Qvm#+U0hLQMW zc5xJ^hqmJin5J~v;-0FqUINK7C~QN0kpJCq%1Xc8Z9wp86gCR$93=naoz}V5gO}1q zHb=Vb;vI$RLJ+nJ`b>k1<13H0=b8L=d(Lm?@Sm~5OtB$F4uj+<;P8@?I{UPduh8z?aq|=>&A%JO9x)oaos6oTNw@*pP?!IK^ql6PFwD5SxV#q|%p@|upR`;#w)0zUJ~=y^OXu!AR0ilsJyssoK`gz+w_WJ$c|crk zGTU!@ppeez1n`odBg6eE}>sNP_~iXEqC~W;vDSv3Rb_i$Ia$)u`#H> zc*c>Z$BHWhxp=}Z*rScA=c5Z;`eKx~=O8}ICFAzwc=Zd3@qV)<8q`g<*l>UOwRBI4EFdmpKlH(Sx#5$*~tmKqP$dUk~Q`Y zUotQtP`?&S=u4aJZ{yUDjyk#!2j8p*5O@o1=!kt0+k?DC-c`nWPBz(T!8+v}TT%B= z0c?56?g$i-(rL$AE_+MKd;Q$bD3bob`kwkwo-`mY*90^(A-{j{g30EaJyUd9G$=Rc z%=am8WL5NgP`KqKv;pXTDiBtoJb0)$M%#dL@BVhmx!chIo{J`h$=hU5N?h@65LSOI zcw`Zz2gEGLjRoYk&9EvyST=HT*=w9NRf;&8qy+OV6prGzvbYP&R_>*HlO@6KS zh?i&OGI)qeVDetPQC=uFXddbdvL!d9Q4{NuD!X$Q&dPbPSg2qFB4_#K25kZ^bzA>R zmH~0Y$BZLD6MV-Ou%4BFbSf@wW9qnhN|`Ax>~s-io;6awB1}i8S?K_8Bjj-j?0Y8m zqUQ{U8~uWAtKp^jDfoLNRo;FkCa}}MmFRMsV2BHSYdJ;kU}h$4O+%L**X7!N1LmpE zK=?|YfNf^U8a#E|qPV@?m}S*o6a@YBly&O@NFO>nk1ao>=fO}NSpkl20E10Uc2uT@ z^OkUic|m+l=w-k^WXw9k-mdn08S<+%BUk&g1Am9%3P4*SvUCe{c?zjNW880s@ED#_ z_oy4iyGtN`@rE+c*-#HJAd?Q%$!?>rPs_7L^b!3H>Qd~@mLnr9BQv4XS)`4Ue9M45 zo1@!l55rgV1ogA^Xh(odx~{sNRDEDUg_2mGDQ(*v$gRB&Nseb-KkH8OOUJH{hVM%{ zotEPFV&9y*e#+(}eC#Ud%~%$Cv$sJdkHk_b=tMeCdD?f~Zy5|-@i$WI8_EQ65N}V2 z?0KvXe`*J;Yma@u>0;uIg*mj3YID0rY}v{b|z;1ktXz! z4zfnNwr$b72mtiUzn$|TpEjIm%Se;_Q~z+f1jK7uRVey&>$D+*%n^?qX%L6y*7Q@B z^rPh*;u>foFf4g9h|b%<@Qy{DnO#__gKB}2^9uWFxSl2U>9mP?2lo$WhYy(bf-Mpf z8TNc9Wv(7iH<*`T35jEcQpt@$A@A)==;dheooB~GUX`bPdFEAH91|-PnhaPB6dMdK zSV~HN7*-Ux*`yn6HKub`xY0naPhQbc9lrCts!G}N(eJZU3U{SEz7WGfZtqM&cQ&c? z0<@Vv3K_cDD_{5VKi`v)awef;W!U23q!hTH>gD>*KRb zmO!r%IWYBGK;UddlSe6*H6QtPL9Krd6*pT)kPOfE7)Gv6lR9SoVl~}6;0aXrm|v@o&uECoM&~A=Tq{W> zT5bn;{n%TmSRQmVzi*DtucW2!?1m>cx{%x55;piIE|YrID9W{Q(5_d5p!?l{DVS|k z&9ETDhA@}W^Y!b!;4gx5=(6a1-v)b!>A2d^ zB(8QKjO&vvTwS`wU!QTj+UIpZROh|t&>O%>ZY6cgboZsxc{RO&yn*J1Z4S8}7)qNL zw;N3$`d}`3i*ahbE$6`nWn%xi(9O45!0O~P8Awpu^yIaN(zTCf{$7RT&AJ|2NNzEc z%^|m(Kj+Eq7_C#B&+fc~_E%}*s*Ir5vd_X1$y^T{>p_l%rv9@D{wAK>sTZ4w@5O)9 zs`A3n&m;@wr{hI^sPmycAiw%^d2opifX6ysE8pf9Vc{*8N~d@{2#t_(iCx}hcy=l~ zfVWI}n@o?_r#ZU*C|hgU#_KKn0K1RQ7ae?g!R{bUdbSN@OXcir5p=COEjK@xy|UR; z+kE6Vu6f%XN4C#4cf?QGM55#Lp={9Ck7e5uC%Q6|8W~8F-zVxP9FtespQrGi!8Hbw z&?UOWz9!QqAatcuiai~^>>n_ooylz$q+y5Is6rPB)`Ya775S+_ebEvP5F)eoooG2dvf#u*lTQk{KSq)k%JfZEmb`=VpjQHNA~{U#-(D4_3yZWH=y{GT*) zn&Z&!aqWBMpo<9wm!WvB_|=b}ogYcQ(f7q;{4(KXKJh(5xgjc-=|v>m@}4|Y6omC# zs0@}+9~IwnpGh9#t+;UFtJ7ftoccbCMLwd-f8r-lI2|T!kb&OOf1Y7e5)bfYfvj<9^@M$>JL~arJnGid_K_6cWtf>g=6(RgXL+D zl%C4HGl_h1FTbEAjJHRCZ6V}Td2j#0^!z%Y%oR87n^JH)N0}r4@Tc->KAM+}N&{gj zcd-sIxspjOu0>_Zc>53C3WW?>_UU^6k_*Zqt_1H0O{XkOWTzAAvu5%AeuHZ50 zbM3lMIf^dH)%X@0IY}7o$k?Bf1?!Wgvc z!PnD=sx^z!M|AUU6Tx4{w*cj%CozI)P`FRrD!xLHNXhAL}f~1D}aXas=hMm$2ge)NlOfQ9tlAdhEj-IAk;}oK=HnFNZ?+bL-pEnPG3^f|(`Gu?%A?yV z=cD5Bq0(^p(0)_Efuup+xCkFXY|MrD&El}f)@S1cU1;xiYkw1Pq>UQg*$YxI%I6l)Dd-3oNTV;_hHa|8GG2y3N z!8V_D<(Zlb>`K)$*|nYsiI=H&f%XD@)qOV7P`=zhfi^gqki12L&fz;GeD^7JVV$w$ zY8x#3cC=@5Oi-&1qhnHRi7#o6I%~+UsDtO-*CUQDkAZT9>%2rCM>i1OPH>%3cyyM( zKdCV5^+VYyOmHi_!hwEU20odVPDb%GFY=~h>)Y7##25MrmT;zte_R_Eb)}?`i7e|i zzK>16dDJDYQ%+OPofMU!ei;`(g~IE>hDTM7^%Hf@o~YugO=R573#)M~-`YYE?F=Z6 zb;7?Dh;U%=Wt9|3E)G=$ICc7>^qYy>h*G4HNCCJIDR#E`UAA4|@oUcz*t|!V5 z`B$gK9T%53B$7{=B&xhrq$OfPEpq(<^)}LeCUE+QhKv$~j~I>Ob1AC4I;RfGX(s)=;u1Nq5x=`W%=gt_}^ zWef%*=*CE1aYJ2oeTBcfU`eps3EH@B=S1RDRMnkGQ795c>5pY2|2vU{+BSF^9kCPA z&E6h#GFb1ntl|euCi@MLU1cD`k)Oy=TqgBod&rTmmRAqBI-lWcPqLi8c5e6NwMVm) z$MBUhVgLjK96ejIE$6MU6xZWdAIUK|IGa8B%<1g-m6e_KYZc2yP!B*4{+gbD0nq&2 zzoWLaOqY@Z=K)(Y_Q#}CK8Qt?3yi`Imp%9g;O!7#at3%df#nSb(@|*MJGG}q|2+3w z%aQ{h)j5C!yimJnrw;BP`J6{jS5d#a75JHLr-?wPBG)o_FkWz zFJx!(mdkQ8J9u6$3wYtk?C^z!uIHIVQT%4T?2^qn?Etp%sV7;WV{aAuGs&XktHoPC zMpq&)DhFK;Z^T!7$soS-B7Y4}K*%}G`pKiOJV`}ia<2i;1{eB65trQ1nTe5;pVm!0 z9sJqm;W@O5UtBAUV$0%E$+?OlbtZ$K?}(1dckBv^smc9j^}Jo$6WYA zeURHsdp6zJh1I8 z8mS{GTLv$buId}BVp)h~cokQU=dx$!>NhA>r*p6$e)IfP>7A~Qy%ihjpvSIm_jbUt zLi>=iwu5FvX~?gC0yA5GZxKKwQMHW9o10j$zS9 z(XtEK4la5k$m&?v#jSh_&IWZ${c-sl-V737u^FAGrVUr+x(gn>f@kv6lO|JESgsvk z!ExbqukzjtHsVX^>i_BSC#AzP*u<7ti@WQY)T8L*`$;H2>3xN#J+a$oQIVdh?s(!` zk)8V6EIL*Ck#F6EmI~X0aU78cm_>9@Ox^5u3_b;w@0hOcQ8+~(@nbcHt3PkUgUn-e+0%9&rc0eO}#qpwKc z4fy~r7x87yo}cKf*si$!qkPNN?O5e?q>X&)o@rFMSeL#DoEG7(4^l-IIJ@#~B++6% z${wFi?A;WRwX%ue`%~~9`ENTh$KCmL8(_VGJrlPJo@An4!8_N*pJ7aS!Kp7PSHb7{ zM?1z*c|22FhE6d`*8G+VI!4z_dSXvT2l0mfsC$sLjSPq>Z+uERW`t^yZL73Zkmjm_ zKKGr%glW<195eVHT?B7K8@4AO=y#sbC2}51W-)~5Sst=I*3z=(1wzOPM75mAVLMna zQP1_vY05Pj(S322*Mk>bFG1UxJ{L`G8*`6%tzVgR(=*;6>2qgm$fs--`VVq`rn=$2 z4$n;@dFyl0OFCTA7V@@|%SLs8sDS;4Kjg=DlODG28v789v|s2Lx7*U;vdG7{$piUR zyAa>{!6(Jr<4Vp@^Aq|^1F}O~Kz>J=FyxgjSV`9xLi|KvoF4U2_YS1jaBWk-gVt*f zqjDYF5k0%^$MApYSAAneBt?3M*+dC4e4FC@x!DK*!{1RCAW{Fm-}n1{oZ=I&XVs;# z5aSnnvzHF8SS4@`eEYZmdv!MAcm1C4s52$8cXxLB_NlzN3=oWw7Cw%@;I(jPMgOSeDt`nX z)U7&4aH&9Jgnk1>w76qZw^5dZfU~ugelP#P_Vx>4=g06r@x|dcZ{H|N8u4ZZ_K=Uz z-~3_amjG>F{yG25=TrR9Pk)i>LKM?tPK6K@Pj{rKljP^4|M_M5c6|*0@AEPIN^`k< zF$$pc#zOobIRi~q*{iHR{sRwuoZ^>#>*WtH|L`Z2hUsFJ^0`-S{?vaqRZhV#|JMIs zosIZ=KlKGZE|w!DAOC^t856tW`)l9*i|TB|FaOrRTW2GF=p$dKL{UO2?Xbt?HyBmL z?~m=EWmkMZ`l+AeV>hJ4g^XsF9rh?KUHduDXvl!%?W2GCb8r_M%v=;be* zd9^F6&UtlS4XGQkkZLeEzw5*IKk_k^(F7{#FRbNbbvEK3zxI`u4dmBGrPBJypSk=Y{ax4<--kX?AEhsOgO4A0S3Z_L#gD$6 zkGazk8tOkRSGWZqwPl+>;U|6|2KN-d;+rpj;O`%ODjy@KQ`q>xdw#smM*PUfzQ8)S z;Q`$$_pn<82tW0M@Aq+vum0xCA6)#<$KF5agMhpsx4GAK70}T_cQtmE@$@;sPv65U z=RVS;s?5?T2VeG{%O6_*k)KvRm|*KSu2^A>k{X~6kRto=4{pmJ_?6%MH|uP~hd%l~ z9|tPcc6{l3K3o?g{^2Lzr@YsN;8o(r#w+6&`*b{4vw!yesh3my%5VPbbvEKJe(L1bnZGO2jH&kD!e?R|oFVpuUAAN6~sY&yG-+~%M26VGEO4{Tf|8rmJ;}pN@ zcU}Hiu=|Fhq9`D2&==;fbhl5NoPO1lR!Ar)Dm()e=r;XnUB$jJn|;`>p_ zpI3tuPEj=7UOYgQCC@{|6L6;oSuBeJbY1kxNAcM{%qXLF+UD=4udZjY^T^WvgVLXq z*iK%f?Mi+dZ6uHJm7FTvAnUndy!4%yJG@Q%+l^fx!@vL9&-d}-TaMFh*QOcb+TYbO zsGA*Ttk;HbN3Xo}hi`80?!qU3TL$Qshq6B;H@3G*Zravf9G%Zz_^!|R{3iJH?_lA` zzB^!vGECt6A!oHEFrCMD{L%Ud<^(_e4TtjGObdTL=TF3*d^3Fdn=+`=e5I`!ryuQOMfDDXNpgJ9g|BVOoe2Y$rj9NAH5K4ggch1%kTP=m-F)SZ@%X?;ou%}f1b$_ z#dqjQl;n{*^5TDdz5MOM$A4XQZ1s<}Y3#`5n8~Wy>~sHoI-65`{A;o@p5W$_`1YRv za;)obgpVmKaC@$B%{OQm2S-ORFpQs}Q!YNRQvL8SlLC&%f6mNoy;i?S&8i29&JJhi zi>!L*ZF|t)rlddgu0MZ0ny-tO|L2FZg98RVAXRaTq!<71uljn5T_3~$;{W7J>g=y)J4gGnJ6SBZR@b8R zGQ4tIc{Y3JU%f1Aul%a}^$i*P#P8={Hh*>_$#3Dq{|ZsC618s7_ZuWcdd;$VKKsJ| zZ|=Mq{`oItFs2eJ{_G07>tpzb^)Y2e}`=meNTDtVo%}Zajk@xjP>_g23Yo(jA6nhdSkFl>HnL0a8dIU zwD>XD4Dn%~epc7rS8Oz2hQa%7e;%8<1pJIPxUc)PQ9|7`hmO?4uldf)w(NEB7ryO( zQfEQuAB^-&(DKri3@>AalY=g`3D|tP-?kSv1%1Et!+M|(RM;U7fDIBm?`yy3zs{`* zc76>1laYh&=XE=@Yk@0$GwLMcH2vH*lhEzf*Z)U9{qf_kp-zc^bNB`;3$`Sv(*V( zQ0ZJcVO3$QXXM5DjuZVY=ZF4SKDw>PC)w`PTaFRl-uMSkbyzHBOFw4|&d5K{v5PVW z>stnGe@}iOL-<3t_*))I59f(gfvxQT3+@5_Jt?AdqMVKo*aj{gk%b1xCKEG^|3Y`` zMKBWNcsL>d;!9qfnEKFp>mKn1J`$JhKG_{SOZ@PvK!#0Zrzb$45Idphu6Pq}V!Iop zBYxm~DNdFD)*1L|-b}}7+Jw&!)&-;G6t8sAe z`Pu&62X=F|^=T$QLr`(ZFOEr;rvZhUK|6kDVqEC6+;A#Jv!xajBFh72G^H%$-;*=U zy2OmBBc}P#7Y3Qy{Rs*^@je3DHF*w378!DR|OzfA|~)m%SUWgz}A|@ryQ1 zhUqk+iXU0OcJ)wxNLxX@yHv9eiZPsaMN;=KFf^7H^_$&Ko0A;C#pD zx}a0bzSvo-b*L6wmt-$7#)xvpol|*}m z)6GHt|PMa2Ybf<%@DubA=n;7-7Z4HIY>VbVNI{V&Db9TectYn_LGvWPGuDs8$eNN%M8lZ3mPTAN;HKvW?X@gm`{7 zqYdVxpllTo*&9~3JY$?MSkbI>&Zu)`_rOCdkD!gk>%wof4)RZQ$VSUh@x)I6_u~5J z)u7Y^jBfkc25+#WFrn*wwtsXsJGe6+T=S~w-p9tJ4xB1qQqk0b<5zf_HuW7tx*dof zZ@R!p#V&e2n}Hb4Z5+sLB!6U0jyHn#<-9G6WWQaPOo~7GA13DqmW20jRT}_E#)~|3 z!oUOPUa_Vd^8@tQ)9Z*STs_gRYSS&NxILxkwlW#@e%L#}s$sLqPX7|wwJ=UHpcka; z(4TCTMEO*l^TX7XUEqGa<(Huf`BxpAE!3tX<9;stTYZ`C0AJOPo}DOLV-N?@;^-{`zd2tfIW@VeTC>*wVnkdV{U*Q$JUUXwe| z5{r9kAMdKZ-8-8tA1IkSSy78xMW<|(w{*}i!xL)qn7)#zb$_938}m1-^VtGyxl|wR z;9$1De<)Y0%P-*J zCOCfe$?Qb#^mW<=*|pN)v>E3Nn4sgyuqdD}O}lsa96A8Lz=-0{pkGG&gZ`JD5xNJy zDbDDZgpaK7to(^jU8adx@`QbbY#>|oHzfadJj0La4AAFe84(`(5>M`Mp0nIf+SYMy zW5&3GGtsiUu09nkJW5CT>J)N>hNekyUizM#!$^0sO^*1IyZVn@sa@yo5q~R8{KOw) z3h5UUGj@w(mCbefCeHvK&8TsQ zAwN5yUWs^t-U)wqbD46h{w)_*l*Kav;`|gqM>>xcu*czIQ>k5LyiX3AyY5r=Y>kC% zA!D8tpq@#Nc(ZVS|9SaSf5+p5#816Yx#`?>%JM>#k(q3-DZmz-(+LHj`+|+dbUX(H`YfWkDU}Z6)3yK|c)R?1WZ+!t2B}I3lg`G)>&& zDA&G#kL53AtTdI^zUTh1ZCkG8dDI6!9hA7H0Qf4?iAG^AV&n< z=frD6l(a~Pw7JN&oq!U;dAqSm!^w9%7T(H@t80s&_>Ce{x=VH5)YyA6WA#KzMoMdi z&=co@a6zA&6dUi_QT|Q(k%v#EL*+0x|@pZuDn17=0Z1zOgx>?De zpR04lYER<#gk38y>Ocn7u7@y}J-+!EW`C6FI!M`#a^jBh+kpLhsyhc#=;AAmNfu-d zkwN9z^(#r&1m9Ch5dD)($efF8P^PZ#y618Xd|GmOEin1WUd4owLk}STQzr`I_X2XC z`cIx2P+&qZ+p(z7<0iB{D{KuetHB#|*GI{y@J03>MXOfW6W$^dfb;7@p(`(}u3>ebUA0q*kNUSx>tNFgUj0w_$?2vub{ER3fY#ZCiWQk)%_T1x2y|0Kz)eZwcJ3%sOO@f zuAun}IG&;xm%&wK-TwvTuJp=)%D)FV3Q%H>K*z*U)@}oo4zjm;628%1;^;hhpw9*~ zdD0;y%uXJi&Q4w{+s}C=-?S+g>j2cY`xh5I5H^=A;=J2Y#ukkI=Xe`A`nDZ9p0|ME zU+esI=u&3+)&d{ry<$ta+rnj>jwcg4%PnuWY zVxFJI263H$cGm&vEVVDR`#42x$D7?(fwe+>WZxg!hfZ`1%+a6UUKQAq(-Z04nch3l z_3m<_!wM&PlLdDocl?>PkBUi7X?P;$CLkPy&HS-^>LU5;6}!lfx5bi;nu+dzt2lQ*q_c>WQ2ZM9xzxZxA&s_ zslQPZbFDkkgW!BMsc>5$)tdqOSL^lc_~ha22xi_s>MnXdBg_a5tvT zCuvOD@m)ZtIo7uZiF9JvvorGJ$>@B z2bpPy*Qc+z?3^FkG18-MDPL{_iiZ8em)wU>*w++)#YmI!shnzWRt?5XuAU zhTT+uOaOggpl#sK1ys4k)Phk$=;TEGN%y8%wquz55V4)&P@0Y`;22iDz7pMBxMJBF_+l&pKCJo&a#v z$Y<39(PlYqdYxv{w;c0R9kEjy^(cVmN}priPFA9}-%$EI7yYIq{^3i?N~zM`p%1nq z-39b^j{MrY^%XzGJJdBjG;hQwPejS_oUvK!KIK~g=+z(p3hc~lxaS! ziLN!NO&mf9)2|1w5a$gICM{OIdg9rF2@pDBd+PM2^ZPV|%LqX#5ruX>7p-z$Ku6!1 z@3U}@S60jyvTYa&Ku>xA8G&SgUDrbgPrz{7m z`GILHC30ObiGw)$L!Ly%q}#QjGF4-;+-G0oUNQ96BStxL$AlgY3QAu0OE#YtRH=k* zxzkaiw>V54u%g51DP_seukTg)UKa7vEt8_{0j2=`&_AUQYOyuBM!Ef%k zfkmci9B-Kh+vO}ox8liw^6v7YEL^^vpG%+MSozb*Pq$mV25iXNh@qer4{j$EuV~}P zd5(Z%%3Xxz)-^D6u6UEF;C#(hetZi@@j6b$2{V=J1leLE$WED>T%?sqX(E}&@v!-D-3i53?$;x z*^dtHPTNJ0XXm?ZaI#?@iZ7DAb9jy%KVvXKzBgC=DzmNwgUmHetT4JJVq7PmV;v}z zPC@3{4Jh740?2jZF*l)23~^`MHVJZ^y2_LI6uU64C5!mCQF|hTaY;Ka-#FPitY&TJ zG!>p$hDZvrLy|(HX)=o5&vtZOq8xBsJ6Dubxy4<{C-z4{=4u|HJymCt<-81bDm z#Zl!O{yke*0?V*(yEXUoZ1b4T%ANuFEZ7Jb(NZz^Yj zQ#w~?C*rXe4atov`%3Tz%uvT{k4Fd3Rw-vMlq$D5;{(dl8`C;?0mMO0h_PbLwqd%+ zA|thfD9*IDT&eNBOsEwZLQ_*$1o=&keF$?K11XH3!`%5Fb8o-H2i>s;|l z*Wdz4?A`0@&+FoJl`{2!rTRWC6VDRclXI0Hmmw2(S0u~Z`Qxfn@dFtxc;JR` z#Dzdp;bixbr<0T2eU*NDeXcOrWw*^Q6MGDL0oNm!vq*wo#eJjL%_9DZ#w+c;%ixV> z>Vx&~Dc>Ps5bRl?av_rD49uu5d4~(Py~*!Iz}@_x=A*fhBWE&&eo@fHYU?zS{?+EKm}5fa>x1H}(*O2-p%ZiB`;ZC~)*VJ-t(YqXKB2j~eu zh*Qqx+OpMv|B|08(%l8ucgdsk(u4faPA)8qDbu$Dq)J&WWJf~7v|ZQ&Y=HgP`;<3r z##Ml4mP?(FV)x8Ixl<1CjyA1riOaZ9UYtXhbP94ypMp0m7+V}|5a5gsAkSPf<_I>@ zv-w7v&ON!u_*2Gku+yU6?;>~{KDbD#+7$#eC z-(D;4wB?*nh!wciWOsAwDf$UjpdS!hr{_oJ4c zFfrd7#D_kcWXo@XD()4FjU-#>jC>m{6GMdQl-?8y?+F%#bV74JPAJFLS-NSrf2T(~ z-W*xYPlcdCOoe>b2*WY}yMO1v?%JU6sWf7s0jZqUoj!V0lNnEDr+yuejy0=Z`V3=G6 zQj2RqX>reCHmufUrRFu^H;ejvJBpY|jrlT8M2jZMFsX9x0UQPm2BrGupqxC2NK{WX z$s&68B?mPjhua#gdkaBcnPA!QcGj&B0s7}>=AFL zbJwrIFS3uJc}+Oj7(Np$8BFuQn(D+=<<=7{gHcQr29g;Wcq??BQ6wktx5XI8Id3!8 ze$AI5d33#8$f&{C7w>DOF?y!mbpe<7?*KI)3m=w+# zRQI=>bgvTZx@7$hNVoiRPC46I*XrIzvU)Cl$gw?*Vo-F*g5soJ`}_*%u_x4VQmEG9 zOuXX6E7Cyjt_{)W2@T#F={HAq0UpSCLR0YMN;?(;h^`FyJv-1D^>%QoKXmTwt}09F z5g^4f8P z4#_P?T@SMAt8>52$sjgu7yejaarA(;Io~nRP5IJKcHSOuxTy^~^fn?mzDbcf5ZBvv zLc;}~Q#arhGH>_U4ZekdJAEXhS&r}8?O`XmUdLfuP0MOL4{u9AW^1o`tSi|rb77+K`=6m7EO6yNz~4rdl4 z-79ytKJY{^^12H{nTbAVpyN;aICq4te<`!Lo@BVH?Q+=3v)1!R?+8OqUQvB=|7JHm zmjP{4(D7D=oKY@2p4cPk$8mx$_eUovTvmiL!6%(keXZ-jD?^nwX?Q@PbT9TxY?#39 zj`OXbJEmMuADfT8AcDFKT&GozF1u?2*+CvaR@qL|uiZ3%6~h2*4*D_Flf*IiAT#4S*44%5>j3%htsz@JrgZp{GO6-UdXzbG zquX+n4Y~+Bb0hB1Y; zNR_<#KTZa*+ocr78 zU(rK6>l*uUd(b~*RzG`EnA{^{(pTtH)6jBMbyl*Ng@oY^Z`c5j8!3GJuoz^*8`leL zLu|A7Gg=ptPT%!8bS1oLzz>f+wn?4naK%q(_4wJDC!zqf_1MB#?_HyEzJ=UN9;xSf z^BVt2xzKdf&*g_7r@vO1BfH2>>KXh#ef-nXiH~NhlTX|A_zU#yAH8Tj-nyK{{N9p` z^NMc@;`Dlz0=wYM>BsB0+-KW4^(ka)duOIS*^KbJGXcGYyi_o@OXj)qhpy}izNh#Y z{%;8*S^*XY!=WhnzkcVx%9J+_&kxI2L6M8;CI*4r^mPa@BV;~-U6%e zo_8RK|9|%WJj%8$JL?1YX(Qq`uYcLMk}^}uM!={)@EE2uHXuY**^*KXAW@WTBnCA#sqA>+3NeGFqz#vd6)w#-0U|a?Y;ZYt{4B1jXNvQ@YyO*!am-*hiO~h&I z`+alHz4wW8;@%TC;@*7nc;AT?yIXs$x#pT{uDP1M)+Tmsn!k&_XI_kSc}8a{=U69~ zbm|_B%HkZ2y~J`RWB72>D5^aSygZr(r;*{%t<72+%rCtZ6hfDk0e*+aQnD!xnKa7X zY1Ak#*^h9dw=BFviH-!_(JB}lrKCgNofHQq<>3J{#a(I1v{k+`Yq@)-dpaFw=iE|Z z#*=}RlnjIXdZ50{F}PKi5}`7vKlA-PKZ#wN;XhTIpzB>1_N0%9>3r-1L8r)MSr&hT z|AzdR0wxTMnW>kvS~s8m{_W1jH~sEgneIp-pX-0%b=#Yu|7320UIwuhfIA-a&dF`% zfzB1*XMSKijyHV6%c3J@NJd6A%?IAFy#e@7J;x^Pac-Ih>*kpc@7hFu*XH%VCeJ#& z<(riL*(=TPaHw)ah0rw5{!n(X^{^|vr=I_!JQGqNpZd z+-)9SICC?6I#x&ItpZ^wvEHW8Q2`E{PwfbA7vBE$d|Fvwa0SQS_lE6q^wekG;bR#D zMZZz^girm*+w<(scbeYp%aDo{x^QY_xkwQi@!>GB4?C%Kt-vea$WTY5oElr z!$<-cB!FDGKydBkmj~3{61o1Na=Xm%e|$c;ESTv3c;CTna{qZS)FWTYV*D~ZEr^Y)45rH<#_i-?_Kd}*CzM7@Q$x}s(Uq!?)SYZWTTI# zo_#}}37L<-{G(s)<0krPI2-Ty>i>$n3-iz~C;-|y(U|@TM&PRW(Hx6Tyr75c;glmHFpx3Fd)MhVl+JqqN#GuW( z)F(j)`!+oM7oPTcAH?y6z}cJO%Pta&rw^sQK$4^b=Qprht| zfA99@|1W%NG(01J;@#sXB&U~%xBj_pJ^B29bhVjYSDZcBdHLX{^6bud>z{pFo^|;A zhtj4=b+?oa{>0zv^h$^A{C(k@ANB0v=_8?6=c>zJp8RA!?eNzBayuO_{=Teh$Ew>T z(lk&+tD+`w`bq)ORIs^LK8C_pXm@zq<>&Hp73%oK0x{Y5Z z;OHzKB&xg{5onwvy>uk{COUY#JRqOkkAa8iw5mx#=ApuJe}F(d)Vug)Fd=TrCAp#7 zu|^{PAcYRO*!LkiIGg5w^B4acAMYoA?2r6AabjL3fuaju6n*_c$D)n&`6)bg0=OU@ zbjWu4)Ey;;Jcvi6F_tOUOUPrJhwHsJ!@v1_*f0@gMhx2g>?7~>X-YY$a{0TyXFJ}D z;O~Cxuk(?ZTh?Tp1@n(Qm(1FJwof*+|8XBL3;S+{|B?UvEAs5l_}c%|_PhVL-}mdC zuVAURy_*^0EoEfLQEsTTe)ISJ6Z`4o2mZu%yubU;Z~OcE|JiTLv-9J3{kiS%{^qxS zh3E^Ov$;Lzw!OH;7sY;tZ0ksZJei53?n-aEe0V}4rGyeKeb7jMmI(5C%46sSom(LE zp7=4AO}F5_?lFin8BMGexMnq+@XL*CgXx{138bbnZPHDt*Fozg_-sh;Jz+t<(` zL#D5Ts+@Btp0kH>=wSCfXP62V{ZiX~^xLUCi!>1fIxO2v6(2zc6XH5ST05|;;luHjXObS1-QzunL>NGH zlAjwoPoTZ(dX{kIm*??SAj>D;P%xyMaHFnS4d}a8+he7=Yaly{6vLFrqk=9<{5YINX&>cVrOg~XDb$ad4o8;p-$L$LW!BPfd zeXY^|YUAE8@E}WOLnQhFpn>2<2dJe6oQ2s zPvN8v=gSz}v79QeW;45e;Zf~lMx5D?BW7r_AIoUUUNXveoZ_yILU))lLM^9%cCO%+ zdGHlC8n0rI1ti~2qXw7A+XXXPS-WZnC>p~dv%{HfuDoYo3Kc*)u14aoF2ds(sHfx~ zd-mKF&=r|-&sd(sh&+QV3>=Kb%YDIY)^d3#kM|dogNN*va~a(YGW4=}uN*KfG(vT{ z6DujrHSghEA(bp|!eyEA&+<7`v`(YaN8aO3$qH9d#u4swAmtL*FKd?yk_bx}XgCj8 zw;tLGy+M|MD(y2iJ>G@YNR`+@)eoEe>mxW3an)z4<;?eTd!qDmT*P4){MC{giS@OJ zJ4;ouhM|Ry*s&a(!ed}1mKzhz@JRCE_>#t&_36eTkF77m0jtxRO%3wBc268`=c9dq z+`6t#M?Jj@bbffSF=?^0ut-B5@lLrtk@*5&hSII;Gxl6t&oE?YXoWiqog75s<2>Rh z*SAOR3X(QAw5;6cq-bFGgRkt(9CYJObT*G8q=6bogZKO_P=rnozQQLYym!H zUSLC2htY!o%h1kVUN!Sql=pHM0_{z{G_l?zJzbvP4eb&ws-KVx>-l|wjU_jl%3eNP zG-LL_*gxvlevQUybkdP$fd9}#y>JmsRXlK^zb+1U)ZRsRo(<_`>G>#=A=~?+sBho3 z;}Ck-4NE)`rd&+G3xCXF9?q^e&27;vH+yN>%wLvPQCXr4#0LYr`NJT~=-OIsOw~*5 z_b2y-1cNNqHtbKfxf|&4a!1Hq?Ig7$#w^{jC*bX9awT~R%c$4OHf25Vhh$&m%!oaJ z-_hhqRnw%IOTMekc$r}Gpv#kjhVG*ML4dreuSeY0y%Z46`NMK~!6p(-Q3vae`2HaI zaURfLFgbk8`4&m$tJg)&3{E+58g$N)bjc$+fcAgrrS|1~hF;|!{?T20ZO7L$(QyjA z*?884eXu+nVa(ZoWEm5oIQM`K@#|OZ1Hz06tZSE-mJDFh{m*f>@luu)FSNV=;ygCx z1<>km^D*j8+Yc?#vc{cW>L=MtVRQtKaCnL27^WLO+eI2ePjz*L2U`?Ibok2F;Cow2Caqk7q)Ar{}SQk$U)UvXysFMd6s+HAHNcT?9vHNS)h(!Bm9tG z)yYaCI{wv$=r0Ug4_gHJ?m+HQ4zO`(?=ZQe%T3a2U1B*3S@IwY=w~`Ip0Wm9rd)3L zx;&P4qW)xabzXCMK>xVBjGM7-(4459Woe}MO^a`yg2LS>3+ab@{1yw+DI*7cHN*~} zUdprx*qEdopjWZ+M$_whlL_ey^(ch z=-i;&%a*GBVz0j6c>gE*jprwyYrGGiPqf%?ZMXCZ}8QdyzN5G|RcK8^_n)(w~IM7cd@Vp?}6JfXI%- z2C~gWn2}cVEJAUYpZA2RHd&irqJwwzoWV`g6G?MiMqU?2;!DJ^589V2NkExPqhD@* zQ<1JRqCG*yLdUcnGyX3CHgP9I$pEwr8>U|fFcn9}D1(M_tOxC-uNYBP=B(K4aw&nD z#^+J&Pr%m`D39eVoD0-K1yS#29-79*j7|+Ut`-+1d;StafE3YUSQY3RKSA~kp{sA_{hvt|~E#v1<1^hs~J5+(mJa(s} zXSH%2&NMil7~ymHE_?_j{8EA#gc6U&Q#O{@(Vf;5NKwt#GezjWP}F=O1D}Rd$%~u~ z6C7fPBoidFl@-31*{V1w405F)Iz;@%mtA0xZFanDPHxYX1{Kgr@Z~fZ+#IUG&)^E1 zH4PgX`f?QBF8tkbKzuDTHt^_or$A1_$^e1Mfwc=kVMWKX6u|NkJzP?(r#Fg`8H{B@t7&t_>l^62o#$xiSUr~ljIogn| zyP!uSd3s+!6x3^SXC(E`fG%eB+ez-0S%DLn_!4_G?FSmZUNhKVb3oYcJfaeV|Ab9B zu**8eJS(>+sH|}<&Un|K=o2($fW5|Wx`rOFl{~)Ycab6c%gyrjf*ms=2%5SDpxW~XOorr*Z!|e%VkT4xC?v!Cuz@YJVLpnlO-VLRGL0C?DWDc9%pU+1< z8@i!4@iMt zWp=@9?(?Nu{=c8>m zC}UACZX#mXjCT{3wfuGIJRi)bC>(a7dkBm3OsD=a!HIIf#nO6$HP-1|UN;A_-6s$6 zzW%at8k4-X;a3)tCmhxIIZUj}h9^Tx9{7@l0gBDG#GNrdd{}ML>k1&`X??K2oWrNZ z$xAxHCQ%*h&eL%-Q5)AC)`O{N+23|&sZZOgo`gmkPRr885tBGVw;`*xn;rl>5UC%w z1??m{k1h>o)NN-1^~yhi`jWCi{@D&zx$(rwxcjQX{P-o+)2uD8f;Xi8yWSjLW$w1;TVa68*@>f6nCO?4t$#lsx-!*?!9(3Q|!l>L^N2rbD$FxTk1~!QuVN5=cd*NzensNcEuLNJ=lh>e*Y(mdU-@2a!{s+w*GkAgY z;OM))s&I$qZ%wA!f_W2p)Ao@l9#&q7$xn%l0DpX`#iRw>K(aeIhCM`{CW09IcRQ6y zAJ`$JO?sa8KlhhwzKFC}^U}J3wp;DBUE%26#hQMfkWtH!`5QbgSf_K$_dwg9mDhJi z@Ptt8VBmVDiZUI{T+HvVvD+39W-=)o4QBe?aJHZEfu4ypZ|1Iitz}v648prxyun=j zS!m_RsL|+ZZ!TVy7?6AfX7E%2Go@`Nh`Wf!<9a(?7p!g)YI3j+6L>@Ix0ut*|C>zmJr~dj^}Hm&^pOIg&4W2v0d5svvmT zF7j&7Os)*&2L5`*U$88dCY%t30$$*M8>IE%@W9T>cM?kJG=_Sg&Sad|F>S(G>4=w} z5p>2n$}EHB^bF+g@RfiSqUdoa+CjLBV8F)Q?!YEa_^_E*cf#UCvVh#RvbX=c7XiwQ z4H{Q`4X0MOW7WU5avamqeFi84IMdCI-FePzd`l0VvxpOAAsYy|=r913)GmzEvc50w z?X5ikX#{>R5lGG?lqzuI#aLw?vA5{M6ICA83t1uU0UDQ!`E6CC@kLrRfVSav<@svF za;Y1qX@@S{p1^<$BTfO~&U`l_i_P!#4udF6Yk&=O6iLs;Y#b>tWQ+km%aL>*j-Lmt zBQ)Td75QGgJBww-$^r8>Dq|Z9Qv7ZJSw6*n8!EebwF{13;ouzJSqeA#(3fAM_$#+M zKK1Mlh(=yPp`I~uV&4g5=4aAoV+Fa(I;bt{a(jc%d(p2t4dZY3Y_Ab}=TNtz6TK(L z{xZH3G!iZ^67yPkP@S(+>d5fJ7#|CxYByb-{RL zj}G_(QgEYnvHwiUkW<-8Z3ovGyxIZEanvJ{Fa}R&sWkV*@JM!iPJAwXV^dOPp2nQ* z<4D$?fcCxvQAXQNo-=H~ec`g!E2I3jaR$*&TRxMlmaf?kiqr9m*SyEMoXfv{$P-8Z z{D_7)9r_Um>)j*Y?6t5yA`L6+qS?y}^M}FQU0|Kz{aP{ zh>xSurVh9h;6tqUE&i+RM7w=o934)ZqoYH&FKO^w24u%FQ**V-eR>ewJrNU#(Bar6 zI?~v@FOZBmE;-B21At_ca%Oo%#^Kck(AoMzm7P6tdPZ-o+0Ihns?)7sSO-3q^LzC` zmWApEbTX-BgWp(xUddmnEV8tUY?-4+9%+sqeY_c89m<~I>!HwV<3p8;gSC%1fX(Nx zq_Is@*1b=eWsmYe2buB-$8({z_k2WuhAnG?`e^kR?}i?VPC7c&BJa757YQlCt9Bf4 z-tZoE5M@EX2Lj8IVzYd5j5Y#{jwhRFui;VhslcERQSiKQn|gl!~R6h_cC^Z*NAyFl|qb{zVO zj(*MPzf1w2rf{2J$VZ+zbukaOr$OybZSA-sppRY*^@5z4*WF-H4`NLV+ z58c3+@|Lfx_=1G^{9crO_yj_iS6L0Z;5*KGIBB9z2>(GpehZGhy;K;WfO5*YFx%!)tgAui-VkhS%^KUc+m64X@!fyoT3sUhF^6!oUq9 zH2LEqW}}@ne6Ga0ne~;xK46vvp>bI9rA9k4)CVI(eYeX`2bR2Q{Z49z+?_ypyTkNo z8r)%dCPu0V+5>RwhOZ@@_SKDMJ(#zS0k6Sm*bFD(B6K#RXEZZrV)bW{`IE{)el;R6 z`C>U=+6@)QV7OG6%+O)94<7M3H0$@tzefdQ1~g!atNuPWZ9e7feJ^?D5jRHKbk6cL z-t;;7CC3`qgC^EHg(lNQ1}V*q++~RJBY$hg|6;_CQC;qOl$vLxxt4Me7IW5;6ivQG zTzcmq+}=<`!@;3K=IanP*3AWHxEx{0q@JR<7!Oq;<(X%bI8 z%Yx<2yu?|AzZ1O6K0G*Pp4SpIrvPVa#?pdy4EYrBAI!3eygH4=jAa1? zvd_VH`Pj#Bz}m{!LiXn2E&|q@_K2$-`O=OE?*YpKGEuJmvgQ85GloxM_7YSuLFkSM;==(Ff)Bgx5Ru>-g$W`4r* z5<|(Y!jev9`H=WxAeoSLg=bzmo|yd;^}c+m4B$NL%JhKEV|V{o0{9x4G|T>)NiLSm z=9SE@Yc_0vxq5A7s|M$>PluYUU==R)P;qRtUc50^l@??9tF%P$!g3lME7!&BjsJ?fjSF=-f`$( z$~-d^{iT*=P4<&?N2|k6uFE!=G>c=FQQG~fBW2Gs3=`gi?+b*r(ujRey^3Buvs~}M zVu4O(hH=cAALQ~U`yum-I*@Z6Et}#6{G3c!o_T*-BKt;emxQeE|L%EFGnO9|NJ-4H zjk=1IUIcEpW81}59`^;S88DMqzh0ST-Fs-H-4}J~s|TKy9A~XFKhcNld2@2>Saw3w z9KZBRbMo@7W`1MYEN+U|`e9$OPp*nci#FX^R#^4K;qlc8@+UctK7*8PI}XV+gjMMG zn-~f%W^mIsQ|vfscRbJ&VXKgk0z1OQ*)A3$zDg(PpFaS&Aj+9$>YYOIViQH3U0Y}C ziu06p+tmKzMDMrv$;0D@C6K*jk@yYYJcHk%?FV@5z6Uwzc3qIqh^H%WqTaLMM~ai> zjyfGs^+!klZFli)XhL1^RL*<72+U*eL5MN4;!epSM`iMHiX1r{Vl>&pW+gIppgG;!xOQ z$tGW?48p7i5JxX~^;MFim&kn#NShi$}CUC}O> zIPFVpg0hv{pmc(cQoh;tu`=Z$U$Dm4tJVz!>$K@gj=e8wyYXd-?X8xSco&2&_KOaO zrPC@N^d;dsY~n{>%3t+c1NTYLhiX1__g$WKwBDhNEo09hhb@QA!;<|)2VpyZbZLD> zxaMaE+a|~`y4&=DmZJ&EyY6CF`$VqFg3=K67Vi%SbmJYLmr1timx9D zCdv`6Wn*H5Ea^Qz<_0G|sIC`JyqAyUiuXt(=~^nj!B70ePlV6A;5Yr2-Na;n~j}$i7koaHFAxvetpjba_iAD_=s0<)R!0vNB-+09inDNAs-1 zPd)QRUQe(-`6Jj}JP(5~(#X;%tNB&4b-rLzJ>6sTUzMj%|Gn*o-J8EjN=%tl%gT`4 zcR%t!`Mi&xdFhLNoZk#(P|6o_N}0j_XMgZv-|yoszlV;j%>k14KJn9e*5Rj~eW#De zOv^*%4V_?Y0$+IM2lm^G=ye}_G0!3#!u-G+elG8H_^03bYx1naZ}~$%k!KyAdS3Kp z1I;q2bgx&+W7I(A2ZMX>ed6E5#a-}Ezw>{UXB~daANtpM*5Ri~(|T(;s=<_xpI$ z2cHevgwi?hef`h-csD%tOvn|m@g(=D4?mW7?u@s7!;2o^15~=;%bxg{kA3{N-}P_h zS%=^H2me2L*5RX{d3&A_-a|fq{0HLL$D2R+$;f~G@sG0b{x^KW&+dk&p8b;K6iJQx z!f^*}5c$s_oXa-hOP`e9 z1(7wWyOZ94{I67Cdw!9-KEja60+ItetxiVfhU?~&KlJXn?&0lU7c|>&$ROYM`u+I) z)6cw9bxfx-96*mO%bG~}_>XMI`$gaMi*A?{SYG^nZ~jzX-5Edk;=7vVT1Hnc_cA6C@d{OZSi8uhG83-LVu9XIl-12x+h0#E;$?YzAH%6pwo+h{JsK|ieUer)4e z+rbaz zcYRTw-7gH9kN=@rCbkuqXgYMPTbZ`+DT z&%D2V7a-HFx6u#!P1O!SMhRg|=MQJpmq*KHc|-K7&X1MUSoR_6gwg0aHzd=+^Cy1f z^FH1Sp7}}zu4v#)EI+20pe=PEYrK!tE_%a1-p=1&{Js0xY*#)Lbx41(;!XcF%4HwB z!uyi%->z?e@f)}K{OAi|8>2Po5b;D0>O0veBk_=!>9~3Q|Epie2X=*b@TqsH$_u>& z$l|yBtB(G{FZ|B!cgMfx~_72bRPAMeex z4j=pXcli6Sx9R)&FU!4J1k%s>m;B6j8+ccEU;2->o7Xfaq9CTY$vmKq!4~D$dSVPfSgFesRn@UCzh< z;)rm{UbY|Wka#C-RmGq3QXOxJz} zLS@$&NmF&CSNLA4F#EW=Qr|S+_`Uz{JnQhIfAY8I+4=ERfBOHKXC40DxBhzlCr(i* z{y;B-pKS+sp$bJ${;oZ_-_q<~^Jli>{o(&&I~`y5fBwgL*5M=n`F8u@#&ayY1Sy%v zkkqlw@=bf?oBzhY$~ztY_P73KFNcNq`TS+K-M-~-{dhd=;RpW2cD%p)&u`1Y-~Z2k zTb^}z<=LCbrz*K2TeZw$@%CGH#JelJ8!xb|(@b)S4WRO>x|GS=OlmbB7(gKJ`jaeN z|LNG9EXzCGf;7s2>-=7Rf*9Zp9oEOv5$Uet7>_2hFK5k^<@IzQyCnL|)}H8W{|oUz zFF>z5^m$)s%LDNiF+wd7Nxnt?v`MW*1as})lWv6gFl_F0o3h&KjkGt z7t8}_=NR{hBcBSqlh;)ye3kU*=j*D6gep5MsTNpyxiAlM&BS|uWFSaRh!T5~SBA?` zvmDOhYCQJ#0mvUZnJC0l?#r12qI0Qu$CU?(1>*+tgsuTa_1$3xglh*`lGkxku8&>! z?gmC=SyPYE*lok{JYb`Df5kv29>Q@BTF7VyS!x6KaJnxguws@o`>F#DnS$BQ z>LYtai~h6jKf*UyPjpxO&`matXB~PRKROCl3)ZxYbvRpN3SNjNMuc5S`DMaa=n9i0 zkA{azBkNwO5p}{W!!GaaM@Ql?{R*et-ViCPMg?RLu90IcS$AAekuRvs*%#)DXKvuu ztE;*;Q!xXZGh0n)-t*=YdDm4-V}{)2Z@dQ!!iyC}tv1S}PnAiY_0) zcXLGTO=f5BM&wQTkFu~0Hw4n4h2fEHO2kNV!af}Wh9eHW=h?vREQ4*h%w*=psQ&&; z@ZLMDvFg2_^nR~{`)*(sK_NQxcFWayAP)K%Gvv=I3;65)wZ`Ed;1%?&U6zHI0YSQX zDkpxz)2htnIga@lIf%U2ogcfw%an=OZ-;%C%JpF##pd?J*^7dGpH``F%HAln6*xFc zzoCERq7f*)$_)7$*y9Vz9bnVZ+St`;KEvNGgbd0*^w@C|BZazz^znFic$J@syv2UE zx1B%+d7lB6>GkW)aP^S%@lRc7m{jCSZBE2&ga>mA^KVUJgT9_mB%36Dc2*gTB*Ev4*mMo{EmiD(9xi zavE-Oeb5cE0NtiM)A$%p$#?zy)vOw1w~>YLi_JBf@Fk0sx$ejbDPhp%)@NVzi*$_mi&ndv%1SCK z$~rGZI3tyVivWG^`p6BouxT8=;t!7N=W_Hb5UAk=4WI+1k4|`Qs?MjF%Kl#V8{8Mb zQhA0$2V$d}amr70G9cdjBd0{<$Sx80Mrqg_bc~^I!nU;Rz!Mh&ZbUgajc8aaUnJi+ z&sx+gQ6~fRRlLh!EwajFt%V0`i4Ua`GRt+<@yNC7M(ezL2W=LB9k`<1mg&hRng>}f z3fe?&7ulBR*^-wCzC2&WasUdSnX!Bc6ub%>LVP|)yx25LY*X_co>YGAi{ztRzY};L zL~J1;p;JY->$K=(D|xw0pethr?<WuoeWs2}81t|^<5 z-{EI+E$!(&;QC5sed!4^3V?9hb}QvKo%J$#t1>S8j(z&zFZ*fQzU8r=cKf#kF(D6m zZUT80ZYy6h0q73;QJhwtd;fy6k6rHTeU(Z7(&o{RKRckZOB|aMt|E>CaXc76n|Q2) z`G&qkPLl_lRDmubo`FAo*y(i+D9^3W39m;#zWL%b_Jm>2%(L5dr$J|P4Qv?-H)5wf z4$Toy*ge=M#6eujf2F~BjGqU_Pm&)4(U!2H&-F{vQM6Fm<6893A1s{Dir#ITmJHoB zjgYLece-38XeTUWb7FU**Sr_crGs+aBh9qXj?DI~bcMfe-4oD=`~uqm4o~HhuSgVb zgjXHr1!4~hd{*)$H=gj-Oni;c7qhCJLk<~aY5BOxKhv%{k*^X$Hjv|6t~-ENr_g=A zhzd}5S(`+eAZo#OQw!a6SZjYhg7aP1y~thCqUZEAFRT5jYszu83vE~QWmD(qP&GQDLTNXzlR&iRt3(@&%a*VcgwV={fj zZMn&n$C~LOle0xTbq95cV}LmL6ttNae!??_?|%F0i{fs`Kz!lSr(Yqm*c*8<5UH=JtZ#X&K3rjYjH$9QY;Y2Bi z9SYfO9O}83A5bN)f;7lZ+HTW&c~OI=lo4(;Wn`U7D0%0^uO0SkrfgQ69E=uSi7$Ix5>dP2EjVf%@Yf}%hRA*O#C0An9 zVH?Z&teMM|0&@QEg3?q!{_GMZQ+HaP=QJ2tsX;zu&r63~0!-mbJgtpEVYTuEBYVIX zCzp<3hVww>#2tdW;6f9wGv2pBc_>FC4B$P=oZcMV`ywi*;81neRGj3NXQ*I2 zq%+Wyg~%ks`ekp#dmd!rN_wjtGZ^Bl6v;D#EO_jq5&VYF{2%`qb2v7*=cZ|t%lG;+ z##MF54AzRDK^7}9!SC+QH}nRZxvfZo9C!F>jW~ zy?1*&zdK~~jvn#=%i>nZQ0Y73Ca>eTndZt%5Ac~KW)l@(#2NHrKWx@HrVF`CH+yAm#}_Dew^#mZ zWp+!3ZX7V%$pRs|@2QHcBi3wrbG-*aIQM^H<;xjFLx0hCxqkF8#WW3+y2{#jdS5&y?3)?!ydaXm~MaJ6_D0$pT|W47FSN5(onPhl18vZ# zqr1)u*DcU-M*V&nXzf?UWBHQ}@4BCBKpk}syWyg!c3AP^vSE1_7+AE+4!kzK=fz0& z#BGHkdilD2eDJVxy~+`{Rklyd0{q3Mq94S3kL%hXKS<%cdnd{gC-~QWxhPMmLwJ-w z;6c6!$Z+4t^t#Se7R!b~sk`h4>Rk{Wm@2!HX%EP>GN5C56Acyj{RZ?<9-t?d_=4`B z-DPIu4q!4;Ou+Jz+Q_)lVBOh53F*tW&m$C)cpjOkGTZ6^!pg8M%bYmx!qNE)P2@qV zXXWp_@m>tnLzJ_mZx^;`In(C@K}`?7NSh(TF2-o$~fgH6S%m}#MpnxsOxbZt-Dla+Wb$yK@t8`#ucaah3io2 zHMJ@1kAdT)KXsp;>XGs+`d4;5;2L{pgr!+b7Z2*#NdcNx${HkI>Jd^KHLNKUqh~Tk(&HKC|1; zsol%cmoNGreTPvGkDBSx^56oZ6n z5BuRBfJs&9x#QiAb8Lrm$w+v1CbJBY zgwD!Efk%A!yV^{q57{Z9vh|m-)+_?8UsCP(aiYB4k7aU21xImH&}YXC=Ir0u;Pr@e z@P;pOAjbn=`g03HO7+)CabCNf(;ZmOqVmLffWny`E;`&9 ztc)^I_nmg@!fm*`q;nX4XFt??9_X`9IfLk35MO`?y))exLM!~FAk)1IR@91%fo98B z-roxyox~CGkm|VS{c!p)8TwbQ#d)~gLzZ6*6$X7{;Fq|eL}^LahpBTt5V~F#nuJLC zOj#8l=(r2o!l41ppS}aGsKePW-t*BetX9&^v)eJqLYRw9y6y(#sf)iNiaG*!dO5>_ z-^+Ky=(q!sr?8q2oB8cqSr(K>*2^)NW#c_<{%3}he2A#X5>TFjfIYXr}O*Oh^iAj z=*`#5`oSLtS-_gTMA)-Ue06FVXrYk?FT_$@KsE{ToBWBaP`>NlMN#r<8gOa%g#(u> zvkwZoGhfW?03BFrMJTP%6f?g^T|vDk_L;g z?JcJaosFztpL=(Vk#`n33BK%9YHIec}9d8bdbDBaz4ibyci?|ESXeEPD~$ zeFCx=Wg0-U^}1zOd{aGDb=Q4|WkvFiEo41+K09t-?3!pby*Ba}nG-L;m^b$TG{QfQ z@g?PnJNU@67;K4rl~DQ|8$+gpGFA>UT$U|4x;1T9vx#ik(r2eK-Z~jq*9t_}$Ve^e z?boCyY^yAeWxrmRx0pSQf7*ss-_l03{*j&`9G|C)fG9gLnFoX%=zbeNC-}Snpko=n z!e{G~QP^ByOHPz_P;FDU8JV1CnNGlu^jG}wdFEBehy7sNUAlS8b}?V2Q{DF5g!4o+ zNa}aea=+nnZW<88vk_$xf4=g)FBDpvGSTs>lV9?0C-Od>%I;V`M<3h%pnMV!{ekoW zGeF2-pV|q!A2M=AC)*tmd4(Ooq*l544e6U3x@LkkaVqVKuN~-)=Ex55@# zEpE1DI@(t%Kc<;*@R72ZzqSpcdy8D0KTe%xNRoXdxfKC>OU z87A;k%bZ;MnEE`*I`3Bd4w*1?toMi?n+E#)HJ_fj4+;L`Rr!LBba_J=r)+G1dpxi3 zq1p7y`5v)xFUyBR<_>+<3`|9t=N@zK9!=sKgDsx40^L371HjmNCiqbBS7w`t>`)lv(GoW7qovd{4;QU!2L8|OnMuCh^0Wbw^ zQZ5fQYyTqfNMF*%@+Dp-Yfo%cSOo+j4TiR|pm8Q+J2IVXJs+KVSNtChbLpXU2qe0J zFAYZ11I0%t6rVALvSO`bFM%baftgFy;pZ=1{FO`corWQCi>~-&PEK*T^UR8iFje?w z5-2+AH+Y(9k+Hp6F*`)hxCL~|X7V_SDM!+{UdMEv(tskp zETh5KA>@m{5|JA!9m-_AE5X_mgEfjnav{ej!-RKnWX4)c7I!d8M{$nU2p4;_5W4;7(PDnfjh*9HZZs#KQ)B1&mazVa&BjbEfo0EpFvJh6%2C1{OW&ctJac!AE@I*tA#^%;LuK3}rsGL-{i<}5+c#0~xQ)UD zE$VL3bDjZ;U0@kIz9^}5>&nOb0Wb9}zHp8y?}q*gT}QWR z_k$-*RG}dMEd%?Z^xkrQQ|VwuItOYA9Z>d%JGR8f(ZR|Nuza>dHopan7^NN?kG63P z*o55``XJD!C-Mqg#r2r&9C*bbDIL3+pW&^U9Y62#;C>Zmo9kE;E;;uXH?}2JPL$t- z83TQEp2lEbA7!s(@Z8}4eFx>5ej&Fz%^%vDr@tN%Ejq%D)|Qa#e?1au&3ASob-j6t z4&D=vQ+a^Xi*g(zuC^Y@ILXbHe||6ix3oPVAYX0niMD7XOMdefD9Q7^_Ca4BA1u5- zXr3D`w;jdEZY{O7h12{cPwod&m-q_}$!smR?=P&ehx-iP6J;X@R5xRL)8UR>+YXnG z)^qNYmlIEzQ2y#X^hET5SkB;}!t1_z(;fOK95%$kV1bRoMubLq!ZC7=cS#qJpqC)l`XyLcTFU3DMac{ zoum6WTA$HhY=7{L@)$8z{7_J5aSUFJ$5-uwpYl_lgwlrro`-HCezzwXfZ%H&-Zjhg zOme|MA4}NrwG#On{V5ao-yy?L;IMhmx|x2Sv}HU2kVip}>W9i#{H^cvTzw$#SvaguSNb2KzzT=PPS%+Pl&F|U_|6<658j++A{jvXx61#3D zhcyD)G~fB>Ka^)3c5j9s%mlS8lD{BGJusR^1^P}J| zF$4=#1g)DE9e2hNEi?KmNj4VJZrVUZ6Hu5AFKM)w! zHm~1>pMLIr=8Fv^i^Z~e<|Er1`0onur=NSLL@szi#To;G$ppazakCR;N6=dQ2hV(D zdxQ7afAD#|9{gR8sBosu`=9)UeA)q;;WhHQ9)(hT`X6j>hW}gt;Qu$zI($?#8zxEd zBuQ09hYXtb(CRuR^XVUceVq63=C6H0|0B)h1(o9a-?+U=?o-di=9K1h;^`mS4v&rW z168>+&8I)I?QhrS^}F!Yvq~?)D82587M}j_n|$nJS9t&AyZ`Mx>+t5U`ILgo{2VAe z@#Xz*+}@D=qtCom0ucUK-j6RuetCzSzU70lX*qdKLyqe9lRvC?PvNZ}>^5JInR+32 z1$WZ-z+gtrX8FVqZu9ReKD50_-$$Q*Tb`kVuY`Q1%%X2Ri?k=-bCvJHP-*SUcONXZ zKps>D4(U<8BMqPUk&ul(-tyHSb6IHXSH1s%H*Ih5{?v1^IlLRb&>;UG|Do*-%Rjmu@9+4w?aeNK>QirM$+i)vlQ?8OXjvIFzx>0}SEsNmyq|gI zi~TNk1oe0{I3g#yWv1fVi7T|XDBpP@P?q|9I(kfUC{|-jc)75&SD?F1zrvm7(jL|S z$OHuj7I-#X%f9e3SWPoi-O9|>)iDF=J^2_a^Pkz)lb`+lVQ*yU#uI;Idjs2Do7Z19_T3Es`pJ7+dQV$l_>21j=oo%DsgJ30D2ao^lZ9aVVn;(}4 zo#fY`%szYaZ+CjV@a#9G9lVx5CdmjVZ`{tO&CT$`->%K;FB`EL{w99;4{XQl&Fht5 z*Da|-+!!~olS3PZZsv$h!*luF&^eW3h3-1^PF)Y0>2z$nD8iQYphxUEg3Zhf$dMZ8 z=%le&j85_dBlKt6*+Bdi9$%HMo8vccZ;ZYRU-UP(>!il;k3pn=IR4Jf1dB{KFeQ@8cqy;XkB!*;8d`ITe501`68Q zxcBxkUmzYeZ~E`ICwJ`%@9@*A`&Y`5Vyp1xA5Vqf!`(N-*HM4(`2Y0+O6=SW|Ciq5 z_8UO{u-mYS-8q%EG4{Ya{&iPx6)v(F{_qzh2hL*slT1ga3mtRSp)HwQ+-kn$C$pUQ zaM_#TU&P<+~uJES66y*pR_ui*s+3e-`>XowV zffm_XpuW6f&s3TU)r7+Da&}Yn@KAD;tBbU4EFj{R=<6iXoyo|#^a3_>b!-;GMsmg` zw&f6%tr_{wab$XJr}X0Yl0L#${a^pNkM|Ql_J@BHgjf%v_o_VTB$8o$D{Wkj)P&QJ z>8LMD@L4JEpLdzvN6%-5{dIq3dsF&do8jO7Y{u7X$2ttfQ*@eip8+&}#Mj-!Px$)A z@7r#N?b;0g=JUC+_9!P;C@}YR3AOJ9_{Q)37kSoUS9rHy%-Qlud-1_&c@}gt*#H@F zc~YKy(_j7Xe7}#s;|=$P9MD6@U43kOBFNsG;Xj{csO4$pndF5@3aPVx&-ZM%BX))N z4S#k!-ivI8|MD|*J{L{OjO3x~bjfl|ux^@f`CI?e$3Av$uK%3$LfRq7x4+I1D4z~r zV4@{J_FP01g*3RIj#LMpE+>(<^5k-K3c61`E_0+Ky%k^EwvnN<;YB)x`T~^g#AI=v znTQ?j*?yk@w@S8%#}hv)Ap(OdaRxY(Fac%(`~v>IGI-) zgUCS72^X?v^UsO%!SBT~%fIR@wX}Rb@CVD!v`EPR4q&OkKEoq>?3a0-$RGcPYQy`lym8`+=8=x6qXGHHGy8Ih-f zn9iEqdM7f9V|L|`DQZM?gDfawopa55YJm(yuZ@Z|hJ_T0++uc1t`pn^Gf&m1L{OZ$ zyid3~@O6plk@Iui>k#Q3Ok`ZD@xvoJOUY9gD$zN;dPRc5s4y;+*Zekgs9@;a?4Y40 z|26xJbcRED@byg00^EoiL=biX#B+b~b7vy_LD9CI6M}gy!pv@BjdU_-uV#m|25XsO)6k$5r{4U%!sZoNA62Kczchpsh;*RT0YqIIJ}HsY(K3}6p956Eve z*v3F5KYKsR6HC9Tk&hb=luvSz)_X_fJ!K-|iS=#w2RX=(Kjan#;{lfW?PhVJ%1YTW z@Jy#rMl3J2*UWKd^`GHwJ(i*ysNqhh3!NU>@v#>iKQe+7MJYS=wbV-C_MKl*gS<8H zwoq}ad`s@nq9lxi)IAi+&4PIfgc9_1;ol=Fh&x4h9;n{)K2+9MDhpJeXF>Vw0kiSZ z)}Ux1cpH_Njhw99wgCN=2Ff@x(su$CZ8^Y<20G66M@FLHTo(CBS%m>d{?Z8)x)rA; zCqi$>Mr-iId@;j2EaoqJHcY)o7!lXmVAgFv6zjKLKn>y+qSN)o8R<1|$vnk-NBQGE zDJMP{;hVdWUZ`WM^JF)&{*zi;gKISQWm~%D~x9 z=ox*dEzac2F6dqPk9wYpg@BZ@wm!t|k*EZn@XV-bXUmjs))69Ye@s-z;QD&HCAs1X z{sQddLI)>CKk`z6lTOIcdnY&M&Fn_# zviS`rJTN;s3`^=|TwgChNs&m7)Gw}oWx#eDS%J8!zQK8rMfn?zsmS|qalpp1oi&WQ zWIe<#D0xM0BA>c9d+*;PA`DKVyzg4dAf8%vayB!6&mN0eX}& zQG+a`b$k_DPP%7ttr-s=l5Q2Br3c;Mzpb3Xp`X#yJFsqU%9dl+v-C1`6lHA}Y>y~L zHT00}!$?->`%$NPoq3@!UP^jBBT+j5ES!Ir1~lpni3>Yg2`RXDnh>%tJv6%GR{ zt(`CbyuzTtoFyFOXE>gDQdBg$Bc#|jr1X37GQzzK&{07D17G%yr@b!;?}CA7q%Ii^ z)dp1kzeFaKw&{fS66=v)mwaq@USAaOw4LQD8FXV``2)Ok2>RA`#eN9BcKk#R_5~@9 zypG(~%f7!aTt;2aq8>sPT{j_bJnPYQS!mPex|(a+vO3rOuw$`dUj4dqUqt;&Sz|y^ z^-$&*=?(s#kH^(cVgl)6i9H)j<;-WF_dw447B+!w3pv#F{1)*ZShq|M*?9Odonxb? z9R@i(_2~*f9WDEy(oP+XBYtF?bW9E&7XO&cLcZ?@ z53&IA9)9YyTp;8f$Jg4-zBjc9@fkoq{nZ7sdPaM9Z-@}+A~sx<+Mp2Hk&`pqdJh8P zH9T+oMN-ac@X9t<-rEb7%__sH-;$4f9X~mE++L^~aIU*8e;~^IvfBB?S?&&b1-d>& zGdsMaV^Xda9J^lQj&#KBj6d_gilVZWOfo5k!E=MOYZ4j&c4!87w1dOdI?ItVKV zEde?;eo2#Qi8vH_tJhs;%fW}}(Vh-7;T@r~HFnym<1Lz(Vxh;Lo=!NaYWEWf5;KhejWc(@A{N zgCfXf(nrFM0PtgeX1qmeQgL_0z={;Rge^K#Z^R&rjT9LxV<}WxN*43m1kx!6+n(qt;8z zyQag+j{zsg&arbPpY9NpLt(Ko@V*FxT;aO&NeU00PG0u%liB#*ApMZfCNTzXdug+K z#hSdT*^@fLrr}5pyo0ND4CdhcHPrFL~ zG|G23!tBT3Ecmz+cX)IfP(WqaRu&fk9fT}rH)M&Q%K$n7?*iQM(}aQkexmDtCfYpuS+~yQuum!9U6z&It1*Vu&;AX44vuyUe(- zTjSKQ5U-u?Q~6DO5g`Xp_ysDyO_(pPFsMsdD&bD~C)(uqPMs8{S+qO8jdX4!Qmk<9 z;7_W;E2O8Jm`vP6Yd%VLSwe+*fg*y|JCT~u9j)A^lg?`8w{B-%@K-hF5)A @;4e zL%EG|5#a#xaeQUooV*n2N57A+%J6PKw3L4jRL6Ub@=2vBoNu#7hE9|WzJgiIdU*tW z=ymiIbctr$MM-D8u6&o#?arP%Y()FSNvc8 zbT9bNrEDtcb!@tT{2WRDTxXzi*c@KFu5!WTu4q4^KZz1sjAgB8>qLWCp)ZEbxH)Q$ zj`klI*#-9e8BG+X$_Ki&28s89TgGPZ1{vhgQ!!?Dug4i~=OIZKA_9d3ib zTkB;Q4qvHLxnFQ*?FIIct1x5p-E-*X$e`YF|9GR_ro6OmV`e$KAX=$`+D`sayT2Q#;~(vdju&?Yc9AEx>0GX}QFNX9)@|U0^sw@F ze5iQUUSFO>ob37L$qITlVcBnqTkJL3(Xcp{eIXZ1fyY;g)tT%vO2_C1$#H??Sc0TO zYOpNYB_UDeD>@TX<`tg%hHOto*mR`D(n1@N+&8%Vi68I;+9p$$(t#!LR_PY`q{&bj zvHz6Os^g&5Y1jQo?GDJF`RsB=+Q*&I@;39GpXj1Jvyjd6g@fu%@f+9X`v%}&P`^L0h4Yv)L-`=D*_WjTX&t9L+OELC zAJM?RCL3QR_#A&bh}l!$)NcF?sL0^+4$YQz?I;SLz2{E0+iNuPA;y=@OpCd*YG) z6Mv+Ow>sytM!s4X@mTjoZ=u3oFi@#B7W`eT>1#ih*La7x#-g8aNQW{&cN8me3Nc|S z=&&nVlAfZqYn!LPI?cRe0s-+N1Fh_d@7N7ahw^&WDD8x+_f)IsNF9|nWzs`zIAY%m z5pi@VyHi;P@OmbKj#Z(`!LZSY&xtDNNYMT`um8KFH73X;x#b+=D(~$Byvk7luVzaB zA{fn0^lHt758Bhoh-IL}Q$XF3&8$)tMrJ*!P})gBc$OW;iyQ*V7cm}KY0}x?kZC+E)*Vc9|Sv7ZM5jS;ax=tz&=SNM`6(WSz)7Cj5To(bp5 z-wLBkR}>zd`;wzv@i*bwxOrZ{d%y++-%Y}k)Q1ejq_X6*8ld|E(_G@6L5+#Rtd*Jg711q@Ce^(>E z+650FW!l>CcOuFv?rt5)`+#zxz(idv&rk;2y@EkL8yJ#7SF&exB)fv9gG)bG_NVkj zA@s9&rz9goAxAqPe-T>nE&ivR39k4tK6p-rB+X@D+Q5;nS)*@l zJm}nV5@~Xp%jvpk?P%h?GwAExr(B#p+p-td#&HLDgllO!3*nJ8SGu==juR@BGDJ>; zK^EIW8}y3!6iNJm1H74-ZLuxy=ZWW&3)8qjCzk}Ur$ z5j8$|$O9VtLo!MIt$K$&B`m+Tk*ebk-krg}GvMq=T^fK_l%ZH20r?7==i(`ijQ$V) zz>mtCkhtT|-Ew(|L3HkPVVl=<=hTaW2czT;A35?@FGmkwjjuW7=oCMA zC_5}wCIS(2#4Zkq<|;G0P}ICSA->w43ddv@RCvQi`0!fwygPNAh~ljrcN zttLJ&3Bds{VTSzyl!tP>6OH_f>1PJ2N8@V>p0c4(&*1s14VFBYZ5_l<*B^PE5A9e@ z7df4)y)k=PdVVM=!?{dE2NmZr*sgM&ws1Sc?lhK)gSsWXL@95NsP93M-_XS-zFKm}pp7i-x{&?W4j5e-orae4jDxki zqtonIy83172);y|Os|N~L))09kM@tkV}0&sw7ag^ALupm5<5ZXtb?>CXroyNTMw(5 z%`8WyZ^4p)(%anTfp^hzF+M?%#Aw~!Fxtb-iogW!lntir!xwDX+51^LjNxXeVfZH6=U6| zcXr(alU1hG{0w(1I_;|CF2W3y-4IJ@4w~Z|D%X@X30rOQ?7A~`$#SN8^%zNrFCcvH zMERp1{Y+s`g&hvvB{Qw_0edy<4Dz)<5D+#caZ%?o$bXd4|o?|5 zN5riVln2AHWcVCB-HA-7d8D*ke-+J1+j-J^KhWlH@}#J_7pf|44wG`OKq&W>4**&7 z7o(CdOT&^nIPF_`i~F(}^p2Mwb)ACDEmfx2R~$WnjAnUH6d$83po3^{BiG0=X^SP% z>OK2bIJ4vDEQ5>L=k5Guzpf{fhvbd&ST>WK&I$MM%IlN{25$}>Z>28EQN$So;yeil zZ(?sY_8%ckT$KdUNxJk7yyB=di#dL3f4uTnGh@{N1`uka&9avso5q+fL3ny-ZYp#k;9OqSZBVTmx8 z$$T5V7x-vSsH8ugj;loHk0n_ya%P`Wwyccw(TtYRd`DCvN2q6J zp3sGn*C89>csbH+7@`jF{w#uI#Df(qsWv(|Y9?31ji>U@ zphO!{-vN$<-%lG$o^)TelnbN)+97hGd{8X=g5}v5TwuL!28KL1G*e}(f*zxjbe1u) zd|k(IW%O-gld`+PgHmFA8G58)exhsf5jL}oiv7U%Zc{}x6&^7zANoL7+EByE zj}`tlNKd=`RhE;BAUXs>KK+^NIhTezjaVX)3U=ns>$ARKH19mpCU+K3gnssI=($~} zOc%`O9v|IllK0~nPA~ZXK0r?^vn?N9p0KA>2_-r$yU-cf^``XZZ_<8;=%}E9>1x05 z+AZi|U}D&CLA`JXz9c<(JuCV!9>Y1%KI419P>mDnt-B2LCGY)t?P~WIBjbbUq<5Vt zc`m~PCe9E%X@~-%pc|Ct+CAaR}jUo=o zRDOFuk}fZJ%T6-0Sino^$EE7|rOq?zC~Zx1@Gt`|eO(oAJKuWgljoD?%nh2IsfALf%s^#6!y;_)D5m=1gRV4ZfB z$dR}H!blE%?614FK|Z68JA&eHHty=-K7csy94|Hw{EdO}@XtP0lx^34+>xBO4M)po zxTyblo_glgB%iS5GtB8j*74LI>qF^)L+Ro( z%4GvxszcH|HsgSf;*Bg>9nO&uVIsR%tZ;bq`R@90Clt-qtFaeSU{en62=R_G92@qM zrr=eSbvl{Omxg^oUco^0tYher?2XiCFWLPs1;tlS8X}+MV##0RXV6TJa&!DWftf$Q zX(@A=wjJ3r5sqfQDGzHY8v29=!5CKnBaM~j(CJQ}Xz%oJz#Kzw81as6IcylGxt`q})ww!5c~Nw;X+LF{ zj%eDzQ|af&?2rL}4Pd*bLr0a)&Jiz&bSZu5e9!l@J~|gH$(9S(cjlY!O0QbBATNK& zE3UpGKNEV#gFf`*ow9q+i?I2ra}^&)cRVY8*SXLK_4ktQ%R%3+gd$S~53$kGjyM;T zhaoR&`zSE@OdRID>}T8AlJD{OusJw-+~s^UX26fHJR}Q_JNRMQa9&VH2jVLS&f<>g zC!dAT6Lp`}17u^cR9u#~_=*ABr$XysJA!hC4D&q7c`R9GI6R&En(*U(S0;%IKX^qyMR5G%;O7b(J8C|=rK^E>awPrtgr7nS zgDsY;!PHC6Ryu=Udfx+XI8Nn`-wgkM`^~YG6uNV+gqIHWU;|+?@W`{nmE9X!M6u?ZMgq!f9x-a)}VPYSH@0O&Fdf9 z?qGTL^9&{>Yvi9ihJT|Rq;Ta;T6O7+iTrP|;?r1RG@{c~FK19-qXWXhk?9CIo@g8f zhBYA4Tl&YNX@x9|2teOR<+dvk4D#|L0uh=_dOMK|rNV4JW>i!fD0KZwa(PUJv&kcb zZKrWcIuz$;fB62-5PIF$CohylMy=PmuZG*$N~aZx3LtB1kFP|+7q@~R&+gcSf7fRC zPdyhKjm9b<>t=GLH*LSc*EDe7$$f+%{HbTfd)T1hDIeIByEeXm^Y8q;k9?J-|33e~8@4z6 zed_t#92Gei|9~rIfn*>r%yMO^GddJO4YGXl!{?dpesB1#fAD|Ivkp&v=8MFFRQ$Qd z|I;7dZ!_p!cW7u z{Gsg){P)FMKiF-EUFBof2LAu}yMIHTb$H7MKVkV`P{oZNPzuzCD5DI>#kJ7t+eG_!#lqEXPw`H zIDY&`Kj7p2#8-aX_U4a2{rua!JS3A6C?DYC|Mjo(aTArVcgEYl>VIzQRrL63v1~r@ zmS^Hd4^MsOZF(x5E+yxNK^weII8XWOOII{NdbY$K;Hwk{S|$%g*YosDkz>2=pj`a5|kmLr=ftU#YiC7%wE1hxfu{5!g(4=SmDFU{WF|+kG?%UJVbfG^^VT zu0+SGCwOFe_kYgmu+R5A*bH>*@$b9br5--}``IS~iX(nH)owi|Sv!Tp7rx9or^B#$ z;;(OS_}=Bh`SH1LyWYmZ0lWXPzqW15@7fIi@VWQKONP=T`)BF_Eo|br%QCFd5l8tD zPj$*{(-x}B7q?^|=yX0?s?OHCWS+uhVn*!?$IRjFo|VB7A0?sr9DK#w0oM_}8`@ z=KXZ7n-k^N^dZ%)QU^6|@Z^u4PnX>dFZ>4-WayE;qdg@UuR?_`iBro^{x@ zdHvOA-q##VuZn+>cJ?Bq0|ma#`MR2$(v@%grycJKyTZHv{Ck@I7zbg!@t<8T4|Z*a z|L}8BpDk=JgUFlOqk@hN^z`fh#dbPg_;=uAWZ2DHbSQ-!QWv?SLie$w-}$do_gxZp zZH7Pkg=m`*XVgW*=1YDuboIU9=RdHi59l;pe(}%dRfoe*{aUBdHld|6JAbn4S19b>TtC~Vi49xL%oq1910fggJJ5ZW zT;fAEw}0KK&%LC}FP;I18K)iMW|ZbS<0O?wFT8%5%U|_p_+4aGWp+95Z|a?}K2PfM z92`A)-N*ZhlNZA_s*XzPAeM9owds4=VqyDH*ReEi)iK2#4y&D;++Q|6@}b|X7#TQM zMk_D)LhOTo`A70;hkx(~eq)?CZ^CZr@=!v~M08NMG4cD# z6KUM`aO(w>uILb}pdGvW_k7>>M*6$(cfKVzzK3QX2F=wcw)>J^e)c6lD}N*L=l6c! zKlgbbJ2%6BF7q?lQ}WC{FiM%z2j$=V*MHpi`?&1Q@GpYz{oiMPB>l+j_1ACn>gH!d zC(w}&yO^-RvC_>xAjnr;bA&Z4DaH}~g1+-0K=z-plou-jcHnoi=Vd&nVI z3=oE$sqoVHXF$;pkr(*xxMJ|u=kc%$PpBo#SOPcl3jGtdmi1&r>Tr17aTK`ccp`o? zBH{X#u;rqz70zNGz;bJ*fwg}T0w&cI`rOHGUEQc z40FSVWp<##8!e8ixL21aE1N*SXnL5)rd2%CA+;Ynt>LL-xQf~B13 z0GA(hG{HU)h;|r5{F7wJ4v;h>1!pv7P)6r8+}P`c%wpEYgc){ZguNx;3l#^Sh$#ak z*i?uXBxgRJ)4@l7!VW#eAyqo&>kO8$iBC1%5R&uAW36q_EIx8H#eTZ47}>d{Y&4*t7XfWaYjRAF`qP}qlfiy-OO$-n%T=iLp3A{WsB4x3w0$f z?7^U;Q0dx*=~0#`>8S`$=lpR^^)&mOboc)HnHg)bF0q{KF-MM5m~*}sc0HCZ59p53 zAu~=D=K=PTWW)73&#}XFUe^q|Qr^?(c6tftvf(H*Ub%jwq7O$6Y3T;jd)0$ygM9EZ z4sLj0qn;yV_t^5Js^S$q~Ky$au#^OI(Etab){QdAAN`AY2w$%Y)A_an6_94>)a z-*#|0OPSn-+Sh>iaA&n&g6$EuL`w2>HOi0L1e5Ec=jvSdk%fIgIOXmFrz>V&dMS;T zzPpD(=efV`vo~x~IuR(7s-cFmg>=p!3vhmH)W5p+k7F-?lLv4smH~^|k>q9D=5XCB zf6y*>a%FX@FJ$VG(PEl~2($+e+$ z+oYLZpEi>#x|Y7JWkeOQ{6w8kyiA~rubJUx&_sK7tTr?gNNK;8+W>5Z)?#jpxYpx5 z+M`Z%mT7go*6&?@gwCRjMrUg*ugShp)Aq{|Q1b2$)B@p`djP03c*!(R34*dME$oDFY)qco_i zWn0$lgjYL~eh?*b8_}nX*XW0Fag*1P@)GAu>|4oL$QdCaFR_h9=``Cjc-b22KlP@8AQUKEE&?#OD~#s-GdK4@8qC#E$@e)OeeY{=_5Ts2Yeo=eH9az z;cqR)R`#)|@IV!Hh`;u7;KY&P3c;N$3qIv}`KkNx3i>n6OD5yvS z4{C^x$m3-*M@NVzXy?9ptKXOUEV%R@s{C|qaBP{aq7lmYQQzkWFrJjR7+CX{KgI0wkkuio!O`LaCGg%p+LkSWH3>!AyP zFIaG`vZ(33r{LxC%uD`Kxc0>8ASxmLc_2e>C(y>Ed8A4~#`$=_9#D5e$U-RLZH%Ya zy!4uty~+f#?6N>S;v*Y4)>0L<{(BPY_rDNOYD^Dq;K9_aJnj*#PFA{H@m?^z`-Mn% zUR(q!8#u~{agMCCULR4$RR;3CR^Q7FRUf)yrt<}zOF1{qB{TIBH^X^3x{(@t4E8Zo z;x)jP_%CCnzGC`9A;e{EM;U25ChiqV8g-Oi&p7U$LJdV0qNPqk;8?*<8hsyUu)zQ~R&E(oS$}sgVHjGZIagwCAh)tG*kI39$NN3Zd z&60e<$=+VxQgcX-53@NM44SxoCfe4MW_&RAGGoLUORk)O;#JD=P85;(cz*msbNot9 zT2kYgM%bNo2QT*BeqgCaf4!~zCN9bwxx5z;R!3Dri`)eNam*Zr*Rj+FvQ61VPh|aP zVOIcty^a9Cx{&iAi|neC&&`_IOS--#f43Fx45L})VmWFK4`V=?CBz0SOE@P_cFXTY zQ0=CY`NbI%o%RI{adC;%ivG3oSavI&x??raM<=m|P)thS3xfmcYO^i)XC7V}BF(!{ zUy;*vV}Q*vl=-)qBfr_%wF8zF{g_-y`IsI(>irrhPrTwzB)JC(=qdUy0+)A(LD?5y z&gjgHc5n`6sEl9OM!0lj=9wKjSDH+x%d_gt8@E+&(k9&xW3|`DY7=@aeWtY1-;*nu z7z%%Ub*MTKJ`f*u^DUjmGOz(NS3gU_~kYFSFY$6&L#|up|t14)oHYXFFfMZ5I)~&Uya8+DKGZuCR0vO$FO5 zsqZ<`860~nbORI7m((BNyjWS-7h(U=DJdBfoo7w>uzt_7C5DQ}+4eD?1D8XwLQ$Ch zqKnDUJ0R^P5v#TrwZramem4+~1$YPGNy%U2E%7q7H`K}rT6$E1N&|?i7$;}5J+tt zJ@*pF+?2j%kf)0|5WJ(^nFB)UqqSvl=3VfL$u8Ip{wZ$a#FmvuUzbhGfEi1RyPc+c z3@8t#4=D`#tE8K~1ionEOBA1RU+MH!#2tN##Ls=5VeBNFPiATIRhS$+ZfEFr$WFWq zpM0P^DqrTSSSAiTd4xRa$)G>^PDchx?Ud#*bxSqB zI}o!YDWp=!I%m*r7p$yoWpWYs3|{5y3TEaZ3pnp15glZ70&`p~P&&#Jiqt)%v5yVq ztjcR~#z3h&*|{V7ocT>>NaTg+rfkUVf@gIo51V-mvYg$3gHfRjEx)_7Lm^3jArFnh zp=?-A;Ay7C0FXd$zl}~Yk$aLKpJzJ1a3Jn*U8R2SsPfS;ScmRD&+Ov|0Hh+E%1c)E z7eQ3cnU}s1hkZcYq2rlIK;cIT(CCz&mK)kg5G#kObhATsO;Jdh>Bgmfxls9HxTHjv)HlC%w8I-$I=Wb1s@Yj9FjM4ESIsrN$mzHZAx?MdK zd$**J!^aH5bm+bZSZuqdN5L+N7G?X7W{FHR2hj_eUSSulc+Us5Aq`nom> zwLRc?qOlZTyvA1}P;vT8moP?&eLutoTcv)g(%%b=Y?nP5le(zE-3NmKJ<)oaJ% z)rlHqD&yQ^ZTRuQ(49(=PiaS>D|H@?FYG+h8i(;w@G(-;(c}q8ERjN|j|}bmGT3su zj5zLXxRF-Rlt*-KUp8vb9)K*iohbXD%D&w6YPcF`L{{uPm~vY(#rn|L(6XBsH)XFX zE;)bpKf0oL!ybyknkXO9kt|t1I8r`PJ|yFZk|()cplkqth0a$`wXWVyAPZeSjIUuI zhbM;_^IBLUph_3?1iWICu23r#rxHej*&Ff2zs@t-!26Tm*q&7 zvT<-1hLSjvZAjA$(2+K}sx%!wW)7AP-WTCl+CzNtghe8_G@KpQLT%2q>Lc>x=*pAL z;Su^eJ3Yu^@~|h@eQOz4ySuJTs)`C0E?HmrHGzAA~k5R@NoV`cu9 zO|lK*QEaq3&za{B1XPhKbHR?}Q6=i0k!dFXPuNFE?aq?}J2uDnY8Gx8Y7^`a@<`U*0rH1; zEf?lRq@i?MyMLN~^OF~KkGK_{^qL21bRPDeDjeRN{_~v1F;_j&xWC zDX;LqXTP1|+5LifspC*~Yw+2O-iGsv=ad!fsjMf>^FTkn_XNUn6w*&}^%eORM5E;k zS%a>NM0^IHndEHyg8`S}rVV^I92`6mG9VW+p__6HLXf~Qv)Rw$^Q#Rle@Mh`n!U%F z+7zRb5$6YfX{-3cpbZp*SJ>qp-{}_}Nte)eLce&qskDotd?dJOvq2394 zB7!K-#E*>fJoH>#@Vxx#*r!i1^K+jlVdxHNV{%gHknl%)X2W(=*rV}v>AKgMma+xS zC)?0TU%}-@PT@IUu)DDd@uxg+yFF|%1o3x4#R|v4P#l2Xz<5gAHmrU#80Kx(vl zcA)Yw3>^vw@rzFi-^X+`p1h{792--y2`P=*5ra}KFCGAt21LhSd%&j$c>KH&A~%gn}h4S_oE^2>^PS@lPlsi1vJtC@8whP;pn*a01|xl zfJTOtg&zaem*in&*M&ew*doJCr@va<<~2MlBm z$t~A+>QG1ypDrh-;L45iK-%oLbMTi6+a0}PB=YYO>|s1!j`RZ1Na*M(*86bAvzh5A{%6HWXgy zT{b3`oJv{7l1H{$V5TP_f)89U*)nV+B&btAn* z!v&`@;=zPySh!Im8^OjtWr#r11tsT$C!P2tQ(|K{3}SE|9RXdYV=VgIn3yL$L(jTj z&cev<*GbX&CSODsQMO>hMZlEFANj*kmmYPM&bGe2WDr5o7zD@pY3RQ5DRs@c20``) zlTN};LdMUlv&qLP`v#=_vyzeJoDP;cskr*mVzGXunH{UFuo0!4Cz~iA>3`yD^$=eM z#2;?P2amX%oChO1GL#N~NpprB$=AuNf#gTF*~u#_f4wn#dELxk8R;kw_rzurd>Y&L zJm^O|B#fxNQE932;|?J4$~q}!2>A_A=1V8@EM+L=F20n<7~aO=!PH-^a0Ijqm}JBt z%dDNaqc9a0of&r7*0@Zpn4l!xITxRB&~Y)uS1j1N1NMA86c4zIPElI0A17*Go(Ds| z2AeFK@wHVmx*BEleq%DB^N+0LU*!K79jm-%k0DU&%%4W>PvaT&DTCJaE}Qz3j6|(- z|A8(GIle6Wy!5x6>)P$I2f`+Vf7wa)Due9-bg<0?(ttLlJd;6@rhB4YVZ~QIrQ@*% zB)^iG#cj2gdh_L$i|6H?6*>5FgvlAlmW|;EnpI=oLL#+gl^-WJJJm59y(*0Ji-7B^~x}5-#roVveC~I zQd*@5(%l(pzQmL0NJS4rH|-RzvvbyEHxqonVSb`R&?(gseg^QH{)@UcjmYU4vlp649KG$JVV12tk=pObJ=GgOS;ceXX95ErkC#7V=Iwy%X2GDjM8R8m3{yZ7VJZ4o0dVj z>}$-|MzSLT{oRDc2K|&j=PMpkfAIAZ4qBMlHCQnT9$IhhzZw2-{)%tOGn8s%wnu=t zrp$|h^dXH7Q&31e=@$kp!(pnGsF{?+bkKa)pZiaIeLwL>{={D+%`GTQPh9<6UUhip zB^nxekry*kbItMIUr zQmgQKbZ@I8}EDk7xJpZPd)RtIKeAr zEX#!9Q-xV&Ib|R^6@WaD9zBMpVIyNcpYTTQ3Glu*+<$p~>ND?*ld<#LfA7f(G?n_XgjphJWWb_IXl_s0G5@*?=yXLI9m#qTmwS(LExD(u?OeqVg_ zGbtNF80YKe(?9gZaifQ?_|W!dl21MNE^%WdD#C~h15JNf83&T+qMhgbOKi<>_ZO0? z7e?G4H1B`?C*%Ho#795<<~$QzHU`c6-gN)ted_7As{U6ldiEk%E8b7%d55Q-7JVt> z?)1^$2j059iTq{bqn~+0oG4F-6I*b-L=Ryw>waeQ``_?%oZJI`>XWbE)JFmhX&ZPY zGeXrPag#F0=hoMKhkNc=5P0wOvXp#v3-~IKeaZkE+t)kht!Svh!jbZXj)j<*p>ymV zomS_hmsRXxb_-o8sg?0LT&qzTqvG+f1!3uS*$N3dpU{j^_ytoOQba7PhP6VcF;Dysx;3@OVGAu@92K^1BvdW zf06GVL_8$}03I#QGm%p}It4-i_=mpxXuze_A zMx#aNOfZ4Jh8`+wmy!wCZ73PouWRWPWML>h%2zH7u&m~4z#S;RQ+$`}lm}(pish_) zE|aRg5nTnyXi%5zq1v zG(`(+0_+C2LH_8#vU?|VW~;m&(Ackd^{|>gIYIB0$A8Ml%fjJj-W4oTTq93>BU$LW z%twyWPcOgjU;9}fN1uLoGx3a6*`&yue*6Xf%IEQ++g?khcX(B9IhO8PHuR6a{Mbh$ zkRGl*|7F1sVLc9>E^jCtbSmwE(NQy&PW#;B|AU`h79M`?SG!$Afwta^uT|)9 z$ial*OAtxk-hS(L8J_&oyBwBv#Q|JUc%o zzx;tXNtrKu4^$n~wHt(_1!|V>zV~={VeqkR3-qx5(ruf3^z-j-X)Hv0o$^eXM{jX6 zXk~MJ+H&CJ9Y6159|s?Qx9Uk`KE7B5bZUWiKto{V2hi^_uvlb0S`#K{Gy08N{sgubJ^l${h|hU@&xM}$*Z15!TQc5@=aly1uB=mcJitIq#v zde9m8YVE62aJW9HkOJKAU{+o`6QVi zN0@vWyOh2g>Q{LSJ(THPo80fh&F9m0$&PGfhK_vbZ#!*4GNanC;QH&f^W&xGUP@ZA zttE?;5d~JViT$z6eo5}SFbRaaE4&-e-E`DdP8g)S{<`h7y&`|0(`(D-p&gsoUj(l_ z$Cp0TCEMi$e);G&M|&lgj1%0Smv)K+N`I6Q94c*k_=t{tb;lkW;n($@K-xjR<^QL3 zK$Sbnc=+fe$}2hr9Z_Z1eoaHh<9yfKRo+Dp_5pg%U+;{AuPixhUDHOSFx&E*>DD3Y zXr)8Cv(qt(odoyFdtYCbtjARc56b%8-g`LgADuYNL_46Td+;vy8DIEIKj0oCBCMedf4&ys@mMm-=J>&0Y`L-Q zeI^|eb_`xg0`xq1uvp%7nPe}Qh02a)g$M9}=r|~9jqUHGYNnD0_;=F8gRv?K z6rx;h#!fyty;L4D=&j^GhVH|ShCBI-e#wcVa7-U(kC3|zp*%r!5$@8dyd)&=h*E~RuV|Fv+}KpS46?vVbT&(J?TPACw1UfM zP}ZI~nq>o*u`0dHAdo?G)&{2)23+v5bI6E!ZO))n!#LN?^rU}ueyco<8YxVVs;gYn zpmL*%clS@*g+OKLy;-tis8odLs&YAU<#!Qy**Vhh2r_(^;lNsD826x1dOPUhAbpwc zGElNZSsSXdtWN2DfbNS~50XbY1_Qn6ZieY_%|ibRr}Oy59aq4VRWi_-2!BZ%vbtMu zTskW5M0a-o5w>q}V|UCLT@0|`?BhWZ$kzw{0zo-Dl}$5X!UbjCITywM65!B?hJ+~} zYDTdCF=(ONQSTrZx@K@rVzXTG33blE;)&$NoqoueWv&BPu&tzTS%dr7H0V;>8^Ksx z2H7FPJ>)nHPUw(+L`9%#C7ujCA6~yEceR;bnWzpV?#`|u#?aSc3q_DoHvH9tKumpi z7G?~xI2BL`UFbo|NxbDJqLcb>FjZNWz2t_w;(|Bhw%tjc5os-(geAkmR?_`^qznF~ zOXwa0G-+=ei`&a)!M-3KsKJR&d2#140|R_H+=u9878VVxan9VmbXW$IK~7KPAw-Rl zWAUAa7d-S5BeD-_)B1C5UcV=h1AjTrvZf4Foe{;7jqPRM*zA$qd$N$yF_(S8*U>n> zEL$-+hK-$e8hfqKrnR&BR^#eGcF+_7m8>ZbXlPsV#S_z`dTu?Ns{O$iwZR)4e2MaN zM&ZVrk8qEMES8nX@qeJB;|Rwf%lwtG-O@|z4`{`8@bXa ziyQ3Sly`g2!SuS$VKVpqEHFJ7H`lK}EcZ||n;+ZNAPWO5Bjio*Roh{3q_iK27Yk*Y z+86_wE%7|;m!K=0XDs$QP%jHn)}!7xzql602iK+Vuh^bC3$&qPG8=kWHj3H?9KmR$ z^hl1;d!wmr1nHJJ1F(u|xQ&M0=R(PIfKqa1qNo8J2M5UVX7hKTJ#}rH+W@!RYWt_DEUP$^L?a0OWS1 z*}1M~HKUrc;`|^^=MjLI?lfH7z;Am?jtP^o=SXZsO}y}uqxGiaOB+Ym;gAjLRCtJu zk$lcDK^)~5m$FnK%%T83M8{yg8HoJDo=JIETwSL*eNDuz_pv>I;k+aOn=DtJr&}+y}IHTMskK0h=|7k?tpbL67dRus+jB`zX|#w*SH(U&7*m z?F?Lb6d``sl?eV-B%yJ@st$ZXqI?l=8DwdpdknB}Kgu>`kZ>Zui+<{w7S2DVUo^9n zn{V+?@o_YNeVu&JUA6S|KR6Z7IpCSkgJJNo&aZAejM8)3iFJ6$N)3!Q$vl6nx)U(jNZ4CE>^(;DR41y(X z3es7dzYUPrxN~%1W8m1iBO{EG+TVs)I>$9Lhg3#bhGNesYE~7m$Dm@$hmHegWM?D5 z+18^QqlQ5>Z$j(F2@Ub0<^IE!3(F6QCYD%iX`^T(j~GvC@LvSvVYSZ0wV9pZyoy#xC=0PJ)6j+NCv0}ckh9(C4SK=_We!8j zY4+I)y{vQewTw`XPOtfqY1O%-ByRtrzNkSG+hX$IhM4?DndMmeI^HU9Rs-TjPX=rt z5_d*zn?Ujy^@yNnQQxahLU%4l&0KBbB88f1p?Hl`Z95vHJ1_baxTEq|8nN`j_ z*diPq9W)1rQ`yXiDkEbRx0B|Cj#uT;baL2?r5_kz;VTwqGUD7WwZ0e6bzD!RD=?TL zGgX1(nK6)o{s=mk^UVoKmw~bJ1lNLmQ@)@t7OV*_d#al)ya{OtlT2Pul=i9GcN~GU zpMQsvH~m=dcXYsvN|vD8UBLWB6-~oM)Pp#}hcPjrqay?Gmy9SYqLPL>XUZVWTA!&PfJW2-_VjN{a`s z-6jlLhtcOdjqF1>o`mPt%r#r^O`(9=PvLS`Y5?H4e+g zMg6!B!Y+??DxJut+44bNg}rGV2rZd^`+!Nd?r(rk#K6oTj+Qf}%KABEg0FIXepf)9 zDZDFMS-(U$_8y(s1AJ9kE)evEt;axE+;=|eUD8co5xUERA@IU}u^Cu``L<;4VLgjI zQKv^w%3gVr$mB1|vdfIhP{>A=6WuKu6i*ELq02*ensyvC^mz^K)^*eYOxnSglv$yA z_Hxw)$$p1xNj6^Kio^lIqA3Sbauo*dgaj7l0W$54-s@7dIkNDu8(k9nNR1u zVv@e;3*NG~Tj+k|m}rrO3m)er=D5F4GKeb-@=b@B_LQ)Kk%+RD0unGNbxfu=6!(bCV5XjC{I>1$%GUUMo!;d1cRx{k;+eeofcrNX5CV}qPHj4 z2K30CX9LnuWOC*lY09)Ef9uzoMF&{IN2JC+JyKTzu)YyjV|}D;_EnyYAP5 zuZGV0a_Eu~gDhQ|&3x&dayDEpi0Gi^EHa$g66XT^N9H9@rneeMiLIr&a=f z_Jd-FdM~S!by_89eym1|9Pps92O0GInB~~S2lzHyW%k=+tIdQodAC2WkaXgTW9i0_N*i;;mGiYHl3-%-Y4LcLvO2bI!v_Tf4 zdNq;ksv#=J5~_5N39s!#)bJ(I_r# zBW4M**0sv8y+VzH1}ccNq2l(HvvM1}x)Xc{PkW6FGSIFeU)2*x|RK=YCOC#}^cB|LQcU@Ts{e%!?Pfc$_byvwokGn$N=$>EXO zSBK5yh`=RZlt1LAbxC(Q@s|5lHsO7jesYQPE{?Dk@*d$?kaeKFXSwKckGME+RNhsb z-o!WubZm1uZoOw&<1~2a_f7#`mu=JsuN8tX+|ymca5(4>*(Wki#&XbD>F3KG^1u_7 zML)7eIre}MX|mkQR;uy8;{P?qZe-rWL$m8yZ!C&+_^`Lvb zT)H>db|s(Cd+?`o1^QQ%TmD5oK-BxU$BJ(92(KGg7apt$_+mZScc9S(O023 zB5dg#(}tc7J018uPPcKV!o3sW|4#Mby`oPE6EgS$#RDQ|OysmR1^qsdm!Z?4E!sq~ zD{7DqUX$0t>=v7;-|&|sGs)lljxor`2%hw~J^W5jcfqxb>bPoMt45ZhWBG^61ByA?@hX}Kc zD}O!{pZs-mTL!|uCv2A;y%TmwMn_WggI<;`CI5nELHAfzm5Dusj~$E7oE|=D2g2r- zSM;IMrYOuKr-%POkM>dp8)dHpeiyVMg-DYebYbJ_p~=*JzCGhhNJ)XNgV(H-LY@-F zW~g@r-oshIHyo8-=YtHgvBMG#`g31=kfi7M;QT>=_#<9#WFy0JC&UFhuyFteZouR! z-8A%IwuK{&hva>M^?6q_3z_%5x{WV8;j4%=0gcy-gjq#-tkO*I!#0}oyRs32P)J}6l_KoQ5K;vct4hhs|v|V zB)?#42UmjJgf5b4?8m~=$DSoOh)vSVJqW1C+4*xWgGejep z<8CNj6zZu8HA|C-7yfd|17YFljQ7_LdL}8-E#!QIK`qD=y(~ZBC?^}0dcQ<6Fu--N zR{6t!DLV$O#BXQAT<1DjExCqPc_C_)5)})Is1)Zt!e64vW=C;AD$dI-iG~tilgfrai99=Pgg~R(1FVz@pZ6R(3Z_zi zU|sS#po(gJt6AVys`SR;AcsK~%EyC1TLBGJ9{FY2mPG0(+FQQgJJ`d)Ve4n6^`WpS zA604HZ&X=`+(*Y*=tTxbRk#bonaxSW5(Az4!DT$1CpP>2&7<{w_N5s zCP2J(+@b8)PsOKrEyopg@fqO-icme43WH;jPDB@ibKhmH@cQn z`HO~4$FQ~$d#_MZ_$r1k8~rJ^%Wud?>9eu}Y}h73ZUhE~jgBYQ5j}fMLKye`Ur0GD zJ<1OdwWGIf!bQ}ZVN-N@;7&z~qMohjm~(w8ibjXhO~e)NN4*zuGl&!59%UK-43cbj zK%9l~wSnBQnOq+?(}&bZ(zO_4R}Ea?`vQ&nFbE0x%{c$2*DolsUU@%2)dd;0(y2%wjP97{G6FJEu4aWa#w;Dra)b^w*(!6e#t za>yI{n~npij%Fksg>xpZsOob3GR8J766B8i-KAL^s-U5Fgz^R*42~)%N6(U z9mRh1DCGjjq*7AJ&l5}?r=U2IW!EW}pInFSvLdv$z#V|DkGzv#ojVPBpGhRh8iW1N zPT9W`2*OTc!hW!xK;*OxuDo*w2YBM>atRa(q2foyhRJX6*~++gWd)4{aMy!I6Iq{MSAz z=0A3+3_0W_21?G+-j(b)e^Q1FpT{-%*p?L+q&RiFJAhc&QCG=%4;dy$51F-pC_9y9 zUqjDTU!mKhC1z?Ad5Tml;0r%IhnI+Ty3 zmu0q`_WZT)L31*YuXaPHC=P{RgCFdRvQpcCa)N%0{=4{kWOBrkak>Y;=?^7r-)S>V zAYT-Z9lB2PtFW-8ko}Nn(ty5-vK+4kjn0beWaB20J@`aX1g(hU4=yyHv9flWgl7d(?P)B`=wIFMZi4*a!^^cp;Y zK4^1ZKwAVC^e8UUUuDYsxFG)uj{z5!6mvWdKY(BIyzVS{pS;%%cso`(#Z{Ri|FBZg znY4Mz+1{4UGY>@{(a`SHLCGfFLh%9=-SAau@w=z&KuD)9?a0*)?%AdkH&j9L-eh`J z!HJ*rBPb3Jww!k}d>Ggo76phaN)_Se(h-3{JIgoxea~P1Pkp?f`1WuA(|Ok6*&ER~ zUwDI67$tgi^gsxm=eayrvZ^kIEW>=XpVu@?lMr475r+xlDtM{H+bO zC2|TwJQaV;TZFrx|Fzs1vo1L-<&RDEb-N7U5Q?Z6hErv5&OWE$0^RWuj1I3V5Cx0nF zB~!!&?>iX_aIa+1Wk!!r%jWnHKRtQGNF*8*0p-A9$0Gt@lV&!xpX3)sE^8{p{V#Ib z8So=19%Ul~8P3mK`@PQ=8>MU{oRwzWj026)%0rc3!G-v*SjYAz%%{{H9UMN9gRiY$n+3@e|8l}13mCfS_rmjQkGa23CvGm6n`Bb z#|IC)k^=R9e1Vpo7WkKdmfSGF#WjYnJCb^c&a5mey(Cdqz{u;y1Z=2NUOG|~Z@!z@ z(82CFmqM5Q*LA3Ld|>t`Slo&-2s~>n>9Nwae;C`nSEtos2wll~`;Yg8R(I+u%ZQ=d zAP{n0xO^x*6_3#i(*qgp%jK(%d0&W%l)pZsMDJ;t6X4nD0fead z0bz#cc(>w+(!L?v1?aQv1(I}LD3wi_QWAc*wDv_|K5Y1NS9xN6Is_{A*nR!<45W0eJ}Lerw79xfR+z=pbI_v93&X*7NBRKb-N%`3$7&qti_kipd__ z_sbck>;UiA24oxfc`rQt4jbwv={osCP7HaOT+6h})(QF3xe^&vxRO!yYBffy)u8*8gP-xSkB8@9 z-s;z~nW(pyESIRtnfzPMnPIQsl@yjUL!WMxA))j(G8*L&J0-%UYFOp6Iia@$USbkp z;{}PC2GOiKXf?<(k`IxyMXh&_r(|3EE?-lo4(M!>&Yx#q@t!NDu6%+jfBk`GKS2-$ z&z$#J=hrm&F4y&x+ueE4raXN(avvZ+(ODDzO!GYGw(ThLiVP+!ke{Ax)`qYfi{s6F z2Q;=k2}nFftr5y_Onxd{e?6o-PLKR}@I{CuE1x&(6wuZEl^-w}VprsER39s71^Kay*wADtfb4Xp4MI!+Y-i+-nt0}TIw zcz|_%K4V>SFKMhxo=>SC^z8QSWpi|>ICNS3W;wZ+UcTY$KEe)D*pYyi2HXC1FO^J9 zRzwbv7pG6pm_ZD}mSly8`m!4h7I6KZsJnC$6+KlKwe~22aEew#H1P}BL=HMYZG~4n zj+=DKpofA64{Q`YP9u!sw4<@m(Wf}|i*n1k?)M|F3x!c-8=J*CNtbQgg7o>ZLZgFA z=l!|_eG5&@JDkiTM zv%XG^w?c+^6TU>)^{kKb*HULX;);&v(c~dNWxyNs`!Y&S!Re3*q3$uO+PqRav2%H^ zzjRk@QqLsZo_(|>e+n`A3$Wn{e~|vjPcNyBtfW87wLNha_lT!YxAP(8zVZY)E!sh~ zpMsYiYM`Y3;>7YeAZVu)#nG= z@}l=Q;s*|xFe&fQ5yQ9_jJ2XuQ;i!p&DB8}p*Pp>qo{OJB70@~Fxy6EVu}DEoST@_8R)B^S~m zc@nMlB?`K!({qU|E68%E^Q1TQ4yR>vvD{}M-siZbPy2b%OLwGG;UF(kTE(X-!=Y2) zAN*#52v^uWU3fuX((P~#r8~2tFF=oJ=-w-STBh`JH|PgQCtv0B1!A^&6nXTEAzvYf zl}?V%+e~NWMcanYG}rSM$YK!AL*MeXP9u+$4&9Hut}ue{)5FIc?o#>$c>tk%{JQSN zlH2v3Jo7Kk3ywe1u;3$zQ}j7q7=F6VX7~6d1nM+=w&~*@VR3{8#Z`Ta*kZHe7n+51 zDd`_cKP+XhM!pHUht7cv_`R++I<%XwNg~1fgom_qWdrF)c-Te`GyCZA!h6_$(9ISH z=N@Q@0ZQivQv9LASbr=PMkR%CEN9Ra zAq}Uj-*?rWB=C~2T|7gjW@!K!);_cYEegxD6g7IT@M`APaEfv3(-wnO-pf}|I(-Gw zg%#+_00k}@7=ARC?Hxw--+JhAFQ`x2@rm}Hh%jWX~&x5-MC-*R|uul(MG2^ z?a?*MPh|dO-L2QdNQ53|vcP)Z8L+Q;XFR^<0V=SP9`w4h&@oa0oGQO=hu`%O+7wQ{ z8|Y{utu7DT%J5oc==2b;9xuuNAeIUg?=fp8upVRrGHAlYkd1~nm1{hh=ir2sN8?Kk zUn<=;&dd*2V#%8_l)B1GGFP;4Y~zgMXdE5=h2=bEQJIBpff1lll?et$4YmNjglY|% z#Obf0ki)gYHO3ekU3`SgxI&&v;l>*Monc7_An&FpjI>sE;#NRB@LoD%MXx`ntstov zSaMG&V~iyf3ta;tV4sprmSI~Rn;C+h;-UEII~#B4zw*1C5v_ZvJ4l?Lc~OZZgDZ%e`|Coaq1n|MW>jK~!l*N5KemiRiL_z2A>q zx2&&}&jmWDYQUp|Qr@SrMHg7{KJri4pih)>jrSt)lr8|JFO2l(P3SV+=u#ggFYkN9 zFZsNWr=EFdob>qA<(aAQvERT5I-xJ}xjK#s!?KKC?Sha#+2l>gccw2vJkf~G*z^7I zG{SbrcY2RTHvW2%_~GVtt8X(vcxB2D!r$toA3y)#Z#<)Zk9`ryr=CCZ%-In4*hIXm zPl9q2&o*s;RNY};(O z3ywGB^Atr9mX7uHWaps>#E;@S{bKJ%gdpB!2L#Wm;}l~y_K}c(rPEDBa`}hSchONX#tg9z^re!EV=#o_CU*{>tE|5`gD0*IvgnMq_Kk9 z*s4m8x{dGy%UhBEq@5~-emTCBF$>|R7_ndwaTM_cPX&zqIv1+*X*i8W)#7HPjSbpk zEJ%Kl1&deYh3i`e*sLeHpTJu-I6IlkJWg~Im!N_0qKuTkR+mB}a$4B9?sHscb-#^A zjRMgRJTFA=j;~Sg>OI>^F{oBHplva|>q$b&Z!aHH5$IhgEws1uF19!Dl3@zF;PK8h}fg1*&F;y^bKy+i}c z5rSBPLOhxj4f2J(vWOY2>>oloT(ZAUMlhL79R_JQcOGDCwGzg#m@k~9Qg zBCe_4hZY?E(2a)pz@UqlaM2}lT=WsM`IcX;cujryB)B~%l2<3prX{~a=2mm)Sed5` z43Dq%7$lUPLpfjGn433%&NRm@+9(p(;V}?`z0Z;rAxqI=#8StsfnH$;rJkKH#LQIL z-?j~+Zt=h#op1sZ3ET81iqCy;Z-Pu4;)LE|P5sdrdh~qAEOF`fn=Hv0U)MoP@SW3? zQ@MzZ`={a|UC9$@Wq=6O{#(&e7dmpowm%(?Q1Q}6EwnnV@(oH(rQID*J$=v`3h9q} zn>s4;Aow3Zx9FTd!tVuZe_ZQX(I8K4n0=TgpY)%_d7mz)Pq%BdH{)t`7<`Ij3_{T#6%!lEZ#%G|XX!P|V(`oL zhy3$ZqHRX&kfJT(2^%`zZaYa6#KT?#9i$(`DC|5220ZAX=j1~>sicpJi!|X+yr}%@ zhsu5LfhAZj?N9GiTG5?pL%944t?Vo8)8~Fa`55^e{w-^S*UE%+hzHXbdP8BDM(n?o z7li>mT=na;wp~~J2W?tYx9B=-0qUN}AHrdRoMV=EWEK9Ab`P>Zn$nEjW%~ug!pTSA z(5DseQu-h|+GBD<$Y9rJK-keXYGp+47oQ5yQUA@CK8oN(@Kz@#Tye<*e4r~Bcn>w` zPur7p9b9?6!*!>#j!V(PS4|_)wosa!N6~usO-ol3(J5 zW=UJU(?R9V_c`r!rQvWZj`$jcun4>D!^wAC=O^8qMEs&#ualmBtgWs~y8Gp{4MJ#X ztu(jk6vZkl-q%E7)g*%cS7~J)mr=Wayjg)_dF=>P$#VChJ((oF?Go`mtqYsvI16Y;4#AQRdkj3Mi23Gm68r(b_| zy$iF#;q$q?A*Vv7Jo1cLtR~;raky$GM-N*N`tT=NKKdZ=j^0fp+X_yEbq#sWC0uG; zRVBB<3f2vF7#;eRpr4{tb!-$0Ca7AK;GeMB~v4$1JC<_2^bl~;t1{1}z*+%V};!29qf z>B2hsQ-J0$2Bm=9`yO!ug3C6d{4v`|LX&BP76v9xe=Xv?Na3OaM=`nahr&aa_1;?i zg=g(7%9d1_H{vH1T?>flNYW{d@whQoL)AtaNEVcgf|{9K4MKMSE+x-yJj5-GSwbVs zs+ioFooJ)Re_g=aHrj}zD(`~#Wg+Y;XH}7<0kJ$$L(6A@t`brjL`G|*CEEUpHq-kE z8eDtupd3Ltm$-Dj!mo}EU0woK5Bz@?wLYqe! zlPfC0Y3#h|6d4JfTOEoZ_UYP;tJ4P+CbLI7`l=(p_#Wu|au$_mLhqg~GaGv&q}QU4 zu=)*v_rLKIdDek}mj2fw@Nju*&#~61FgkjwlLJJVN0!o<(>ql^SjNaJM}b_YUMo0B z=r8HV%0H#szcNS^Z5bj}U+}yS#}y|nnfU2l8Vt0o+d-B%mJOjw(Fe*JEaA%mbfv?Q z_}6lsOctnjOP93Ji&2K^d9P0C!;g!O9^}nst^denMh`f&??s(XxRpoH>Ac`EWvz|6 zWUZs2_yAEruD^wh`KNMM4UdRg?`H$gS8gQvwm=#qZ}=*Yo6eW^d57u2D2WO=K@Wm9kC{y7WF`$d#Gh(GFtZFY>~T6U7%DEPC$zjPSbhlJEOaVVy#z z*Kindjm*>=txkj{o=av&y**S|@@Y+-eSkeCoeeAH4|~+J*;#IiddTm_JC2Kke%Z(8 zPUcEur3HCruyvfgVg(uKnUj|+gE~>XOaxesWW$7)RZa|8NN)U|2WJ#tsyaFYW-l{g zL>I&(p>*e)yigzUl{JHoeDxKghexGZx?rVy%UK9P-$sf2qLVbPNyp)%G2w$USn^eC zV0-x|gGlpS1QFACiX4#+@rD5lAqD_YqT#oe(;Hn8Ot*J)9E$w4LZqRIv|ck zQ*}y)UbP5#X%)po-AMxEH|Q25?}QI64Ek7~I||Ba`hh0@F(?yZG0+n79eG7Z2fk@b zjmHc)VHZc*J(*&3TWu`)RTAkCD=2b-+VRf3k|32mW7Ob?yt@5keshCa>&Q>Eou*fU?#PnJBexNh-<8L7UK2022<0zi zvPWZ*%(Cl#q-z%eyLzK@sdT^-$&p_-Ucx`wzcyAB(N%;;L> zxoW#+*HPyLf6-H<2s&w(2OUl;C&|k`LS_OX^Wlg4L(`-@fj7!K!e!zB`j9UVgAV+j zN^j~m`jiO0(qHX8)2Cm*ECS!tkE6>3^i~=&5GDZBxIN$r}kK>c*|2Ra|Rz8&3jT`Qk^^k;St>&=P(<89}K0smXTmd1G)=407I> zkho7>FExs!Z$|GN-t(b`>RGYEtzo4rO2`+d|d@fo+ z#a(%2X7!!}r>Uq=n&g-K@k#)?jUMx4F}x5Sd7ylZzL0nef3w>!=!E>IZQPY(!iv0v z2I)ne5>&jZCwU|CB3x(Bbi4rABupCTeS`NT2ZV18v?J}G{mGvwF?F!p8O0h_& z>oad?Ht`%zby%W5Vm52s_e`cCMmMwjeXB*yG~hOZ?XMx|?a!cy$1&B5$+m)*=D?!S zbG~LVvi$Ih$s`0$GL5Y=ji^OeR}s|9?F_BC;+J5cJRDSgmBLIio%0+-Wth(jdR`Sr z`70o}Nt})mS9P5BXU&YJ(U=9L6kUjtAJx&kR_n!Owq+cE0eLFal25>OD8UsCiC}%_ z4^W`#Y{92L<;=KO3J?8eV=Z)mL1VAqkq_ACW`5jNvQ;QC{74IV0x3>cDjy@mZ97bR zu+i8fKN=OHGdo+ERUS$s2J+g$I{^E$F%Qtq$a;NM5;vh|-Zu0LbRN<<7|YWHsLZ1R z2t%^+u&s1duE;*iLvNr5tQM59RKh@cilRlAlydb<6}?7YM49aTBma~Vhnj;}rf(xm z)Go3fylE*QO!zM6ikBqe#hp7mv@c_z#&drlVsu5yw9gx}L;54X9CK$w#?%@)(^M`! zxKiQRmXR*fwz5lkF+$K4a;AcO)-C9#ytGT)0Md<4L9T%OMCHQ^aVyY zh%(Y42DWsMKol;~(XrfbShO9zM-Q8i{SG5{qF|5~okDdiY@kg?96;OX5~>0(gU}u6 z3G{dWOTP$7eCWk#nAdsFhd6)#n?C7dA0K=1SGhus1joG?*y5cGqmSOLVJ;T~YBoxE zNS*JqfIlTxnj&qK4`jQ?1f9BbB=xtSWCONz4V@2tig;Q^cjzF(JVi5wgTqE#z4N?J z9<+NfnLg+Y{W6+R?vFM8VhNp0z5-M0}; z-nZ}QAhBVvFS1+uhDt&A-LTI(9Y3Lyxh9}EaNMwU6bO%;kDMf0Lmqkb{gN$c)DQjE z^WWMR1?Z9iYcHA3#qwr!+&S!$1rR**Qk`i?(s@wqVNVgmyw%OF*fgWV=mZ@9;Dzh; zNV!1x*g%TF2Di$Q_wOS@=nxNL`4q?Az6c2}dqj^+QXccV(^+`NgMx8`GtS+yD&4uE ze^bUl+ZYupgwQ!1+_-7=N&-64cf6IMOp>0J8Ufaw%yyRyMfHQ|Z^o;tDlcfi-##iz>n7P9Q9s0U^y9J-&*wCB#cQRjPj>{$WYdUi|YIz(TSrI_~(v^HeZcU zKdJoZSKs)zJ*s#qGlqhr9H9%U1HSx$32Xi_*pm6K7xfHX5sszlta=uqd!dnf5B)?E zg)ht5LyN?N!dYl9P}(u!Ww zIbV&Gjp+_QJ)S(A_P1ok_Vvk0GrzrTrbnTN*yt8`P`(G`baZ&M**RCZ4IeBtrU5FT zZ!*22{17dok$Y>_rPm4eIRih2_(2{NKiV|vn)5pHwNgAl-*YZ{D2Ld*exIem4xKJ2 zn924}Rcp|;T}T!PtNp6g;RxB8ee0%<&U@nPy)0O!Gw*oRPOK3ers`|Ue5QkZM=Cqp zVUwSR-Yeb0yZPo$l-;z6j>e9*&L3fO?RE;CQi{NXY9!Ax68>DCMN5>N}!l<@E@DgpNpZlX=zH}$_@dj;g zo+sUX6hF%^praE16^{WsX%CubL5Fp4y`SWUoMyekBxX8~^={Y>yn{_1b@qlGl;ISh z(!5t(_U9Y$j()4K|JpJFP0*V1XgVpYRhQ+UBOq;rIXz^_xEr=X0Pn>Nc=QwcE%iz2 z1D!a2LI{~WMenI=P+|Us_+}5mfoDWdwOEbSkfqX3@cU|9zeJ z<7y%LtYbj&fK$tt@9svWJ81&7`=aFA)VAU(T~wB8#fxt z-tpID3+p#*ziL-7T)j}7464|^ReYB1EC-WGv@P84;`=-gTJ|4k`ECE9i7UYbk=YSY z+b~z=@ad?bM^3v4Mic-%qX2*BU-$!D`QGIr<2Ba1_h@;kl#wWs(zOieHLtlX1r(jS zqKnQ<2|>2m>_79dt2iW_^)*WfQ~0UpWkB>hYaLk+(Vz-=pO&luN;qQxC&FO=6+pfZ zSz^J^z3gBsw1QS%(&%jqt%x*jB8xS*`&iEqY`s6p{48WxEVkSm}j|V z)7hS~0(<#a!MK3vZ#YR~r9??VjRuGAJZk;wEN0v0oz`**u%2@9AHZKPQ2{bs3Px}I z#POG+ak!FemN2kU*$MzkX4o8Ff7C{vCna-RN#dL+mn;dTK>2!MsfJan@J6c``Gq}9 zQS1R(Lt*#J6`(_I#Ala1xI>T`vI&;BfL_m#RyegpSaHO%m>2DrLIrrsXugDLm7PX- zb!Auie!6(!U;F^ie!9p__$t+#)|V$VR%5ALSnxehR(yVC#;IJ16M_E zzig53uFpukU!em#8f+M;5HH(s&Hw}9EXn9Fkt0_=;&*RS!XnF7bU@$@f5C@M zL^{TNt$^VzQY@?TKbn#bovY4k^|fok9ZH`QJ3t>!FY5xn!3IfP~4lc(-q}t;bAa&@uh`%L~!vFEI#n zNyqxJ>VEXCkZD97!j4h-mrfWCL%-MTFP_By?mE}GJ=G*dF~DBd@b+{mQ@>7*SC*5IoSk$)hBNKAu2B+a4z@p$%K`^1bc-pto=9ZrEN)K+)Jo^%rb( zGM|EVV-g(t7CNxQlvfU0R(CtWu2M@LUTY?N9Y&ri>ezE2@{j>*d`?(4R5UJT=vkg1 z&%v|P&73o2Hle;#ue!X(iR)-j6_+ zmJ=RkfuJ+dr`+oy+H;XUIwFE@=qtpT>EDn?&<_n8CFHV|M;-Z@`J%m6bXYL>N3gnA ze%p2uawPxUZ{^$n1JDQTC$FK+{A^_#S&Rub?)WZbcur&bZQC)TC(hZIX46gx^f;n$ z+x#q@KnJ{Tt>#R0i?ZOOo>>Hxm(ia9O%ZpTQx2FMf?SQHJ8w3zpBFI(y{%qR26`fi zgwjh)3-MJSWf?sc^$ck3ihe_aLRYcF3DmoNK3g7r z(*EE4awJ}|p44@Hz2Q15>5A|(64S`JTtA*dy<>kI2`dMp^mBf-Gzs!oZT@agq^>+h zxzb(z6(2$#@k#wlen~G@yos265QzBdI*Cejd1K{*XI}&47TWt?(1kxi-ipR8z3lww z=>Li%gCSKOspqFxUf+gMc{V%#tmU+=SBOht zSg)8*8A+8FKh8iv(GMIq{^FgGY4SkV+ye6KwyR%K_9Q{vu%Hg8hz8Jn%xgdXEfWCq3u*qUHDbNQV}T;UySF z!0o__)2e@`Li{U#>GXaq>*hm${4e^fpZTwQXt#p8SNy3z^(XVJ!?*ph|59=n^!G7b zGHNFws#*K#AxTRPDvK%DmE1*)@)q3T323;E6b?%or2zcPPj<#(;n%-41kVK_XXdYK zVbk8=$&Y_}+c5nNUlazeVuh-fUeCfz!+_^M{;6%F?Ki&j5yxlahenJ$jw8M@DBDB| zo{W_ARY!kRK0UhZy?X~(p$Kr>d-UiXUt_!xw|>w6VAokxc=PX((vcrzv_?p?J*L8X z&@5*iFP$GEt(4p|KahEFAMuuNmN9!Ao5C8aE26jfCWu!kgg#a?Mn;qFRTu;&ywDdU z;n^RI^@sa-{ns-(oEL`jt{5XkXG7CG{R7+Y?u*xdkl9$9w2*_&%Zz(4*0tqU^6ez( zTw3WfKk&Gp-wWRK4Qw2$@=w&g=&Srxsq7ZFZ+LJQ408aj8WI2+SX#yWQoNu3p?i<_&0q7W zIH|lzW4p4N+w3pW8aN3$jz9UsZ^^6k<1JsqV2L%P(XkjAs4JbJGs~0UPEXTXex$8* z+RqnvJoG`B$eBEb@ssbS>_G)OFVNlFfc&BxP7k1b>PO$>V;}ESUUr=hT{x}Ln%Ic9 zyWM}~6s@?p{=|=bsgHNV+rQ?geH>*6Vi{G)u9q4jyq-vV({RV7`xQ0DaGzJ=VQa7& z{O>FbnU(O!sd%(;8sp>Z|#FHQ-Uoj9;5$R(_*T2S*ykb??#v`69=eQ z=nSYqxM~PP4f#&~mA%#S)(3^t){%kkON9>A&}6V>dZ_%JUu}kmAt&n@VQ0RvACs3p z3rg3j*WKZsdbyTsi=sW1&8zfMR_5GbAR-492Xw4Oo>Unl4GeNkt{0~_F&u zE0$dqtYeiIk9_ZT+u)@?66LaOT%D3l1_7(CXR-(9VRy-|WOfys(ZqFMe&nS(PgASXe!Fgqm=kXAh7t1p#(|_>8Lx z=_zoxsM)k5bXO1ix+QNkhlf)=X4$8OcxEEZ zpYTPWH20LCwMRk!Ch~MGgOum5Iu94YUxp^|Jg{2M!vU`hpJ2 zk_DEFLyjnieoOM%*{Mq3Rb3zJS>_MzaKiUKVB(#Nmi&*di05igjgGE0$Da=wAS{+4 zBh7>l9b_8=B^=FvxySzRB{LnK{~gr55hs2lerKZJuX?lm0Lo~R>6fbG_+T3H&pWZn za(Yr3^B{8asosT8KBgX_^P-)6Dd3l{ql*4lZft+)itLyELx*ykc<4;3a#8K7{!(nw zDN6mCI?Vr)o?gD(2}yzf*Sjr9By>v;^Tc}G3Ge*bUhEyQZ|BD^`g{XDdMJnFaT+GR zN2eb3H+1`%;PPsI%b#z>{o=`KdSezkZxLpM%OFeDBg1uc90Ta}K#SsI0t4}*3v2(I z`ufW2;8!#m?fh1!Z;MucjVro5?n7GnQ=Vd9<6P!@dE>ejUgl)9f{Pkyu-ru%AQtE) zu9}d_-bsXsyfApAlBe@iXoJoZXaK}piRzsrpM^?Sb$SEeA&u0FzJp9e{p3Clg+&<4 zw8P&0^W9{M!pFWu`bhzy8{MWbEdaX$9Tep^{kHy;Mbd*ob5Ka0 z&{n8HhR|QK%}Wk=7akaK^naq%JJr^SK^(HRlVi(azFYNcly~J7HVyV)@&{Bb2S_eraMLnaR??8qbCC5`FTao1~lOdV!A^WNl$y*P>E710**gKSpE z{x0L6J#z4{pL=47(!zQFOD6Dj-~BIq?BgRJ`b}bQ^;s!}*i7Oj?{qTP z;C=zJKofef;fj{f%un z_1=H;GZWoN-fbzx8iz`@0DK_P2etkBeD+5rtKPP2)aVmD~EFKiVHjhtmgH zlr3Zme(Ik7T<1z|=NoJ@}>bjXvmJew4gf9}5fGQ}XYxQp(nsN9(D{k?Xg5-;)vaj1au! zm_6!0&;3rx49oaQmx}(-A-h4I2Q_8cagyn3V}#_9wFF*kz+!8wH*XOXZfCB@Ya+;4DBmcT`B( zX2v;?UC6Yr2CRv$Fz515Cp@z`YGC6GWW8s;+0duHalMLyj%R0rfdD$fR!X_$5c-^Q z-?P&>jcPkObmY-ajjnc(g*+>#Fc4ZB1~>#gpV6=!cufj~BcCb!GL}w*HJ529d5;k) zYq{Yd90O4UKKW0_o+5loOoc~>)Pq1QX|eWl7_qLq^6u0R{@5|VB4X3EuUxvKat0>bP&_wJiWw)tIlw9J@2V`Z)Cw+>@yvjU<4h+84Om)X>Y&wFvlym2a(oKHI zna8Fr_!d6`(mUzSLUh(BZZFlN_dJsvoh;`lj?;zl6>$(}>J?=tagPtLyTie%Ae)Nz}^)8fxOpoLfnnNZ-ZX)gBAJDN!XF2eu z_!$W7t1lb^Q6BjRZ)@q7+3}(|IaV4LqB}b$BW%&5d?bsUA2KEfYt>uqqb6_NzI6e< z;`3Lyo44-~6$s&_E~m4m=C4@J+z~*1BReY^fcmLS zAO|HQbU0ckQ)UtsEMJOvJdk{mU(+Rjgn4*P?}-lf4Pk&_c^f;0*P_C2775VvHT7D`>kdqSVYj_Jw@ls`73OdM^7M1XJ!y) z>I0!q!O6>^S8(tUFj(aQ7quO5EDwg7aJoewoy$54 z$Gb^E%93B;ysqn9&Uf;hd~$-b7HjSnA@ zEC#>XDBJsl>_E^;`$ut6t|U7&a?yM>5eRysO!!Rx2C_+1zC;>dcf{aifG<+mPbK)P zd=h&GV*hgTIS&*Lk0d+87fka|ak?`>aYmXMFqt%0uDqeSa`d|9=;-ynJ3eL01g&zO zR1$d)=p>-rkZuN7(6b%@l^@z%%#y5$0FX@4q|cv07Qm8w-rS#XfNoo+vdperHipgd zi?2jShwgWEOz?mlBOm#ihxE7{oqD_y5=Z8+tyLs&KK1ia`-d975`+)tX?`m zkL+)ux?~}~+WtqD(6tK5OK(U=Fo@+mrmj_)x9ln^@;UYi;5FVQ710r4|8iHaGAIPf zA2P#$PLvZ11F!0gcq3ov@VVu@u4NaIBd19quPs+Nz03Uwy+i2K=zIY@FF(cWK<`b{ z6h0-zx{MBX{MXL|5!AKlL&*rd2zsIo#S%U~uecRvr76;Cf+b^RFDbA2k+#SrU;8}4 zDhar1FEYs04s@9Z_>W7Lt~%KP}1E@6d(m2ATKsC8}7<_!+dkq6{GaffXc zwsy3&WzWf9P>x){YjkT2Dino|);x`SZDhTC?^sNJ%M0?yRhwrii?;1TX8pB;UbODf zJ^CU%*xZJ73dMvr{_t7@85?K`;uwx}+v&2Ff~Tkz;0OMw4G0r{c#?GgT{%A|J-|H3 zKrFWmV1^EDXM01h{Rh8--r{ZWJ>)U`#Qs*&q1o9R?*>k8Kj*w-&=f~!F6}2|+V!Gb z$eF@bUJ~y3=y8|*ZnBghQus0@@+PhUc@VTw_Z&zLRj{%9ciG}# zdi12rleyncZcSR0#sYM?4T(J?&wOFxdd&8SN_NX{>TmhuC8r-98F}wpx<`2kJ#Swb zF5%E8p!$GteIH$^vvll3S~5=9gvC3qZ+Wh`-MxcNqu}%X1axTyBinile zMC15e8yBIcH`3}H*AU?Br3UPwd6F8WY|QN1~c}GMrOc~ z)J!kS7mW^BE+rZ*fX)a80}zaO4}tMZ+t7W_s&nHk((k1X@|?kzvj$uk_(3l(X9$vL zWFQC!nZqy;oB=y9Y>r&%cz{M>;OHd5QQ+*DaS1czP@EPf&!81O%>Go}KFH61eMI0D zGWSh{_(KEDd|^78_+a5p;WSRIQCwKgXqc%WvB{-dR#8wX^bGv4Yz1yCx0-`ikYA_1) zV#8kg-ZMvy952zHrJ<{d}GS zOOz8kz8GVGKotiYv~sk<7XJV2{RxUHluN4hBh>&4XP@QRi%=u za;(hC@x2!jcZmM~{%fssPQ*Po-i_hCO4R<}*m35)*Is+=wb!1NBL1!ea!fwNaVdXk zXqH@#Vt)KaU?|ZT+jnT+Q4@LPG6=m8v;p!;-+3xL6(?o#)s751>j>rRzBPRTL)UJqfd9n<-b24&Y<9~lh<3_A**yKds`_x5kG|1=mvek?KPX`RhW)nxM$kpsXqRDF zJ`+wi8O~Li7NL6H&#zp=)09EtKsdxR(~)Ogn1T6WyjMTK{~7zbNJrY~o9T?r81*g5 zMMEC?SD+EyaypN)9h%W8zynoqG;p&-;sX0Y_vN7LJaRP*{Dx0>sB(ac?J{&Z8}_nX zSj1*KINwu-@Qvi4baOTMB5$^R-B1q?^d1|-@2Rv=**_7_aFO%E(LrY!hmW!c*k`1c zU-GC-)7R07oWVa=jOB$pT^vW*4tm9Ll&i)yULsv%AXEBMav}bno;6~Vf^?FM5EqZ& zk}jqp6nAtB`r=(WnDAq9i-t=1qwmC^c$nZmb`N&Qcu#2{UW{Z5?M#$MZJBrmH&Rk-NH5pU_BfhtpGJwBB^Hfko< zX(W=Kq}-HU%raDVhvMI%_`$L4deLed5<5!aS|=oEv~j~t-a2|o=Ys8`Dk`8;!B{TI z52^<=Glk*VE)hQ-MI3cLjy!{`F~ihv$PbQT%fSS$@h`rQhjEU4(dgnvCx_X4Pe2!y zF2@fzU*CuW?KAeR0`2HMop=&5isN-0ogFmZFODc<6q{S)W=UtB+|I$I znWJwhL-h^%5#BR1gK*slre}wTFE{fA4ZxXi6nHcoir1Ebj@ML<;RQc;_UPwwO+3Om zZS)Px1D0JJI+sQ^;xxxe>&LDOtHYWDW%lvHXd-;fT|y$2jN9=JnB3F|$NBpW#E2oDa) ze4=}F^is)VJ35K6>l>F+s8#m=|Yol?meJ@}+b9%CT z?@OYY4rBKB$)$S4f4=uVamt6&-B;V$mYK?yIq99h;~P82B>v+Ec@RB9$CKl3dF452 zK|JI#UJ+Nh@Zu!oHS#t^N6Fv$Z3fXQE=MmnF`I>S=X=t;Yut`|+>IZ8ljilq&&BOS z`J?=%pWn@IOp3@1IfN%cJ2yGE8Uo0xUZ&9yxv%`t$%1_LH#Gk7Oy~MJ9InYv=Kt9D zH-dLtpeOY|Uw0V}!Jzo+^B6Ji&Hxci=TfAhG%ImHo`sU-HDr>SZsI8W4*&2SN4#+X z!sR_a3OLPm+u|WRWiq+Xezp97iIPPxv!>^~Px?)FAG9xHIz!;E@_dvDS-$%i;Yjnv z{{f`Oh91bB>I z*@HuVAB-q}{y>K5$!h@~u{^LepIzB=pz2-LVS3NftazIL9ObupQ|W#h zdI#QEZWR~jNo+a!PaX(@Kpjt_FPEkNiza~H>N;GwrXy1P@5`c4^y;5!;Cv!J&GsJ7 zH|`B=Un2X^5;yFSP0QpZ;0AOZOAe>g`=Z?_9!LB)zY(B{w{9iERR`Lk#3=pA=C>eG~lgjsy zJLpGlA|4z$m2ZCJCCv01@)q*gl?6`M^uyojM;&#^ARLwP);W4=I2Z<Q}A_Llv&|APFcZbX?`b>P-tBd_us=&%=xtDPP#6b5a6t{24H0(qRPq+Q{&3dL;y z(KZ}pzdaBnQJ3Sq$;?s-np30H1)M4_#B zh&* z4F&CJkaaSLaE$kqrgFdqFK$N}R;~)|axO3j;P?(f*$jIhNB%+-?ALXe^IZS-L3$^I)f$>xdDEGfg%$FQ=~}M$)O-u@Vh!q1bUz z$&~KV&%Ead{T8;11KK@rJBYRj zmmm3p#^P88Xd8rX$9pPe;oK<3{!e2@17`zO0{s^a#-w}b@-TcAU#C$zqF=Q3SV0=q zvIm<$vBhXTmrv3c9ypQ9_7Gn@HUGytdc?5q>5t%f%8VErnFlmg zIOYA6gVqn7SK35WyB}%kJIIIJrjDiXyC1Inq%x^I&g_EOb@93eaZCM0Criw5nO>LC zC^ymh>{^%CocB$){E-c}v%<#HpIGiaPV|U|7#bwqpbWi|L1vdS0KkI)Y+GfXn~Nq~ z{w@X5Q+dUm4?1E$QU;A>d%>c~HOcM&6&;?GFVSTG2JkZZ;W{ zX0j(cPwCAogn_?)Xa~>cN`vEOvS0iQJ>+s)hz=6T<(}m4e#xO6nBNZKIWE{Q(1?4d zQJq8{Wi7Y7r3xHQbvWTcm?ka_{bn4d&H9nmqra_%&yTnGAFn9 zz@*u|AARlDYzpwjNbz3I#b4D08a9)bU2SubLk2pfV=-~;iGMzH8WB(4$GVt&vZzHstOfDS)8 znm4y@K4V>r{liKIb5-6?q8Nb=xMpvW4JzHl2U+4K=QwE_y(`+NABujK3|sA>ODG2@ z|GBR>sH-^+Nt<~Ra>Si_I;Uk=H$1~cA66rpEJgh%e-TG!jlhMa-VvdxB+iMS5wDeiOAV5 zcC>h;{5?8mf=wZDgX$<+&H9Ubw-kYdC z5PVInE&@-j8YcfMF>OQBG!#+U{EW46J z*$pg-h1@%BN>)yRbn+1%`g<4^X%p1*OnJd?32pfBi!jM2JSEPe6CP!Ux$o&YZy()$ zTIu?dh+SmEG0PrGABuLuqWvg<{L_FP`G<6!NS8A^-NA^bW^KL)oR$i^mK|d$HOeK| z7iAb7>%;2!4iw!Hukt6-KH&RuTt|nRWXZNv@W!*Hl%K-x3;(Pu2p_tMy8%u5lMaX1 zl;8LV{bkRC=xDWP8-5B8S~<83BBGRQ3zY%r){v>N zB{stHGjZp9S3U^HApC;%5(4BF+ZdWHgX_RA2Jn#nHFIPL&gV)C0~VbSw5vl&P1sLa zPoQ$bJ@TMsUQqDl&yaa^R^$#-O5X2vKH+#5SJ$L(d>h~J2VxKf@4-prKsS+P-k1O6 zRs7*ub+}Yr2814`EXU8t!zIH6;W|(1(hPDPq?^C#@=d+#*`DwKzfD#rk9BU__V5M0 zqWXi%!c=_8pmTL1`R9x7+p8bL^aPjm!lC|l>}F2=zDj%&;yV<|1M%$Pw=gbzu(=2a`Hl41PGO(D1 zz-*+Pk%SUEW@Zi!o-2OhR$?MLXmDYKA+qWB z!@1)RgJ`rbL-1P25&0zLdk~5r%RU@WRGE{DR|CX##&2P@i_kb zN1Tp(M#2S9%L_!oE8j_19Q-wp`+%pCH)gT5f_5>KERE@$q(Q3(d=B3go{te{{#QC* z6qQ#LY5Pcl-UlK2hwjyTZYX7x)Fh{;nWD~}{2#|CT&Zl5HZ<%|!9w3f97IIxco)t{YWpm0-XupH)FA6)O$2GSf5aiaE-Aff1;7#J~tYVCpBW)pBm;(4-p&D z#t38On<&G!L*=(rl!+;!t5Gp?vF4>-%^f`8SQn zHRv0a6K*u7{PMDjN-gsz(?#Aynn@m+h6yW}m4_`tS)9Cy1`>3(!Lh~XB~D_Hgz;d2g|^_ z@LDzwoyMf&mH81_+A2I8Neet zLZTqUsFDfc1o&8%y=0k{a@atrH}RQ#y(Ck2~Sup=VJ@ zr+eub$qar|DGnFBD%9v;fILH^8|8EMFH44593!9skY>y#VFWeyoaole(O54zpkZ%c z%-GlSiOL9F&JVlBpr}7dw)x&!ECbSe%8o(^Xr;$Ux~N-S0lKjHq73I-I)&zo+j5jO z^JXF0VAiGUCFptm$jzjsc_@VK$(7PrJZ8i9$yk+dcNhglbm~NhQ86OoH=zN}^o3uQ zSG=F6Z4Yb=rH6RK3=w#{I#7I3UDCaDXpgVyopkoM%>XoJvUzjl$sts^Q2YSMN;xo{ z?KQLAYl<^GhaIvp5|r^S2cAHS2Y3Un~I5m)apYs3vOk{9F#2fxv` zZU~i5o$kG=naO$9l;mO!)(56S^il3d_{5F(@xPrllDf9|s1twZ2C6=-eZUuJ5{>W# z$2s57XdHekO!%Q!ne7cP{Ardk9P1pq?DP$FrnU?q9N_S}wD)boCvJ{k$bBJruXK}4 z?B2KE%x;KJdr7Z9j&#sR;`g!3jD>V)vo2ve5>N=dJYsj{unpe|dYx8nV}GFD zGp%ybsJ?KA0eX^jiS(j;AfY(uPv>b}& zj6oYo&#pp-c@KY~oi-Y1#sl6Htw=P3Ww8G#hs^(e`KPm@%Y5djYdTx#$Y7-udF=3< zH~n6`6XE6!$1#qyr<4u=evHd^IMUgIf7n&gnMvBmY#W?j^1Fbtax&Rdnq0F3MQhL$ zw6yd%Fl3x#=Z^tzijjU6&b&k4=nA>uQvhA)f6E$$n_h65K(_s= z4xc<~09h5 zr=Qzd0ywA)!9CFUg5zD;d!OsKv zi4)hvk1_!o0SDcW_JaX>Qy$SBgvgIFouyFJ8^E}6uH;jU~1q=3~gQ?s0eN*)nT-NwyyAozcu>z+rRk_`Pj!d{(+>=OaXCp zB4>PE2om3VMZkFL!?NWHg$`8Q1R4Qa!$#j%FB$kBKK(?Vb@<9ROF_2)g+O}0@zp2C z^sdoJMnhrvNyd5GJO8E6`}nTE|F%5q@KtY)N<$y-eD{y%S%=Sj`UB1&M(QgoN;hcf zLKSa(al;wHM3j2ovWBZ0i9LELg^x~#Hr<=%slR%XUz_mn{N7LGS%;55`7ZeZ|K&FY zj9|J1H&P^?`m5_o{TKb-kLTI>@!x;T2lK4Mkbgh?+`A)^0tMl!md|T(`dWALou|M5 zK_B~g^uxI+oa8A+nI1PEc=$7MuZO?)XMc8{b$Iiyk7I>MMg9Yid@8Tb#*lxn`*qLD z6Zuy0lMVjl_ph&A`G#Mk3Uj_gS|Jbbf6Y40L->1t_UGnVhu8mV)~Y|*apc)SGP)3H zf^r3g2F6~#EU+I5C*Mcy>o3T&4sZPM7nL>; z!e~BKp2j=Pdtdz%`Sfi3-EaN*dDh|e9|~GPap%3wkVa){lI#--q2pJMMnnMY2NqfcJlnUzpdLquMivL3nfHCt+7l%tpTQM8_q72 zk+ZlR&+|gG(3wG{{{-Z183qwf2xu836ykA@1`a9_3MZfa^bfql$2;MdePn%O!5@B- zG5}*M@(pE0!4>nC?mBiD+W7u$zxLBnb}9~LkMO?NcJg-?e)yR;~yr5CDz(K5OVcis#DQrk@oce=_7Bh)TeVgel42ALdA6uv8{+mBX|Mf0W>g6H!2xCA+ z#fA9Ass34Bla3xa-ZUQ>i!1++G)X^fOmzsEq~Redtffc#6-jvOqyO_P(im_aBind> z+(wV;Ov*4ogWnL5+y*lYSvcf;Sxi#uK$mJ>RsWb?@`J|0K@ z1kgx_4t_aLCuo?X|D*B(+`ulKJ+RXpy^sV6nAH8W^pd0s>%s3_-*o45fB2{J>?E!~ zD_cyM?8dSgl*^q z=?{D)F7@qvep`2xuhV$9Y~_1;vDw?3x(xCR2)%#KAFbIH zU3z`?BkT6w{!>w|OtOA4x*oP6a#HZ%tK>`hM>y>aM18urNj&w``UpOABp#8Lajp1{ zSXF?E^Q~w|6sF8FQ(eqoN-mGxLB_~i#n+jGdIfc?@N+49mpx0&5BPkuz9}3sN)WQ4jRD zTu6o##%upp*tC6o=C`cdMAsgFpO3M}3tq}ErGpz6;3M@@#f1(OKi6-%f1k@3H+m2z zdmBhr(A&Dyx3~R%)N7%Q#xL=Ge66{CJ2t6D23wI7Kg?&z>{#;dTXOR`gFzM}2)>WmBYLS*wpDkMl9# zRsFg2`ANMl{wSW#yY?FSO?rj49Pu~Mq30+qr+ugQTiaCVxR7T$5C{Gvv+Z+a2O29c zFmqM3qmyUXgJw50Ds7mR0Oq%z)BEB@4k}?HRFpYRS;sy0B7^QWB*V0GOLYa;kK(4~ z4Uwt6n#!)g4^OlbSVC(l`GTVG7rsJo$YOOsBR9;@z+b>2-q!m%lhu)T35I+KozbWt zvH*>wGjBwC!jn8{|0756jkF5=66op(@vXy$PMw%Tx{vM{&mL&r{>k;Wt{?s7Kb&VB z#y|c}>6qZ1(?0z+lD6phz2?;QdlAKEQPYe~NPP+ok$x)-JUy#A2J+!|g?8|n(mUF; z;Gb{!KX2Pp&K9x1LOc_%@n7Fr&&qFnhsKtdI`91N-A|amse3~9d(gXdnE#4D^*8fI zhrj;&ezA{HZ{QEU5pnW9>7b+1+I0t=^E-`*kw4eBeY)a_^$FinUIar=yjM#Mjb=)Z zBW4OI?z9sMLmS@@;lKUA{kwVA;np+jI?xpL!nXYKQyfE&P-caV#Qi9jWM5r-wE6I# z{sG_b<75BvFUzy@<7@wu^?J^be;@i|>+k)g-_EA_y|hr8U4MAH!NI?3z`wuzkzW$J znWRr$KC~JB_x+Jynr9tuJxgax%m4v&;{3)xH?;9R8|n9CQ@p+Jk-U-tn9PQ)F_BqzM4Bd^z+&U59T@??}J`eiu@qRggTV6%Pv(tka-P2LYu{$vn_ z%S1W!`KC@T@(Xk?=v+!*$EhYF-t377F=&YP!HMYLe$=C}m#|4<=~+6p7xNb#Ic9`| z1!a#AaU>{gs%k5epSCfe7&vCzLZLI-QGuCZ$#^r3<%-G;fOqQ`(>cYYGlAcI2f;=3 zFsuMEp6x<;vq>ioVJf-@fk7bS*CTl*GOl%wJ67$(7>4Zo!qKj0Y~2ZwR`5qYr`v?p zB1S4PjXWF`x_szw$+$V1j3i`j;!GR!$TfIGPxq47ZMYs)d~x81M*>rDW|$5`uFvl; z8ARXeKzxv6-EYGqdJ@S;lwG+qAtTdE+N4~U!MhD8?CqpLa8C``*Z36ffxyEo-8s`>NDdeyLd;!-%+e=_U-csswBSrpCKq zO1WddpvysY%PG}$l-ocG&)X5WqPgFxd=a>l#V2t%8~KvtvI^ykg9y~oT4NBDF+1*L zk^D)oS0m$vQ2~`4OO7y7qr-y{QcOvXYYKAHW*tL05{5~)x5&D|1&dDbCd1)B9W2p# z$S6<3P^HhKCE}ZnWz^P)uv*!NZu2bkW;_L)byu4Z-wBEX6=h~PZVL=1Is&P@2S3Ee zJc1K?yW;K21dcLA`PONzbm!S+(0UN@4jml%hBWmo1R9ZDx$njClI2#Q{FJjSC>_YR z(&@DX0Mg(8IsTGAMkYZk>)qd_LaFdrjsq#=%m%5Y^Q18Woe z84Z}SgQoX4#I3&4}JyDq9RbTgWR_Hw(nH_WHL7Ni!p=AO9uLuew8m%pO6OSH=qGy zN4dwkBK_&3yA@}V&N%Eu$+GY187_hl4Z2&6Tf!_>?lWi*n;$Hj`EAi9JMic>`5|N? z8SinNEs1(nVINx z)x*$>o!!fF*UYBz=y`k3KRT5-6-_zQV!4C{>Onlv{YWg&;xO{spXuC=AL%4J$_=Fo z8~w?v;~8lf-^54y6RkUXKAz~k$!_d50?o|SPg`<4NxQ>W@hNXagKym11~j%zri=te zw$Zz)zqvsQ;NQrNCV(ZuXw+UFh8;u$&0MmB%-x#)dNW^+ znxn;`=qBDYcK75%Wm7c7V)Lj@j*gO}v7GNi-cuK5ekTm#X-9fH%_%b@@>MqV;d}ve z;hVw%bYd~;*!TS`;#_GL0pK@s6n;DJk+67O3k z{f2p}fiH@d4??v4zI?vZZJmOID7~rNHm*iK+(GPTQN5C6<1i>}ME)%f{3l_E*OW5`@~wyF}ODNm`~Xrzcxy zCcg>Wc_v;!R!9fz68!XXR?zQRBjT;-n(aO)FWE4>^cG>jbNH$>BahRRmP;Uq44?x; z4-SFZP|ON1Ua+51)kh7{;Da6MM7qj99cS#YaN=CXmUL2_SM;t9@axT9JN47C})MdY3g|qyp zqX9oDhd}xienKy4Rp+3>Y5{STPl6!-=RG;{M9oe;jmkS!_l^80|C|ql5207$-0?dF z?$q5rf9qYxKhvS|uRG~^SFa$GoM2-Bc)-CwUk8O3pejbWRP%0(2U{ zi=*4!;LTSA5b%Cn2GZqxP+23J3%zH(JWwud0_hmv1U)BY;1o#FE?tMy7kP7hWkC)WbUr61O5-Zu;MgyU`VEe~QKq^4TB~1$N}Eo*^dPyXkvMCvU3;C9sPs;RvDCXx|4iB)rQcZb=ibr5(+&r^j&47t{QiPoK(}Hii@&mm zsn@c69OVV50Sf`_p>4sw6k;3=Cr+ee6$-5B$}#{@mx(kC6>270g(B@kWtI@O)*S~N`n9y!$Jf9s4#A5B&x0WHA&kVCJAUzpc95sk}{yYJR3Z_ES$l`Kgt!0 z9pQ82;g=S4u!J#_mEY`SDMcPjtH{uiF-xZz?kq&dRAkQ`@(YS&ODv=ma5NO-E(`Kd zRB-PA@}3lN*qM?3mw`KR1vd=P!NR7uhU6+|i~)C$v>688$LY!Z!t-@RLlOmv{FhMm z74WtwgOpK}R|3m5ehvG#;|}dEJ{O_+G|&ro?68pxdK3GU#j9vAb>#xRB)1Wn;a!2* z%$9Qi;pjOb8nMCvF!EWYZQk^M3e(Wby|O|yk?;MZ!0tg3<|EHs4#)_ybD0o^&s8GI zKpHckTcJ81bo!=@r*KO19v@DFWg=KI0;gJ&l3{yVS>_HIVd;Sh%MfK4lRf+(-%+;o z!`6K&i>}OsOeaULjzi>8g~!NQ=XVT3j3qfYAkyim{N=_d#4e4>i^BRJJ?;n)Hqs!z zFu23{hX)wGVUU)r@E@+w@PVw*&`KI|Y3SWZQiHT-MoTRfC=Z-=JFeu! zJDk8-pOIF|lgK5NdN28*`*xWp0__*g?8Zn=o;h5}!2Kh43e4_T8b2t5pW?AAF7e14 z#dn|~UH)Oik$x)gy+l|xpcwd_`IMq*GP_UinjJKck7HCK4e88gY2#QB-`FspGLl&= zIN}2zkzIFU$bXg%3pw*g?e8L3&SNms@=*EbQ1X1F%2M;3c+o8d6m-s%Zyr)y=m>ns z-(bX?3>O)uVy^tccI0&$-iLeUAO z@FizewxLgSAwDP#bD#)*(=inLO5Bz{pQuv(V6(ToXWy0#R;b|q^Q&t_p?vH4Aoi{{|P7!^#}9c9oY_Z`4)3q8R8qZvTZ;Ic3< zl`S#7hFqf~Dccw%py#}k?;%^3FL^<{95?LAmGX($u##P|JW`pfpY0*i9G9Tcm?g>Q zN6$7#htJ7<(fq^KVZR1!8`4%%BC_d#k$&BKwep)}f_et`6+9q}qOA*|K=_hj>r8Bw zu$%k@zLxxCydpisC%u>6w>W)$7T`_Uf#!RjaSn~nr|J6kS+ylV2fxUBrvTwTDu1QV zPCvdGv$SM1LK4@gqlCNw$E*C*G16H1SMRa>WRxorZqZB!OJ6=r_X#A|$#-%E-_3Uk zcb%ghD(|e>QW;lng@5Q9bcNzdeJ2t5xkDRAKGHW_hePksDb8|Ce1(ibnQUL;FX!d< zrDKq_@m|^x7lip%=>;+R3)5KLu_W{) zzpVj}NMF7Y&rZne36!64ber-3&@a_iVB4W5*Y_Hc{?Q5OB|;_pEV=AwqOqKHq8*4U z%bw*w_~JBTze>5{gpu!&_fLTLb)WJ!@&wEFORw2abVum3gIiC^=6cZ`7e}|hpgWPz zDC4Jl4@zTDWh>U=X<^D#uc10 z4o1EkXT&Z>y*tqr2X`j$HDT*r8Ilo5BEKxB&>*$8pb$T#NMl!3-xp;H(WH>VC3kKjZ$Z!)>*^=s#zl2 zf-op{%pW-~H*g715p~@*fdbixO>%t!P%#PD6$~yM*r!Ci9j%n+a>u9R7YqnlHlNSp zwPcjE5z6>K7cw0FUro7+hh#+QSdIfIL(ln@3J{F}mjD%`s!T=t4fDVS#GOooZDvr_8 zu#zFhM!<}KK10`S0f$A|h5aCdVLGKTSAJ7I@SMh=bbdeMUtF+Jr;3C-C>F>J9Ubh= zgX}5aAj9&>WlfHzAzeobmyx0Nk3Wpu#*Q%hfXN>ig%PJnx7#Z>dNMn4UvjXSYFfO;j}}HLPw!LZ{e~(z*BJ$`>lrpo$$x}KgDDkTc)&7tcAhQ5M&Yrp z@n|JmQ-tooD+VJWrlMnKc|A9L7Y_(nn7@EbNTy%P*od~p0TnUPrgGhlKsloLd`Qlw z{cIkm%0b4%4mLA=Z*deeMrg*Gj@`KejW~V=W<2bbv+fY00;cb6H|tNg zy+qbR-&pL)t1=Xvo_eN7WS1jnZPi3x6q!o%X!PP14PVeJX)C!Cuc5n*gJAy3xpJ>t zbTYIckUWN@blBUQHP^50+rfJ~8WQv_v9$iuF?2Bv_Q<5F3!sS5nxdU7b9@MOs zW~@As%WMULRu5oNJ&aj%60v4_KLazc_xF{>kWu+1ntA)^2;JDIlKz0AA-iU0uUU?+ zH;2^kDCbiD(eOY=)clBYP#-ub{DE&=GXo~l)%hi9T)=xF>b|-s+89trx$QhDT^PE- z9_k)(jBjHG5BcqR$@oo&F<(6|nPX)7p~_-pkTNLvMOxw~4fE64Ls=J4I9b=&1|#Ya zqRC~3^jVfKH z%s|!qlU?>GdQguPJ_81vO`$V+@4yKMUgkgw(!)FsoWDS;7ETxlbatr>*$(~gn> z;vMIIe@J}d)NKHcWXU7XgNAK@3{tj|=h}`6jvn-obaSs@`sExICkQXJ@6hp4oi5e! z8Tnb@n2yo!@SAg%$!SSe9ycxhdYP_)!?WB4Pta?9+RU0fwodQ0`6u59dobm{_dR|> zGkdZOfx$$iq1#3%Z+mc@@;m-pr-$(AT;+yjtwqIE@3-{(BlxI%B6$fOQIAcKVcva7kum_=%s;z} zgSHzdZCr#q5BSjZ=w!pECI5Hw+2xMHM-E($Uovi&f{3k|BNJwhOz*S3w0G^b?woUE z4^&(!H$6awLEEZ-VoM-fZC(+qll|j6@)5S#ZZq3|*!itZ6Nf?Glnlfj zsTlla$-9+1TRd|_y7uVyQ?kuolwXub%7>mQPF?6hcfc?p1z;yf`h<_p_tr}R&!h#q zP1%A?gO z{t!wBNI(!`Ntg5JB%bsgf`^fd!6PSQt(4&95s?Xpu}fq{p%T(z!$cfpoB=vmC~N?q z+Q%rDWcY`%Yh@;ZgSj+xy3t8~k5v(!?Cjey%Dx&WoO$txYb$9+)I@<&{tbhV5*8R! z<4cz0U>SMp*HSA4aU7jZ~PW zD=p^zfdGxFc6W|q0ODs%B>T}bB zfva=A1mRzl8AdB3>9Sz)jD{SE3u2~F`Eq$sz_)ou;b+Wb)KHn5t4!`1os5d$8g@Jb zWy1aqCU1NG(}+J(xrl*818jHzFX5XUylDBO1ON026;_-LHdQLns~Pyk;lj9FAZA#E zF-m$eTZG19hpB5RlyH~CWOASL%V@eM?lIC_#^tfXm7^^0rxQ*Rr?2>5aSnO4OY)<` zL=t$+C~mzc*>U55$_wOmDY*>3$>))dC0ltsx`{mi|Is0m^__V$ovQqr(2$W8SKgJg z{}yMy)sscLnW|`sKzo^7i1&D7}EPcD2d&adv zV=&R#i^>kP?#xEb?0$Wx@_M@SfHJKTS`It$xS{N&@lm-x%Tg$zvt_lQlV#Z~SY~J; zS#EBtV)R0@JdjKiPX;AT6i3O5XNrs;Xm%eAoj6*BY_K;AaX5OBidxWPz$8^rq=D!sqylpZ)OdpdWf&$s;qG zz;s21J#L!){atska0H89qX0|Mkl=h-*qzOEOKD98U z`bga4-NaJh!gRve^X=cEU6skki; zUvhau$2v>A)y!k^q1Q3z=X`_yijkLg!q}r%l^3jU{YE|tKgQRNo9TV~&F;1PrT3I} z3-Rgz{)>-twjK28a*6DBT%|s}8mFF>htOd8f&VUdLN-f&qXSlaq7E8gZ3Q|IX}HFJ zHwM`6d}zc4@dECEf)>ShF21s4+FW&Zob|iplRY9Jiu#HEn@;%b*>{o?H%=3d%3Qv2 z1nd+SH%2)qeamg`my82=QP7L+h2Qp>WgjTbBHailIvEL( zf2wW4eCA!sNBLnt<&)_&p+d9;WJKcD7HFeI9C7wsp*VcvL>V98ycz)urWxAv+IdS~ zFcQ3$R4e#Py=Z>w9orM4nSm3?Z`kXSG?xvsVP&hd?LUMIEwU%7F_OVVrqB0P?#G)x zuAMtfpE&%WK{TO{W%pqJ7`dHZv@9Er{lgPhF07 z&j`012)+bAUMUE^LzC!@TbDwY_T{%vw?c_V95c@j06s%=%gYVv%Ruj#>3zd=oM&+K zRfD*=OjiUCnK^RwVsmu+ndac;(~@7=735{h_p3dS!;pMit`RfUy)pS+56^sW)|y|* zH0zf*?fuhj-IqVi_80D)B>_+3tKK4EYxl{K z!8zG)-uCu?mDe3U^ONtlAJtjnjTZ~tvJ4$Je{dsxT;TQj&f01V$KJnCB6>i51fH4K&5lKaUc>J%1Vb{lye;)^<=meH~!}IWLXS8bG_sIID`Ja6H zEqWC}!~oC@;uu3&bqtzWdhhWcc&*R-_?qAS&+@Fp-~HDAO`di5n&16T^Q^-so_LG+ z7#VXk4qiU?(JVmkfFb`r`GnFf<4WYmvun+JU%kG8BjKJv<~@G#b^L$q2j1voAHU=y z|0K^k{KyyH>tn@5!qdF((e?cMi6`EiX9c~?9czesrQ6m`jLN}XC2Bv42wuO zL7ud_S|CoKMoC0C5mFd?87j}?RA^5+^ymb<(Hb5oFzKC$fA{U@|61smK87~K|HM;o zmRirefPpB~#&xFEfyuugj7@U;c;o-!lMs?ufe*g%@jUDBiO1fo*CGr&#HgqN)YZ2+ z8b8#iE)@B*me5=rG@tpN^?1DLSAJ3?DO?B5QM{=1@1t+vCcl3A2S4azA48krfBdmW z^GrZij9y$FJmI4MX#huua~)wa>XNtJC?I_1`@8a}@XNpPZ|7NukAMEPoxNbFB4opz z^Dcc$f3^2Aet><`su2a*VC)Sll_kLdONjAVD?=rpy#_3FBDM!$=^sW4dTCRA$HwP| zzt@dS#9))c8`HoMWt#h?<-ZM2?os}y%s3CoD>vxOF@z`Gbn0Gwi2p<19P3*5(dnCe zi=oZ%?|ZTI5Hu;C)saqg;iGk2+{3O}+=eH<40eozrz6UuHc!6DbSIw)xYrU@W+fEMkgD)YE+%GUR$p*X>qfc4v&6x(_k3Dcip>j4dUMOzwtr+kNkVgU>{u_%?}&a zxu#Qw(dX<<_TXQ7!tZxDZa({wb(`p|-y|cBK|apW0Mk&?KK_8N^|U+#gejt zMmv=c*hrP1;ocQclqBE2>r}QQ?RN2`zCU)|` z5~XkXC)>3b4B<0BUw#XOU1jA^C+|D{Mb!E4girt6{MPK!KgDP0+t2r#a>oBk z?_L{4fj8d$>FsFwv3DLghtVEE#}OSL@A*{JCHolK41e;e_gbGBDc>TjmGvPEK7(LU zK?ex&J8f6dX5|4naZ%!BT@$y&i_BLv92RPJj62cN9*s5yu8D8R_73|?$w0M!@SV^z zpbgWAr+xg&Kl4B2+4=D|e*Z5Kjgp;`+0xgFPnDGmZ@SGdI!c`Wdfm(FGWacNv(2vi zB^RWJmwIfMiVWB$mOPC-XfDF=K$#rhR^#rd@dqJx*;=NJ12Dp@`cI?)jz)B&;6sg-@~?>;s3yYwEo`B zXXwC1=BQsp{`-x8em#sK4Egur|7^V;wk`gv-}Y7Jo8>|XUahwQ-uwdjLT@?!V{`T2 z{OA8(JnZ2w{MN6w458CX27lXMSeJv#;Q#r%zP4E$cJ?v0%KeY7)BMs?)Wu35l$Mf9 zv_o{b^PS`-WwpQeZ0tc4HZPyszURx-qezW?ZSytXvlWN*t>R9;A?hB4k7i*%PX$?z5yQPHClKCrb8!iJN>ikJiahso+A(=Sug7! zhDz`PLeC4);w6d1ZY4enCe9U48J>1iMujd4S8rJit9=+(M-gHU*kZakjZxeVkp`EMm7=f)Dr)apRR#)0Bk0;U7h zcI4|{I%gIiMJ%HznP$u^A8#nzGguX0?|E|$um)x=!$prVh0FZb3qhlPCZ*US8sO1J zJ_#svG8vhVOxYG_84rHv0n4bQeW>^;pD6Q}vrUpb22o*7E}kbC=<+NPIYz_Ph`234 z{zXKsM<=3heDMm&d4MR4W>V%7vvNDr7`Mh(0+)G|sj8Hzyr_)? zyEMKt2%}~_+2J>I$exH`$LH;nk(^9V!arK?yfh4rpS z((oO5D9g8s105_249;Gjfq2;k3Y;4hztANuFJ<2}*NtOq@G#ZE_P$M7v$YEOu| zjx%5B|0^5O=#X?O-lQ2OjF-T5c7@lBZe;X!yjHOz+bUs_Q(#9GkNa)6xN?I|yeyP% zrK?zu&hCc7xz19Od+ubp8*l}QwBMgLArsg`lIAgrtIlw zpvPhz^z(p$4PJ&Z^Nwe)TmsH7iXLfx^n%JHl}qFs_LCv;4_^o#Y{KzG_75GThz9?* z1iYR-Flv;v5x#Usu#<-K;w=C4zn9#h-y=OvJUD@&=W$IqPG|Y+5z=xrz*prJoxb!k z%W>UdQ&@crz0>)lXo-GwOV)K1=4e;??%Mt0-=6a&Hud~P^qevzqH>yy7Cbopuzwxr z$Bc5$k%#83&dR=XA!h-F9UH!?Fb4Uo2A!s-p; zCs}niCB5lnA>Jzgbk2xfX4KH33x8PlNi{`1i@Kdh%G!1sO5^k4BzHMSr=Wn557oUD zKB0I|4iSoTL(3(AZP41TmUmj_pQGQFJv5A zbyv4*sax~X^d-;zztCMVW29z{Tn5m@^1S4`k?QZ14Y6n8eKELGaV)(Kozw{&f7*#G z3mk%0uPCB8R2xprA_-o@uhIvEN!uUIgSI*3%wOA&ilxrakK~O=vi=bd9jBJ|pb@wM znK*DS@4Ngo?|o@lclv~Xy$3x62gH}Ge-Z!4^Y|GyMVszd4BL$~%#&zeLPUB+Jc;S1 z^rH?2$Ex#jla8egfx0a^Ja~BZpfl7R4N7C%3uh)##*9DFj(spcy4lRxmlHW>Mh5l7 z`O9`uCSeyyZzwM4C)b-1q2x_Slm3&3k{_Nqf^1?t>%MJA$zO zpGP`4w@#IZ^*yuF9B0xg<(jg;K66{O{Es{u)X|xQt9)yJDaYDypohGxH|!$+Sf|Ac zy4TZBDJSKKEA-9wA8GR`_i(mXeCHe((Kt^a6-Gf7t<}-_3YIk-Ly(LUZ=xISGO$4` z3(+q5xhFLgH=fA=@*2HLD6}mWsly|{U{Z|e5uM_87LuONzf7g-VtgFhBy` z3FC^5QybQ-OsB$(V>LkF7AR{nH2i`u`X**L$dCT4mpdT#(2+rwj^%IQr#Y6LDpAm7 z!CBal?x#lqkO9Y2M(#_tF?MmO6t;oWdnseX4ePx|7`M(~xOdL)`~ECFktDj&N$fyUbnu= zPQ3Py@5>49d>H_A0>ZQFC_N1?50Z{i+Rk%wNCR#(l8$BrYU%%@TNp)>P&PUkfcK!# zvCehC|fIO+y|!V-6Ws9d8A8A%3kZdEUNma`$d zfqz3tzUZHR@;41S!}7o}&jp@`i+n@cGcuA+7GA6+Lp%y8y*XjD0*BWgL@pzgRep-E z9)T>!y1RT2Rs7u9!Ut))aLO!>dY?F>Uw3A*2X<4AK!#z!ucRNku|eoOiwNo)=oBrR zDle}rRD+LXMYJCu?>Da5;H#)xO|XEeGdekmWT(vR$TKZ2BT z=bK9aKg@iEhYjbYX_77mqaD4pvb$=~5LxLLG8zI*{}UZNJ4?ma_NDZI^N-{Kca8?* zSf(rl%UL9{#@2{N(y$Fl6K}YD8HmTuLobOY{FR^6J-PjnXYEbzV7`oH{~X?woXnAd z?aM=SIE@}tmUb{pNN*nK-&(yv4tee0kB{Q?9EkLd?~rGLZP9v(&=YRmXdet9>9Yg< zV|Rb&+Nv2}SKcA}WMh3Sp{L6A?U$S5@uHc(q%!3;`n$>+{XF|=2%X<&0jinZ;d5*j z{i5NwzSU7Qu*?{;O^3qjrt;m*JNtcJlr0=(zfMjt|6(Yc*k!a3oo8`g%QexVLW3c* zS7s9EnXYHEn4Ly^k$YX)O)YfujGUE8ULGse{shCIZ;*& zz~ROzZ2F&;zp&Gvd z%a7CUxigkM!qVuXq2#EKi%Gw%QTL5lB!>MGy+D0x4ckqaA501p9|#&^<-hWm2O($2rQ=?C zKxt;K!JlNC?J8c-cMMeGl=lE}b7xI@(64t@XCz0Q{oNJ{EA&~)4#89Z?uC64K_9Ba z^2?FC{4*jl?qq|$4e(w)`kvVcl{Ul?S@7Ph*nVexe_@!;i0_WuMYF;EO97=7dY5=R z3!Rm4lAX$*o4{bRqgzioUlGsBKUayUFIQqyR&CHZ&JPk zZVUIUAkikhakiB7KnDvh8XH8g10#ThrLuQ@0gPqbv0N3)@?hAVcO=_sn4})elx@LM zVcrXbi(n+5Gi}~(w%<(HnQ=aEyex+tKe1Q^x+>U8<64J*L@#T`nrz;vtrur$NX}n8Gfw!Ik>Y6)mNYoio#x7%M~XL}S)*Eo%ib(>uLcUzx_q%vA*NU4{|H(Yf+DX%gvEaoSmi zBWkUzA>5g7==_+>)~8Z#0^hDyQp^h}ayjo!;~8m6JB%%`A+J&>dBiKr{CPRWa+Ow< z23HK?E7(Zkw1T@ZpiwUM{3ePm!^vv`t-RAm6~N~Qp>Bvsh3Rk$K|{FnfkM@JKl8jh z09|P)zk(lOM39CZ>fDtMJK`I>@b{weBt=|foWwJX*qWIYqo(q0d#v+*V0Qxar;7^I zPBYnkK)PCaK+Xn4zPbj}(<@sR!=os>Mq>F?jiSV{r9J8A{#ezUJ>^5(hJ7t+~Jx_7n33dn4oy|7hH(rN%&Om?kkikF+d^ z4%0PK+F-BfnP;d@z}V zSI`m1&e7QwaXu^FXY&MkMW$#ZsJ(eu63WX$0Y#QQQSRi=*??n3=a4_Tr$4WIeQ?wq z-HyF{xaWEkC-TCxDDsP84Ef#vLOxliD{iWbQ9e=@Ige6~Cd6IwSGtb|;+b@q$~D|o zqwEV-bC}K^(&^c;+ZJtpL^kxt(qzF021O9N2nv24&5xRSM%~LO^MPPH-MuZ0LVwV@ zj7GWH?rWe}UN0mUsso;llC7xaaT1}bbO9pRDU0o651HDYi%IPVAyRxt^uy@WyM zNRO~N_(Zx)-}TG$O>l#d;$}Ndd?c^OUUI{A`Auj^m0z0%To$U65%L(Uh}=i`(&u`H z-kQ)MBDZ_rea&QldmT1}&{dqobs=OQ5kvS+J-h;ViM%YUJV?>$p>W6(LYXC`6V7Ft zuH)%;Ano{$dZ*iL&Jm3mh$$i*zIa^Ua?XX1Akx&0n5L6~1)W{bk^IPiyuc038bRk- zCY_&x_kcDGw`1s@2N^2gGvM&(;0y9wX+!$4;*85bg+%?@^^5zUEbj+G=X5&SG-g=D z!SYU7*3FSj`mw%ZbTRXl*_*ruW#8qLp^&MFVOd+@hr z3l`v~?L*xU+ddHazNKs{SO#@;Jw;)|$J$#0{|$~l*PCRh45Dat9y54HceCv&=vha^ zEgFoY1Ad}BPnznNadSC&#c*trrU>J*<;Ud!e;jA=mQLp(PzSCuC*I$L?uk3??gIay zqvVe8BJU4_{7;$5o7OR)1V!J6-lDCHHeU8aiKVc-zq)95hh@r%Zs@;#@;iY1WBD>I zNgML0R|v-WifbXh^~s52wZX)-{L+UNC-N@zP4^yASoB9kz95fA+^F~RiFB!dukAFm{YRVGwMWlLkyB_h zfI~b5Q+at40Mz1(B=WdAF%-A9k{~#V)ALY%!x0|u?Ki6(g(*QVHw?a)Q0(M}Uz_3!i}h%{%VzCV z(mS_enJ>4(tHN=pVwFuj``#!B409?RO`~sA;i|^vsGw0O)r&!o%Vzh8D`V%9Voqls zZwrycemU-_r~<==i7NJNiciHs8KFA2?6L!F2+o9-3%!%Zq~ooM1b0_U#j%x}El{u0 z$wHb23!UCL)1$CTmSB>Vd2(wj9Mjm=HBzx0)wZaxkWY>lw|jtgMu&cEKD*jczB!aa z678#l$VXlN+ycqF4!ZE3I+dQ`*r%k{nWWPMWxOp$QyNj^OI4<=l7hyzXMO|CCkzGi zIOu8LwgBY$6~ap`dT1>n5x^A%LOjn*pNO9wg;SdjAntG0SL--QdHFK{XQJNGh;vuu z^0zhgs*Ma6qPwk5>nbMlP3PqztPCaN91S)&@&L&|HottuS?`HP8{S1L{7D{F2M7)P zHrUW@Ztw}`Z#-gRJ48odWNt54Bxe%P&2k=feimC=Ix!rEN1(BJGbTZDM z1C)+X&te=#b^P0y$8XUYoRxoa(U2PzWJ13fNFVH%FqV8rG~>{TG^DdRbHgl-UPTdJ zkakYLxRJ;6qv8Yl=lI#$KHLoU*FOXO$#XWjpWYZX`w!Hni;6>*T^O;Jp<_yZeGA?B z11k@7K(|R(RQf19cn}Q_oRgN}0MU-d^K9Hzna*I2)g1dk#yF1UMRhcvl!mb>pxn;O zUZQfcAB_%eUP4d2!V$Beqq2_MVYy9-&*DgNT~1oQQlysQV=hW$}!i&7C|nt?MPqi#;J}>acP&N1H^he z)SE{~(FlCrrHEpL?a4fRSwuRcFE9+CN4C89?+Tr+yV(yXu@ddm8xy&)`1O$9?d-QZ zgGP@RnuF&KRKdOFin?bKIG>5<)`>IEc)>*lnfUkOenEu3Ltb$@M;}Pf*w)tZ@>ow3 z>z4&fU?9tcnU1Mr)HPUlRdl%lXopHR=^;71cAEEGnW^Z>-Zr6Kqv0Nz)+KM48^~U#e)vs`4 zmhh0=`Y253M3=n53mRVOWMQLPmohF>7kVAJ7<;LnG3Dqbu)p8Mxys&HGW!0|FG8e6 zI5Ev}JS_$1hkQVn$~h0gHiv()^2+q&w^g2QMpEzh6c>()7cxLz-(-soVOyDTV`}E* z(r>`^8-xOw4%rlbreh8)y%e0U;dNdM4zma3@~Yu-5nj3st~d}c5t6};srz}Q4Q!q0 zFgXt*|H}SHry#d<+HHv`16TEZ)$yUxPS-RlRs)|q0#5^eo`O3?#xy?ex`7l&c~$u) z^n#FST)?OBjpw~YQo6stV#I_jS)@2XzSL zDeI_;Utu79Hep9;7T-b#ex9TSzlLaRk$HD0PvJ_3u0fxX7Jv>GJIVj<{-e!!k0s=k zuAaeowSYA-2wk?!-m7(fx$@((=qF5=zJ^+ss2)$dCFJ}La*6#bNCG8CvLiANxo&E`5bbOw`gH^;mGM9G z9c4Rp%6hN-b^C$nAx_0(y{!8a+r*3c3wlgPU<~ZznafJQ({+$LmQJUB=o}F`>a?A# z@ofk4SfpFIXG(Y$P9-m_~{9pE4TQu~XjAPGQS)n25R3U1AX3dj-WxcX8v>E=# zpMFQ2&~OJJLgDt83ESA1mvRP}#X{b7oRYk%Xg%>)){Uw+{RR|S&`yIEc<-w|>0=*k z){jBl0$RMBTwGS+_T<2(?~i`?1-+mX$xz{gul-D(b@=$x?~=TYm5I9%N>6<>)==$Z zc=P(7oo5|h_w_HDJ}NLr2O(omeIFa4p2U!UKlp1FgE+XD!ldUy0XW55QZeseJn#o^me8gWhVKK#=@_VJ0wUN0}8 zow6w!pH3h%@K68sP7f7^HpBnKKl^3aXMb=# z++Y5U>zhA*;<4A|*-2DKhr{EC0qby5CNNl&g_GQGW48Nh9}V52@r8=y(aXdMKH(>u zkY;5`WkndOgeP9Ae6b!#5H_ye3||ZhUPpLzumC!ASQodjI6_V(nfjI^h%(@d-;`$^@GsEu@!|ixH}fg+`9HFr z-?qgY|I_twU;0Bd5Y0TR)OuzzYHs|g(D!}3@R5`BG4uDO{U7mpA8-2Or^+6qhzj#VV z8S66r+;5LE!;l!UZ_5ie*3L431M``?mw#8!6+$U4LeHlFT!dJ^ae^xX|H>b{h^lwFjMjxN~EuYG> zvvK{Y_lQs8>kf4iQ7!tzR_MwfmSzL|_e@TeiSs!fOi>obNZ)wp_5ZK+^my!l8%mI} zpPBsA*@Ml?kNm%V?@oBffBo(}>+rd+Rz2J0w?dWiK-u%Qe;Ty(@tL2`J3$xaDyg!1 z$9i3A2=Dx!^>9D)Z>Sz%eeCo?%iSRz&@h{iI{mjofmOU_% z4H0STRU;H<jF-uY>Nb0@s}W9zo(PrOgMBt%dC2A%Kv z(N1R-3V{eHeF)Lw10dPMhHuDy<5UW(i_9iHY@h>U{GMj|N3jz+qJgc4F6XRy!YL|^WWBg6YOgazy8ntgE;SD z+s*L5?~nY_JUbg-_n)qR`(3~NtIZd;55P~w8-h$3{35Y+@gMw`|ByQ;@K^sY>*4;o zZ(8T+U-`qoB+t%|U;D?`{rhvj>E9%QeU5yal?h)f&$^B#SS0dY;$jb{yI)6$&Bfqt2A+Y}q z%LLNqet7F?-4Trrhcg1oFhR;TSL8`R$85Ce$2-;q*cnb!-Rtv^qi8~ZRNnD>Lf9mF z-}1nLZ}}>oCwK1*M>=U6%8Zhb9=#cb9EyD1_}hfzMHI3aQ$e2;CXI+vARcT&BhX3}DrE!Gw*Ew*9W-Spi)XI%Iw?-T@~WuF zW^pHrVB?Vt!Lnj>W=XbV?ZI`FaZh6_vj$i;ZV0Y;AbaUhFs=y8@5+=XI%0YVzNVbD zZXGD5M!FQYMV+X6$W9Gxup4#A(0I(Ut&igz{2O0w1|_F>pK2zG`SWfrO z6N4I!#kZjs*Bc57q0d71@V>K$@(zyCV&@4rI=w?SY#7=|8iq%PFd{)lg*#b*qKZ7& zIF~<;x)4hWu@qONeT;IApQJ*+kd+}U<}YRWK>m?_mo9=I=;Zh&O4Eqv`S{$2SA!D2 zV#;{v@YXoGVno_7@-ov$jI!?YC>Z`!R_)0#FhQ(z#YCi>MGlSG@P4q9g@mZY*an%W zNyBg*SDn73myIMzOB!)djdQyA8Ajvz5E6m6^4G?r9C95@(oeKd#`@BX>KxF6#Y-zY z7Y%eM61vXp`+xo@p*cE+)S^9t|1%4Gmrl5v8fN=cA85LBm>omeOWl%boT;mr0nHI zl+ehVH*DE}h$HC_|28n@t|7ubn!n&>OfLiHYQ;D5H~yZ_ztSmelz+J1e!mgX!G}~T zMDptf9=hTj8IKpkT>?94A36_Ho|NBPg1EA;$>POTGn=kAWS#};tfQHDb)-I*?)B*|{dYYd8GfWkA^-wh&8o(Wx1F`l6Uomr;2E z?R2m#7t3afJu`hk`IAZ#o%OOCbpIHqy2)6)*qiOS(a~{M!3|x=!Vp3{C=+=9@_H?7 zZ1iw+vTTA&RMo|TU+Cw{@yhu;Wx@VlQb#+xnt#LrkB9Rmx|`A6aUSu%45D66qMV&M z*e}Ipv}p8z35!3C_E4d`=ti&b1Ky&8s6#TS<5EZ-TW{S%Fkp_hEzj7^StCO*T|L_F zCY_87$H<}qF=ma7W7deSgGbnlG&Xi^5kvG;K3U9P%yc8=qTB)Y3&x+wPrBm{SaR=4 zKTC4Pvum~|gICgxW5KI^~5Rd!YqWDh=*oG4^rX}x^W==PFta_?v zAyga+j!UI8|Mchj*en{*iNBR}XUA4t3_U~MhOjtffG+W+KBqcDjq1Nb1Wh6uns62Q zF9nh>F0&;@d89U|E#9EDwNN0v`HUPGVZ zpwaKiZ{#}4=xHSaa;7Ef-wsa*8DFE?{(<@ykLs=I-fQHS>;Uc|50;61 zYMJH0mw@}?r_Z-QG!o-Ud{{05%!m-kwn#5(gmZtU$T0A`?*N{3aQ)Z!pk-6kGT_#2 zLWC1DRg^HY-q}-x4i?9Ar0m67?&$}&e0xlfmkJt;PzeCbh~YMYO_0NfpoipHRzt;7 zg3FQ|K2va9c7gqo%NSSt+g;OO2PTvGZGFbF! z>-4RcdsD%~-Z^CY4f29~(#hhC&9vDK9fGV+ABCZ4VtsM=zz9#`NXOh6arJ0mJF$QF zy4?^$!O34ba&YdPxj2qljzMm*dcHZ9Ea0{U8_Y&yv1FCBMhV^nI8`M`edkT^aW?Eq z8ix=v;X+*e-lVUNkMw*Y<7_3R&7K5ubfmGty*IfZ#9864V`nBAmb;rEXGZRnbJVvF z&%E*L@jY@K*TF;b%Xu0Gs}qBQjnOx2BXAO-w|Al=!_${`yy{OS=~esP)ww95$RYu@aBzE(t|Vg5Y% z96BREMsTIabtD|!+*~$Z4oS8DgX0}lI@n}48$Q_QYjJ?S@KeWcQyx6Qw?2r}1%RF6 zj?=sjZ}=yzp^6F}7SQS0ODdnZE*e3VF`KB}426Lo3NUn&&bfA(6Z_}b0F>idn@%m_ zduFv%V|Gl@j{M|KJ6+H2lg=`695erTX))a*c&9zj3&=;(QwXL=E@ga5W|nixyQ5}) zJJyDdyn_>8C~gTb9U5Y1rZ~C5C3At7wvylK+bue zhG+Ck@mHT&Ukc2yK0RZ(1$?tyP^nNJEj@QZxLh-j;XnH5B>i^_t^z1|$v`sUAp@aP zLI3=&Kxu$OP8fKL4PW(b+Z@()G!pjG(=sJDX1~EbX(ndC#UL3R_M-EHOS4zUpicD!z69M@@>ELeUjIO8}@7Yd$&QODz-n%GlOcIJ9dw~ zi0g@)<6Gd|{EtTFonB{xbzZW}cAnmomb4#Z=Nsv1(oEqv`fbO_b|7y}ciB%T%WS6+ zj&fZ30J@OdmiP`%qeTB4yUR;$A_vO9)MY$Ku&2}d?>oFrP&&KQLEo~Jsh2aoa-F#i9`3|>U_C9qvRw)u!&d z*IsLf2T>NbkvE(daG8%RPY#1l9BPK& zJpn>FR;7AJ24{8@xjhMYM?j+}mELi-at0fM(rpjJA0CN6Dkzro%ERHuY7tHk!*TyS zX#xSgynPN;yftiW(|GLlYDuN-!w8uOxp09=+%kT#eyenS>c?$BVdzZ=Jq1pWg@DwuVRWQWnU#LJs(j ze}oy0gJFb*A+;?mSNwd$R*L;fCV33|Amkhwf|ihP;;3WNiEYsa) zcAi8xQD#x0J(gjavn_DUxS->oY(-}?9sGimL17(v)&_neOJQv9jOWs~`XHmto?9J= z8;wWduWJADOXrKsOY+mRL2c0Tox;ve&sQ?w0r{w9al*C)X@c#la$#|s&cl^myi00F z+}mYrH^CnB&T+`N_;?xE-h#iJBR}^F3@Fior4zkuU7uk+gv^RphX~TBVb8;R2G6(> zf949?4B9>q4}tw}yd|2EGO;yC@6ZdrI@p37Uo(_PsQfg{<)<7#6QnW#I9YwEdHu4hLc@AVyS5JPVrZi+1NhH z>4@jy(V@z&*yquAHsmAUSDv5@V%fDbl5Q*5PB0DnIc?7JkasSZ{-+V4$zRIfOMv`Z zdA74RhY!C(C)Qu{bNt*!>dxE!-paL(`gVT<*jM;<`8W1}o{ z3|&0M{@|OE8Q%3bN>84KkNVkY}@54(8($GI*w0m z`$CIkDt=u^cN?+K$aT@U@5a>%*$uE}7jy-m%(sebmgn#&>aHzp#WllSx~ zd^=VlNk@riwZs$E!ME>hA#W|`FWGmucTtbG+n2u&HnY9gWLOL`j=BlgKJ?O*)dlQa z55(p`CyyeH{GJ)$^ZE`R^xc`bVjbH@f1jw3ojcHS4^U}oUYDGhcXy8u7e`R*|E4u; z^pX>&Ef4j~d)~3?f$M18lgy)6bn3x;hcD>0h2%2!8$te%J7nFm=)5B5{H=rJ%>K&* z4{lW2c@_(PXF8f^@{9Zy>B}=e@-<5(vfLk#^{R^YLI(vkW-uC$YX6&D?m#b{@i#iTMK>gu%1R5{L@8Lxa#Tn+N%;A=eH26$%2 zMfl)Ne5J%dv<1++|DFt zt@IQWV0Oy#_`vRXhi?~n6m$(>jY4KxWQsVEFpSwtK_=F`~iF#v&O8o~)xfSpbcOC+f95(6M5} zGu`|^GC)~@d?N?;e>e?SJx4EQJB^_eA9*5b{_vSF7Ub%;U2(w z5}Fgp>$ZrzDp|)$+Rz9Mm}!DM;i8d{>9LG(CyvRiaus#aaV}c;NtQ}Z;p0^!^i$|D z^3S=#;N7H+SVaSIbf%ZAl6TIB_drX+O;4oA)(=%o=; zqDl8Mmd(qagFYPPfSg~^FY=}Mrt7Ly)1i(t%vb2h_}KHj@;`3y4l;rM)Oo&o9z=PF zU-}q+XSjhnUL7bGA(L$7a1|z@FgtI0?RqoWSDCV_G9NuH1bsdoMCmvXx*a)?-nVh1 z5Bc_t?@t5Ts-prUF!E|T`9s<*SIiQ*-8vgo3(~k~4xP*LE$2Z=FAhM1XQj~bh|Wj8 z)74v!TBX07d4cmg0`)dnVJBWo1d%E?Fya@q%T4wqt0|-7X;ysoi5o5PvQb&BFr5~9 zIGXyz`Ol~i00T6*;0R0nNU|&a0s)m*eOGqCXjg8gK&JA4HnJ|wk6!Tz`3(C-5mQ>} z9C0KG_$i*tLkqhHosd4OBgxeq<6S&=8N;`VEN%!61DT4Bsy4h!fSH%139@r{Hp5?s z_j3?Gh$VS!Q)49WVZ*^sSD+A;dj#a0ilIBB;C0@=C~Dt6w;p9AE8qS6g`i`uA1w7t>@paju*Rea$ z%ZDm|dg*)-xHARX;U0Uh(7;Stl;xwR4JqE4#*BtuFknLUL_REe!VcO*361kncMZ9@ z3ZQoj)~^F->!3=rtAO=#oo|fod4QhOkAZ@1y<#17uCP}tWhx_lX>_^_V$}wv>Yn`G zQ>ni}hQ`wen%Q2r*Jj%>BtCe+PnQI7UqXaD)V^?+g7pIWD$3V;0c6}Zn1Z&QbVes; zmC=(~H~8jCfy~;`@gtg~&lu2V84)|mCX+RyN6~QaL14}eL;(AXv|w;3c4g)fB{kga zbas!or*v^i#d5_g8kSGx8`1>~!X#H^8$b7+c~yL}HEN_0mW(-56@lwN6b4LntJ%pal(PlTo7 zPuc8Fab(N&jdPX_O4HECDl5gySOp?F0BdF-_D0zpUba37vpg%E+&CP!9B;6Yp2xWy z$-IlRT>HheTN9hgG^Z_qM{XAw)?t@{SP;%(h0gqvA&IdqQrBxJZoe{s9FVRpRhG}V zs(Udzin=g*gV|U5iUI<8D47sK{-O<(PQXJt*(KM=5KDJOr)tO|?YdmEbl2{+N0oQ* zGuo0PT=*zg?NM^AJoV6*dGagY0pydju**mf{7W6iyZ=Bk65F6TOMu&J}A<%H|MtYQk48TVpS|4>VnPKAor#>95k{gfo++N{=VaYKKuDN>C}q4r2Fl6h^gyA!wPc>vz9zeN*P4 z&FjDNjS{p~#9_Q21?)fkbST_DzWQws$ln?l?9s`qS^#XQ@a; zq~oGEuiDu*kuJoU86h^@Do#2$W0HA#@GJo0uAsf21-}K~V>raOPkv92v5BG0@PGK( zpW`F3SSU^>R?Siv-7;Fd5q_U&5SvCPhTEYeuaE!b_1QF!e)yzZF~aNpkF0Na_ak3? zk9iYe2}E%c>9V{XGQeooC%7*;^7A#Sr20f zfA7!!+&t?rv>E;nJ=JYY%Zw(J*puJ?Xx`}%8{Zc_f+GFFfz9TB=*d$X-RcuYQ(=VB z3AIE1mQv-x@i;0Iq4=BTr@woh_iu2xDg>sf3&e`|y=Gm8hVY}$#s=Hf3y&gyd?0Q^ zc-`04hRzsHj4(QGKJeQ0O+be>%^%zh{|Wfg@sGmtb02+8UUhiGuOeL1I^N~~`v>?u zgik*C4$(?Ms0)1<1ymvA2Sc-ex8I-ze-JspNqk@bIp6Q&Z-3h_%(D(}`ckpI zNx0Pkd8BAWFJVN%3zZR`u6*2%KIx;+pP%}{5Bj{1q0R6=`Pdumuc7bb94B8gU0lh? zGy!aiZv#=h^E)YQ%%=SG_pPVL&}R6beEju!mXKc&K~D#zs|I&{8RHq%;X-5IhyL|N|> zI4(c+8u@m0sPK13&Egh~0`bm?8L(*|wszuyjPsG+o$oXcee(;x*GHQ^_ZUN);otXS zoL~PDYSw5YTuByYNT@NqV zAU)2MR~0_9ZqR*4i=*b&Yt}cRe(Sfd$M>@z*)qP*{al3+mEKyi_Eq1#KJaSDzqkFl z)A5Dkv(k6dv(4Xp_IIvt?ET>Lzd-z0xooGx4sRa)Z!X@z{LHT^TPF1@9nwcJv#rYm zN{iV+Gh0L>0Q!f0XkPs{)_FCw8UB4wg&v!z%))kB<|s^7X`lhIxWItI()VDYdLQY} zvSGenglu}BNb~_^XnyeKf0Xq1@ab>(@jUCW`}z0VKR4pK6Gr!TlLwS1xm2TNLXXRT zj9a@e!Kl73_Px-Qb23tEp9e%`=^oieGK{cu8*#VyX|K9 zmwE5qKd`>Z{kEIoU*^5pXW!*AkA`~e@u|v$xBf3t2f8Z!_}8xMm-qZP>o)4pX81cl z{PKD*5V~Yrq`18)E*(Dg4(s{k1?cPjwn;T@ zIAD8Rp0TtJQCxXun*5=YR$k^JLagYL`{jb8gJ&ETdJLN=>UiDr;F%5%R{yxx z0S@lH`sy3)PviEp)G4sT85|~_`4{pGzYFYbW4m9p_wDs|zZIeZ-95h1;S|w{y{V!u zuTWHGeE8efH~$~n4FA>_vd)9P;-H^{QaIEdf^G4P#_kHIX0G%>qqpUTbN^3Zw~{s< zOc3<{y6;@4?=Sz3uU45sTzEaw@W!L-?H-5EhYmGF0`mC{-?3eN^1FZMSLd0KvT^O< z^(Fj*?@m>EoA9NV<@5QIehDM^K*RMTdzZT5WSk_F-h?VPi9$?6| z1M~e51j6qfeLG~xXLp2NS)#RDM++PFohAcOnukMv)3G;uB(_^yp(oTfLr;xnhYiueI zR{`SP#cCVyt-pr~5+X*g)gB3#g)4L@HJq*?(1|lAoD_m{ghTw}pT5+mCjFck&#rr> zN;Cw8D?l6ZrqUfoq3AuHq=U6xh<>UBi$+=r);a7H8kD2gP>#ZN!-nWgEsQC*7~zb{ zjRr0RkP#5IUj7gmwZt@GoYO&tXLPcV5)#Upl)Oi!VgOJ9i$bLw!pt=Ba;%fgDA%1a z%Dfu308_W3hqQW0w}F?5lC06m!XnqA&P%rWNXw7T0vV1D9uaWbd7qV{xsIaTGo47!ef8G_nF4@dJp?J*AOlLvG`qF6$^6b)iQmLf+pFiU^fglE7)P zL9Vui<+5`wAO{fKLH$QFw8#u*gHwLH$k^7ph7_@=H9A^1%6LQy$uY zmEJF!1E$^%*)3hm`o_3E97i9kKn0YA(3OoaX^?2Bgi>OEMxql5J*icxfT!kapjX_`!qNSA?~)A2iKfCqV$- z6n{W`w;jAs29-f-qGka+2%X@xtbqu6>=_C!zeC;vDKma;`*8hg>+}zqr_yGBafOtF zzMgV?v59(ihrS=JCUTVLv35}ma8RXK<<;&DId`(?PA+$NbaUR!UzS0AOQk4{*$R6+ zQkoowo|*S%2m(lJqYX@&{t*oNF__TK{2T9QV;P`)!NKZ`OXxMlxon>N{*??y3C6M$ z*F-MyBQMS*zv4g3#fA{+c`WbYwCev#R?Wy)etZqt8SERfI=hn6gH(<#enW)={NlrDl-;z*ejCQF?`2{`N)Ag-mLe~hkUIsdIR|G z1iohEH~Q2Kd~(dvr;Mc$Zy|oHRJUU0479|)0x6@HgmaPe61K>J?Q}-qBZt`a*d6~X zHbAmCovQ9HH9XzZzrKEW1%UlAD3AG-zVfmz&ah5#AFmwge;|%^r@ecgGPC!t%Utr}dRNRCnJ->wj#xhK@LAFOLeyQ9$8F2!tP#_qpZy(E_J}6h zt9%}|wL6IJ0V+*A!hJ!T(A;%=Y;8um*-=iu_JQsyKac5HSCaoF4Eh!fI!YD2x@2*3?VUTIr@LEly-Dfo zJf(b6ZO06{aa*r!5N3{SjaD|4-{c>I7~MH$w)g6AdJlQ9?76JxdGI7I;7ZAhj(Rup z39=q-SbVo!L|)=K?Plbs8ZhMV;9c>!Y*A=T=gz~NDT&_VJ=>}Eu5a+?e+njTXh_O@ z%PXc2*%E5cZSJ`fl>2hd>-FPX<&Ri`EZ)Phe_hv+63+1V(!z4+ZN34}W!iLkPAN(6 z?N6NZ+ffA#M+3lRP=ek^RPr+1f#+wTuRK^PWBV@!HqT_Q6o)TGLIPR1_uLSQ-?eWD zv_%^Z?2Kzb0Z8SB41#ka*gq&a2Q_5q+(dr4kOJF~YV3DYd*0v(!36{jR&*A5y~g1N z;v95s(8;nhrE^8!Pf+v<5VGaQGEhh3TtbMB4=UnhE|gUYE%C>wHbgV7OF zw9%({FO~XBh0~_h)xmj46~R)Z=$~OE?*t4? z(%7Almcolf+YaOd61EcevWd+1m7j4NK{)CB z+Vv;N~;#c8Ed_zy8C%mUf`!w<)ANBV^ ziDkj;k(}OAp>3l=3N#wc^evAneelXW?Oo@y`j*Zh)Q`&<8`0YVgB(L5I%xP_v{8Q8 zaHO()!|q-HeeZ!7a%5LJdFi}gdHENd;st%l8}`$QJjb$&QJy&d=>TcM?_$XBoL8v4 z!jrLrS6)*Zy1dT9HOl)v$g+b->mJ^Qwr#<;!#>@-J*$L?eSl2ZRbZIcl30y+^%bhw=EbXkL!5JgAEdr_(G z8p54coJjwZx5+N!=7x%Dmf^eRQBMClz?D~bE{lJ*9aVOYWDD($n%xH;vYTFy(U;~U zqtSKJ+Bv=%j{mQGgj}}y&1Ie9ekeV6z>=w?_uYtzvTd$~`Lt=N0VT+9UC2 zGOTx$-#ucrtw@RoW;tmROBQSfFP7Vc@W(cWE5rD&aLJ@NBfj@~?gFx~yZf-uhtUu7 ztgufa8rfC;XXke;D_GdxpR*BVM)=qF^YnEeo1cx@8&G^hFE9%9(hY-|zEjmHCp#=n zO^)frPp8*U|h?xB^-LNrqTG>vhyUU!wMXLYrL`C& z$R2~2z)(Zu(ZSQr{O~!&ZM>XFP4D-ismHtqN{fb{<9t1-!%$`Ic}*Gx`xdIX`%&VXqO}r=lhD^PUG% zP4;prMv}{Qq%Q%AJsCgm!J9mfjsi52I76D4$D#AkS>~e$;xYp`?Lhr(za$?P3_50s zQNBM1+;JmkO_^y(%G45FUhbYU+|QJj_Mh`e)Sy9e($Vj2QD50y$BagD!iiOE;_hiI z=P!B?^!)I7)i1Aad~YL&i)E8MdvD}nw*RogindwK%|GatGdU^iXF@#YjXS(`Ayhh6 z-iPvEDvwlt>y<(bkMllOlXW5 zg##ggorA$4WD*cpB%wb9rN06Go#2Kl){1urPbt-PAV~AWPLQj^z>W6NYS&D5H#Iox zc{&=E*Fc`q_o2AMEo7WSR~1Tz(#Zt`M;a&)T1J4D@bV~s=fSb}WeEd692ud@?C~$1 z=p-$eZN#WCI#@gtN)FjA`5lCee;SFH)i9b2j06A?wB2Y|VWs07=h;9x)&7n+gAJth zs*$3S^VD4BJ$J5DT9KyPB74%>>~Lv_M=E%kay#0IHBCiSI1U-!UBQXXn1>M!&ev=N zA+uJdLr5NCIPR<@Pjc+bfD9e$lh(0eEqRYjO!nyOryimsfES9!?U`K-xLy9({#yz_ z9JDeV0)VTQN;HMA^yjs9v>=rA9dY^8<%!lqB_2f{1#o! zk25MYEEj3RR&l}r@Ehbuj9~PRzmNBUejAh z*hcQrqFEd;QZVEAiU#tB-NvlC;3J)@J4?z3@%~75;6m54MKig^y55qZS?0N13aMCs zE}QjB1Ul!CpIXw#cBaxiFXDJNFhM3m9-PM|;~W*JcpTv?C4BrD4f34wA$-S0euNL{ z5TuRRjz4W47mBC06`UW*?-_>EJ7^foewwR7e$|M2$yl}{`w?{Oad$W?zI{OJdE^6s z>zmWxogF62ZtaXI&zH^K?#%A8sKJR#bjk5Vb;>Yo1Bdks$J%ByGyZ11;MfZ{E3=KUYc_-g`d7P4apft@T?IUj$ih*<*M|J^vO9?$(13NfMunYsOy>L zEQ@N!h#QH;i|UN1c*3_y&MIfdk0C}@M+tEyN^q>c*$%;%NUM?SbL`ne2gXF{t;&@A zS4w4@MpvKBGJ?-^grWVgBjq+>_^IWBj&}P>o9J-+q0>3fEkCmxd9@upP!|CZ&pgZN z9)Qi=Yu`^ce2-2Z_EQNb&_I~_+&Tss zVpdA(1PAR*a1tJ5ZCc5@@hiBqM0&LCaIQF&BYl;h=LgR@ZLM<&Uvx6~2)JWW_gX&4 zk1hmV%K1LeD^9`*`+`4ofPU`Nh$nYObg%@`z@0286^=CiA_NwM^Pr8suaxcv#07yA zAl$%zln4b!7qL5mjaa?pl{ev4818}I5~2m=%F-tu-OjlUKG85`ZAU5JM#7Pf$tf)@3aWVcmCGjN0>26b2FlS zJZa-o{^^p&1-zh9XK^Hc%)@xKJZD@;AII6(2&o<-CKv)r%hf!3VLc5_ZnD=^{O$2cxbhbLgV3$@&wGcdFTy=$P81?VtVX4@!hc!%Tt`lg5RuBxwc+hO=U zGHDrbG&WLUig?OZnw~?PJ*tbK^w|kTdO@(3>3G5t2KW5hI-fbq zytF0I31bl%GK;aC1!K>9mYkJvw6Q>rMGDT{lwU?E*Y>f{keBBaE}Lj9}#lx$0Dp^ea>V zx|0Po4rAH=jxh3B3t45X=MdJagxbKf6F2umQ-+_>tc;a+|fMNlQA#NYB_b zn+!kpJ(KQFP4M}GKCLhK7{27CF6=MP(w=zMp+6FZg@+r2^K81~SpSx9d(7GQQw&-mb6It4GpYnGL~eQ?m+x~+PwiWlxprqv)4z*lC{0*aE+ zn9dMiWI(7?79gvdoa9X#*N=d8ZHOQS?MuO z_0kj_g>~C2+fYkI0UD*fUaq8y;ng#OxQ{ zkU!)AS%Q9!?ydbJty^@?$nRK+2RiZ@4TnXS-f@1y<#S$b>zx_-s*BX@zv>)d*`m;6 zayt6EOX|}LLG*{7m2MKB`VGW>O#ROKE+XW8E1(y$b?$~_*Hy3qv4i8i(>Pbm{4#bY zK?VOvgQLUeZ9}6wJ!`~thONLyQTOMx(z25wU~fq;*DLbfM9j`v$5`ny_BZlhN9smH zz;DaH{ORg#TOuMFM|pIwW*54yZvHCWJU~%(6Sv<`(896mmamn2 z)bDhi7_|L{?1kr9TutaqnGUw!R_Xr+(tSc?SPu*2+Krsb2VruX^)!Kda0W0-=Nawoq0a_1Hqf zjj;q0MM=6M)IqwAd=wYXBsnu=wUkWYZN5jv+>MO@$v`&0nRi+~uAebI)o}a9W^* z6u&Ni+qfc+8FYH;@5zs@FU2yndHoQ6jC!Ye;WsuZ39n!U##2O$Ll`)qCen`G6LTBnos)J$H$*~tKzNqS`j*K9{-;8 zbt=E+cmMM|>+p$ZPH*1o(4?=Ge*Q~&NqEneG|)fy-RpdQ!`ET-(g24N2W&vUzCrIN zzwj0}jJ7jz7NfyU?qC0*r+qXRf_cqj-}i`*eGF}0KZH+OuEL)%)|B7A|Fu5$G34Lh z`L?gjvkq@y6M4aMiMLAgp^fi<=&?7MpGE}VJn^wN$4L*b|Mz1P>R6^E%8;M>=z4r( z^ZJncu0ci^kU7w=#6R}e-k9ede(6WnH;?|Jr*!|-PK;=RAq*P;`@DnHo( zfp*2?b02%R@AWaX8U81qe!cxsVHP(yq-wL2dsN z=5g_&c$LPB^O}BjAN=$WetDjC7~Bm1@i*!#My9kWlSfeZNK?v%D7XEt;@YN>z*09O z>7Sqc*!m{?L!06M=u>Z3JY%|Y3xc-Sq($5^%-5hLWH=rY{v>C%FybFuV!9W4+O!>K z`ZDuT@-x|wS$u`6JPd&~@mr*hFj)T4Mk3|Tjto&osXZXS#C>F)3SKL_a?p<4LM9z9 zDI@%Ma>iwgSAFyPrs|LVvCuDf!t4K|H{{vb7~151TU>iSHVS4|li?_Zo&w7w$%piL z=~WjUSP)*&e-5wx)Cq+ z_`&a9=k>GSaMG5=RDIR=RD($P2|oLg&*WK$S3j?CRmRVyJ4VVw*bmr_d_|sGjzT{@ z^q1Ck!tiGJQHJy}w0ZqiW_R~h&0KYc>IA{2c+)?OH~JXb41fP~p;Ot6-ZO)xJJGMm1A|mla5(Ts{`MFA zULQaCl?v}vLGt#0R{5vH(B}2yPsvDS4 zo8eDCBVDdYwT+!(+v1%+5$8Q@yBYp_ez0q6D17RJj09JH){oT|ke%aqt>@Jty!&J8 z{#|M_{2zO(<JntU$M0fL>$egvfNJ3raUPT?|};g5do9hT*4Lv`%!LJ;1V2Zuav6hBhdXGkhEx!GG-@I<8 zUo}4V`@R~oO{eP*vQ63Kzg-3k`@-!vs*lmpGLHSPSX!{)Hb0^XACvFF>#_LR)kpJ@ z{^578`X7h*7h3*Gc2dJ{6KpFPyzjM8QI<$HH5N2RbZ&=U@Dv z@~Xp-e=j^4_EpK$2^mGeQfv%oelDVX1hgY_Ye#a39f@8j`dUAQn2}UpVY^U=COrdV z+SK524!GmK<q@Q$#v~^9>Rle(g`;kuYh-=ZrDLRJz&AI2jXbP#DcdyYFw$reL z=w$c7^eV2A0oR+8FZqd(@kJjyEMK;912OYg@VDsG(%xHOM-^`zoh*22C2B_K-tn#! zn2eMjv+o2Lzc{+3<82p&6b{26Hsv;h#$uRb21)mgnj87#f;b(VbkxWja4Yt5?%mZ* zHb#{dYv)Z;ml7;F3t*c%@(cmdA9tW{Q`-ll6}${ZHM(yA1(|zfact0v@D2bv++bo- zFjf&BDRP$lqJi1_>mZCoP?tM0pj3E}l(l@DN%v{RC;X+6W~Bl+Xw8@882#y}mrKyW zQk^VhEZnw8Q42>fN^kezCy$wd;Mr9Q--cfXj9ik@?SW{f0BC#uw*b@QV}pNsyVFno zEU!x$a30#=H$74qS4PLSaOEe{oBc#=DD6s?m=)u-G{Si%l;Z29-C$jib72rKm%UWF z7WrF=+CW?mwaUqZY*`ae9&bx6Yug(||fxPnOLiz@G zE*=Dh5e6hH&aN;@7QIxjON65n zH(Kj^cYL?s#5+cYwH-os9GdkjGF~%ebgnQr=B*7dO%W}5FaOPAU6}WZ4aY5kk%jB) z{u6xa#T8=)*DovJVPN|(1LRS@LU%|0j_dL%o;$OOhS8J_2SuwpUgC*S@!k^M$nST#!!@}{ufQa9I@r7n7`w2UM^^tMNAx7!)KnbaWYpgM9R& z98o+$e8u|}j>(kKjg0=HEQe?n| zf9Rmrp%?TGS|DsGbVZiEYq}`j90Kx-Oxkwql{4tV$wd0l7357oKk8kD9i1fz%jU59 zppykUcN7;le9Dj2^sreRA2#!qbeQch8 z4CWz3M|KV)E@_6w_ zdEGh%eI7cCXFT=H4CT>i^N7aO(iKGy`8W{Aei>$4T^>0kr$@*C>TqcrPVYK0zSz}m zoFOyi1=>V2Gd0jjY&^c0zi`4vZaY0_*9q_Jm-k;8fceb37X-9c_`!Sf8f8rEU&&H( z!Ru8slMLdlpXFi?ABdFWFVo9$&vamRqBrdqqHNYl%a84VTv)y$kZ?Vmw~l!lH0Bpv zzdYstm7wwjJWxE~PLxoQFL=JV3(KZ%i^|fRlrDg-Zq^8$1+VjQ8$|hzck68vmVtuL z$rl`Ci>MwLbwScWx7xg}OVh-A$Y=~?^bBR^?}&iqd3r;2svCOBARC_Rdq3nK`U!p~ zef|&Ro6>#kWwGyXSY?RU{fPmM!JB#)kfxpytZ=X?$k&ulE{|bqhI4r9Nx3Kde17nS z=J57Y?qmUUyv+7u4<8UVkwTImwi}>D&&p=*=*qbCp&(D)IRgYFhWRKr8HsUnqhor$ zrFi?y+XBnu+w4axKV!4@W|jlkmuJT(?mH~|5&jH;;CC8~9Hl{yYCR2qo!&T9{j)L8EjFqjsc;`r zAd7a^5+O=imKSPyo*}TtWsH0c7d+{`TN0*Q?i|9HkYnGQ(eXK!4wDDbK!$-V0iPs4 zM~aIZJ|dDdn2)IJSa(V;+dYNIj#-gBoe|DJO@l+ZxuT&8rW=K6n4iKg`NgORMSIlT zXSY0DG|L0{upLI@YpMuEW0o6ko5N;#bYvHRei*1s%xoFS1+#K+m%$Fak)LHmVIOS^ zD_b8^xNxG&KA9il6P=J^gF6GMJlakfrn%@S`LQA&fb-H!il2^)vEFe7eM>-#lFWIK z4ja=M-$(A&58jfW&~*#xCg~Jc3OAy{kN6M4Jj&TT@+^)6KtgeY1>pry9V;#@&IosV z5Qj)(raxKt4*Th5yJZ83);=gIaRqc<4Rem5ahU{WIS z3R-*e5E3`D4d@m1{J9v80MC z?4m+pj<1C+F}^l$rZ+~-{H0a1kmLFMcF@a4;odA7@xW3k?~c0;3+eB{!m+ zM4vG@fZ3NgKB;)W(n0j43;K;HpxUCXC*U{WU8@c82Kz=8a4&D^=W-hc7rc_-%BIRX z50W5_u$iPTVox94r|c#hTrp@o0PIJ!xH*zj<@SJ)qS!;%g8#|ppDEaxhuswelvGZQ zmDkz(!|3t``PYtnZVb~=-`R#HlePJXW4SZX>IVG4>7LTM>>Jy3zPXMua^diCkg(Hy}=Q#6+3Mpq;Q;EKBF1MIg*@ z-FG`Gc*fZ*Cx6;KnF6x5~vgQ`;z@O_VVoy*hBY zi!z;jE<}5Zklr|-(!l4qfY3t)H-zfj@%Wn5vvSj%y-*ZieNUU5>q2yz(CDb2?RI@1 zONr?v#i8<(b+u4=-?R|cseInftm%O~?R>5Gt+N~-UK%Ov7{G>oJ= z$~L0Og(UN$pus1Wii%9xt#N-bP@iC(_P%4}5>pQ&o)OpT zSSc6bqqM|Y6b{BH{NWjKw)3ZhAYWT)A!sRlgUFN{@5!i;+XTLkk=iPFGhFV`tKIjx zl4GpOP=U@BH>6Foz|cF)U z+L9_~AQ~&7lS~qBsY!0*ff8O3es5>@5oQ#e4Xsr29{?R5|M`F zXGdNCP`u^1PdZr6Nb`)>I{3QcZBMwlhA_HdLeFi2o<(63BUCN}428-!7(W|z$(D%y zL>TFPpZs25dap$=R3G&Dvkp&f&$M893-f&gB5f+|V&p{l+vjxKY5a(>zpp|c@} z3QGAcr}L=baGi8WrYY~N^D)3VcUdU8%)thcSK&GS@(l-$oCVEw?vTR!L|iz%%54c` zrvEndI)`$z+=(~N2AgE#3ZA`2J`$T&b23S!-?o@syXNw0vM)onrwS@v(b0Ls{9&ms zxa4>#Pne&2hcMkyx-IZmegx0uz5PZvi5Cj1+|li4l$NnUAU4E;*&;f}V51CQTK{Yx zUx0i#oOEy>SF^5=6_4_@UgKRpvI4TBlf}?`^Mmxq(cqs?jFt0{WS;LlyHlm!wP5n? z=UEO&u{MvzQ-yPM3!8+e1jv8=#HRU?64xCs#8cE;wvU?Ck=&t-Rc^N|h;KQL_n6rt znU|4i@{to}eXw5(Gor z80}8O_IQP3bvtz>vyl3>i)_2b_40`G)k8d!uqN29}LzI?tprc-H-EzUAoqKKu2U54Oa#rKs5>>fHS zNIUBTrO`s=eJoEQ-8a3a`$OrmJzQZ|S}>a2bw+`(So_~$)^SUqrRWH99Z>ZcY>MJA z`=PJ|SSPDeR($8o#FETN7Ndh{`}nrriU#U}Z6~VyqS46l%s8J0 z1Nw+f)Lp}-Js;NPDjH!#fF3zt+zr@!`JH+8p1`^TImxo>E(AR~&iX#`N@4#c1a`)h z4i?TO=X4e#>+>V&8g!;)SC)~VUnOYNMt;gJ4HtBrK5h-(m#irD@`iY=dsXkXK$Y?3 zS0cZ<<63#QIuUAc3>edPk@0t(g7k8l@hvtZgLSe)*DvAqDSmMeUi!NNf)&Dr9PoYl zaq_+5(bSy+INA{JB}@-_9bU->o%Cj`RJ^dkk(;S>JOk5c=;!`)KSs7khsDGCqT-!t zM7k#*0yNlmGxOldNq%gH6P-J!zW2a6!dHA;chK|0+fOUp82ks&ue|4d8Kv7N)BElC z=5$B(T6&)W+QR@k8@kXlgjjiii*w8UDbTPUgPeocB;8d5{@Gi54$EH5{Yw;P|k+gJMqkibPZBhQ5YzNZ0{;;uQ&t;WX;sIgw--0jkS=gLzPs;Xf zcm-`P&(rTJ^NwymX@?xsDR?9qogW6xbXL&uQssH2u{#%WsWaSu#zT^*exkvzS9oo> zzOZAtFy~u2=OZ5S$h6ZrAKz5K{O3-Tn*r+t)v4k2l1(Hf?~6Hm_sZeF=yOMm;Msck zWnPV?i{&t?b#Lq3K;&18!_HYb2LUOr=W1Lgl4N#oRxfvHOeBP)Efqr}Xu2qfFOBkc zPACewlL+NWIDIFjphU%B^fyIDk+mh5cRy zymKlO+fU20GVjIFd1Fb(m%{XvebHtCP=!Z@XwA6d+;U2KNO8r;g>%TM`BzS{SmDGG zGLLw+q7`ySezMWOXjySihu=BEATKS&5A#Iy(QzeDbuXS9bRfAC35SB)oaWoYI$_l* z&2yBsk_V+P`bCbBi5^vhgFe9=qf?Toh)nX)4zu5ucW!hlZV!Quy@F-?94tVe!`tz$ zWSs^uRTL_qkR!P~Vr1b)jBLp1&ZmI_SK^rtyxG)Ibjr~lnlDF;(>GJIIlM%{D=_%`Ti-i#-^VmQ|KhYapTxK*JIBV zp_643eFJFoll5BY{Lqcn$VcW#*9)_)06F{&Pw5Bh*`~&W@FcA2I)k`W5mrg5_QTtT>kKWCA)!6Hb+gjmIpFInZfA~ z_|vm2n?jD2mZU3b>bxx5ZZ1_ZqGCt-QHhA9)UF!i>)Buc$d6v~Br4hG$!GssLcE>b zuehV~?g(_aVDJzpo0%EX}^Wq5Awpc|vwdb<}?e;5xZ}^ISz@ zK7Xl|58FMhzPe%{M_z_KmUN2Qna&hOlwaHDkCVX8z<?jrKIhV^q+8S+xbD` z*$Zu`)IaodW1~s4M}E&8{(e*3Q{GyMS0~VVauU4j&9KWqp}(39I?i^=@E; z=U0u4qB#f6a@fV_MH+@Z7*Y2ktpbc>r|x`6!|=f~?ieDSC%eoTd9jz5iGzG5e~)J> zJDGJ9WkNlxIQRX(6VMlZemdRqd;50EuRd3~^1vu;)RoE-(G9&cI@9@s!+%h19FTcF z9ib2%D13`@!)jEH+vLT|>O0#ijyPeV`>#F^lUCI+86Xn*UlD?bcTIO}fhd!dcgIud z@%xo-DFe<|~s(E&l4_T<3~AuV*ObI#ns zpm(in7(~rI-;cZm?fxtQFNq6ZNBa>ovYv`rBYM#@T=bN-wtm?~rza1rzxqGEY*xFXS%yapNF2;UBPoNvB zo>WJ^E`Pl&@AjMF|CT%x2yjKpvMGk?IxKECny|7rafF||Ro;MpQ1 zQqPEb#EaU|m?h@KS8p%?7ie3T`h;m7ow8!EsSg zB1VNK0k0$^|M>Ik8!!EvukS0P;M=?3yS^FScm4hKO*Vhwo0R$Xb5n8Hp703VIf8-E zHqAf!>8@wJ@KtY#hGT?)7rkUyixl2|K4a8bD(Av@6tkLm71?SHn@sbkzxRw0?^lFJ zKHQg$N(W|{+%I}EO*0|N5V657JpIx2{Tqfh!~evS!TXUiOA8__{-9{w$SOSk-Rq4I zkN#@angx`bmlF{!Up};X_!Dn6k53>o?1;u4p{)pHQt=oC=d{Xq-Iygj_T3jRy2XCCSh#^7sc|x4ywC8_QdM1nW@A{S)82zRCR%UjOwmTA*K9`oL?~H*5U(6Kv+5 z37B}|`x#Mk60iSow;>$-z-aiuYu7hs{N%Im)PER<>B@|&kP(kc4i*~pv=eHphZMKZ zeeeBoei!jIzx$u%S%*)G2Tap$8&nj(CqK5n!TYv&!`HC}Wyp*-CX`%#`5QjxXMGH9 zhJV%gB_H`GdDh|Mk1M}9ePBC{aLQXBTi;lDTfF{PW`4^&0*2!Ix4-S*%Cin{{LmAv z!FXabwVtrJ3@8z;Fi0z%hb-nT|I>Ak4)EAtU*C}Qs`19J{Z!C&8t^&uFvp+z0rK0$ z@Rkq#q<9r!u=f*q|LY(3v5&v`ZC{gT9p3U`<$ZTvhi;~E`lmj&z9H#V2gPGvquLC)DM-8wF5UlUL1SjXKW-^ZNT)qf9Tqhk+#d4jiLp?)= zvh1qL+KQQ`%wjR(8DJDMmsD_W{PFcXIJ6o5^%uL1bBhfeSSl?lj8P!Id}G~i8p3_I z-Y@y0;X3GZ=N9n}(Q8&J3-<1hGKPi|I$Aw4RDm;!DMsH*W^yC*<)NP8)e@@URTtm5 z78oEQlzbOn{hdRbarVDIA71=J*Bjb_N#ETE!XCNtCu7awK87~0zyIa;H%DGZE>P(X zJu{YO5g06S<6E}$@22vvTXT{0i2sA%32~=!@%V1q41fO%?^SZaYnAZ|A9;PvUmU7O zTs-XOzVVu5Blxm92pN3Uf3Xv^IqKyzU|rE7&g%`XXe?;+X?E&8 z{Fk5gaWgi@{l(uDqjuflr8JyOM$K~%{!l#Z;jQ1kUS14shJT|M-^tE>t=+|v6U!z> zLr!*XG&lZ2EY(nP1VfwQTegJJeAMjj%8plly!Mx#@x7B6iesOboAK1wM*eB}sx*1+ zf18b&Yp8Ix^Ski;ue#wcqoE@Fc;CmhC3$X(PuxE~D&um8L2W&9Jr zwCVyZEu{L2-<2QYnSIlD*83`Rk-M@7K-Fz@rtk8U#@XZ0`PTQ4ty}QN^rh^+;UCnu z=f~s!c8tzn%tKCS5IT6%x_%#hCgl%Zj!xF^ZU3L(%?T9kcfe2n0`bDSDn6jW^yn?0 z^m!lKZiYYk%)9dpgr6=u%(OV?^zHxidVTFOo8eDB{VoSr4c^opNlUIPO=-Y-Ls*UvK;kO}Tf|3-clzlf*4L+-1N8I7%U>ZZOcUYvlwkQ{jVUc&UZ=ns8Q=ZS#=&!nmucqc$OkWkm^l~lql!Bbvwnlu zDsPnzTr!INL*MeZ@};|n@BPNF&a)1`_B+=%hyR}674=xBr+!i2)K%7F0r!3EwZDL0 z_nrS^o^=@74FA?Mvg6>N&fPhlEbDB>0uK~gwh5v)e#4(%4`W+=_wNu7>}40uwTIVd zoNT=r{xh^gVM7s_C=Y?-WKhSLHNW9I|6X2qxa!UDFM~h-o4?XBNqd@8TWNj$;q`Lx zrKh9a&3RGrGE%PVTmH2+kABVE+5>6>qow>b*`=-w6bmj!u+e=>9?hEV|6K3Bkzq zM5xTals{DduNo01jVp55KrjS4Se#H&q+Sln3CR1+tCJV zfR8vQxrAafJ*ScOQnNgY(SNwb(SdxK$%xu*CUU2z2Nr4yA#ps}$s(})mgpF<#|8q+ zjEAM-a(tghqLp*cp3=%AI!cI1^OhHPAKvsnU4 zQwA#_)3_%U`J9V)1id&}U=`eZ+;+00d~5(>Y0-4)UUEQX7q-T=mqyFS&Koos9aAZZ z(RCOJ(ZFzVMErtIX6D3ld_zz{zJw2?xm=OF1t$A@%~&pQ7GL5%v#I)1^iG4BGvsUM zZS#2;DAiKJeJ~R*wg)dkAz4m{;Uk^D7^` zl0bpw%EalEx&Si6*if)<=kXB(1pP6bzXRc)*+@F2{6&5T3LB&5v|K{hJpzW;iA{CQ zli)|?n-hk}MKG4G_2@y$6XJR*zGuO|;~wc$oh*KbSwONcVl)un(AhHa#(^vWHN7@&X4fWm7C-)_9L{eo zn)z*XLD)GHsn)T|ecWWafe%$K@H-?t$P-YJSER# z8{NvI{SK!);P`MPn@O}v+%59UT_zC`5vd&_)HJMp&B#UU2pR;!);SViZ#3iC^=32; zyNbAsW-5Cpa=YT0{9yT@b_#ic!9?j|7L42__g5PPL8#t2y|3~$5!((&w^#ah+`8F) z6Xipl&s5GU-AP~7K=bW8V`2G-1{-jv`oNW9lJ-cF>-=`NAemui^PtFY393_GwZU{2 ztx7}x!lproQ=jniyL#%Z952QwRo%3F)+p7DxN{nY?My=|X{daWGwd#k>0;Mzce&q; zWiO78RXK%FsxB*9pwXEx%<8%?wSOu5i?TP$+0{yVhM+fx? z>&(c4F$?id4 zBY%F544M#M^AS3xf;N3-6o<=|quAoe9Ns{e8!-kz+S|6#i_}T40--nILyWw=9AHkl z0OdLyH`mW6E?dKKP`aTPoQBz0&^DSO1LuYKfj5i81KABj0|dTwpkBz#8lz*i*h@O5 z>>#`6fa?o#VTYjy?jc%v?`W>k*`OWt>i1~N;yJ5!gxne`dnpg5*Ir}#tuypJoh+V> zBEKtM&PP5Y%8cfY@@Aq!soF|T^T2i=x*=7KciIMh!TRSC2pLQ{MCh};xj5iPbVAY~&%h6-ujnk- zUjpux3OMhwO7xN*o9qb3Q+1P=#l(t8vDXOa!GlPvN#tR`DM<5=*f0g*SmmaGUPIr{-Q%Q z=<1S9 zR|vuIt{^hu3nJl%;XoZv;dm^CugWHy*Lwr|IXyoT?1c;j{Nck(u6H{GGeZTl%LmhD zR<0oga!(ZiDJL1AUQ#GKm{15SC_DI6{molLPUkQc9qi4u^j=;2T@%Og6g^5s+DJ36vT zQEaoPfHN$4jLri(bnKSyWXTu8aVmE_BAro);y>}fg5?VWL@?bDtb=7(i9fiI{q5jo z2vAPbRWshBBWry&5Wx7MvWvmkOcXENMnGq{;PyJ&&bM@=i_?bMYc?YCy=8o*yu=87 zr`;wW?>^A05jr|HI*Kj>;v4x``L`!auOze_Cw(r*%NM|p z&<943jnG^90p~r5^w5TU@f&A)?h(+>ayCd5Hp{nQRNAn-D$v*sKXB)jQKwHDagy_s zvxn{;BCS;5jYcwE&z4@s!=J+JIyMmgb@yGIr)&-l&?s?T$v(ri-$HZ#-05Sv&+q+FIf;lWsOObC z2E#C-+0)!@ydJB}m46=K!4z@yV#Hx9D7{_LhPKh6yu^=;e-DHK@2b(6sr8Ga=cDn; zJSANDr5_!GEX(Lh3;Z}`^D!tx1xi6HVY+q|o|j&{#mE*E7Tb+ZS@;U3tLYnt5$MmkE) zs2rfbCI5tJ+4X0cw{(p?g=78e%^hspb0U_N=;C-8pc~jfY9ZT{Wvs@kPmQT-jAgs3 z93?3B{x}KZHVo?*@|n)Jqp$qh?B_{fLqZumA2s{CyUpIleK1W$&ux#0fsSe8*Y#;I zE35WsAystXZaRSM4a?u&wTGRS%w_@jGoCOIFl2$zyCdXF`5s=n{?QKO2EhxT>Dh!% z#hw_Q;6LYbr|VzmMeG3+3fW;M?WYkP29h7?s_1N_e7HDl>s5Kui{nLse?xVf&W0zD zD+p*K$agfrg{{g`C&i;0mAfryld&JTR_Do+6K5XPXmhBC6f!2TuEy$B0`sAGDW-u%A*d6ZG1FQSn+_87Sr zaD%DhY+1G|`vhL3lYWdk8#1-7SE#3S`S>2dVRanbH2BYS=|@8~@<8hJ_oKm<1?W!O zcqF^y>Dya@a)@%oAIq)TyS}fmM5EgYi>FtD^gZS7GJscj=Dl!K-q2n;o-#ur*g^Wj z%U3#zUJ%?F=8cy=^}u23*RmO7`n$_d9N!`n-9R1q)AO}AdzLnms0gJv; z-U7VCHB0MxsW!hW4|+1e9rU-`CMIm2&;FP%DX-G0i45UgECU7{Px)`3IZZNYvu8#O z12wp12OR`}%kK)y9q&VeW7vYIU$gFF3C=N{5724QC#hcA{~09dxiP zR|k6KC>Y16#bhE|JG#wWeBj6^&gmpJ(27ou9^L)(Q*f{I^m;fc!w~%KKp{wB7*ISc zAW<2Je6TrgeqC{Qg{?YRPJ?IM=CC7P(7AFb#VO~t>F8kb@*qmQmH41z_(H;UvT`>O zo8QYR5vn6B;vJMAjyV3uPiM$&KEE2A;g_=n%32vtG@iYOkt#qlrt7MrqP#G22bU@t zyE3e3^Qd%kx@0UbM~(yL_YpJu*f?$4=~FKmHbPIt^>}w|H`U?6*R6Ffv`D)~n2 z_vZbybX~#lNVWqb7`MgB18@|^_`2lxn!G^L@T|jmD?7&Bmv<$dMo z9J5R$pLUeD>j&d0Pj(-i*fGM=vQL8a`RU9lxy^O(m-Cl=y%~2(i=-tpeVc?AM5xxC zW;&gz8YTJCy~B|z%<>qs>sYqtXsyn$na0qCLEoLr^CJE{kvML4Me9to?#&ozg|56) zIOj({hNS<|(Xdj8RLKA2E60V#OTNQxmUHTf3>x(M<7xY`bl7o2XEWsqKvCPYg zwTSRMV^ZIv=b_V^@n)DO_@C$acNs(@Af4D{pAP%y{2+QDIq|a1ySYIGsvo%7&e@PiW=U1fRA*L@y)Uv+sh@@SxD9wBEzi{iD6JyYCK zu6N9hE)cGCBcLKKlNbHcqj+gO zlfIn;Bxv+bmtvxV9a9+&(%mg052ETdt3vUVs=V8uKBOZ_evFjXjtH0xR^>VLG>{_AVWq+ zQyBDj9p1+MJ7tulih7VT3a5|71#if1{p+uli`W+q8w*GEDL1~odVgg zvf^ZSY8Q>U6oOG`!BRV2;P8o_+ldP=$&o7AWOUN*GKl<;exO);aqeTZb4{!iZL4UI zYB%BD3i6-0u%UqpHP!$C|MW>jK~(Y_gMXOjY7Abn*MMHJJe~zTMv-qCQOBrCbaHS{ z9H*04d>=J30vaiC?@B8;7`;Q9yS%tVxOW{Gg6KyRe>s%!_*DEjM}_O2pz@~Z46a|6 z_mS2%oLo)~%kvN@;9c-5}Z$>USkO0E{Bt9BKW;6#%$i6dW%kG+`T|<%oQ_p01Fg(ShQEoYE_@}`b8 z;wVOP=ezMwi2O1hU$>jgST2AvgbH=j%#T*h;lZL|AP`GtAH6)ca~fF&F{0^Q-ciN8 zvq#YVRbH9C7F>j*GoB^0W;Y&e#(R`knKu}SQaX67I7~z%PH~CBAw~P0vHQRS&Gh<1 z@|&_I(r0pF*{v9by)8)dzWo}VCsCQObKFGsp5l+ct>5C7irQn(Vh+UeY0SzdYQ&AQ z5QAT3mS-CAZ8-eKubov?RN%!`1OCtM4;?qXK?BJ4124i-QXF7N6wX1SyepMV6t>0W znm%S-e-B^)S0CR^s5}&Mad*O9-d0`|LspCH=KFc{otI%#8XZ2%6>)kB%bTi@Gq5r1IJHUa%mMBI0pB^?jw1`S!QzPTaa^-Xodq6G&hL!K<2TwOkj|h-#>znbE`i$zn z%Ij?O9($(nc%XAoesQclOgg?`_b{4!;@K;4jg1%O8?N1C9~nvq-HvDKnR^M--ttSl zaQLC!tV38v92?HI5LBAdfa#abN299Ty#}4!8#`Hqe!A$wabo#f5NY1cCa+n8`Rdl_ zcd~%c&vK^~Fy)9SfRC0{g?|}@O_JwwY!h%Ph+LM>TB(lDU;+=WqLH2l`a1_pzNAQN zQ0(7v-EU)umY!n^OlIsgLdWRKc7Qa(7t+bIMqo5NNO_`e0C=aCuf=iKPVe~*(#Z8z zE(nje2s(}dJ#6KaXXpTIj*x55I1^}J-@EpDpVJl-9WJChc8~m4`O0kEIA?H%{IHBD zeBBEY$glp)@11}y+qN3N93ZZ4+tH6UR?D6HCuqloSE?s3Spg$H!dsRTV}^^U^D{b? zJcuR3+p$@$xzQd8MeSzQ;_uyZ27&OiMUcJ7d=2he4 zPq5*62jc5><3SK7npoRC;yT_{hLjyZbl(5S`bM5V{=(1oh>-qBFE{#-5&6i`k7ui; z45D`A+fMWTN7pwN{GrElV{iDT&s@mMn?e-&DojO}ua_)kMUOGhe9NJ=g^X|NohFo1 zty9=lwpCd?m=A7fzb$_F*$>)y^&TdwtQqWUlASA-@Kidja>)jk4?eoS`Tr0;`Bccg zWyL_ABCN>67!BcPge2tBULSnz`lh%afAXz)Cg?Nt`p$&34u4$P5uM(fg|zG&=DI)H zjZT`gufACaM^dHe_0H}?Id zA6egQ(3|x;5yW?;0fwvPT?m6R@?9AP&Ktd0)Vl>{U^yRgJM+*7UcX(QxePw>xbg>K znqCLaZAB}L;ga_cyx}n)FM=O_@(q?#VQE0NaLdN4jO=%Vj$`rRlJvq7Zvab2l-t!;~BF=R7T8I*}&js@Pxv& zafx1}5fd6Bn8Zkxa_JuV&rD>{8tg3V<*Z=>eGgb)G4oMjktbgD&FiD?hc?51;P%h+ z(fg_>2J9Jv5xZmh!Z||lO5w)Xoa7l{<_Ihs$0{Oud*pp?BvaW@GTIG)V!#leg^uz5 zV;mWLp!eV{V7bunNw;%Z64PON^i4c6ACO)1P;qbd1f88UT%3lUA3d_Z3G!vI|IGVa za*5w6o8S$;)7&kFOAs4jQ`%Kd2x4rW8WJuy-(py zLl%>tRd-m(ex>XJH}C&fK3*lReeuggHfhoExL?UHI&Qscoe!76{V#rnk4xn-mXkYH zUVUNjfA+mT?tlKhkY~P(XdD!5QwWE*j+M8fF(d{o?KG47q>Ck2w3kHvDdZ?}Qp$R! zGFOo&dLVBobKHJ(J)O42{m(|-;+W;ML@ObqpJ{iCC2@m}7Y1znSG^#LeKUk0yw z;TPmtjD(aRHP1fqPxIc@;QABq?cxKf(kNgLTbJl@jVy%@*F7ambZC+GlnJ~0k2Hse zFEqDa`!D@oAN!A^6G*?{JMl5=oL@-W$T#E6C+Mvuoixa+?D{Bkf=1h9@FFqYeU*>x ztVLI@g3jA-ytw@BKlVZC4V722m*4>-^^t$j*70>&w1c8*@%D?`>66dAtMf<*TO7nq z%Ym?X$ESSkWA@qD%)Mq{naMrBJc?S^ZQBXa$>+;=tkY~-PGRwmb=zt3sor~8<}jKa z?-_;9z8Iiwv=?e{qE28{_JLvv-6mt0*>CaPT%y? zvdOLEs(gv~f*2@;O*4|ML)k59tvof7HXGver@u@xM!j3Pj zX}Jt`ax?tWhoE#KsF^5k2u)Nvc!pWVlRPleuie`y-{~V}oy2SdI#F33zk5+Ws0Y$4K z{AlZJn)@EP;d^%zx4wYQ4K1oiF*8Njd#JN>3Wv`zFr1~YRW6E`=B>y-s-@b@KizWL zcIm+RP&{ruLt9giiK!FAk4od<9Y79CPZpwnNx;KlY>VZs;QgH01p@Y_LxL;_O4_c! zW_{+-!Sm26*^?|`AA0MBcog4RPqcSBh~^>xZas6$vPbxQ1)ujGT>t*ydCKhMA&>RJ zeXqHK)o6Nn`DyuY9>Dtu25?TBMcIh8iV|sG9W*Xa^MkfL&G!NJb1N&o`-Og3t*+%F z{sphI{k75u)Vr4Dp11Bq(U0XW%Qh z$493>vjE{$yyE3Hd*AZz-u2h1j{TfJq|?sO^ZCISeab!ZS>=j5Vnw4S0g#b;j)7(_IDMLJ_kT#OL`!d{kH&&S@a{b`X#J5~c(?3MD=gALtwzKr4js0SC#Xc^@)N92?};?}Px8 zSv=xFVK58Hoh*Pj$oQx6g9_Tc0I7t-0L0NaqwHdb;-_F_6fPYZ9!Z^KIjIKFU*-g( z#8YeOJR*TuR>cXW2;!EE7GflcWFifWHSj)+k&8yGP<-Q=+@5%)d#fgT)?-vfRwDGC zd2i*WaI%LtoRlh!BrJu6Y+`9T3~=lb$Cm*#ERPu(6OAV1_hZQ;(!h^YZ{y_n=?n#D zA=w_5UCE(mopBT=+W5;iClUUp^Qfh=^iQKm;<1kGh2%?rEBTON$!xl|;*|Pqq%@$D zC2rA6uIs6c-E2^^ArYtd1YN~WNEr=2K!mtY-s`_}0odqOT%+@j_*De^5#7M&tA=EN zlydrt4hlLu0dsI z5oYpL1|l-w>fyVMD!(`Zjw3%@Xbf9KUi=o=opkCGPsf4%>4ymTZ*1%d~OQ$uVk?Pph)W zsKV9GQ8V6Ugc2R~l!F-4QyYJ5Jj&9gj%&*8h>o!2bL2Ih6O8O1?w6a)u1n@eGA3X4 zM%MFNH+57=dmx@+U$`L-=>4ViEzZk}a!d4|L#}w!ww8XBCv#@!9HH}g3a#*ivOJCR z_#m7vC_iWv@n93)mWnHR!d9n~1#lf3`cro6IFB$qV~uhEeUylSGU2~F5Cy&;&B8BW z8_XW)Lh6~(a*M^GjCG~W20PRQUNLs>+xM)AaFMpdP~gx@(I@BSf)wv&A-?hy8Ng01 z$bO1WmtjAtw81l`**jkLK29e4<7V&v2b$S6%A2bP%YnvnPlTzm9>@K3g7tP@d=p()hS;N8m_%D9j zCPi;ZwzFahEbF{s-d`Np2$6$KLi(5f`j7a;^V1;TI)CLa?x`|5rV-54d)YdUxXI{M zEqjJRxN&Cx^zyCcbG}s+Y|LYq0QK0gLKVJvT@9aCiQYs9RY zc1`<}aGQf0l$1i)>DV*oL!@fW`gH!_Uc0o!2C9RRc(*m8tRtQ1q`Ic^=Ow2t6x85L zz2N-ai|PpwB=en#?q>fk_th7eAFr7RtwVcgrAYCU1T&h@J&MeQnzr@s#qS-iMZqyQJ^Oq$vwU z;MeuCS@ZKNpgikVg4&!_r=qKjm(g}AAL*j)9r*}c{)Lh?Ti0JaIY>MoJ%l{;)Qe&a#SD2ycI+ya&*ughIyyrAUPIAZ+2!7U zTNaB9N8HZq#XdJbY{j}`!@;`8Uf+nl^o1APgjw%K=w&HcN- z*gWV5SpFq1m)lpM;{;z|^^qHx;9st5<4!iF}EHhCu#t&+M z7z9Qjyet8RRDNOTbp6pk2D_Qrwy+VJ4eVR6;^6m(z?W&FK1~h3MYs!im1lwLmXh7= zr=#h~1BFF#agY)}Mk7CRvQkNI z@PCnG|F&`ZQv(x%FQS36=AWGp%Ul)uK}Jx&F)=9cT#?&=qWcxtDJ{b@Cf6)im61fz zAC}&}d^_^w-&fF$aG&p4Ta>A&ciYsdyX{$Fl!J1qW3@=a_i)BHabz%t;mTY6Ac^y& zC2#)e9jl9RLa%&5`HuiQoM-W^AG!|oB%FC&fQCB*GUQ!~_)|c-1g6xdlC$d>jaTYZ z8Vh(A9UM=?4x6v#(PDv2Psr4dveu84^sh)a++E~+TvX=zZO$~7vRya^()YnDgKIUw z_HzR^H%b z(eLnof?VDNs>#9<{+V|estoK)$Tq(P-PTfPy($j*{4>Cra&-No%ClM|ohb+q$nJrOhEyY%J|qmjiY? zwtWSK`rqZMa^tAVJ2Ijp$|OegJ*fFBnpAGy5z7;uER{3n*GI$s0cYU92>LShiB=E)JyL&ds01lkdMPrvd`4>kFtRbV84~0Y}Na_&HjUA{mo|c z>GGS+r)w{Ua>47bbnW-`k^YH5*)V9ut_tM;^W>3VKlC&G%KgKy^vj?X^^;$JY+A8Y zpYTb#>!Qj_G-~4)^eS47Y6;~@=LsXMce|Ihl z{3aj^_xY5>K0ue91(w_2m;O%$?T68xG`OEp^{(m47);^-~HCWVUOyOUAo}u_5|(-RAv@zZW2Hmoc&lidT6h9oIYuc%Up&9xLuyN8&3$3qJ;~ z@8A7Zy-^No7kw|icwN7It$X(y1gFMvc- zj$JP;ODR9N?u*&|1>}k$pd`BkFQc6bQd3@@auV?d$gI@;9>vp zbFka!%hV-@=?dRH2KFYDvXg)B+WrzOt=zgUzomPB9C$%Edci}k=AKXwh-TSN541djPA{PI6$~;JNj`*PyYy)uH<-SXi<5QKToua{3sXu!B1Wo zNcp(U5yJa-f9W*j$;29{%_rdUn&s_sGhcEviKlz(EM^28=BK99%blv+0;fD_>2P+9aD6dya-QawRXMPL@ci6ZTF<*fwqACdk z>DxGi07`|@vbqVjS!IF4mLK#GPd{E-E^M3nl`2PlnAPR*^8+*j9PhT@f2V9y5wGXd z=JNUI--|l8{4NX}K&zdzx9N*RPkB~nLqDH|?}6a&{N8a~-hsP&Ik)=#KFF>OItdsx zRZ-P1<>ntg9`rHUayL;J#O=h?GXsgJu;iU8V&jBfOnD7$;+z2Fh5yQ6X-dg>q0|~~mvGDxs zGXD7?`Q%*Ta)7L3UFN+1V`*s_B2ETS)gxc z@%zK(!QY40|f;d`|!YWweYe8Bi5e?e^m>VK5(qZj&hH9WF2 z_Effkzttw}7|cghEiTs^CJTt8_S1_gA%H44Qyvwkhocq`f0RKQh*j&8ppD za|fm90qC^T?!@oFZX~gNDC{=vsC7+YB=`xy1d1K+oBF1*G4H;!jiCPR9`&x-Q1r`_ zbdG^sJu;~R9cD#hD|i4) za^2o%ATDjAX&wq ziO|R>4A6#hg;#h~U4FOvBDZj5_l|x(8nI-t7ymCz)aZvV_H)3C{MHGfm&u~*@pCN} z$w2L&8lvOT)l8E7zC7p;rL)K+3t*XZt$QJ;rvk|vdrjJ@GCTv6m*lED!tevVx>NTV zfcfKe3(Vb-45a)UpzLdqUG=BUNj~`XvwSg6d;+3Y$@sos{0r4V>zi~+x`?0sCden| z_d3s~myi1WPF4S)@sDLMfj_3Gg-6SKl%tUwKi(XgE#b1 zpZQIl057jH;nQ)!<=a0B?&y275*R(HANCkJObhytemXP#h@;D@qyH3$&15%M_?-1E z_kLbv@C85v?T5)xeAkOr&Lj7CRmPOl^?R z?U`^BP9nVt)XBZ%pYo<0m`tO+Yd!rrz?1O|2J83vH~(hy^fAW+y#`jz-#;=5Bmac) zn{}MYY)Kx?oBR_mRKZ#KYOzsDloipaC*psn=jAsM{^_90pI>87otFQE&sD$ZTg5J_(7707uv+{Y+TqBgUa6B^IR?}jG&V+WrcG7|QCo>#iZJuk{{ zESb#7mdO|O3mt?;`hd5{eolB9x{sV*%i}GGA8oGm5BftZ<(U?hy3TmX*L{}^z(;5k zUxi2}U5@Az6L=mI)o(rW4p`&OA}vTV2;zZm3`Ea3Ku~ZleR} zL*BbBw5=)Nh5jQi`~(&V&iCP~@k2|4WhlO}J=mwVS2vTH;87fG)zhcHb)4hVzu7#0 z{@dYq!Q;WZr6SMPU+h0TJIp>Xzt}VTnGhx1^!rSo87w{2t=kV>(XF27r|#eIzz=!w zAe`<)qDMUH$AT9YB@#kE`6rk1-Gh3k5LtxU2iDb(RRHY#pnrYcO5qs{b*I}TiIAEd z6;s6f=Kxmods`|0QRuH!YB$a*lyQe?j~wg_^RMvP>3a*#X{ht-n;I;9Q3K--h2sS1{!R*v zmyRQkTveu^=eI%(j(&3B&wPpZp8@teKBV}qJJhV;v2&sh9?%uBVRw*RJy;^+SOW-O zK+8hWkRu&I1|Y5*IUD*p3LOhNK=*2p^>gGUpIZP2D{$gKVnFzDcB~#Z*JG+AlX|9D z^@?M!eDu|ha_m8;z@5q>`pe{?0$6=Y1;2=Sd9?+xS&kZ{qbO1VH+u=E<*?U=kHSeGXR{qGr_%i z$FY}f9kv^~h9Le)5SRvJ2!lPhkc*lfBY%$>a=pB~gv#O$tElek%fG7WymT$H2ySq=K zmt$`cqS$(KK6?m5q%F{9{y?PB-*}?65^_A|WuZQ#I;r-o) zlgu8zzZ<^*SN(*q?ga3`GxAH_=SLkFajZ-F@4;@~S7-Z=1O~-IPoC#7QsP5@bA->A z@Fd^=cs{1yhz^dXLPU4(UN&rW-@T_Z`q>kLyUj0Um+-Ify}lgm1Mcp3_LI+_Msk9C`Zz! z4hxgwqYu#LwECf=t*!9z#{h%;Waau*VE&?b2@tqm7jNw3f9a%`t!dJT)xf2WHjoY zwjn#Z634?}l&_T7IwYAfxXz^8{Ua;4|B_hxFI}&H@&8DIUXT`>^M(w`({X+eI4%+M zbN!U>-*v}3Gq_p!g1%dbeD2@>wQ0%#e%pgdmuU&wTvex_m0dhcl8-v1tNqcA`v!Py zh4juVb;*Ol;AlJoj^@gw0y{?P+b2IWFd)2s&>TMBg81BZMM3nlU96vdF})!BS%XWFX%$UO*W`vxx!Vk4clS z_e(`hVBY4M% zYn|o9j|p>roFGCy>IE;@0$DfHuaAr@XSsX zcBdFBDteN3u+kI`_{d}!acb9%-g8tJeH`e35+CKsE*By65!v^A!!OX2F(W|fbHx@# zCV=e{zK_Rk=od>iOcIi}p7X;maE=m3{1C1LIe3(5>ef&G82x*Xsac3NrLC_{{`^?>&MI z$l2BFRe|p0bf%D}7*S9UnAG!){p(eb;2_-3d`IJUU@HyC#0m6=1{q90%ki{fRFpB$ z3T;v*cAemm%N>sJ1$%Yu&Yv+v(A)e3{DJe93A&~#X;P1%`>57 zG)1Lbj0;9c6~1t?^4lwFSAHd<99fXC7ty~f!;kSn{OsNcF3D15Jg$(=J$DID4L)F7!QRpm?ruFW#zIPc}-MyqP)tPFvX+O&mb`bUAy)o@9$t zZ@DS&?e0T5Gs?r_WyP{1>!-Mg@#U1T@GWPUkwd|xS+xmO5oJXM?~I11Jc<7QI8>YqP9Zo?LKYCLCzFy7`BIF9`k{~9SW@ zb7UCTa6^j4^lHL~H3e<~}Li>hXzWeHK` z7Z^C^5GXanZ0+lN8||}neFujplI?5?L^k{$Kb|*-N7>KzX=+Da)J$osT|f^`r^|*l z2!Mmp8CG#t7~n~QhHf`>;ag~3e#oGYiJO4@jnuYpC%bBgRw19i|MElH-#-8QzRpfd z@@3w#?=3IkweKU{Wfy3|3Q8Y=slU2sVMIN@9A}v_83^1}8;ERKHTbegz3@O5^-xLA zPo;~46w0Dy3+~Vc4ebL=%DAgv2U326UOEf?eKq8kRdSvv@SWfdyNXVFaIl_%z5E{h zhVFFkR0pXuyZyI*1}=AV6`qgQIv~fj>=vMnlZwR`5s0AcGqz{5IXyAqbWvx#WLuQ1 zM?s|?=$+K%^gE@~y-(hd=&(oUqco{>y!{VUQbo>Em_tAYc0UBlTV7 zHR9xAKfp>a{kx`)p#Mz|;QAnN`HBDGla#Kce72kW@6oxmi(HRCWThSTuW3V1qVJ@j z)25rpDF?%7PAQ|JBh}Q`mg$J`mZW$UAf194{q@( z-^%aBbKVID&q{|6yjLANv!mAoRz@m3q*s|33*`jryt{~h{8Q{JfIpr7$+H*hC7pb% zkI<#}YQs*KkDG_bZ=476$}t?AEzY+Qn4p}vS@iYcoA>gq9y|%+i3rio?#Y9UmnDL( zm>$ZDK1}%S56a&^e5*2IFh~~Jd5{X(DDP@_kEf+g)I0wBvFxVneM>-g#Im$cFZ-_c z0zaL!u@9+(?SC3q`Oyugyz~v|Qw-Yw-1Ya8te=Wq^2RUS)uP7hOK4_b0CWwc%_>(_ zH_40oMe^9s(s$w9SAA{$heTw|gpQwCMO?fnx*>9w97^6s>^s@7iqyJcpPD+VM^D-* zJl~o?_B+X3ZL&Y&tbFBHXM!o%f|K?z`Oy6hXd_2Dw#x!oM}H?g`@! z@l1Osmt2E_dQ3Uy#r~1DLGe84Fe2;6$MUfkFvTDe3kps(2p9QZNu!6=|L>2mufX6O z;d^|#9!JnKxn(DXD5V{O1j|<;#-Xwot@uR-l~wF~vM?K>fupsHa_NWcg!EpZA4rAwB+~=&-I0`U9gMsCULHdq4XA#gNOGY!Zc7 zepn|UJa$+2K=_yv>2i4+qQfg~=3^!oO|1{#ZjPV+ZsY~6q{g08RyRB<&z5JmK|tT7 z-OoGUjmF`X3=O8R?r!t&MgLp}3&)&P!IsLeAuX?*`NRcSZ+*qCsZQ!u^dCK8!2h<) z49eGZH_Zkk_uo6(?8=g|8S+OSO2-&o#!~bj{SY47)ra?gHFuDpmmpA_=4XW)n^srT z3e&dLH;B9hy#_4XGI<3XgjASKm)Z>gNJavEA((7v*%z0kis2IH9(J>K`AT8_Fp_73Uqi zD3cC?Wh$6D>Dh6EK4DC%(l#1!tI_C=LSW);XmNVLROGt3pH*Zm2oz zj<&!93_glWlCrKSP;|Fb;z9Hhf?FKvdR;^~kB@@bL_o%vs(Y(@dbddyW6}b? zLFB7sJ0@E6EK;D%_dYvVcby$iY}EwjWC3)6r}dby&}9e;1C7=kd~8U3WDrn(MQdyn zxN*7_k4h|9CkX&II5*``G=Qh%n)J*47m%=&=cGT5nBMt+=%OAG+pIOMg0^4ah@F`4 z^R83fLUI-~T~5f&A`63XRvx;^bph(wzxeC_Pd!ce@Bh{R#Mc{ICBuo~OI+mTl_7$j zfFE=k^aQ>BM#~DxV|RD2`WD^rE+$>E8I1^ALkC1P&GBtph3};YCa|wA=L#FNcYaXw zI&X#C=mD{c>PqiUk0AVKLIM7!)54zxhlBN}_+$dJ>#Ci3;#M36-~m?R+<#XNW`QS4 zdZ6Fmy_j(N9nVFlr~)q?FN2KugK&NR&9jdqd-~zzkM2Y0xqTS{W!1cQhlS%)hW_a{ zIwVT#x~PBF(}myGua;ZVa4*XvAEDb9!jJ=U+cDUq47k74%*y?JIRHv}mK_4$&L45t zk9Lf*u59g43wDq3bEtFv2xh@>c4ewvZj=SKiNP)X^Ug|j_zpctZoJCV$7L)~>|+-L zB98x((X_uxsbucJ^IZ&g-kI3s{mW**`=GGsC4RxjZ~t#jx5Bqi|H9WHSBZ3O!))&_ zvJtw{9(o|mZ3dY)Z9IoykG<#>e>mog5BU2@>9@6@Aqy6eDbG_!nGB?g^}zr6$dM7> zE1vRHoM{Ir%fzv7lH1McQ%%Y^|A2MGi7Y&a0lli(cub4rwD>pZTW+Sl5wGi>c_&@b ze(*#K-&joi9bd;6L=>eHES%sfzF$}%)6Gcd<=EWwUS;;6cJi~zRCSEOz+yRoJSs0V z7GSWP#S$BTdrlXnHHgl=^x3Rjt4-B!cX-|$759EDc2TH)z3}8^S%A`dZ6xCJpyHpl9$^GqAz z4^+Q9dcKEQvfV@Jf&iMb3te%`@!sEm5Ng@YXJ}!vWbU$k_e~~co}Sskz$8oR@6P%c z88jd-_}Md2p>W!H1{9#R7Y4Yl=^d$BKaQvNt$7cht#9-lkm%G!%RqoQs2k+Pq!2oT z-FJIYdSxH9k~R+e)3kBclS#X2ZV-KbT`gkC{^ zWi}^il$O4Wp9HVOWU)vuGl_wY#4qBzJqSFLp5ng{T+7g%pBg{us^EZy&V7CB0bjr6 z-F_9|ofe%`wBxg|_+rqA?~A@jKj>#yu?NuYEoD=92fw0cEEW_hS2u-L;+`;rS7Z}N zd{Cj6qfHTXJoCtV@RvUD1l_qq4oUBRZ%w%Hp=4kVjO+JGZ_&Z8>F;YGH|NvWMcxS| z%omsCx&3E_C7(RHoE3)5JB$S#xlaIi`dvUY@@!mFM)2zaOn6Wp=xX;b--YEQkZ=X#bE(Vk0p$WCEmA^C{M%yx!Ji5P6hie;ieZ@=tC~ZDSZJ#{3ra? zeM8e|xk|6s_U21KXu1eRw_ho{;6z^OCrjhVOL46myaa#KDo8m-7M^T=mF-HG(UUdh zOk1RXsn1D7{b{;;T;hDhhAE-K$)ia8qHIE&%BJcAdO)0&Rz2j>NQ&6-ehaOWL>&v& zDxPVCB=vLPVFizw>RnHC6Sv0~0P?<(AHUWqWQl#^HX&cY=<^BMe)SG;^yJLq;R5nD zry}U#{ogoj1$I5zN7TRQtz!=eos>x%yY)R37B4WYyjEV|(=ybR#rb@YynbbnMp&B7;ih|5Nu_&@yyR0N#;v$z_!@;67DH>I8YEOVRjK zCtCiafBE0moe+DKB2I{y(LL9O_2>aJOye|!ABA|~XbG-fRSEHa{Ab$Hl7ivpc@;5;>iOp zfZlV&2dncL)6`5U3 zy4&7Mjv^B|Vua6iM44YYTmKnghtByUr(3WQFE;wUceE4^&M0o!qBjstXSlLx9cY6= zR=jLnSD*9mTVHCd$g-yl%%3|DOQePp_~>x40!U$rLLdl`Pj?PUoY)D_I?hH0Ixca-%Dj0IPlSA@BaV4|jnX4UmcSQB*zsjN}S?pt1 zdItFHywr0hqDeFJ9xn|`qg%Y+*qw?yJA{p=all}uQ{7r~q2rx+i8}|Ef+eAir(itR zjU!h2g)ZBGibCD@088ET;&P62VjWy6b~lR1qr=~-H$bcGEv$jLe;v&vODD&Q$OUi~ z|Ha?@f9q+&fB&!kr~11}PY{L7ZC&H&lcS!yVMf2j!%!FfBSt%L*;R$a6bjEo)I0Aa zluWI+)j|0NJZ~dpL)V2o%QSH z_-SAlNFI_OIGI?PkWza7?b60Ti{jcb(mghbLB$5^uFKS~t1N?OI9?^=0B>^X@&$%W zxfb(GKs1j%!PE}g;X%*FahDI>BUGi^9WHuS`+q=(uyc;?0d&)|6K$0j^@p}U_mSu6 zquN06aQ|NTRV;7kb0%@{4*m5A8KQ5rjnn}( z?M&j056wdQcCmXfUh-?%dT^)pU){PC<9D zu1`}&K+bK~dzH0GTIs5t9PKu0ML?|Mw!v6_7tN34$llv^=Rc=V18(oz)wOe33x!r$I9$rD6g(JXDbqH7a zPJEny{K0$xm*O9}vO^Z=dcKj}VmHrDe>y%g{`}kQG+DuZ;|j~`rg@al>VqwKINRQX z_qwOOXY%%)rS+b6tZm#Sv%U5Sw*IE!q_-#Oy3b|1aS~qsRr|nEl<;*f+l0#&=1fDa(&V}4>U>E-kmA9mrdq9 zFzS_bAKcJT9M)gjAmXJx9XnSVR(6!1%Q{JQ$&K4k%UCozNM#_Oorw(h)hI*BwNFU6 zo;iy=?E?c6dln`M@2O5Bn0cr?v42Ga_*_1eF>+9x*Ap!>uF8*x@roNI(0|I{v>Ywn ze1K;Rn&CVv36qMar+;u*pb!>1-&UCzQ|TY_wr`*8;>yxe2wqDD`tuvgAtUO%U4&GcQ2B$KcTR=qeY|tNX)XxUM*R^o~<6VmEU1pz>z&plsZ(CNKc}Tl#tJLjjXtu$!QI z4nKk1!z$qVTzVqQCH8}(?N8{d`YdQa5P7vdHcs=fw~cM+376r63!1(aT0ZgH6E_@B zfLw=l{s459tz*{@c9$_M;+Yry0k~b(k3+LCOQF=~T%hL4m zQu2n7@x-6W&zBP|cbofnf9~su-fRy`Zuf(DGc{ z0ra!$eA@)T3q9%{AU68h_Mb9OIX>r@E`=SLc{3AN}BG=mYwX z4aU#nsLS|lro-`4P7bqg=|`7256+8d?N1f-5ox^SNIlZ~L><6r*LtjfF2m3QbbXAx z%N~&V4ehy4oiSR2ePUgCjSRed(=Ubnr%tr|hyVNkW^@<>Gg(i#*r9MoZUVDbW2Vm& zEJ?Q-Id{mE?4M^x%WRPMkH3_`kT9AQ)uruK4VruOvqGT+9JRsGA_VO?P+8!QU$yW7 z-Oh>}Iq;S{3WbT13~B~g{oY`u)4$z2IS@5il)A6fo@i0ASEmEGdZLBdZ}=g6?u=mo zcy=0+=J@fb&P+Nam*-{}%23)oMX@*@K;_7){&MzvjNe6D_b3xU#~l%HJd0PJ=suGy zf{HW^v~uXq=gd?}iSrfO3_@a~VU5)@KSg%~L?JO4#DIMd3ia0C#a`oZG9kjws$H$l z1=0Fp_zrgiR)(pKK6$y39V#z;qRWG6&AbUyHZGT<1>n}NbW>~sZIo|xA8?+Pz8uZn zT~=%~WD-F)dQClJC0-oR7>ah3M!De3%EYrROq}xf}X9f#bY0z)wEEr-CyfE z?O)B z+J6PY&xb<)=YRHpuYd{v&%gbj`RWPoqJ21>#tEH`Y0^C4i@Gmf^$&V{m6G=kL{@JC zo`l0w6j+VLhdW6E>?A-(%GoYi_8>4NW_wzBb36;-y?vHM%|q&MkaS6huD%!ErBmz1 zfwEFMmysh7d#3dLLB7Qm+&~XPx~iy+Z-DmGQ{u)yQMUTGuN^&=T&`5g=KevvNT+hPI=b}Z z=K14!bN@cH`Y16zOs;h2)3n>bL1o2&A2RY)&?{K+3nnu}nKZgO=(XEk;6?dMrsh#e zJP;(DsfVH2A5g3T$&bJIvc7%z?f+`C?bYr~(1@Pr=c8>2yKZidkppRg9cb4X<);g- zOxvIBqe|yFPBP_18)@B8z+Eo_g1D+LeJ;7Vrd=XM<}<@gZSLWMLtZt z0IR$W$)Z3H%9}w&cMO(yz8%kfqnyz}r2+5#H?ph#KHCJJsjYWoKy{z8X<#=CGV?Bz zqV2wU;RsB0N%i=0X2;s3y}xZYCR+SZHy$jfyz{7vRC%5@r)T9O)!}QA z-YU7u7TeBl9N?uEbTQF#_(u6HEasKs!DHC~=WALfz2wOP9EW$X?)f(%FV?md-QB-e zxZ-A`HMZb!b9nep`7j`ydT{!jBTRsvXxY7IF^lX1<_4ejNqwcg2wvn*-v}3O+KtGr z!G5nFp(p8BDesSURy_V*+!hMQ5c-5M_$PhL0FrmZ|kG(5r*c{rI#Wxy9K$D;S=;ZCVdN|ik zw@c`1$A!L# zMz%@6$ecFtFVt?J)2jQ*i||`nB#&Ew+2nBp%B1U_WnVrrw4+VGL)IH6QxQ z?6SfC8v{rJ@1|2e9zZYO8U9-a-fbq}I3#~Bu;@(xD?ooZ?n~Zn)pyPWSNQS-1j>ef?Q0&8(dd`;#NeTAmP$o-iosFj!5}4oU&;i& z%W)~Ils7k(X$suW-7oA~4a{hw(>5hC+?bvyIYW(^Qx@7A4n|v4e&?X%VfxzZ&LNj zU&X)UXtpM~_{y$cJ(g?+)IH%X1CIw0*ZKk?a;=H8SJ3hxE%%A}b?ErJ8VhLMqi$dm zyDxu}*GlgI2Io`0uCvPkEkL;I+uDW;khOJB*^aVog%Y%H1B@f(YR4D%mUBmM-8Apq zg%)&`vWXoDe+D8g&n<7==?C)M+ON@lPwZMZ%!e~^IwmhT)(o5+o0dW2;O-;k0FQU* znv~=*W$EmShCyr7sB6*)Ds0j#5FXyQjYC%=FYI$<9zR7s*kg89tbk3xM)cS~79Wiq zjUO1}AM3jY;y{;fY12G*+tEZ1ZP<+0lF_?)yg9Q7Q& zn22opx*kTKQy*?%ksvw2Z}ny+=o0$7NE3qGYVii{)GI zi~q!@TzTMs{7dT{fxP!iE-D{%#1GgC@*A%OK>|)>9L%8TG{HwW;~P$=XLgo4jRMBb zZ~e>n^&l!`?6mqN0yGyr+$Z!+Fdd7`$0G4UMPkeJ5BWyR<+&@3Di=MQO6eo41SkxS z)4E!$9U{OxVFWZlo?WNYZeF77fBF5FhW1YlfBTQ=Jnrt*@sv#1Ap+2l)99j{OsX*8 zf&4G}*Bx}AI|dAX;TU$|45JE^T)5C#0a!UUXMqJ20E5#aqKh(WGNH$_;y9dDh^~y@WJ#Ee(p{eOhg=<{`;;5@5R7nF;%BvcqI!2<8nqZd;WM*8b z=#}H))e+So7%GE4|F|3YJI-d7v3}`^7Jzr0kq=H}of-oxiG>rLuzCQtR1uR`<5k zygE!bnM!TDWGheo%DI+rT_3W0tDnKCq1CfAQ$~I@Q22fGT`FOtZep+b;JM}csrUP`ygbD_cdrTASW8K9!9^6dIBXbfKbtC=8lZKJM%3k0 zOs%^Ux)Ep^1{l5YAe%;9FdCdMAQ5k(TR$iR3)(@qHKJoLD+>gklo#|73vEB)IOz*V z(;_s@uc7&p-bYu+r*o!Zopr8hXj!c9aG-fp%g@ z(|Ozs27J+}Qat!WFgD$jE&_tOPIM=j zQ20;IB+)<7)OmGy1MdqpDODM8_8*507_68uaPiQAssnES;F&0#?VoxL5Ep-;1G+2$ z>gCwop>(TG-Xmfr1DLd>eNx#m01T~{I=>(AB#VHmS)V4^JpJ~(dHn9MdHz9xBAy8! zAa$9%Qnt~jz--Itfbb#zbWl72CK%2-zo8T0Ak0WfTw%Eq*W0FNHXFVPM>*erC}L}( z<@n5iB=?k^Iqu|szIp!f1gu;Ev}Q0+D$%=OMt^s=R3 zxd^D!TiOEA@%hjG-ws>hyXXHv(YKxe*s;sD0Da}7{=lVnQ_-F`UPIYijvH$5B;$b{ zQK}~@KiUpD2*W`ZZGF;YV=^06*X$>>9WVYiXX&}+qU!~picYwmD57X zZP_si*k43pyj7UzmhZdib~5TiU-q_N(gyedvep zS=m)iGe!CqX*MV*Tl}lJk86z8xTYclzCC`%XH6sZjstrH)P89%SDD zdq9N0Wc!$~HAv@tRG0`H_S=P zlq;q71Ri*hwb_5zoYXcS7(|ycQBKIfyZnT|Cwpmnj0E2dXG_U#n^GYxSJPL}_8n;1 zdpEn}2Tj}3L#LA*JRxO}ZBg5Lx$AnO_fO}Ijtt)x< zwSjL`WkM-*G;l{u7KL@1o?vNZr2U1L?095XLbZBZ}Rao zm!>8DRm+Gr=3I+H`dBgBNdpLq*dm&5zpw*=9aZ;g%s+mjeQ-vjO*IXb49Ea!=+5z{ z;;Q|9K@V=VZ?_)b1;5l4>m|?bM+mw22`^+M4X2IMI|gJp_MCM3W9V@LLxlk>F7rZD z=tb_gooPMK$dmz3@eygO=-Y`e#YwFE?W4ddQI-6GIm z=nbZ>WDa!w?Yavf561(X9(o!><4qlJ*{$)%f?dU-o~`~ku;w)=t4n_`V%3|sz~wSY zS_oJ`?`Iv8o~mu)nY6uI1egnjB>UuA>RyTKlKQ4UBdmd^Ce3f4l{?2JKw#Py zK<3mvFa&RvR!W4RO`b)EZGyASgaMGT z7uhQr&Ysk1+hJVD!%t57Rp>k@SC5k@GXB`k-=K<)m`3vVxN%`cMsGr7+LOH@g><3g z3*HvF0InzE)AdpBoSWrMd9aXQey+-d@O4}V8LVs--zh;DKm85{lVMM?@cj_)1}Ww{oG^f$1%WUKOD)>nF0;JX`bdx& zl|bW&29Kk{ba|t!a_E&Vz~xM*=0^$fmf=^}4AQi@p_|3|m5Geei&rr7*mBeIZ75gXhFS7b^CW zmvEvtzSm!Dwvyo-6BZ2oO}Y+gz=6ta|BNvKU6$TqU5dxhMOHK@%B%QzJ#YxHO9Y^P zP}bN~>}VVeVF8C@5T_bJa2CCZSA4FZvRS#Xy@E#l4Q;Iar;Ul-2HGhi%!(`sZ*M_k z(p}qfrGaPkqCdO_;LLa+M)&jMt-`+&Sdb1sAc;!nZaQ)TuM`pO36{;pW*Cojhr9{Z zdj?ms`a)bQJOg#KMJW@0b_5Eq0*ao_pI0r{; z9@}NL=WS<@i=gXvpmPOCnZKhAuQb^FY%@OWimMO0#7x+7$>9jbRp3A-o z9=<8(SmauT^iEBauRyQL1FpyNw~GJM>ALyw%U>y7RwtiN)aU5oz5JN%1B1qDGgREr zcapCVV4x*!AS<7GkY)HdvblHcEU{{dj;jB*X>zp53mLhM)vG>|t9N=>GHM@+g_4rm z7xChI@s97o13CbY^hb{$rGJtYZ6kwHdv-=SIyxULm+E}67{qN+jU0D#pZo)}Bf(_8 zLYFf0MFj5s5qR#C*BmfX%tcqwEq9Kk5^YbsU^7bHxoXhKeCNr!K01j(p5u@I zz)Sr~_TnGk=g3iPJd#(@i4pankx*ia#_C$hezaLNVFOK(kDy+q?4Vz|R^1Ey5A+%t zKm#A@?@yj=uXYeJ8KrkGEU?i(`0(xx!jv~1-qWYk=EHYcBy)UD{a~lY?Ux_gHz$!gFGUO59OOS!jzVOO#1Gb02Tev;{lSOG`JiGO!@%m^U7O6 zPfU;Rg$QVS59|;S!gt^Nk35KTk&W&JBIA?=y+7BHjA5zkyUMrl!$9kv2PFs*aXnF3 zVz7)3wL6aY_<=q7M1H69Y4iM4lM6~?oP)<8>3Vq!X?wcAMf*d&IPhH&0V%!E(|(p{ z^#B$3MVJ5@Vn3jN%5t|AUj7wsMby*GzssFE;+-!8`CY!o`1!N}qb-Q~K- z;|7Wr%M_bidHUv7c@=fGRU$IScl(}n!T|rBq)-m%i06P;OXZnfqt!kX0WtqviMNR^T6|OJz*YyvcByly2 z^es45V+;ag7b#xRj(=fY1B9oGVC1yq(F5cYuqm-0j=%7BGYBkL;>TMgYD8w8D% zZ9^tuni@g#s65=yVsU_w*-mu%8NT2^cZ=&LC@WL(XjNZBZ zEqwI<8Z~v~b(xT+b?}S2Soj)-j=+k7<3EV+mT8UKVhdNC*jFa4sT=GPLPvYjg0v|+ z@+riCWH%(Xl-~fow5~7wxXxC-yc!b(Z-D!xx^@{gmkR~DNxsM|eK*NZv{DzL319c{ z>Kh~QVqc*_2x-ff5Yq^))Pb2VIiqv6Xr{^{btdlyh@P}LsZTd!ey`#(u0Rm>7P|q> zUJN4|XI@Fu#ZA0SV2oFJfes=sKT6IDY8_};Z9(&d{AOsNPsAWo`xfBWeeW1?`%rn0 zI;uDhGNIJ9(&r{zSKhzQYo!l>Mq*Cg6SN)?w~$z`&9^|f+wQiF_av+%qx)r>!CmyO zv}8O!badMn`jft)bz^|&^0C*F*H4~k`A`1y|Ff@D$mZ+JcOQh9$rKbAa3@|EnP};- zc2+1~$lq<}4iSL!c;gTup$Y_C$YFO(h6wmjJH04()|U7&z(t&Zb2_2L9laS$DM(1| z)CiER^2YcL&@)CG=NKc$idpaK5O_jKg^VNJt9lGA7@!N;g1=#^u95>2D}u`>DW0xd zJ+Fn`KpTePaVNLXo<+mU`B{|_+zC9LSY1>2eNnON8bxV(Cg1K<=)dK|^H~mnWWZVK z0LM!-xvrdC=}ZZ!&sVOO`A9l(!oR=oBFO5h!cF`pVcwWmb{TYi@FV=KF8zxGEv-IOx{(jMMU<@W`WA=C&*b zKtj-E!b`YE8J_Az5j-6k)sI>Y=|L7n8-ou`TXp_m!R2UqgS*3c7BG=SW3r8-)Ds`u zO^p;Nn(M7@F%W4~K~m{oL8J8ql^ZD@gi|kE$A-tLUkTG#w-CRoTGQD;Q-1 zh^}2d&yMv>(+y@qW_WBK&w5+Dja4HGGe7;*Od1lp%44k;(Xpflh}|o848<>b;ZQKS zLrBZi^j4g1N3ug?(%ul>5;qsw)@2gD@t`x^s0L5*jU60NcnryF&2h>Lyye6zN#EOf z@C^eoZEwK2V9_m;e!pI^2w2WWnJ}kcWbfl13VO1JOuKw+HyWSu zq?EcW`}(q-Hr}v`$@W(7T5suu>)tC`btR7;kg?4GWlz|uVhvqTUWXmWutn$413rEa zt@*IM>fkqRLz0)Nt@`lAL<{y-@AkFg{LIJBp)t`7t8?4sH9K*$4A3c(@s~->97iw_ zwS#WERd~>YF%hkQQ!l%GWJ9ZcoqPl*e;?S*B7B|h^qKEe?Nmp;OQ#l56e?)-_uIfR z%2O$em(w%5U`s%Xb8p98I`t^Jt{gWhM_)-FzRRd_w?FtsSH3+Z=$#K#OVZhWP}yHk z$&a^vu6O%Xa=&%21lVV>F=QZcN0_+zv)S9PxyYYTe2^{RBQ6D9HcWuDeU3A)lA%u1 zVGwwtMK~z#tMp)WJ}u(_C1N{X&ke*do%+w%r^7lKk&U<>ORv52@g);QcXxb~fp^ri zAaLhc^7k0Bkp*GbuM5X#SvNbQ3C76{?|rXp-Fq=l;ot}@%iW?ceg%B;;P9>TmnwP? zRgLK7`A%gO9Oq*?YWDH!7^$oDrQxnu6AP|SQ@(9mu5|?2P&@GCPE|d5^d#MUr~6tR z4bRm19%S>8T7vt>zf^eqENm_G=i|H#%Di{mM*T$u&-J~Sw(l%B0$4Gc!R^iF_+w}% zPETy-=&;1?GN%YwECy^JpG&WT-!c-6_I?3&)iv$IJ=G&^b00UtZf;-2dLND2XMqE; z`@wPi?JPsUoE5DQ+43hGdfM)IQb&PffJ*>I;xYI|T#j`z6dz2qFwjZ(Sz(kMgYK5Q z@VcE)D84(#Us2fTE_q~7PSTUEQ>Pg$B0afUrUJeP!apE<=uP((^bZ^0eqEKHGL(GE zhLn%l3$~C!_s_7!Pe1%y(b4rxoo;NF%8UVgx0T?+7MrG~0ba_lP_}e}ftDHXT4(u= zNrUUFWs!G41~gRXDU(Xidln7&+a(I$macQ0*s+e3gXf!%+Uq%ahDP8;27|I;(2a7) zL^AJ@$&egG5Is<&(O;cySjkSn#3hp*$qT(n`|JU9$w8LEC}_L(55Mw&1V_WIgOjw$ zh@pKF$Z1~@eg`0b!2>&{L}T;_`^~pCpm8tU!Mh%3;+<*aMO`f&O`cOWfh8}?Bf0`) zwQABCl;K4c6Przc=E81E$8Y^6F8TF++VWU2$#TB+-S*6%Vd%ln-qZjdba6 z1O6!O5jfc`LQ?lJz-MxxN99oY8>(LLoPj0UJi_aJNH*N2n|jf@o${7G3MK7)nGv<~ zs#o2`lgvEGkLW#1ty_G8lFjC&BkHznn}O#cm&8TZz6xg#!uyZwp0!uEl9lwa+j(GD zwsduvG_s8J~m5z-TmYD%Ii1Di`OKkuB@^ES0x{1!aMFOPW!>OU8TF@cq!pL zpMLOl^-F=7M<^wmwnN?bf&WZ=A!)-zw+>PFeknxyVjM5J>pIl1@OulUB)32m zW6e4s{rz{*+vT*{66#^2nLC?Q*I0O^n=xSB{zKWC*bm=r1_|knR}R$;Ku5w;dbw zEomHA7vv89J1-28t?GJm6E`yO#4L-_%U1Q|H}sH4+AD|XhYm-Fd`)JvEPp4Yb=2t(Tn}Vcbn&r%WjcnjAt#cVOxq{ur)0JJoRD?V0~|X^~7~0 zqjlNssN^~Ht>n1M+ijcv@gJXKq7mk18qkY%a&6d2{lTs>!G+$D7w=|0B9G)7GW3V5 z5P7lTPn~G_-~J!|o7|MKzC4ALl}Kl9VFV?WKgWeZRO0!F6wyYd9nKj_D#c*1i0_W9 zVBrYtkOO-3N7{fL4Q>@?zgIr2Dr_JNJ6V$~UBg3@j!$GmETMT|LCqc1(F)byH0IUA{fm;hv)myrW>g#PU|m5miuIGxZqR!Whq z^1U*VFyxiIfxAAtL*PaNC$x_gsG=>MmU!z1V6fkiFy2wNEngd-b^z<#?>1uDsle}( z;?+RyFbdJJu2ig;>U-dPS$HdQT$X3@pYeb`Y68NBvE5afIcnq^h)ntk{+LAB*834n zI%XYlF%*CNse#SJlUWi?bn1sLaN!+E6p484AOoqtYJe6NY}|&NOR~zJa_Vn5wUfr= z3w8?F?s4*id+0g!?W8y&own^p{{@8G&{h6)(wXq|{W1_VpgK2p-hIvUmdQwPgjg5r zs3(aspm&MbLA^O5EfLWv+UfoPbL&>?1N8$o{PEka`})K2V!&;7#Hrg9Lj7{dpbEUG zb7ozscLj&X91#RG8tfsBLD!3PCKTSf2DIT*D%X)$a?h$D1_~0db9H0ou!Peg7{?q4 z)`rzWeg)Pi4=M>jVZ_P@+iR%&l=iJ%A~((hFe<g9o#SkK83s>%l9zx)ZDDtW5DFG`JMcgFjo9LtYLU+t!kg{@zeX zc&W=eNYswjbiA^fcD7S>g)So{$BEgztu*&emIl`w(c^F-=pv?`?Vuap6O{TuCO}0r zsS3NO?R${jRh{rrg&bAM8&&wr@ptuI75zsyOBW3iFYz0CVAHmb{NUGZcJf7xCnj3B zPv*Bk1ii){w#K8Frg`goD|-g_8&Lt_oo47fk5V`871~ZV_+!9DcGuxyON$S_72>MQZcyoN2C(GgJpX#McN741 zB?Bmxj)qjYthamlG)$5;KwFpL3Qj6rP`cI+U|%~~oQ80T!UGvSxm$TUyzDDF%;Fq_ z8nM&!Kk6#pRDFP~or!Gk?j=VSKS&tVjhEuxdC;lBf0S%`K%9jvCQo(nu6*%1(USTJ zo>koFb(7Qi0{7ps$f0CWI+E3&rT_9XSmbs8O?N=^ZMXH?0Iw%nLL5;1^`rx~h^T%1qbLs-75Y58EX2*-`3{YZH73SHf{@q|8~ zet;I@6%GW4j1*zCL6%w4Q%8YyU={G7zIm6v*_QH{H2VXK$R0&=(j1Q;CByKa2~FX+ z9c0H&%HUslqS$ zDh~$d14(r`iDv1K>!@gf1^D9FXL2JJU29aZNOqn)Gl38p#(sPahMWa$bHL)ocX~&M zy=9q?;fLpkcYozDzNf%9N|7CdQ~UZ}7UkCE1K!-{8T>rT%D$fxQgB}004#%2H&{h&GzO^>=*!R znarKL0);(16rTbwDzNV6xfjhD$P*l`Te30F{tg+sQ3(W*apc^S`ThKG-$zBgY@WUF zlR8-Kod0qq9~L3vW3@i!tq02V&+Xp=y)#9~>yq+lq&WtdpHg?f1DUG5V&@ilISs<9 zwD|MwhcMYfAKGn4K@S4c=JjF>=U?Uf`v4wRnUUx84JBK>H`HZ&h^!3Fn?T+Gf2?Zu ziS*8kUTk~*!X2YV7G}%-~A#} zRJ=+-}e0C;8$4D5lyR59E_a$(Hc79VzU&eG8C7@dRDiJNi~VQGg#rYS;Bz zgfQ*VEet&sv~JCQ8S&Y{!7)p2@^g8w~P2;Tj}FCC*7qXF*65D3j&Zt93&p|KZN29l_Eajaz) zn-Uo1R6P6o8Y;XOIrl|GQ4f8V@>=f6^egq}1Q0 z*LeM(NHzAs;{Mb#!sfz6JzlT}!CyfF=mUxJP`x&NjsF#p4|JQJmSbVzV&6}ZY&TXM ziW_;u4{ZbYrrOVZi@nPOdQBsfg%xIfQl3cxmb%&w(U&Sa=g>D`R| zC%##D3lH!A##eN)7gGU8w+(z}=a*xb)}&4V?$2I_popO|g}9YDe}H@wqsByw2kk3@jgLAY44PhdX#g&D1b_!bS7;_EpK>^(7-1-@ zf_=*iJG)M!dm6qdb+d<1a)+>(F&#qEa}<+jrC8#%qIFzh#aOMk?)aJaK0r^ENvNyzSpdhd$v+u$1T;O?S@-wKVB10j^*_63=dC&=m4EDkoHsE5a2i4MJYLUGz)sS%q>vimDaD+X{ePTw}Zc@q5mt+7XRIq*<(4`i`?#ZSpngSESg$3 z`U7hS?d3(Z%R#gZJUJ%>RQ{{t7p*?Kwjzj5<&IMmy`!r0-UGfIxqdF!8I+VPc=DV=&GLNc7Bs%;REb_NkU?Edcx(n* zw{bhQ9S7g#eRQ$F5h!zx20^9?cHn^5>5^!aC)Y~H&b+nm0K?AsK51N!y3AFtS%rcm zx-+y+`m-Yd`aE!=IM`SwSiB;xzz%qUb%U$^SqkK{&{WjdeGy*Jbtgyo6)@4Ff98Ro z@bx6b_>j7x_z_O%^@Nzu#7~80K&t1WCoFU!6N*6cfS(rc^%Q>EAz(3a%M*x9JMTOn ze^5IoU7i%_UpcWn4G^Am()7l!N_Kj%ljr-?G4LT<>L#!rA#kj+Xt{bN@o@A@X0nl# zIc*I)OIzQty!H_QwbS8$@)N&+hzVO%;}%K>EbmI+-=rch+jya|(~B;1Z@x-*mWi&0 zRbS&)C=tL!L$`&+v)}Ni2LBw)vwr*fDCkS!qyD4MM6x+mTz_X~C%KF^O|*GX65CN> z)&2#s#8uzccnkJ*WD2aB#*zso;ejvlG|H&utt1QrU6{mE{$NK24D|2nyKgOL`#zSd zqKfD2vVKL6(#EHRj%lyvZt0?_pF8;=3!TXTc2>gWNHK3BRvacXIJU=HIVKw;Sdm)3?8UShk97d6$(}~{I_IBr<`u5_cZ_1#7HkPCB)7fpw zfUk&e0DryjcTBF(zVMX67;)kO7=@S*_`!Cf@hnPEAA?tt!KWYoUa~;vGe~5NRo9}# zq{YsM53baEbd_BSj#**ckAZC>a)++!y8DJ_rN7zX%X>X5KXiwDQn!^?4U)Yu!NL@Z z=*KT}y;GTGVj{SDasrPN{-7khs|-YkdO3NoFa~dW@&Pb!N;7uZ2|d|kvW#n5A?)Le_w(&Hzw&MSNVrOevFUUz6WxS z4ic*-FcjVOQT(UfPMw-Fn%$n20#wnHc9Q5xs4M(PYzf8 z+TZ8Mpy5?d^Of zUo-AHaS0$d>Ol8X_xtxFk9ASdN>c+g*iH!A7aV}#3T|ngbP>D9jC#<#!yCqK1^v3u zkZ<1TnE~LZe=`%zEN_vl;RQD`hQ3$v508JLOBO(*U(=QsjisY)x0~OzO$8N(Uq+dL z?~WY=%8Pp3gUn;+zy8Ia@#Dzj23nSiV_br-=@$K4y$Tdg(yY7foQLRiw56O}lzNvP zkl3cYbKhE#*LD{eyb0z4oL4|5BqP7qGH>WOT#A41E^z?=@dZ??So|Yk(uEx(MynsT z8F)(`$+P++gx3`?{(?y+HjDhGTr8>lw~X2zgV!)@2((bwf^A(u(Z2pFL-01PK`+0m zU+cu0kJL8Arsi(O4OmhR2Qr2Xo=_hE&Tg(Rj)$dNe{WUan6W3?+Fb zaUt^MCj%p_Hx1KrzQy_LKo_U4KVQXm+WDua8q(t5xD*4Gs3q-&lbk#XTQ$EXM?;QF!b~0B7DuY*~+jD-M3) zudo48js8>V1lBv<7fYjqENI6fN8l(O(d3+?hp%%vAN%8Kyb=HE=vl||7=B9*-NCl) zsC?T7F=^B|f&GJ=XYt8OtyT+9V(2<(=nm#6V<0is4%2E8y%MbAclheOx2!3L*Q*f? z%@^S0!7+A;beUscUG9oJ;;qyRig#?lmyT89bpz=7WfZYlKy;;S8_#7sZlQ@4__m*m zj-vM#DsTT4SO-Pl61D3)@6cbr(zPdYp?l3|W1Q-z0J4JWL&a%3t z)g76|K}b8Nj-bCU5HCsB6wkKM5h<1X8xk%Bb_@qq^)n znJeM1dNFl|lnn4?0QseK@8O&M=IM9X%**ECTZNIA$tz)&Z{R9uU6}abBjo{I0!;AG zCF&T1Vrp3=^1Fw|%e%>cCNxAD187ve!_s~c?MoF9Nbh7@aZQW1)h`Eos0vCizQOl4l5OTZbL*9RndKwB)hk z_IpF_`<+2SJCzaHFlcSkm8J(EcJI*%cBQCpomtKGiwxkX%zL-k%c=MjZ10s$ZN87Y zS@O0|@W9}n%CehtDI5Cc9U`Key5GQ&YB#IKcQ2chSFh`x^a}UyEPuG%Ks|)-;}dqR z@+C;TLK`xl2tF4edFhsfs4&ThbVw#op&PRUQg{;YlpdX<}&zkJ{i zx)-gxcaq=JS^O6PwS&IDiN~>1whIcjoIPki+cfCE-YKtV1_UKTjH;?GbrW$CcXv2! zj=z4Z?f()?TTMuao2J}#31~ZN{f$8|FmOPg^lhL4o=->FE3w5Qp+15TE;;@OQFtOm z@!W6Vop7R~)Yr3!r_HA^T?Vb>z`z!L2) zVR;!jt@(thKqhf&k$?;}G7fE0DBX}O6D^9NvY?;Lz3I@;$2$=pdHaTbhl7k0U&S_0 zb~ydX)8^hgqIR289seaPiC=j!Sm7gC^p4#zey4wwQS6u^T7RgP(4c;H?Ogiwd9f9G zfA8ZB!B0ALJN{S}pCk=*fBuxk40FI$eAL!gCO`bmprFvJ(BL|uye+#|U^2O)mt5UO zkQ4>WOWuLU>5ZoZr?@?7!k|=R_W+>)d&+8d;(NeV5lpLaK$9oHs@zwg-U1v=*SlO( zj-W^`UH4ty71nXA)3VX%#_Y$d%vxm1lJ9Ro2Re9o_?0In8rVH}KK^4KEV`K|{?uYd z1$tL9=?F)HeBy)<5VyD-rrjCD<+pYGBN*bryU0(K*WFQas=!8S$PZ} ztK#-?K>&E-QzY^iJBVIE`|7;qq>~(9XHpF7edo7?n5V`a+f*>(0^tw)#blupZH}M* zwNk~ty8Ub%C0FAr9G1;1m=tvGfi?V=hFd_c=x?X(yk^}ed1OQXw^yxy4OSXQ84A)D z;mDx3`B~!vrpq#zW#7;PSr07VJn5OXO7E0l z^jQX=i>jmCwJr7iLJDck@B(`2lL;!A9T?mr^By;*+&Y!pI&f4T@PVD4V0CwQkcI63Wz^{R6^9=)1$_iA#;2ye5J zGS6A|3Ad5finM(f!}Icd(7kRHm04K)i`@gX&4E`G7ufn^o9ZN}!ns54jum;tnDcQs zD(;Ts2_%oBI-K|KB&4o9Qiuzk(2~<|c!VZLhUr$$2>hN^A^BEI4;FdnNqzTYOe|0d z5(Eh$MS#LyIUt+>!i4{(vFUOWFJ4{3YQ?HhI94pfbY)>xDysu4x+m;dakcCuV4`JA zTr@3mfJfLXooHMpjq5^!208cxfK6OrI_pY$QW+m8SH*cz1BqBfLwDxJ%1y5-Paf8PMSs8-x|T^myf#Wi(mJI>8i&V)B$fyisIZ1JrgnA4y-Flz(@JNZB+HEuxz^rl>e?8 zx+x+<)7G{F1P*K3@xIFrtQ`yhlEwfm4XFe-Cj`&Z>#Q)q;bGF}@|3G-P=4e{ed(1e zx2zPQCNKE|(AGx%dQQ1`0<;>$0mgqT8|y-a=5AiQAvY1q16^5nh#>2ZJ9ddQ0)YF5 z4inh<*SlL=_hsb9orZh9pH6|G>ShMG2(Pxl@x>RN;Lcm`gT+`aw^7#oup1TQ1}cw< z$f-w6w;3g)F6;F@j?x%#p<`e7-RW${1el#6fO?obUzb}$A0Oq{L>)w-uF1#WttdQ= zvnTS}#`Q!CkX0JgJK5EuhxqIE?E#~514YEbPv_&hO5Dz-?FPq;G?biEE{cndX?|4a z7-StgJJgxL#_&4&l!(aE?aYQ%Msj@RKkUCbZ;n4GzGyjo6MFaCxr^)RcR#9qO!|?Z z2Q^pTkeOt{2rfJntu3F%b^PI0)_`>k+vKMOIy2$24p@iuzuGylpev*7g#&*Ao5Obn z7$7V&?W|T??^|#w!aWl!H=y?aM|Bn+x0~}bGQEg@bm&y;ID@n3uvc@B z6_exWcLBXp`9&|%|{9jtHn^jZkxu-?|a@pS%PBU!SP|$>?~vuq>Uq-<-X{*;CuQ1wwHq}_ z>6My#h3~|>J(B@7@DJ3Ow_!|TG_xx54CwHvjw|0(0F<6xA^?*xey8{hEH`lM>s{>z z+Vrjj+TQcxHLC%xfg{I*3!hW(ue%Y_>fpc5${Ya5(7d`eV z0QHcoA9JPbsqYLj>=-m*FI|c@X2cD15@qvK0 zM|_skGel}isfi~59`k(x>1(#|3rnuoF>EibTBgvJMic`wYk~#$C`8Godd)-A>t4-U?S;@T7w$hXV2O z6!$)SclSBpZ~|wZJ^27GCJR;Uy;#k(D1dM0BJyKRcJ=Y*mR)Xw52&D&JvdU%$txLV zf*9VVwe(4uJZI9M%$07>Bz5Z$`b4``6Yj8gm5)^7H}qo80D=w=eJo+uKbL`Zi^R|p zdZ>pzjzm3bdH19i(a;M@-Oy|Ue#f8Ue?TJjLbyIgituimfwj-oGIV(^_W=I$I?>YC z8*tp)xA5E(sNfuF3NLUojw8VDoF^K*P4A%3f0H8sy=_y!=Fcq=q*=v?aB zhxdOy7V7xhXkwB9VEClYxBdny$D%iUlhdF?zsRfok`Xd!Ob9FF8#@2D%CBLxe}F50 zJ?p-02EGhq1@?RO@6aD|AB#YhM^#+wZ|4EN0_5FKV~jvBX(M5Hqb`P<0QYUXXQ-}& zUSyE^-Q`Li9UplE&a0CHWU1$-=k>Turym#Pb*mG>>{osk)XmgA#jkvL)nhrpOHJwm zJ=mUs`p$DHt16d%H}Y#hKCj;K)cM~)p*K!s?yCZex1MM*ck&lVP7=QD*YX9HRzl&i z&)`YEpo>kl?&x{_HXzWcT_5$Y(+yiy;dl5c6*-g3q`?N_Ge9qGfa;UttZ~Ogg?Eh1 z`qt&`b{SqpGrG}rq2*|O;zr@C9NQKV4?94*vyXChu%PiEkEIM7h`7k9!93AM>is-k zE@k3A4EhT#Dico@3W0qA0GfH1C*4;%j3OECOBjGVkttKItOR9ZCB_4~l9!JV zBR}D=u@Foig;(J|f41aEtZ_!KV91ff)UWzU*X?9Ln{*GEDOX`G9OiSOv(n?F-jys( z4mbMqy7OTmh(Uuw6D_+^8m*c zy;Vnc4-6P4a=sBE;8NvDat3kuM@Y)VHv@+O*;r;y+{qQDI!#k@_86+;_PT=*Om6|88Qm{w(~q zGumO+U*f^rl3$R%$^aO*x@no-05o*Eg_@!z<=RLT)AVqiG^2)>Yvv4?la11{D zegOntdHNpc=Y_7J7Xt3PJ|~Zc#LvL5?kg{1z-uPr5~uM^yMX>Ru3MblAw##^NfT_v zPw#3m2<^b>uvrJjK(l1`+93t*AOBq8ktJ=E?}e{d%6XANt!}nc!;SL_XMvUGfOWC! z9Kh}nL5{8DhC#4zeS4{oZ1=80I;3fv!>@b5vvSOA1>9aXITQZjo8-|tw?BO6qrUFn zZ#N%*i2c~f_U!gglAk25`U~`jt0xGn#YVdw`+oXe%9GXo&F|?)^f+l(U0C&Hl=0B3 zK$iaeYUN=IIlQ@5?%K0(66xA;rC(Yxc19^hd-+({0!Xr+6Hk5|15Vs~&;;UG zYyn-B9}}Vt*C*A-rXLXc*tQBB%!$PAAWFvwCEm0HHOT^?8q&Lr^(m(Eo}hRPs43j# zBiOxTQUISq{Hkt~Xm7_rV%{iL22JlDzIQvs zbGz{U@pf<`2Xqcak1f!%MUuR*dG3tr9mhE{;Ca^zvqU$OEDhW0LjuU?azxJ5Z6mZO z&rb|0p?9i7HG#Z4C?4hax%*yB{ym42#Q(^EvfzmcR=q!ZMuU0`X2mK09z513o>eETFS_-LOHh$aWdd%?itlv* z#uJ%!-xvFR?*5zOs+>cP9?;qFPhP>N`YPPswFE!JP*|6NB98amA5TZ`Zo!tHR9-#~ z4gN(xGGLJbVd+}}@Lu&?@bSmm*`oKIp9EXJNa)p{8?bCtPoQ8OgpHi^D>>TMH%?>& zD&y4~zDufmY>aI)$%MDdj_>#QxE?(-xX!!NNquz5!8=9NHuH{jz7{|ef1x0|fAVgw z#Ew7EZ46>XKAvPz*x}uuiG2F{pA;s&QW>>=85I9c?Lr6HJ+HFqB0}$aXJ-2iJ;{Q; z-`C);SN|hF$t(S+P=8YwLT2(^Xm%UqEbtBZkDUBEP;m{ic~yI(u=fAa$@|B@l#lnDl4+G56pnYG#iS$14 zSDmEH*0|OS#dE(`SKD+=q`b1mRR0W{H**DEa3qE3G zskRzj7Fu>Q`df}XR6OL8c-^jpuW$?+p@Msb69=D6x1^=s6R&sj0$mO*^TEh#o-?SgAS9-+%S?&?Xm%n!C6z-??&N31}ILwY)sG{Pm~O! zO={;N!82IE09Ok%6(LlNf?FVsd}u5z0{CMWi&A`sAN|9qkiJ1^`a^X+^XdkKM!t9@ zocyyoP(NiwSuk#qEa^;KH^-;nx)L;4iMj|!aBg<~0F&a_d4{&42`7qtW5);ZJ(uyp ze74n6ZYZGuNf>M8ZRcILHh3gaggbgo=sAeVk8|hkoH^nR^r|>?e|$qkjBxkG1RG+S z6h!xk1AUa)h@RC)21l*eA*1E}a!e=9nE(l5-$zQ;LWW_anp$|&p36^?j z10nE-R3)O;b6}?)tIxk}{VoS~>@X8Olo3Xj!3nY>dmoPl855Pk10i-6r_pHWbNg=$ zl|gc=34?5z_g!>!;S@OrIDYGUZd2P!>RkUupu=v*`;f)Sp$Shv=&SazKs0C|h{Ya_i73T>tOiC66?aG&p`# zKIEr|N$%}^fp;nOfE)Q(7DOyWz|fb#(6@?XqhItixZ~5|ibwg`@pL&VpCYsy@&*STgeWih&b!6td5+Hab zH(=Bw6u4fu3AKN3x@3(%=jFKZ0~) zl4Ze=Q_02A^veW%=a(=K;8wW}IVv8j)9t|M)y+hnbs{>`Fgr{ECRl7wWOv3#@C&>O zPonHW`0JUYxN7jlndwr|ou50W$Uig^!A?p&bvSZ5eA~1gHc!7j*;WDg6kFN7_!g8) zY?q5vnBJUdQ8)v$*Ut~K7Zu-cru;f2pq9#QeROSfSSIV1SwG%%)+G0^f!xY(5uWT$ z62DysxR-7)sOGdw_Pt99SLO0a^`mS9J8k3tDq`z+wE=vP8t~)_?+c$N+)fb{TEJl$>wi1% z=$+4}=e3`a5d-sl%=s^z!Y{Z}KF8!K&Ad=v55R4{I-!-XeB*6 zCIP-tW>DCuFY*CJ%^Ts4o}1ghQG^T zF*sFtyZ!y<^hBA8Bb7%w7Hac%&l`UrA6!-B4ao7jRaxkN7Pp}L#$dXD9>Di*5Ynsd zzOW!n?|Zj&#~nw7DPQY`=(Mf!qyd8jk>3eFKtLJzyK{oHeV`If&>3ZD${l5%{1T$D zMaBuNH&%$2W9S8Zgcu+^t3TSn2c_eCfLpd(`gQsA$+Dq;Ll{1pJBWJs^86xST{zdg z1*S`~B?rFskpY_u&rMyD_o%1XW8})S-g$6b_x8~Q)JIZwP6s9_1hxx1z9I2Z@2~Q? z;^UlD{}LaZqFV~I-^PD~7WdPzm;NVP*Y>iC^^W7}ipINMBqe)9pXK=JS@IOlquLJa zPr;q~JJj`_pc7MdNqX!#;P3nhY>$io*7f`Q2j|hpp-BLy@O*l*jCw`7g1!XPi@jzN zG7)+ZfcBVl@af~YKpp{!4(X__*mai!!PGec^`Wh5m!WsmR2p8<)^vWu9tdn-6i!+G zdmp4vdbL$Q0L=gRL*&ML;M_ZFDEpE-MwzlBU-}8~&b=q-l@AjXTygq~ts5L(+V0BJiDj%AvK_ySmX!MNYP=Z+YKx1HjqiJwOKZ8Mi8WVMzMb zv>O>=@I^k*PW^Wqs7EG!dBwf5sVIh)xsyAR9q$wY&T1Fhr-AO{)4z2c$YaKh zlA>S;YsvQpGZ*a9gy`|)0Q`JE=w`9zDwDy-%$a&Wo?J$W(|tPXn{`6+TE9*7wLDfG zYY3eIkHwW;>~y0(Q`R^93nrlk;!ck9I=a>Nh&-~prF}Hwyg80jxNSRoF}DIcOJFSl z^d{h^+}8afMcuz41KF7Ej{2rp%A-GTK)O5HXIyzLZ_&E?v`Eh-({%BS}+jFxv}1#V@Nn*?<|K0N+X zd|?AbTlt?rw1Lox<4r&oyhm2(u5L+#yqFvTcI@Vr&)NMsw+YzF!fUxVo`#{PlUDd| zo`Ke{*Y&N(eb>4PH(>8Ee(IO`EgZebjdz`H$iVa^55n%`&w0}ZoXTGz)*tjS{Oc3d zOC8;f6ziT<0yG>2byH*0j^~0GVRH8p*x(O<3p(zVlgr~!&?e0aL1NHBMB=mDBPC_9!HAr$PkA!!5OsaZ_&`nr6M(Dm1BfF z0A;E-m2Vn)!bqvkS`8fMDR7HJ{1!PY^hY+kL1tyi-YfqIB%iFVJk^nDWZx48$ZyqA z9PR$*Nk&B!whSs>)afy(FpCYvD{5_f^iR+JQ0>CVYD57V>{P@GaJlIjnz`q;oPj~0 z@TOuwTY|=Ji3QjtlA97hL!sefr%&&FR7-)Vt~?nHPw=E1V4ZQldR zK-e(&Xb<71LswwuR~=@==Q0vWQNwW9jv(RveV6M=p{!U|xo4uF!fSPBT*@(1}0SUnQkX7=%~>7Oi4c&$=BjCFnW9Axi)f zUGkDYzUDE{H?|@uO<(IVFjm?E*hs;UwV^XX=c+!4mNZfdA416`VMKHwX!<;;3&7Kt6oO zaXN}8^5y{8$K)mYx?SJy=~PJXt_%=V8zWNJkKoVAvgp?Yj-63^B>d-R>Vf2<^4zJ- z^Y^o8r;LV7od5+gp4Z^AV6sKv$p_Jxqk(vqhr9n)I#6}F{8Nx#H=n#){KjSmO+b0| zf|+cymmE~@kiT_H`MBwGgvnd`G^!Nib4o8YIbl#z_`c&?D|M6=VdpyAe)mvu+o?C` zUjB~#18g6lY}}z(P!A}U7zDPy)Zlab@a6VfKBwPJKW|^(KXF-AyS>}h3b@@?zWA@z zkzaHkyC%Qur9K!Vk>rolL%)9dPd@C}vM-l{9dL7u7_|DrPNCcyNJDwh9>}Cz>m%Uy z`MQkQnj+ZwXj{oeJns&Vo9AP8iQGbH=t(C4*+A#my`u0gXZXnq!s6Xgnr=&2QLvc| z%0#%MPa=rkfKu;;KSyN24{?PTy%o&>eS*YQ?)VR7SMY@&9{yZyB>v`MElB;QLxgrZ96IQglIH0B8WmiRHvdS1p+QwDTc((XKdaM3f z;t@7GePj2dXelvl{-P#1FXByBMfQKUIc(*@t1iOF4;%|E_^t-1|B>cS*QRgS7Rnkr z_<`Sp$H<2;{!3RS>z+*Edo~STgx74U5Rq;BE4lP8 z2_~jEwhZv%4Yf;zSwCxc*r~pOHRP=ec|N@R>zat5ZTyAa2hR_`{d=hc?WFVweRPLs z<`3OzxBQSmAnXV#u6+jX%jOkeckVftUhg=z4Aky(6e@6M5N$rYES9WRa6eo~dUq#v zjlo~WP-sv1P&Va9Ph$?mhenrSgJ|z(Xv<`)$_Kw%&)BP>6M~Vp#A>xE8mSkakn2h- z==w|o@F4fQI?^!xMlmCVE@;64;M|3es(G%wp1B+7bE$g-|U!3C703E;$-;!!A7+Cwd>)`KzO5fZi z|F^+is4CF(vG;cH$k2k?&TLNC0g-jociEJgFp`S4#s!G)u%!$;F2K9d-mj?Z{m=uKVQi42p+ha7p=;p-AYI15WMQOt2X+`L z2`3mhozm0(qKiYn78-%pOY)p!*G?*1!bCOsR~pJEuPfYl$t!mTqL>G_=^YyAF^&f6 z%j>!ZK=0Oi$$jJxrpi9|$b@)Rhmo_}{gF0N3;e6lHros88Aru_~}oz}8t# z%DM|9(9f-03UOxyM0!}{#5YWE3i`ai}<>5JPgHTz6Y;TG%1(M$Ec%5OS zM+c>yk!eJ`@lgzTC8C2#_y)A>oPXbwVaG>5M7#339Vh@ld1FY@gC2%c@m+y>z^NQd zWJjDdme8gvVYQnAxKo*V66{RJM*=e)^L^9X4X(kf^3-5c5N8>!vc1CrabHDxQ{>z~ z{3;);6}gtH!e6%2Sy>&B(`Pj<2RY>IW-%ap_|9{oG=*7RFL0pZxfs-0uV9YIYB+tW zfuhnaCn2H`t*iknukDZW0Y{S|`FM9ul~>mnF!rqeXwWOpThJ3Nc5FIYDRL$~C_6vu zb|o<3HvSd-VrRYMkVyCZSNZgjIDRAa=FNC3uhR3CR6Zb0ifax2069i1cp6_Wb$}Xr@|+m%pxaf^N8*o)vG?yH4hk zuAPnU{M^uEe551fmc}`NRJ>VFI%k1z%bt*Qys8`VVVWvEk=jm&*5t?E?i36snq);c zPI#Qd(g9sbF`p!DH=@MXs;@+9L=N_zhO) z4mXoV0`p%3#9zo$_}KNqo`X3o!m@n^1!&(`M0Dvx}F(9v&~k!?AG}ckGcT z6EYsW-_2bj=TC}kQeV+n^iX^~c+W)X<%C~@?hxRiEXfYPDD?E0<6dn6gfMx5jX8gk z+#c>ckVA7~7`&^Vm7cJ;W&6TM(lg-(AoJD#0N|0j=}vxyIS_EVx~Dy>*TBt$fT3TC zf9S1ds5_lxyM0$W{9J9VOhVgNfPp@P+O45;$~Ob7vSGsIoi0b+i!^^nVQpti^lwhI zR5tcCBopvos!y}$TRP|#1Fdz0k?RCO%F~O8CYi#Q2g-c-y#}5kg4|V>@}H1%^Vowy zD~t&jF*M7h=r6zyq)&Ub?95LAi=sHE{mf1Z!Tzz@f(?^|C6FplFZvi2UHZ82w8Hgc zXzKJMHw#^~l|J<@V(8AoF#VG~^aO3?dA*OV+Fu@2Jd!&TXO@X<&{Cg??fO`G`n!qB z`TqV_eg@7Qd!#T={#ch8ys!Aiz}whY(+WUG=^%CK%D0VFclfw9G~$o$YjIE0On=9N zJiGR@QfIE8Djs=AmX?EppyToW8|Mp8-ofHQCWRDE-$R$67gF?x{NDoaMlvr$`i7w+ z{3~101O0<%1B9W!85qH)u?id@_PV;3Pm{bq)BdQ0EY6e-dF_PzoublXF*p5jL*jZzGsMET^ zVz`~tJ^hN$&(Em~Zcl_m;jaHd7a9fjBP%Qjx#|X8QyZQ^_QXv)N+f)Xrj0?FIw#)Q zh@UoqEtdlG{wl1&_E72ed-PXvz-5{67P-=Xhz{iwc@{3-qYG_+DHFZJXQ14f;PXIh z=}W%lA>KSmOukcBcLxSk+cr|C;kh0aZStyt|mkc<0**q?s6 z0(P-(0n+i!81i1DTQ5}p=Tm&~Ingrn!vAGFhaDIIePiNcvxg5?yt?SR?n-{GhapCq zWt8QI2q@#XV3lQ;bLWNbt&0eawBoR0edQZCe*SyKLC=_|c-6KMyNMBGFf;e71aInQ zL1>JwwEbImi?m(qf!{CEFMr7ke8lO2Utk@R=#Qj#Ign}$DmPRfO}Vj`EQiiX2JYwL z1MsZ+Nj%c5a&Kt5o4$rnE?C0bS9Tq<50>_3<~L;;pk5s^rdT0B(*j=G+?6iB%sWHK+o{qv^m-|{S<{P}aHooc8H67MCUni|a-@-e`q5}B!y|}9Z8So+Z)^~Pq zfIi>7VbND6VVHQi0h6b^_zy4D9sv&5du$r`vnZx$)O{#UIzA22yG1A$`Yn!8k=`mp zL*ewT|4Pm*YOnHdnW3|^f3(?_w=>oSdZAPBg|0a~y2{<%ZXTz1=`j-WuQ3D4JxM8z z#IsDQe2Lo&;*1X+G;^r^hCrKK(1_-IFcE?y{#p1g_UMhB(mu(F!hZ)f1nQdtZiI3T{+Kc=qqpYMkY)+*N zIBzhY$pHOI(A^=TG0h;FuC?6nT1)b}K|t}h_0eCBx*+9H5+JAw@|OSIpaztpjKnDH z;>$4TQa+0^APbM@(P>e9S61;ij_az-Id;K?TST2dM;-$xvND1IwBXeCZVdyY;5-&t zlgt|ioe$tjwi7+1E2qSjyJ!TF<0?6`potLWw!^wi!Wo>m-dewO?QD&@hJlkIq6e)1Taz zOq`3H&xF=H;q1H!8D+A99_`0*Rh?^F&~>5danclzKw%u|MpzN$&IV8uXXp%NVpSHr zT%@n?RQlhLdY~HyM#+gr#931h!dp-FybaKj>jY74f(z=t8=p0fKBaRJj;d+8XyOdd>Snlfd=c(I%#L)`{z~v#R`g>l}YXJDgNYS0s~EH*QRVd=vy|S%L=;3iM6HY`iN4!dXYPq-)p)L~3s>7hHT(4B#6`A=%2`sh?(PKxHb+lwaqCxWXmi3X=hh`Gkz zw7#U>BX3qRV&j;=u#il?Cp#4{ozBQK0tV-TRq?TnKI-m79MwOH!u>wIk#5~HnJK6_ z8y~R-+=*Op_t9ZYv>*ka0WQ!h{UkTNKJ4#>Q#?{2*kjX`dhWPHf)DYW!5@x7Lxxiq zxDv+IM}`SJurG#PU(I8HI@5h*>Tc2zUbI`Mf&;((#NdRgl;{&|100~&6L24C+T<8M@7rPZ*(E{Ol6_)u@gx@%Yay_zsD2tV?Vaa*YV0O zfpG4?5s&xZOXkwa^N*pM{Q8K@kf?Z}Ikb~^(~@u|?PN)a;b+@5rNz%-!jJ)fQ1y3H z>~}V9JzEwvae>xGHqa}5pznom#(UA(AE$S{hG%%!GbxgLf$*~MgS-_v5d^I#oyPUd zg8=YD-t=Wtz|f!gip~G(hXeLm7r!%fb7QRfPh6Fa{vkh4jPq&%s$$F58T6%ugFe~j z)Oboy99&K{a3=Yq8@3MumtTYM7`OgoGk+iWl!1z}XBRIZ{r55RQ5BGzt~HO*jxzaU z84{NC7q#_GFS>W9I$%8(nt-UQvQPcjRkp(mlXOqLA!>GulLgUyez8bYv{ClP#eZs2#a-ny=*&CPGs)6& zS--O!JrSrbaV5oi{TkTbk$>4V@}SOmObGJIHw0#%34U(znnKard^EnBe%V4BaU0y1 z*T2}QV0|rzxhRfyBY1kUDCrtz`p7SNx6ST8z)E|=SUkSab_11&^6ZDmPtXX3g2iaP z3!rz40Nwrr!$z3T%FniWg7sQ;BypAuZtkI>`MeDW81!x(rjDe2(}SYAjC7C9f_2KB z?~1$$h1%mV+#8qjt?=zZeGtBPC}=xx_3konIW54EjOa(#{RYa@MPc00gCUFZ3uvQ> z!*_gqOc!}E5v!}~uWav_lzIJa5hCTr?_HjznXsudd-1daQLZ&E0bfIwJVTe|5u4<& z#<@V-E8Z{`5gFy3?&=!Cx_=!z968uGDLo-}Vg`o2AntMxolR5wK0wQ%%LqtFXbY8P zLyPX#VcW4zFZsEAcv$H3yY}-fbh+{a`y*Kw6LoK$9sRz`GBUzXy_2!@0mHIsz|UjBznQh(KufbZtq}W zX9!fdpurPfysDQ51z=TFPb#qL&~l&yQI3`yqAqVsCTT)f5R#@1T*m>T#0Xcy9up44 z6Ghb+Gr`ggBG47d3 zPNx}OvZ|DhLOC6)%qe5>WJ5Yx6K}=OB5(6P_z#Z5hYy}8c{wVaxckYckBP%Jlua>> zGD5?F0w`V;1*?n!4>&UDA$mOEOEm(ubgIh%=NtOIm|Wr3X!WNYc5t-L`+G5h)mdri zE)uN0Wp->if|kH4W4`=~30;)zBLtiL^JQ%{Uy-1l%-eejofJ zpCyeQ#BO+un8xbCoyG?1D7Z?F06NlGI>St-4woc+;Rr5(FBM00eb(_>>)XKIkjK{NY`OVAQ1ns7`B8fPsFx-&5W=?Y=d z4m6%A_X#a4+hg(Ea^agL?ReTQ2-eONxElM4xAU4Gc2(S)hC6Zj>zL38sjf@BPF_H_ zw*Yuo=LK-vx8w~B2U8Fl^^ZDKeDOSVqIWz13`pu9(6pt_!(X85A~N!Bfr4JZ;5tn{ z@Uy1_o0J@pK^<~^HqFp*+C08LsH1t7{Z<(7RhLQAzJdn=UEdX&ECw8Zyx7NJX9)u` z;9TXIdJ)1}As&Ss0+hi`YAQyp2;dT>3;em+o_9q94_`q&xhXqy{&+3fis_@cw3 z*=XRkNa;a1K2(4Ij=>ycfPD+T)}5TK9Dae*r|6^;0J`jIQs=_AG4zfJ6w*(9uKPN! z1ieB`{+^54L%xAGJJ0-4exfg{bOXI}8ra@Nw|N{pb)Z`T{en7>1#`Xe=m?Dms@o@in5!D@>bh_9Nqd7+)` zWB>T8e6QpCaYe85WuPO^ms-qlp#D-uhhV!rOYw8Hgkn*tN|@kv;9q9=fDn=H%Zj~_U8xF2TQihZCt;u8|* zC)LUNpnI{d_JD!W%PV~sKFL0PHPL&|PF!|o1^-s^aT{0Pu{`}2d8+OERyf4R%g0h` zLG&IP;S0R6M}*J5OVR<|P66hO{uGKqV(U5I{y6*Hs8jL>x$OZ(+8mAmY;d$;Z^(;B zCouFRG3`2Wv+yLa{~$biOcNQLd-x=AMe7~eTk0#-T5@^$RBeWUx`eL6hjm)XA0EH= zU?e0kA;82)cC>ILA^bpy^i0?2gUZgk?D*zN@OIrBa&X*wr+ao&EH!UHCaUyaac8?c z<1t}aC`*=C)ludBxdv@nfTefuuHG)SIsWd`=Fh&-we09c<>ZgwODDtM{v>a?j5zY}LMJ7w!V0Ym~qE z^KoB#<_I%fLH9e{*DQKnhN9>3n_nqCN1kS^!YkDaH#fOO z^P9HV3izM665bHsj_|Y{K>Otl9%rh2$fa!y(DGT+8%pMZ+z%Vay$ASe+(qqk?_}&F zylijv+*|?4gJ*1juA@AWX%=L5w(IT<%WsK0pvrJ^Gof=04T0N5b|lAc#J0TUV;UAc zS@SVH{jO=_x$60C>>d6+M$3E8dor7^XUxn2Bw{urCbgAsgAfh1S zU9xFW-h`P?-?~mUxQ$VK=xtiM{Ri=w#L~;vSDGNa!VNuRY;$0mgnd!&EptIn_~36- z_i1BIY8hpAi+CbJkA0LFboUODnJ)mLNk{!dMxms_bZOmuU01N}i6yS8{eF1&S59yq z6CrJfpaA{nZ=PQRAwvSf;l(|b-u6{6KTt2XM0sE*fYFx%fn-Iv@ip-zs0_v=kltl+ zEad2A%XsKAkUDD}k-R&!+zw!|uv^%D!QGl!I(bYJ{_{}SDI&5Om zmd8pK8Vha0x~xjq8pspdMaXvljcoDXIo+sp;FWExQqlu{m4eAvI6IvDnx=7Gpr1nT zqz}KK>oTFanR*qS!hb@3dEb2^vN=9iKLBKve1+iFOZ|79|LGGg|AmwlgZxfcIX$mB z4~Jb0^;yE9LqtXohx$;K04JA;7Kl{qttLbFLNPiaMJyKxBNSDc#zRnXaD-NQ8mHja zUx=b54=Mi=AIH%vN>~92bV6OS`jqD+7@gt;TFJUn-5|Gu>zN><4ek{1jF&tpYzkN5 z&4d7jCnipKR}>~zaHf%M(j`eNa=uBUz?sDtK$)T7R`{wX_!NE~+1CwxfKE=&sMG?J z>AYu}ZUBhYXqfHugxUxp-@5BTDDbih+V_gt4!zPCzaY+H;{d?Z#1}5&nkMv)_rh7} z#~>DuUU8kr!-ov`#-}1Z>5{)?isCTHVEL+?g)hcIdamg1+>=L<-!LXx3@K$~*{dd; zn7`_jgX85mpUnh+%K&6>MDG{*zo?_No~4fyH;hinWt{iAUCK^4ITpbyggUupq=%3Y z@M{cAJ9MgRMNSeHz5J>eW_?IR55}x=(S75))VEmR@pU8a`sA`~jwWvOfu9>pc$zAp z=X%er-u2)v(OQpmSO4h(W-tM8@#+B{yQ98)kdZwngRw=I6_%p6Ro8=|MWk~!%?cn> z2a*G6bRi6qNPELFFAEs3B2A|kxKXbta}cc4NEbyfvH6%9dfKwe)>nYI!8dfuAQ?3w zH)W7GtIilohAFSkpN2Dc1y4}WZ3Fpn@$ zo#}~|2Bj%#4bcK(t`4;7ZaGTG2|er16!Ambtv;G|__BgbF!r( Gf*?h3&mmmNh0 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

iDYY3i(S|I?tA! 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 z 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

MV;T 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�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 D|KGAf literal 1146767 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 auU1gqqN2Hug2@w}@fj-19R{W< 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