From b72057a74d153a65cc25471b827ddfc1dd0c6f93 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Mon, 18 Aug 2025 14:08:55 +0200 Subject: [PATCH 01/11] initial changes Signed-off-by: Holger Hees --- .../README.md | 566 +++-------------- .../doc/console_pythonscripting_console.png | Bin 0 -> 15065 bytes .../doc/console_pythonscripting_info.png | Bin 0 -> 39513 bytes .../console_pythonscripting_pip_install.png | Bin 0 -> 148781 bytes .../doc/console_pythonscripting_pip_list.png | Bin 0 -> 14259 bytes .../doc/console_pythonscripting_pip_show.png | Bin 0 -> 30158 bytes .../doc/console_pythonscripting_typing.png | Bin 0 -> 72494 bytes .../doc/console_pythonscripting_update.png | Bin 0 -> 19683 bytes .../doc/ide_autocompletion.png | Bin 0 -> 47842 bytes .../doc/pythonscripting_configuration.png | Bin 0 -> 84311 bytes .../doc/venv_info.png | Bin 0 -> 53110 bytes .../pom.xml | 18 +- .../src/main/feature/feature.xml | 14 +- .../internal/PythonScriptEngine.java | 481 +++++++++------ .../PythonScriptEngineConfiguration.java | 477 ++++++++++++++- .../internal/PythonScriptEngineFactory.java | 178 ++---- .../PythonConsoleCommandExtension.java | 389 ++++++++++++ .../internal/console/handler/InfoCmd.java | 113 ++++ .../internal/console/handler/TypingCmd.java | 175 ++++++ .../internal/console/handler/UpdateCmd.java | 203 ++++++ .../handler/typing/ClassCollector.java | 313 ++++++++++ .../handler/typing/ClassConverter.java | 576 ++++++++++++++++++ .../internal/context/ContextInput.java | 52 ++ .../internal/context/ContextOutput.java | 51 ++ .../ContextOutputLogger.java} | 22 +- .../internal/fs/DelegatingFileSystem.java | 129 +++- .../{watch => }/PythonDependencyTracker.java | 6 +- .../{watch => }/PythonScriptFileWatcher.java | 17 +- .../AbstractScriptExtensionProvider.java | 3 +- .../helper => provider}/LifecycleTracker.java | 2 +- .../OSGiScriptExtensionProvider.java | 2 +- .../ScriptExtensionModuleProvider.java | 6 +- ...nvocableAndCompilableAndAutocloseable.java | 141 ----- ...ocationInterceptingPythonScriptEngine.java | 99 +++ ...nvocableAndCompilableAndAutoCloseable.java | 196 ------ .../graal/GraalPythonBindings.java | 85 ++- .../graal/GraalPythonScriptEngine.java | 409 +++++-------- .../graal/GraalPythonScriptEngineFactory.java | 53 +- .../internal/wrapper/ModuleLocator.java | 28 - .../main/resources/OH-INF/config/config.xml | 30 +- .../OH-INF/i18n/pythonscripting.properties | 6 +- .../OH-INF/i18n/pythonscripting_de.properties | 26 - 42 files changed, 3276 insertions(+), 1590 deletions(-) create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_console.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_info.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_pip_install.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_pip_list.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_pip_show.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_typing.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_update.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/ide_autocompletion.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/pythonscripting_configuration.png create mode 100644 bundles/org.openhab.automation.pythonscripting/doc/venv_info.png create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/PythonConsoleCommandExtension.java create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/InfoCmd.java create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/TypingCmd.java create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/UpdateCmd.java create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/typing/ClassCollector.java create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/typing/ClassConverter.java create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutput.java rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/{scriptengine/helper/LogOutputStream.java => context/ContextOutputLogger.java} (88%) rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/{watch => }/PythonDependencyTracker.java (92%) rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/{watch => }/PythonScriptFileWatcher.java (77%) rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/{scope => provider}/AbstractScriptExtensionProvider.java (96%) rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/{scriptengine/helper => provider}/LifecycleTracker.java (92%) rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/{scope => provider}/OSGiScriptExtensionProvider.java (94%) rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/{wrapper => provider}/ScriptExtensionModuleProvider.java (95%) delete mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable.java create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/InvocationInterceptingPythonScriptEngine.java delete mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable.java rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/{ => scriptengine}/graal/GraalPythonBindings.java (72%) rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/{ => scriptengine}/graal/GraalPythonScriptEngine.java (50%) rename bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/{ => scriptengine}/graal/GraalPythonScriptEngineFactory.java (66%) delete mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/wrapper/ModuleLocator.java delete mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting_de.properties diff --git a/bundles/org.openhab.automation.pythonscripting/README.md b/bundles/org.openhab.automation.pythonscripting/README.md index b4f92158d8651..76bd59ccbbf48 100644 --- a/bundles/org.openhab.automation.pythonscripting/README.md +++ b/bundles/org.openhab.automation.pythonscripting/README.md @@ -26,9 +26,9 @@ enable debug logging for the automation functionality: log:set DEBUG org.openhab.automation.pythonscripting ``` -## Scripting Basics +### Rules -Lets start with a simple script +Lets start with a simple rule ```python from openhab import rule @@ -40,547 +40,177 @@ class Test: self.logger.info("Rule was triggered") ``` -or another one, using the [scope module](#module-scope) +### `PY` Transformation -```python -from openhab import rule -from openhab.triggers import ItemCommandTrigger - -import scope - -@rule( triggers = [ ItemCommandTrigger("Item1", scope.ON) ] ) -class Test: - def execute(self, module, input): - self.logger.info("Rule was triggered") -``` - -::: tip Note -By default, the scope, Registry and logger is automatically imported for UI based rules -::: - -## `PY` Transformation - -openHAB provides several [data transformation services](https://www.openhab.org/addons/#transform) as well as the script transformations, that are available from the framework and need no additional installation. -It allows transforming values using any of the available scripting languages, which means Python Scripting is supported as well. -See the [transformation docs](https://openhab.org/docs/configuration/transformations.html#script-transformation) for more general information on the usage of script transformations. - -Use Python Scripting as script transformation by: - -1. Creating a script in the `$OPENHAB_CONF/transform` folder with the `.py` extension. - The script should take one argument `input` and return a value that supports `toString()` or `null`: - - ```python - "String has " + str(len(input)) + " characters" - ``` - - or - - ```python - def calc(input): - if input is None: - return 0 - - return "String has " + str(len(input)) + " characters" - calc(input) - ``` - -1. Using `PY(.py):%s` as Item state transformation. -1. Passing parameters is also possible by using a URL like syntax: `PY(.py?arg=value)`. - Parameters are injected into the script and can be referenced like variables. - -Simple transformations can also be given as an inline script: `PY(|...)`, e.g. `PY(|"String has " + str(len(input)) + "characters")`. -It should start with the `|` character, quotes within the script may need to be escaped with a backslash `\` when used with another quoted string as in text configurations. - -::: tip Note -By default, the scope, Registry and logger is automatically imported for `PY` Transformation scripts -::: - -## Examples - -### Simple rule - -```python -from openhab import rule, Registry -from openhab.triggers import GenericCronTrigger, ItemStateUpdateTrigger, ItemCommandTrigger, EphemerisCondition, when, onlyif - -import scope - -@rule() -@when("Time cron */5 * * * * ?") -def test1(module, input): - test1.logger.info("Rule 1 was triggered") - -@rule() -@when("Item Item1 received command") -@when("Item Item1 received update") -@onlyif("Today is a holiday") -def test2(module, input): - Registry.getItem("Item2").sendCommand(scope.ON) - -@rule( - triggers = [ GenericCronTrigger("*/5 * * * * ?") ] -) -class Test3: - def execute(self, module, input): - self.logger.info("Rule 3 was triggered") - -@rule( - triggers = [ - ItemStateUpdateTrigger("Item1"), - ItemCommandTrigger("Item1", scope.ON) - ], - conditions = [ - EphemerisCondition("notholiday") - ] -) -class Test4: - def execute(self, module, input): - if Registry.getItem("Item2").postUpdateIfDifferent(scope.OFF): - self.logger.info("Item2 was updated") -``` +Or as transformation inline script -### Query thing status info - -```python -from openhab import logger, Registry - -info = Registry.getThing("zwave:serial_zstick:512").getStatusInfo() -logger.info(info.toString()); +```text +String Test "Test [PY(|'String has ' + str(len(input)) + 'characters'):%s]" ``` -### Query historic item +### More Scripting -```python -from openhab import logger, Registry -from datetime import datetime +A complete Documentation about Python Scripting Rules and Transformation Scripts can be found at -historicItem = Registry.getItem("Item1").getPersistence().persistedState( datetime.now().astimezone() ) -logger.info( historicItem.getState().toString() ); +[>> openHAB Python Scripting <<](https://github.com/openhab/openhab-python/blob/main/README.md) -historicItem = Registry.getItem("Item2").getPersistence("jdbc").persistedState( datetime.now().astimezone() ) -logger.info( historicItem.getState().toString() ); -``` +including all examples above, much more detailed. -### Using scope +## Add-on Administration -Simple usage of jsr223 scope objects +### Configuration -```python -from openhab import Registry +Check via Web UI => Settings / Add-on Settings / Python Scripting -from scope import ON +![Pythonscripting configuration](doc/pythonscripting_configuration.png) -Registry.getItem("Item1").sendCommand(ON) -``` +### Console -### Logging +The [openHAB Console](https://www.openhab.org/docs/administration/console.html) provides access to additional features of these Add-on. -There are 3 ways of logging. +1. `pythonscripting info` is showing you additional data like version numbers, activated features and used path locations

![Pythonscripting info](doc/console_pythonscripting_info.png) -1. using normal print statements. In this case they are redirected to the default openHAB logfile and marked with log level INFO or ERROR +2. `pythonscripting console` provides an interactive python console where you can try live python features

![Pythonscripting console](doc/console_pythonscripting_console.png) -```python -import sys +3. `pythonscripting update` allowes you to check, list, update or downgrade your helper lib

![Pythonscripting update](doc/console_pythonscripting_update.png) -print("log message") +4. `pythonscripting pip` allowes you check, install or remove external python modules.

Check [pip usage](#using-pip-to-install-external-modules) for details -print("error message", file=sys.stderr) +5. `pythonscripting typing` generates python type hint stub files.

Check [python autocompletion](#enable-pyhton-autocompletion) for details -``` +### Enabling VEnv -1. using the logging module. Here you get a logging object, already initialized with the prefix "org.openhab.automation.pythonscripting" +VEnv based python runtimes are optional, but needed to provide support for additional modules via 'pip' and for native modules. To activate this feature, simply follow the steps below. -```python -from openhab import logging +1. Login into [openHAB console](https://www.openhab.org/docs/administration/console.html) and check your current pythonscripting environment by calling `pythonscripting info`

Important values are: -logging.info("info message") +- `GraalVM version: 24.2.1` +- `VEnv path: /openhab/userdata/cache/org.openhab.automation.pythonscripting/venv`

![Add-on informations](doc/venv_info.png) -logging.error("error message") -``` +These values are needed during the next step -1. using the rule based logging module. Here you get a logging object, already initialized with the prefix "org.openhab.automation.pythonscripting.\" +2. Download graalpy-community and create venv -```python -from openhab import rule -from openhab.triggers import GenericCronTrigger + ```shell + # The downloaded graalpy-community tar.gz must match your operating system (linux, windows or macos), your architecture (amd64, aarch64) and your "GraalVM version" of openHAB + wget -qO- https://github.com/oracle/graalpython/releases/download/graal-24.2.1/graalpy-community-24.2.1-linux-amd64.tar.gz | gunzip | tar xvf - + cd graalpy-community-24.2.1-linux-amd64/ -@rule( triggers = [ GenericCronTrigger("*/5 * * * * ?") ] ) -class Test: - def execute(self, module, input): - self.logger.info("Rule was triggered") -``` - -## Decorators - -### decorator @rule + # The venv target dir must match your "VEnv path" of openHAB + ./bin/graalpy -m venv /openhab/userdata/cache/org.openhab.automation.pythonscripting/venv + ``` -The decorator will register the decorated class as a rule. -It will wrap and extend the class with the following functionalities +3. Install 'patchelf' which is needed for native module support in graalpy (optional). -- Register the class or function as a rule -- If name is not provided, a fallback name in the form "{filename}.{function_or_classname}" is created -- Triggers can be added with argument "triggers", with a function called "buildTriggers" (only classes) or with an [@when decorator](#decorator-when) -- Conditions can be added with argument "conditions", with a function called "buildConditions" (only classes) or with an [@onlyif decorator](#decorator-onlyif) -- The execute function is wrapped within a try / except to provide meaningful error logs -- A logger object (self.logger or {functionname}.logger) with the prefix "org.automation.pythonscripting.{filename}.{function_or_classname}" is available -- You can enable a profiler to analyze runtime with argument "profile=1" -- Every run is logging total runtime and trigger reasons + ``` + apt-get install patchelf + # zypper install patchelf + # yum install patchelf + ``` -```python -from openhab import rule -from openhab.triggers import GenericCronTrigger +After these steps, venv setup is done and will be detected automatically during next openHAB restart. -@rule( triggers = [ GenericCronTrigger("*/5 * * * * ?") ] ) -class Test: - def execute(self, module, input): - self.logger.info("Rule 3 was triggered") -``` +::: tip VEnv note +Theoretically you can create venvs with a native python installation too. But it is strongly recommended to use graalpy for it. It will install a "special" version of pip in this venv, which will install patched python modules if available. This increases the compatibility of python modules with graalpython. -```text -2025-01-09 09:35:11.002 [INFO ] [tomation.pythonscripting.demo1.Test2] - Rule executed in 0.1 ms [Item: Item1] -2025-01-09 09:35:15.472 [INFO ] [tomation.pythonscripting.demo1.Test1] - Rule executed in 0.1 ms [Other: TimerEvent] -``` - -**'execute'** callback **'input'** parameter - -Depending on which trigger type is used, corresponding [event objects](https://www.openhab.org/javadoc/latest/org/openhab/core/items/events/itemevent) are passed via the "input" parameter - -The type of the event can also be queried via [AbstractEvent.getTopic](https://www.openhab.org/javadoc/latest/org/openhab/core/events/abstractevent) - -### decorator @when - -```python -@when("Item Test_String_1 changed from 'old test string' to 'new test string'") -@when("Item gTest_Contact_Sensors changed") -@when("Member of gTest_Contact_Sensors changed from ON to OFF") -@when("Descendent of gTest_Contact_Sensors changed from OPEN to CLOSED") - -@when("Item Test_Switch_2 received update ON") -@when("Member of gTest_Switches received update") - -@when("Item Test_Switch_1 received command") -@when("Item Test_Switch_2 received command OFF") - -@when("Thing hue:device:default:lamp1 received update ONLINE") +In container environments, you should mount the 'graalpy' folder to, because the venv is using symbolik links. +::: -@when("Thing hue:device:default:lamp1 changed from ONLINE to OFFLINE") +### Using pip to install external modules -@when("Channel hue:device:default:lamp1:color triggered START") +As first, you must enable [VEnv](#enabling-venv). After this is enabled, you can use pip in 2 ways. -@when("System started") -@when("System reached start level 50") +1. Using the pythonscripting console

![Pythonscripting pip install](doc/console_pythonscripting_pip_install.png)![Pythonscripting pip install](doc/console_pythonscripting_pip_list.png)![Pythonscripting pip install](doc/console_pythonscripting_pip_show.png) -@when("Time cron 55 55 5 * * ?") -@when("Time is midnight") -@when("Time is noon") +2. Using venv pip on your host system -@when("Time is 10:50") + ``` + /openhab/userdata/cache/org.openhab.automation.pythonscripting/venv/bin/pip install requests + ``` -@when("Datetime is Test_Datetime_1") -@when("Datetime is Test_Datetime_2 time only") +### Enable Pyhton Autocompletion -@when("Item added") -@when("Item removed") -@when("Item updated") +Before you can enable autocompletion, you must generate the required type hint stub files. Login into [openHAB console](https://www.openhab.org/docs/administration/console.html) and run -@when("Thing added") -@when("Thing removed") -@when("Thing updated") ``` - -### decorator @onlyif - -```python -@onlyif("Item Test_Switch_2 equals ON") -@onlyif("Today is a holiday") -@onlyif("It's not a holiday") -@onlyif("Tomorrow is not a holiday") -@onlyif("Today plus 1 is weekend") -@onlyif("Today minus 1 is weekday") -@onlyif("Today plus 3 is a weekend") -@onlyif("Today offset -3 is a weekend") -@onylyf("Today minus 3 is not a holiday") -@onlyif("Yesterday was in dayset") -@onlyif("Time 9:00 to 14:00") +pythonscripting typing ``` -## Modules +This will scan your current openHAB instance, including all installed Add-ons, for public java class methods and create corresponding python type hint stub files. -### module scope +![Pythonscripting typing](doc/console_pythonscripting_typing.png) -The scope module encapsulates all [default jsr223 objects/presents](https://www.openhab.org/docs/configuration/jsr223.html#default-preset-importpreset-not-required) into a new object. -You can use it like below +The files are stored in the folder `/openhab/conf/automation/python/typings/`. -```python -from scope import * # this makes all jsr223 objects available +As a final step, the folders `/openhab/conf/automation/python/libs/` and `/openhab>/conf/automation/python/typings/` must be added as "extraPaths" in your IDE. -print(ON) -``` +![Pythonscripting autocompletion](doc/ide_autocompletion.png) -```python -from scope import ON, OFF # this imports specific jsr223 objects +## Typical log errors -print(ON) -``` +### Graal python language not initialized. ... -```python -import scope # this imports just the module - -print(scope.ON) +```log +2025-07-25 12:10:06.001 [ERROR] [g.internal.PythonScriptEngineFactory] - Graal python language not initialized. Restart openhab to initialize available graal languages properly. ``` -You can also import additional [jsr223 presents](https://www.openhab.org/docs/configuration/jsr223.html#rulesimple-preset) like - -```python -from scope import RuleSimple -from scope import RuleSupport -from scope import RuleFactories -from scope import ScriptAction -from scope import cache -from scope import osgi -``` +This can happen after a new Add-on installation, if JSScripting is active at the same time. -Additionally you can import all Java classes from 'org.openhab' package like +Just restart openhab to initialize available graal languages properly. -```python -from org.openhab.core import OpenHAB +### User timezone 'XYZ' is different than openhab regional timezone ... -print(str(OpenHAB.getVersion())) +```log +2025-07-22 09:15:53.705 [WARN ] [g.internal.PythonScriptEngineFactory] - User timezone 'Europe/London' is different than openhab regional timezone 'Europe/Berlin'. Python Scripting is running with timezone 'Europe/London'. ``` -### module openhab - -| Class | Usage | Description | -| ------------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| rule | @rule( name=None, description=None, tags=None, triggers=None, conditions=None, profile=None) | [Rule decorator](#decorator-rule) to wrap a custom class into a rule | -| logger | logger.info, logger.warn ... | Logger object with prefix 'org.automation.pythonscripting.{filename}' | -| Registry | see [Registry class](#class-registry) | Static Registry class used to get items, things or channels | -| Timer | see [Timer class](#class-timer) | Static Timer class to create, start and stop timers | -| Set | see [Set class](#class-set) | Set object | - -### module openhab.actions - -| Class | Usage | Description | -| ------------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| Audio | see [openHAB Audio API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/audio) | | -| BusEvent | see [openHAB BusEvent API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/busevent) | | -| Ephemeris | see [openHAB Ephemeris API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/ephemeris) | | -| Exec | see [openHAB Exec API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/exec) | e.g. Exec.executeCommandLine(timedelta(seconds=1), "whoami") | -| HTTP | see [openHAB HTTP API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/http) | | -| Log | see [openHAB Log API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/log) | | -| Ping | see [openHAB Ping API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/ping) | | -| ScriptExecution | see [openHAB ScriptExecution API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/scriptexecution) | | -| Semantic | see [openHAB Semantic API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/semantic) | | -| Things | see [openHAB Things API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/things) | | -| Transformation | see [openHAB Transformation API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/transformation) | | -| Voice | see [openHAB Voice API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/voice) | | -| NotificationAction | | e.g. NotificationAction.sendNotification("test\@test.org", "Window is open") | - -### module openhab.triggers - -| Class | Usage | Description | -| ------------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| when | @when(term_as_string) | [When trigger decorator](#decorator-when) to create a trigger by a term | -| onlyif | @onlyif(term_as_string) | [Onlyif condition decorator](#decorator-onlyif) to create a condition by a term | -| ChannelEventTrigger | ChannelEventTrigger(channel_uid, event=None, trigger_name=None) | | -| ItemStateUpdateTrigger | ItemStateUpdateTrigger(item_name, state=None, trigger_name=None) | | -| ItemStateChangeTrigger | ItemStateChangeTrigger(item_name, state=None, previous_state=None, trigger_name=None) | | -| ItemCommandTrigger | ItemCommandTrigger(item_name, command=None, trigger_name=None) | | -| GroupStateUpdateTrigger | GroupStateUpdateTrigger(group_name, state=None, trigger_name=None) | | -| GroupStateChangeTrigger | GroupStateChangeTrigger(group_name, state=None, previous_state=None, trigger_name=None)| | -| GroupCommandTrigger | GroupCommandTrigger(group_name, command=None, trigger_name=None) | | -| ThingStatusUpdateTrigger | ThingStatusUpdateTrigger(thing_uid, status=None, trigger_name=None) | | -| ThingStatusChangeTrigger | ThingStatusChangeTrigger(thing_uid, status=None, previous_status=None, trigger_name=None)| | -| SystemStartlevelTrigger | SystemStartlevelTrigger(startlevel, trigger_name=None) | for startlevel see [openHAB StartLevelService API](https://www.openhab.org/javadoc/latest/org/openhab/core/service/startlevelservice#) | -| GenericCronTrigger | GenericCronTrigger(cron_expression, trigger_name=None) | | -| TimeOfDayTrigger | TimeOfDayTrigger(time, trigger_name=None) | | -| DateTimeTrigger | DateTimeTrigger(cron_expression, trigger_name=None) | | -| PWMTrigger | PWMTrigger(cron_expression, trigger_name=None) | | -| GenericEventTrigger | GenericEventTrigger(event_source, event_types, event_topic="\*/\*", trigger_name=None) | | -| ItemEventTrigger | ItemEventTrigger(event_types, item_name=None, trigger_name=None) | | -| ThingEventTrigger | ThingEventTrigger(event_types, thing_uid=None, trigger_name=None) | | -| | | | -| ItemStateCondition | ItemStateCondition(item_name, operator, state, condition_name=None) | | -| EphemerisCondition | EphemerisCondition(dayset, offset=0, condition_name=None) | | -| TimeOfDayCondition | TimeOfDayCondition(start_time, end_time, condition_name=None) | | -| IntervalCondition | IntervalCondition(min_interval, condition_name=None) | | - -## Classes - -### class Registry - -| Function | Usage | Return Value | -| ------------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| getThing | getThing(uid) | [Thing](#class-thing) | -| getChannel | getChannel(uid) | [Channel](#class-channel) | -| getItemMetadata | getItemMetadata(item_or_item_name, namespace) | [openHAB Metadata](https://www.openhab.org/javadoc/latest/org/openhab/core/items/metadata) | -| setItemMetadata | setItemMetadata(item_or_item_name, namespace, value, configuration=None) | [openHAB Metadata](https://www.openhab.org/javadoc/latest/org/openhab/core/items/metadata) | -| removeItemMetadata | removeItemMetadata(item_or_item_name, namespace = None) | [openHAB Metadata](https://www.openhab.org/javadoc/latest/org/openhab/core/items/metadata) | -| getItemState | getItemState(item_name, default = None) | [openHAB State](https://www.openhab.org/javadoc/latest/org/openhab/core/types/state) | -| getItem | getItem(item_name) | [Item](#class-item) or [GroupItem](#class-groupitem) | -| resolveItem | resolveItem(item_or_item_name) | [Item](#class-item) or [GroupItem](#class-groupitem) | -| addItem | addItem(item_config) | [Item](#class-item) or [GroupItem](#class-groupitem) | -| safeItemName | safeItemName(item_name) | | - -### class Item - -Item is a wrapper around [openHAB Item](https://www.openhab.org/javadoc/latest/org/openhab/core/items/item) with additional functionality. - -| Function | Usage | Return Value | -| ------------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| postUpdate | postUpdate(state) | | -| postUpdateIfDifferent | postUpdateIfDifferent(state) | | -| sendCommand | sendCommand(command) | | -| sendCommandIfDifferent | sendCommandIfDifferent(command) | | -| getPersistence | getPersistence(service_id = None) | [ItemPersistence](#class-itempersistence) | -| getSemantic | getSemantic() | [ItemSemantic](#class-itemsemantic) | -| <...> | see [openHAB Item API](https://www.openhab.org/javadoc/latest/org/openhab/core/items/item) | | - -### class GroupItem - -GroupItem is an extended [Item](#class-item) which wraps results from getAllMembers & getMembers into [Items](#class-item) - -### class ItemPersistence - -ItemPersistence is a wrapper around [openHAB PersistenceExtensions](https://www.openhab.org/javadoc/latest/org/openhab/core/persistence/extensions/persistenceextensions). The parameters 'item' and 'serviceId', as part of the Wrapped Java API, are not needed, because they are inserted automatically. - -| Function | Usage | Description | -| ------------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| getStableMinMaxState | getStableMinMaxState(time_slot, end_time = None) | Average calculation which takes into account the values depending on their duration | -| getStableState | getStableState(time_slot, end_time = None) | Average calculation which takes into account the values depending on their duration | -| <...> | see [openHAB PersistenceExtensions API](https://www.openhab.org/javadoc/latest/org/openhab/core/persistence/extensions/persistenceextensions) | | - -### class ItemSemantic - -ItemSemantic is a wrapper around [openHAB Semantics](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/semantics). The parameters 'item', as part of the Wrapped Java API, is not needed because it is inserted automatically. - -| Function | Usage | -| ------------------------ | ------------------------------------------------------------------------------------- | -| <...> | see [openHAB Semantics API](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/semantics) | - -### class Thing - -Thing is a wrapper around [openHAB Thing](https://www.openhab.org/javadoc/latest/org/openhab/core/thing/thing). - -| Function | Usage | -| ------------------------ | ------------------------------------------------------------------------------------- | -| <...> | see [openHAB Thing API](https://www.openhab.org/javadoc/latest/org/openhab/core/thing/thing) | - -### class Channel - -Channel is a wrapper around [openHAB Channel](https://www.openhab.org/javadoc/latest/org/openhab/core/thing/type/channelgrouptype). - -| Function | Usage | -| ------------------------ | ------------------------------------------------------------------------------------- | -| <...> | see [openHAB Channel API](https://www.openhab.org/javadoc/latest/org/openhab/core/thing/type/channelgrouptype) | - -### class Timer - -| Function | Usage | Description | -| ------------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| createTimeout | createTimeout(duration, callback, args=[], kwargs={}, old_timer = None, max_count = 0 ) | Create a timer that will run callback with arguments args and keyword arguments kwargs, after duration seconds have passed. If old_timer from e.g previous call is provided, it will be stopped if not already triggered. If max_count together with old_timer is provided, then 'max_count' times the old timer will be stopped and recreated, before the callback will be triggered immediately | +These error happens if timezone settings are provided in several ways and some of them are different. -### class Set +- Check that your EXTRA_JAVA_OPTS="-Duser.timezone=" setting is matching your openHAB regional setting. +- Additionally the ENVIRONMENT variable 'TZ', if provided, must match your openHAB regional setting. -This is a helper class which makes it possible to use a Python 'set' as an argument for Java class method calls +e.g. in openHABian this can be changed in /etc/default/openhab -## Others +or for containers, this can be provided as a additional environment variable. -### Threading +### Can't install pip modules. VEnv not enabled. -Thread or timer objects which was started by itself should be registered in the lifecycleTracker to be cleaned during script unload. - -```python -import scope -import threading - -class Timer(theading.Timer): - def __init__(self, duration, callback): - super().__init__(duration, callback) - - def shutdown(self): - if not self.is_alive(): - return - self.cancel() - self.join() - -def test(): - print("timer triggered") - -job = Timer(60, test) -job.start() - -scope.lifecycleTracker.addDisposeHook(job.shutdown) +```log +2025-07-22 09:19:05.759 [ERROR] [rnal.PythonScriptEngineConfiguration] - Can't install pip modules. VEnv not enabled. ``` -Timer objects created via `openhab.Timer.createTimeout`, however, automatically register in the disposeHook and are cleaned on script unload. - -```python -from openhab import Timer - -def test(): - print("timer triggered") - -Timer.createTimeout(60, test) -``` - -Below is a complex example of 2 sensor values that are expected to be transmitted in a certain time window (e.g. one after the other). - -After the first state change, the timer wait 5 seconds, before it updates the final target value. -If the second value arrives before this time frame, the final target value is updated immediately. +You configured preinstalled pip modules, but the mandatory VEnv setup is not initialized or detected. Please confirm the correct setup, by following the steps about [Enabling VEnv](#enabling-venv) -```python -from openhab import rule, Registry -from openhab.triggers import ItemStateChangeTrigger - -@rule( - triggers = [ - ItemStateChangeTrigger("Room_Temperature_Value"), - ItemStateChangeTrigger("Room_Humidity_Value") - ] -) -class UpdateInfo: - def __init__(self): - self.update_timer = None - - def updateInfoMessage(self): - msg = "{}{} °C, {} %".format(Registry.getItemState("Room_Temperature_Value").format("%.1f"), Registry.getItemState("Room_Temperature_Value").format("%.0f")) - Registry.getItem("Room_Info").postUpdate(msg) - self.update_timer = None - - def execute(self, module, input): - self.update_timer = Timer.createTimeout(5, self.updateInfoMessage, old_timer = self.update_timer, max_count=2 ) +### Exception during helper lib initialisation +```log +2025-07-20 09:15:05.100 [ERROR] [rnal.PythonScriptEngineConfiguration] - Exception during helper lib initialisation ``` -### Python <=> Java conversion - -In addition to standard [value type mappings](https://www.graalvm.org/python/docs/#mapping-types-between-python-and-other-languages), the following type mappings are available. - -| Python class | Java class | -| ------------------------- | ------------- | -| datetime with timezone | ZonedDateTime | -| datetime without timezone | Instant | -| timedelta | Duration | -| list | Set | -| Item | Item | - -### Typical log errors - -#### Exception during helper lib initialisation - There were problems during the deployment of the helper libs. A typical error is an insufficient permission. The folder "conf/automation/python/" must be writeable by openHAB. -#### Failed to inject import wrapper +### Failed to inject import wrapper for engine ... + +```log +2025-07-20 10:01:17.211 [ERROR] [cripting.internal.PythonScriptEngine] - Failed to inject import wrapper for engine +``` -The reading the Python source file "conf/automation/python/lib/openhab/\_\_wrapper\_\_py" failed. +The reading the Python source file "conf/automation/python/lib/openhab/\_\_wrapper\_\_.py" failed. This could either a permission/owner problem or a problem during deployment of the helper libs. You should check that this file exists and it is readable by openHAB. You should also check your logs for a message related to the helper lib deployment by just grep for "helper lib". -### Limitations +### SystemError, Option python.NativeModules is set to 'true' and a second GraalPy context ... + +```log +SystemError, Option python.NativeModules is set to 'true' and a second GraalPy context attempted to load a native module '' from path '.so'. At least one context in this process runs with 'IsolateNativeModules' set to false. Depending on the order of context creation, this means some contexts in the process cannot use native module, all other contexts must fall back and set python.NativeModules to 'false' to run native extensions in LLVM mode. This is recommended only for extensions included in the Python standard library. Running a 3rd party extension in LLVM mode requires a custom build of the extension and is generally discouraged due to compatibility reasons. +``` + +These errors can occur if you use a native library in your external module but forgot to enable "native modules". Check the [Add-on configuration](#configuration) and enable + +## Limitations -- GraalPy can't handle arguments in constructors of Java objects. Means you can't instantiate a Java object in Python with a parameter. +- GraalPy can't handle arguments in constructors of Java objects. Means you can't instantiate a Java object in Python with a parameter. https://github.com/oracle/graalpython/issues/367 diff --git a/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_console.png b/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_console.png new file mode 100644 index 0000000000000000000000000000000000000000..ce3f2fce52101403a974872a36e002f21d4bf478 GIT binary patch literal 15065 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 CJq0)b literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_info.png b/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_info.png new file mode 100644 index 0000000000000000000000000000000000000000..946701d47cd02cb85c65ab33f54cb7b215f0af46 GIT binary patch literal 39513 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 z zYS?8nRN}HMl$JGNy7Z|vE;BVX$D%yC7FFYP;tt@xn>wI)uD{XNZd-pD`xzJ!c=fcd=)&7^|DOg1o9S7jgj4XH*~Nou?tnJMVrvw(HB7l6v3 zT-N%oAhk z>&OvOgh;nu&)cGX;g`)fCAMUJz{BP0ENfUVJt z8PuuG&pCgeKEX4=c6fvrnSg?6dtGFnArr6dB^~L z`;RGD)uii^G6fR;u!rSibKd%#&a?a`G*zF>pkNei+nz?HKj#dz>0aYgeMym#@SH)X ztl)r*wTWx#Gour;gI74{5j_%JlFM=yFG}GD>oIYR4O8_sTg+U~>CC55t~wq;UwzHb zK>3YBR!ZYzV$(5K$R(aZ52F1^cI%asbc?CctpRxP{1atf9@ju)B|(PYP@HqYx18{O z*e;W2Y#Hxjsm=gQ=@dF34?Lr;BY(J*gj--s?%=}DXgq%Q`Yirn;g|C}4&3z&sme|md(ZrE(~};MT_j>4R!t-5pt01NZwe5UK~Uh{eWf;MVOc*B(@ zfJf?`+llz+YK_TSryzJ3P5K=DL})XuOpW2AH3N8S?2e0hi^SPczT5Ar3h73wbk6I< zItV?{=uJ`I((0D7&1@jb)!pWY-*daf=qvdwWwVEud`)4-c$x27>EnaT41YJIZ0rpPvHrBUheeyODU+0$j zI*CWNhnA66yr_i>SK-1;(GyNHn+Hj^bPs==&unawPcL;T!W;@*$m)Imjz(8yl%UZ6 z%nv|Gv2Wr!vBe@QQg!yAd=+Z~Cn)ecM_i0sWo)xb3tm8V zzQ-{mV6rQqfx#DeGC1e<8&C?!{G41Q{A1p#Gm!eWx~Jmy&_}4*S2KFUf^GaZ^urf4 zg!YDAab{oNN_S_pW)eyQPWm5v5kw(2RL`YxsNR4IZpySRAKF&OMh?jxBFR+ZixWR+ zWMo7e%Q=-DI1713hRnl`l)oj}qzf%?)SGaxEZGKYsYt$!j1XK7e#`oi#cD$9(NO?_ zvQwrz_soyYQ5}C=lsnnwDmZbg$$QtkAf8kab;{ql(8d#^@0Dga{=XAMOv(Mna;;lt zg_f!x9#BtsP4?zG`}{aYZ}#L41@)5^bmsmcFFmq!aU*Ihy+btW>?mW7Ty{d|7c-Cj zdmfyYSu3t?S4V}=;-q7&h~V}BzV;F$BzXhxzFL=9o*s-jSNg;js%0heb{$V5Lw;_* z7%}*>^Q}y;i{W=O0=dOZpqb{slJdwTYaW}dv8y(ekC^;?K=&-~IeHIMjw`uL8f`#J z!ah6KNSjXf{ZZy@oD}LSI4nq;N^uopsC2=9X|W6iqBOybos*Q8IqhwXM_UnmHg-T} zBbhzBtLM!vdr3UxSkpR602AWAL)BK^fd@S_`AZg*iHvVwl@6?_Bf_pom{k;T@Vo5GY{hxAUk_*a-CvDQM z<}egItg&^Q+jX9Lr-@;uXzu1}TXNtf3?#gBLO6ZX)Lf4mneou{H1Cq}X=8XA)u`2x zqe9Puh|6t!Q+yjYdiy*Jp9ou38c!&!))oZpe5^KKO=#gbLdNtMoEleom?Cj_@0
  • SMz~Nq1knC2bqfD&uQJRBN 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 Um1_J|WICXk8d?~X>$yDm7k7NvbN~PV literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_pip_install.png b/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_pip_install.png new file mode 100644 index 0000000000000000000000000000000000000000..d02253ea4e1d572f68da83e77e6ccc7f1c731212 GIT binary patch literal 148781 zcmZ^KWmKEn)-_bH7HM%W&_W9ZN^vh<9EwA6cMVRU#T|-kiWCX%?yiC2?gR}IJOn<@ zeZSlH+&j+uBgq&$BRk2np0(DTYt9|2q#%WjMTUiff`TpmS^NtM3K}O03TiC|+QSMr z%9E3a7fgrGTFxjaINg6eP!pJN$R8H5TqHDIZ0yY~jSX!yQ9hV%h!;JqKL6XQ777RZ zM=u3h>xcEXma3XA&Hy7RQ+r!e7bg!nOJ|pdWi?evW*(IPUSI6pefS-(P^860RNeIs zmfXAvOz+xHAj394a~5<#^%yvs0^L$z(K+rhQDQT&7|s?5PG zhqsSJKZ`!g7*obmeey&U``f2I*zi%bjp*!wK-1il=T|;$dd+&N<{>axH< zXH0%2Pp0gGZHa*U^P4N2R#QoQ>Ex zNA&!qkaEFW^`9<&|HaWY`t^l;JMPgB*CYkWU2CUM5c&;sclhZLHl8Q2P; zjO-hz1Aa1$(z(oyXG>@^m%h1N=1NxPC4ocn8aLnKeV=o~yPlcu4V!$mfzewx5MVQU zeD=G759ie-M4l~Dg=B^06~`8dI)uExEHkKL-7BIxJ=^r^S6>_g%98BGUT&q{iN(n_ zUEJAlNHA#!najdSKPu~TK;5ZF+)?x1kkPgkiA<06CMz%`0-4Rp8#*#1XBmndH&HD# zvFBsYedQgbHrGCDNnYKYeK%FN79agtTfZ(w1Aj|1V2y#`En2NmyL9WC2aptr0ES7> zZ&J4c?2i{I3g$!7$>&$WL|8D2vq)u3V;8_+=TU{{+)8D1 z=3WgLNVcF`u8L$sqNwgb9=C0S8kn?t8Cmj+U7i(r+D*BR?0ApDsa~NA3IgMsP}V#l zUNOGaF!nLva^Q<45_MoCoVZ5=o8pj!`{=1v>2;`;#xw&xEy$Kyc<7n_5e;! z>-eGuQ?M%S>AiQ<031j|?7&6Z8}92HzrR;MS7kxvwQ#XIR&UsRE#}+{L^5VUaMzB~ zbn$+t5Wl2??)cZSpG$EE84a&GnXRxc@N52WCeeroYMkZ;>0!?-`FwB#%Fm`*I;aUd z9l^qdEOC0Z+CzF=N@)+KmMqvx2E4$+rJ%NU$7ZZj1e)R94YMINOr&T!v019Lujamu zC+d->+VCI~2BOcXdVZ;&a*FhF-h;%$k0??LN?;hb{4J?J#?%E+ zFfU*`YQ%DbiDA@G1Cz&|&&?JkJM}()Dw+#il)BlN7o_aFDA`F^Sof@Ex|Z_ouJC5> ztZ~AWSh+2%D_5&RjOQ`ii5`IID&|EYp^Mw&^Q!~Z9 z6*WI<#4dZQ!zse8*XKiEKP1|)W=C>5vN77|yrcemt@4or+*Ue0qAAp^)&1K7_fj7N zVv!<^J#nAt3|c~1=Xv?%qRPCm&xPZs^LZT!*ShH_mrn@mo!}3>6@iXy_7`Ws9qCdz zCxV}7nH7=}QzUsL@I*y}ShB*m`3tV!B!ai-{^lBLNRrM~Jz zkE=%@nywx6eI%PX5^rRwaxcAvRS?T=S2hJ5E=S*53VRpviA+WhoSFYtbL-FIZ{;Hy zHC9VAgN%1kIVK`&Z68O)0UWup-dS*0jjQ-dR{5z28&QPxExmuVp1N9ELEYCZXu-02 z>_*aL>`)iNvSV&)Y%{MhcH}_T$d6W336*I|2yflvuNJ^R%op4-Gc6{;{?MTne2WgF zhuY)Du-}jk%c!vx5tX{K+zcL#oxY!Kd)n6uu1}K?xhdmmO_7?tipJD+dQ>!oy{XU~ z*KEBmh$JZfO0h!yRueL;??_SdeIJVKhZd#AQs>ZR0|`Ga;bJt8oH+DvY+Rt(ld39AWiujD&Bc zL9#E5(OcVxMLQAts44-Mmq}*YU@(If@d;+B>0trw zDJATtdKt7eD8l3|nwa39_{%WR%kGsHOLewMs)6UtT4#mHQ?oLrfrdJ|ME=K8gI4Ja zir-#DZ4HYGmuOZLS3Tv~{YSpV4B`=DKK`Q%+BimNYz2=SoSTXG<_1 zK>t-k?HwjDA@?8!}KUtG8pT#DXGE2=yZwQkHJ)r+);)D7GhAP_Q&jiz)asFE&}G>5&%g}wIHh6?>`Flm zm*}G&$2{TEAkJ~JCP(kXYuyOZM8KVK=Iy|Mgmbr1AgUI@CVQvokkI8Zg^u}ej0}+E zTQsw9786{HNNcDJ1-n)p%ury}tw%?uUNd>%LHrA~3FOFiN?q^eD?sspudmlULQjc!Cb z19jv2@+$Ug+=r+)65RFg6;M`a7^|OFD3j&t;1S7AS!7J0)H^nbVK6sKS&8FQ zmO2ugC!;)xWyg3m^Zx9qy0<+G_TqCZL0Bc>8wAAmjLm6&4*#@ z1%n_GtvA zm!o?k`mFDH*8%X2dI%ce0kQc~7|&=GFLTGtydm?s<_?g*V$E6sQqN*zqlh}{E)lS+ zc7ewOZub}*56-_Lt3Ns(2>2Iipnvs1V7$9k-uW(BeIQVv{j|zN-G@IRh)yu-HtIw( zHEJsN&2>W5I?t-TuGk0inI6h5l=s!%-1Vo=sIa$$6#8-LuLVoHDS!D>h0W#Sm<=pw zv}&1;u`{iK_mLLwB=l~3?D+E{o9TFP#N$?4Jw^0VIXl#@W|@7fEj*XG((_*MDKiJN zVsP8+!qBe)qAe|M~m?e6kNvZWVNm*}vcEo-l7Z@=0t246TASdsHhvNl^gM1f1H z7rkC;#Z3F7!;U_EEeL`Yi*}7Z-uW`qE~nEq=wnL))M3g#$4JGdR+#Bb`?76#K?N4i z7dk9l56Rsv*V);7ujxCL+_63EEBrU4*8MAY^Nj_ZBuX(Uo10P&CQL_0_br z=(g>rwsq}MAxCoavhZ#;UrHMDX8j%cF7Q-Dx|jXhFn*m=t>Wvbzy-EN6qbmsAq;-) zjCA3p!IZwc=mV~CU|YI!w;Y4ZoKP{4JNA0h)}-#_N!D;UX!fwTIzj&Px@W}vjDzd& zhzaLVFAvqM8~q2|O4p-==G5}Uc;EB2q#1n!$rEaX>ygP#n)D=TQhQ#c_0`OX+Ot-J z^)gV{QgW?}QE78zQk$lz)gEK3M>ZcOYcu2~n{`Js{c~pT^L-Yxykdi?bqx}N5<|)~ zNRj=mD5Ne`eN|aZVRsTK9Xxl zePn%L&|3OtY9fz}y+8f>h~e*ODc&M7mFwA=6E{iC0JSiR&~-pe3#y(;Yy8g1=3N8R zaE9zGOQFw=!CHS*ppLIG zrSz!_JcE+7@iuDXhx6a=*?=p-XJ<)70eTsWu|EB76mQOoKr#ZJGV!cTjr1P=o-z1V z9Vr_DESixt(a&H0y_l`k{1ybt{O!vhc3tOoilq|X+Pv{CHNFX%uYERYz0?COq;|6I zD0`&uKy2h;O2uAHTvmD;@3l8;TKMRrHk&J~PGCvl{1@n9#vnC&>s|{!JXPQJEJPXP zM3eHO0@Z~4dbdBzbb>^0`Mxf{OfY9^0R5(ODJ-j}o-z9;iw@agK89dg?@z=tk4qylELADfw~_Y5r-+ zm4Jj?4Tio$vE9*s=6#*2OU7f0Ui zSO5N>UzcTkRJ!IYFj#?^;(I~o#n%@;y%z-vYxq>EwonVz-P6}q#4UXxW(uF^>~@4T zn_UQX>b!>!PkN{l4IlV&dRg-AG0!r>n`=N83WsHkU@+N~E`cy7h^q{Ju$=XMLoh+C z+dXzP&>IB7?dic&{yfQFwU=<%t(uKqQui5ymr}`W1PQ0t>FgwLv38Qo-ukXwa|NoQ zpLz{z8Ou#-{=5{*&pzx;>hQb1+1j;1Aj$(7KmL6tK3%FKyBButeWQeq_!mm5zIDp#D8l`e_Z15 zc2)QN)A0*xSmB{_Nm#+&aH~*8b<+`OSne|o;1DZu)B}`{m^tz8`ZQ(6TD`&kdW2kT zKl=mi?&Y47S)|RUH)=jNj>>hy63m4cf@|QLCkIwk1SjvJjeDMa^$)BuX=4E&>Q3dY z+an&!jQan3;6}qpaZbo+FKG<(xVF@`xne@{xk2-|qdz#DRxK*2snijUhwSpCUea@I zEwCA1*=XPxINFSAmXd#nHErn8)9xSl8=cZ%x9etp?&*NaNlhkQ_V!b_aX zjoaanej?{jh}s2m1FUY23kF%_HX{r}mf&#`=v?m{RP z9rUHJ=Sw$kj&gfT`%8SqvYn~TtYvMez%TblTH1e(C{&HmV8JRg>3hvvHXAw^>FA5ih3|?KzBVu#l z_cHgb$Q{8QULsTQ0?LQdpSG%xa_q=^?~#u52~sWXhv!3dXpzZ!ZVo=ZHfA;_neWrM z(g2RO`k#$l718t#8=e#YPDO1oIO$~Ge0OtQLd=h9V;p5x_kqKO>=GLWsqr~7+?#%1 z>{m;uUs2>#5+>5+@jljEQqIUWCu$RTAqBgCowkqQWUVK$O(TA4s+-iYrQK9YJy%)8 zSCT6A#T(aV(o&)-eWZBq1-1ABPA#>vx09eBA6yGm&)a3||D>{&joI-R(`}Z6kZl-6)v8 zq>`OY{y1!WTkEEl_621Djj}`{i>fvwFJ&Fj;&Y+=xNR*NZ)%zv#FV%E(Wi};eQfNTA-~|S0U4gZs+sz!`8VV z{_1z>aO4SE%V>o6k)mVpq)n54F&kNf+HjMSf0;cf)xqH%GT3U~qTufEalw>sN}Z^Z zeXp%$JhuPgZ1ln=gDtoPsy|X`U!_BQiThq|I2YPpgo!SyeVJ3|#rCYugMPeJzamSv z>z)g3v()sanmPUBw?(=G*&$3DofFcg`>zPISm#@keE0-!EHJ*S@08b3z&{zRhULm5 zvMHfEW9l$BZAY|XzaX`tF7FUXX#k_S7 zpPM(9(%oe6JrS$4(OR|Cj%p1}r1dUvp5V0hNAh~^B|x6d?^wZS*U6o20I_&gqDW5c zi|A@iygl?%wXs^Z_vY%WpnYScH1#t-(PmnrrX~38yegb{?5k}y(%aJAnN*7@!r}G5sOvKj>RRVthQST37hFS3_-SnCG6|uh0@6WH(JTOCh6}{k+L1Hl*-__&K0_r3 zZ|JW9c*<?bOe=%aSZQRXYtcjIE9(-{@T<=d7 z0TYKT9wKTzgPSg9YlJ@qPEP?8%hcj5%uI0+6M@cY@@9F`a$6*4AA9lUZ*UjMK*P|1 zU3ZOe+qA>R`ni_3v2imvxjF0sMK|ZKS$V%51`-2p5l^LRkc4&$+XGz`7dL*6uNK0N zW*-mLuqIlf(&sI7yZD=G?F5;NVbQYgHL~~*)w;^#*sh?CXe$)~%=a>X*Mn7bQ){h; zTWwcPWR+}JavBLKKWAKn6`Avd@t4V>_Tf?w(`bE9T#Aul4s5BAJR6lEV_74twU(Q) zZinB6_8L*|^}f1fX={PFSne)@vlDL*{x^7{Z;byHyn|_pikAH_E`ZwA%AHK_pWYr4 zR-l@6R6N1JOF91o{1?Uisqss@I8BAr`~#uwQ)2Y5Hpm@IDy^{~UvIW=42es>O*dCl0(F0vV&yZtoo{_|iE=isWn}ZhrJ$%hWZu$J@!lH!&3?dhj<;7JsTe z1le4&IF8}7aE0Fty1YqES#)nOhfy~>ckD@a+6~ z^LF<;LE!6|*Ad2{(BRBSNjLa_FKpwC-0gU0#!`s2G%?lmn;AQ|tF1QS`i3Y9u|+}w zS&=j21_8anQ*wXxP(8Qh_PH|2$__+uNrG({V6G}8P)gWrl{15Pf;~95LO9(kJv3V% z70^PGMWg9)Em5Xn>nqVBU)B8?SVt&vU?<#gK`iDdA$yiYJP}z)4n-t763#R~0hz z5~KCg$0lh%)$BgyxTAY<0(4$bpFhf!Qj!qr0hF}nnAPRHzV`yn=@akVFfh z%0yKJRe6~r`QFufi#|{&jYO5x;>+&hvzCHdx13NPofm1TN-&6x(Vy-t-eZhdvlzj6 z^ZtGDj(&kypFnkDe2Z;8KwQTt0?+D^Ncf!`zI|$ z1Wl{!LfvuJb&fx8yuldydXo+LR)6Qo9zfI=}TaJKng_S8o7Z z413;|#bW5mQDRRyIF-2)1vrv65z)q_s&9Mjm_^oDg@w(J`%_l;F-Fc7lGRCZ8X>@a z{iYXEI4}#f&x=~i2N6jR>G@a?9*Ng|-Q30YfRC&XL)XllNR^U65KMa<5kn>fHuIih6&DyYMBc zm8q^52_X3R)SMbVL$xQR^;AI_1mN=EQ%ebJKb*-h839k(Jg4lnjdZO7 z)G=Lg;p(67mW>`H_u)9^e$i>Hi;#5d9!GxTx3K34#h8h=4fLLRw(9Xjjbldmgu#=7 z$@@&zz`Mt7yiT~h?2Xcqm+HAC-OiO#H{K`a>+JbuHCqX!&r|^D5Wdp#%Z?L7QQZNWn>ip4ucqji7u zD*s05jJybzA?M2;%D3@yw%QToA5Ku9z=Z#ehqyJi)t1~8cfqwhPyU-5eJ_+u{#$8 z`g4UTpe0G$4*eNJm(+rgqy%cC-?rEeZ*RUS3@6l`oD$1^me=j!R#atJ3%u0QKVUl; zG`~UbSrf+TMAX*#Guu4+-TbhB@sih@GWy~-Tlzj%Tj#{d6%hGjwtz9G zE9!zO6SQyzcj8bmc26TpGR5bw-I?>}(uy)B5RVx`HKfvX_|_mj6MtH9`g$3z3pqS{ zQC+nH0jXg`(*d3u{Wnp!dRrGv8#`sWSWMT2Uf1JnUmihlUT9Sn3Go#gs&QRHpS@_2 z*t`SS4D$6hmN10MEc9L!f2{U+$Z^w*xvHoU=oB|F3%Vd(EPLn2uc){+Wm2HQN+dt7 z?tXl##fq|7@y7CL>|yD;dxezZ(@t}5VjqN75c;E>htm~du zZ_8|1^BW>yBP(s!&k)qj8HG(Py{a`&D_NA0?#64>a{x$&x01UlTMV!*VSQn+mFl8G zAA^{Ob<{c&D!c@BhBA>W`x4zgYQQ@w+*6sl(24V@wEt%3`)%?^nGd8#J=XezQj*vo zFwlJzGQ!Qtf^8VtIMyPzxW9<7Fm2P&GI?qM+BHpxb>1uKl3t#=-&1&P|3Hy z#O2zO>X{5&`8a&oPUoG@0imqLNM;1mSpKD%J<`_B;_E9g@0S`R(ZSxqoWWeeVozI%cORd-LrpsOHA~$;!H0e~TL%_0jpA zHL6 z8!z1U)mI+ZX(MYAv@qBb=)CWED)jbQgcOl6IuHb>Vb);EpX&YB#>&dqt%X?{YkMzz zH`>D0s{s3G>bFN~L7ZpK44pNx+(EcMS9a!dJ%q8urqt>A&S5uxS~&|>-cgAu6`6{9 z8KXh$r>61Flf3x<@w*rqsb^}i$ri8a?;AHT%7nO*g<%tg6BXQdFw0vm4pBNf%=0_v ztm38DkoiO8%nGmYe{WFmF!I5$9HOL4t%PL^c-OFJ929Td)_W6$16>}k+HeFA3oFtB zx;&@75kkgZs`Ls#o04FZ=%d>vvos#B{(S(txE2Wx!+kl~De$yu< zq8%1UJa(ct9}ZjTyK#Ym-J7oyS(3Z`EKnZQ_3BNnZSlG#8-+QF1`+|?W8TDZ^MLinWsaNA~=G zU4`&s@z>@90y^u7Xr3c>XIABrtinrjLHwXDSz+VR*r+qhqcfmodxWPC$?V$%-2B{_ zMDy4da~%EBGWlq`sd2IS5AFsS@RjS3^S;v#fi8$_Vnx?XWZ3U=h02eHoD9tU3snh} z*MI_Q`%mKNo;52&>7?YJ-Jp&i4C%w86W66aIn8|ZnI}?6`2>4$@oVethV$f(LYd@3 z3a2rD{*w9J^_HBvxfibX4=Xv!XaCIwXgdi;g+?Y0>$yNJ~xl6n;26Sfr5bLNUZ%cX@%h0T&s9!P_SNtRfU~`X*%yE-(Ntt)z`dB zDh+V@WS4>H_~vJ5@kOgA)t5ly6vxTZUBAc6kyMFKQ z)r>dOH7&gXdH$a<0E)e#5|+55Z%sdWrc3P+l%~_Y?xLP$c&W29)7}2hP}dsazv9DLE&MLAu}3CUckJ|#7xZQ5@wNU)#@pEB_E1pee@ z9M5%A)FwcN)k{nET4s}R<(Y*pu>1Ydi(2g~-G}DePvy@^Jf+aVBsf-I-PnEBW%CL+ zR8LYYtu-6Uu)FN7C90`Js@A%8wXcR2|3ToXf00Fo&-^3tfzvTAhuSstj|}t;56~9v z^s(7EZP$VRqdA-`oI3U_k3@qa%qC}WVBXx{CTqg4Oyr0en@}(9ggmwhT>-$z&GVw` z?E&rA!u+B3Q5gu}cYqD5y>I#mrGByDP$TK>uib_POreGULyz#I__9Ja!qmin{ClQo zw%Q4&Y~>4ej)fx;!;gHnuEy|`cTAc!SA=L1#0a$SUJMf}a@nKxPq=KqcD31+$_yMa z5ExS$k8ZYARE(@he@*E2LPk~HnG+{o&alde5rPm>LMg{MQs}KxgY(yNR#)tWeWQXm zjQ=Ed;AbQ=*>7yICdQ;ThS_HpD0DtMsuEhM5~}5e&-~piKof9fYxy99Fb%yy45c{| zDgxmzw7&7OwXdC1nO3`Mxz=6x!c+>hW_)GVxbXgEj&RGO&2^{A{RIQsnXDe zefE5*KNYlz_6K783w)pGz|Um~+N>qLxh31K`0ORMHz`&|hfg3ClEAk*e`fN3b=|9x zfsOosqlEu?$5FbTCmQ5by*6+ScdtBepvGo>7mz&oVvqXtLZl2p49W-gmppCzL0N8q zNYJui)ziIxcRAU>Q>X#{yuU6s=A5emZ8SHJskCDzS8weZoBeXZs&N6Jbn)&0D|r-t zK7hWpAf%a*Wa=G7Cgv{`w#MX#=}xJCd+T)QOz!;PrPK=7Os$Nvg;Q_HOc@r69<$-1 zj@Z7_4Pgtv3d!PNys7|u^ETXp_LGIOFC_Rx@RLgXMq7LtfEtJx+4y1Q>mS~CTtIHb z(#OmhOh=l6<)K@%qx-@7l6X&jz1}TMM@%f2eT>haTSVlpIAXEWxGU}MR3!mLM5~Yf zt%1BdhnN2mN!~3HD||m>V97Lq_FK5)lL+|%bIjw+G7-)_XA2`@ z*9{a#JbfD2cX|ZTOBS4|_I19HQp%n?pSm9dGePcdDp>TO(dnF&CIFMZ;24Jfku-!{ zrL4;bWdE)b@%WJ>{nz|1X z?Xo(G#XXMXcQOs6r7ykbLGd$u8akoB4dY4}`}y^BowfBP0o#-8$)Tz>R@Vh@H2Hk( zIw^PGWvp5oZOCAm-Uf^*XOJsTFPNMGsL*)|uvut~<%A2H-9|<_5OFQ^{45Avm)X{) z+Z*Kf@Y#OJWg}y{l&$Cvba<@zpxqGMPI)U4G_<}N;?Fl3C5VUThtQx%X51SO{wOK- zZe@bjnw=-to@d*rL=;9qqCXxmc=wgQG&xNC<|9P7|I$F{(5n2*gIE7UUt3sKI%NOR zqHp5Q)HZ{@_q}$@LkWy%%B{e-OW&>Lk}E((5`%b;5>QGxN61Y+^Hctk??$hkU;}c4 z!Vb7)iKdFVd7SlvjFfb7K;bWEEb|8R_Z>{49NFE2ze%w>wO;7t&5Ec3?mrsD}e1apkpg*E^h;>)fgroxsWQv~Vc^^e#iEK`chcr>`e}V}mxrGOpv9YJ{ zgPq44U42}6Jx~HBEQbj)?P?R+Rs{WENSMLmy=$y3sx~27gjb44-`zmW!{52|eQ|p| z6}-Fpgkq{7F{x8n3OnEap5McAgYW^Z5M*S;3$g+?;CUf5c)#>A1x*jY-e^px+EgHK zeBOI1k-DgsdUMIQzTW4C^T8f%XRg_0SDrt2v3(wCiB@uIEd}$c#^7}oETFIt7y$HQyaXL|H9@d(8l4%yCA1$S508SXAYgt?|5LrAltmiq-+ z>Cwwwk3f+na($zV-vAr!Yfk&c=?I7R{|m4)9KsL`?D$_k>o$G=<-82ty#oliQE{#Z z-TC*(YE%G*`WC7554J=93C8EFHgnDb4JKibfZg!9a-qP6GU4t32r=A<+ZQx4Rxo)1 zT+V0<8`=Mnd}o3SCLC&1ez3&KXLNx9g}E%5quu1>1n(jLsMtC08_g(^ipA__Q{X#r z85~bgA0LJRZ1n0P8dN057zrqBL9b|bc^e5@KKxs}yP2Cq_swc^;Tej2vg}*KTOBZe8Le zA^iF*3kUVU>j3fYdZ31p)fJ9cSS;e}0(K?usg|&wOKl9fgxP(=2ONO8d=YPadD;J0 z6ZN6??wof(lrz4T)0YXlY!W}>GA*52NS66flbhS0Vnt0_nu^|TXV>u{4;+boC&5QF zzqQ6xE1l|NB%JaD*S7gZ9W8SfBlyl?k>wJwmTQTa#aQ@+rODjDb0zFpJda9!^(4~-ra1811-tB|d%WIDBn zJpNA0da=K5vG}bha%%X_l~oJ&9(ZR)&qV7rUia&ME`j$=Qo9OAl**62W{LBg$y@T9o{^!9)ay38{x@2_^!RMp$`5< z1rt<6t0@flQns~8 z!b3wT9Tz-$E~ds-aK#I%6C}QvP*lUeAXun2@)&F;h&=51D_6`;98}7VMgv^UfB(35 zP_(6-@=7td@}jm&Vn46Veh9vP=??MjX+Zti(@JyP5amm(z0E`Ol@}1bS)UkWFvVm` zcAhzdcA5g94!(J=yL+-qYZc}B?FBaW{}_wEEpi`9MUCDwArTijmp>ou@0hFG$9uT$ zHdg?bz2E-()biQOaf*&&#b}!UvNEH|nP}OKTcvMUe1h&3k#esSp$XRerQ$~BY7jhG zQv3(481(?FbN=Lbh;CKbZLDU0q}jFcsfLs%OZoqy5}zFuL^4^BC$twV1fBT$rb}-r zvpRVBbomN5kqlO{xEinLA`9v~YI}(2m%XtM8*$8r)AcJj9RA3-yzv3mW}jF!n;pVI ziVjbCrFe(jfl9(R_W;yBSH+EGROF5ilBac~y#4= zns8RdI;XA&WybE!s@eJ>f$w6{c{@Wfa2Yyxt@SvKJeNAoNvl#Sdc3-h$Mc43jL20m zD-&-k2OcUz%Aq}#&Gz&WSIKOEHhaA83(bUmdlJm# z5FVFZ+ullmQhf)(*X1NK<@}&aHx`?PhZ?{Lwk2EGx`u?~{;>{Z)|GMWRcC9BK6nP$ z4p)Yr$e##(js2ezV5DEVM|}2B0-nb&$YYO?MzOOdEoNK0HEeE*y4RaanVMD_P0t(* zu<^o?N#5tWbft&uN8H?to8qpkvG1xhn_q_pPEcj3Oa*b2{(?RA1N=z9EaJ5kSCaj1u&-6zkD!0IBbvOe?2O_?IyrR#1U260I!S3CJ&cBx3%nN@X$7JIGpyia0= z{-_C{_VVYO!rsXWhX!U^YtCPe=NQFR=(FXfZODNyu?C2z?NWM^|H|58_T1srF36nS zN3PuRIo&$B^GCC=q-qqW?d5Z!E`9(snjJ^U=%{eUa3|w%j?Wm!t7QfC!SyvBSor3^ zSv}DwcVrQ4jd?Egx`54pD4cPICd@b?%u`U%+r}4_a^=u!%+5}&4}HoJA0=|97WcHw z_reqrz$Uk#Tu-MOQ5YhUuUt0{Uq`1?VBq2kA4OKHH;@}s9rgG6dW-LQXb8)s5S#wh z#Jf=pykL}@r}56JlWiskgWllNY)#@B2>ILrY_z-s8-qLB!fArKo=clym^4hR0{4Vk zOeigHxo>RE?WCW9VV8efh)>*dj|3|S&3iI{amI`cuIH6R=PztDl_>w-H%E|MFJ*8~ zPIf78Fa^A=hWtKUlc$|&Bsb;t(sY!-nCMv07ff>7R_3(fnsmz(Z6&9x%nIhJGaCNR z2d4ym1c8wOmGtG2y1cmHd9`zu;&7`bPJ-*n`29z&*QztG!kP`*R+w!r0mY1)8x#_R zh^>p|!tT2X*0gJ;JXPbHG&jN~xJVoH=Fa$dVB357sG(e57$9Hpw$`#-SI=Q4wDJnL zAVgMY^_{MnI4;io^s_ViixHhK&NJ$+4dp(p_yUN_HDEMl?SXUNViMC$;lnYD5LvMX zwaSDzF$D_}LkYy{hjhc3xWfh%tIX|gX^1msNmcr=gL0va=?duc$(Yd%`&!9by^wDJ z`OU?z%l7eMxe14W0#6UkITK>R_mhD`B^wwfzGf4OWdyQ>bpH4Zg6KR<{`hY)qrd#n zEBrW~!Z7gmIZ~BxH}ih_&v^qAOQ)BzaZvV(V3E%OQ1rE8xsM9OEUan6a&gInY$QO$ zT#r&B;6#v~W-26FsJDYdACm4;<)uu^P)7M#${a)Ed|z76>Cu8uOEt%X!$BmxQ1n+b ze)`+n4g>g;z6oq2Mi4?o7`|zUgW#E~kbCxlZHYdQ{QZz9cSPk>K6cwasrUgSFe%ta z@AhO$QO(?QOOugUKWWiL!Q@6bOEt1EcBGO!)5z@ZlirQdyZyL)c1sH}L|F|HW-Z89 z2)=Gkbzn8d$`m(|5_pt++CMbo=*>eKz6ATh&EYpT?YlaCWg?`gzHQ4f=N^xa7^xOjM2x8cKNIMrHJ0I24~~8-h@LglfmaMwRiZ&I}*0~1qfRKM)Y_8YkuAgg6H zHj9T8EE&wV@&NNP^1)ADH2oUPr)32L*5t6tgyDpSm%hDwHE{P|hd4iKp-%Md@@UtJAiqZ{r$n@PgbhRr*$Up+)qn&ax)lnI1=|i}#IzI2tv-5Fny4gU*H9 zhLkKjl}$M#QR_K2`%7|dP znjqGhtJy#}-*dI~VE2IJw~X&eG4$aYx$(w~&?WunTu}dS>HCO?j-yj=5CkDeT)UqS z#_VZ)TW8sG`n^fP#K{7IV=?_*yM$lmGQL+WWAAshn(>7#BGaZF)*`1h+k!iz#tWy) zB~cqyML4MmCm0|w9Sh%X&;z3o?W`0Shl)sdN}Oba$vnLh?~5b(E_u2!rWZPMsP&)1 zbDbjmCm7hnT287z@%wiD{)dAlm(599$vZo#Xm1p-Rb^%%|83N{r~Kw|`XoPlJ=77! zZj7<#OHUkNe-rb!;``Ne5qzyfBpaF(|G&<=h>DCdDs!qsReRqpf`O7uWy0zBXN_-r zU*GfeecUL}oj^rz=Kt;mp(Ub1CV!i8*_MM){OG;&yA1wvkYE?3`j7Ua(MX$AR8|SP z_M0>18EAZjVoT-;)QuH=Z_6W|mKAz3{#QQ!f9YVYF`(xQr#6%W#cmOXC;ALh5NVO! z#Tk`Nh3}VReYG>k>7C14$ZjBTPbK`r`ekoLw{zQ+UDV>;&C?-`2cT;JXUX0qL+_w> zZEqbhYcqM22udf7gl)&&FZS(n!&b-3CPrHf#~8==N6C2*Q=hrqp&C=$8Uwb)A-lbk zk=ZLceoh5%+A**@28V?2M`9Sw?=E6p;Ra$_vLZ0CNn^C~lB<8KIx0 zJ|>w5;==WoolEVIJ?89rNKY$Ogcwt5HEeK3hg#?oy5DMO9M`vVCjQZb%Q$g$kYQz# z&E>-caO+d6md%WTp~v0AavL=8-(CP83s%IUkEQ0mh7j<8clbbEK!e@C#Y+&P=r*~P zm!xkzh6{m1FKd;r;z$E!l87UBwl7Wq$U38CLN*jG=yHAtmXpVYvrAOjY{GT*NO&9k zecVRT%G$S%BZ6k0O761Z`vhID(+`vvh?q|gqt-}EJ`6XqJ(Bi3`bp=7!zwP9@VQQ= zmAg(Y?(`+Dq}&!d(lMH-=nP%kh2<4vP}R$@sb(K+G|>LbFy@CmMtZ#jjH;e%{cgBc z=`m1FO?^8Gl)E%Ucsjnb9smyi80|5qsvgP*Ap^4MRaKq$Eo}6gsBLSH^0kS#T*;Sa zxj;ciy2~qot6S%qY;V4J&e`2ilk+-UZm&#e? z$r~hHb=FZn6h4fO+yhF;GzieJpl@BsW5boOq=h*QXIo~zbdgHPcc zTa;1?1)wQp^lx|7?+$`KYk4hJb^Y-~o!L~QY*&a;6iz0>m~+M{9bJ4^apuVtXgkAg zzrn-~guj3;H2UUY>E4XCZN=E{S5%|3++2Q!t^Mo;a8EES``#=Hmzk)ky9KQ%C4CS~ zovy>#vVz!0H(tK3d{u&uySVbLUI}|iD=;Vnee74MdE`GFo{AdM7bZ8=Cg#7^xps{W z?})w)RdA%Sh?3#hU5X=;h@M#L%a%ajy`EJ$<4^1Vo^76t_OseK*MLe}c5s<%kuRH> zO%j9CGt$6fL_XK%0w76Ba(}+tRQe!D9Eld^4?c`0!K1^~oW+YXL2Gq2wA#@>=Z@E0 zm~T14Jd#_28OIA1y}&%QmV5_9jeO5ei~mtZD|l|Z-EZG^3aEf)`N<#L%|CQ#^;f)A z*Yemc(+04ETfqr);wBW5Pigu>wH40t2wv41Y|1@QleKEC_9Lk@wqc#R^g`|#p8Hj+ zB=+N~Xw_l=$Y;v3gKWs{9=GSJ**2y{pxu`q01yQzI&^ z_S_k_-_E!AXQkPN(Y#>~t^0!8cW{=i-sl)l8^|3Uh#ua8gyVyjk}viPoxQg~7E6_c zBigmuT0>C+6+GcbD`cWxke)Y9Z0BGN_5xp>J&kaB#@ZJ?)JS|mNHM)>(*I-ZEu-S< zmVIvs7J>wK3GVLNctUUq5L|-0y9L({-nhHFL-1gYySuyl?Y-~0XYc1Z`@G}*)T4X! z=(&2$s+u)_^`Etnj;<|m@?Qa-rX-|OH?J3WjA6gvM31LC@+=~B&@CCu^PTEd?<{<0 zl|AWpWXvPf>SrbsOK1%vtOC(6q|v@kC{L5bqJ4)Ttu@l`a;HMB?1(eBZF-e$x+Cee zf|+~nV7|L$fjhOGV%$Z=t}ef&t$_Wd^LI+0x2l(;KAr2sWssc89c-(XAbX*o)vdsi zjKO+KdVqC@&I1+j+K=DUMN`pk?E8_qnrmw4Fp51*!usGYLeX2E@!HHUWV8Ssq%^RX zBt1$FbLzp9D%JK#hwe=qyBmYQi?{Z@43GrC$$>_pf8f1?Xz;nGQ~MK^?Oe)bBXFhI zswVBbfqCK9icyFtYr3s}^d51p4_@%{uRXMnp2o{xb(poAPF8cF-Y%rLnp?ZrmIoVQRv+Y{6sC$ z5aDHs(`!?Zl}0NZB#g07cZgKtQSjb~RVNE6i~ZE(#JySk2PEU#{ePI41IeM*eCT{Dw_qy*|cH&CdTCt-~0H76}@_H z(K{@my|tY+HXCZ~E;5~Tab$n|nQL=0e)b!sfFR6nZA+yED`Xxa%nF+v}WeUpzg;nfd|N?h0N)2~{GoJXK-8`(-vansg3mB~)UjeUzSH7!qs;azNtEFFlmsRq{KUsa{A~jE7Fd=Cm zg>qiviY|_l;WjIHmPbJ#_~@Q!(K?3?Q2^*pun{T_RUeBd^7U^bfCoZx7*=Y{jU=#L-QvgxCuSojA%W>)OYeBQ?D&(wACW9HqrFusN8HPeNfpH=S}Wk_Pi92H#fmwm z#^wT_FM)pobrqK(z%oN&Z|M#|LyvNu;K`n&=S={3gY!fs-JOr=A&R&#dfr-~sdhQY ziDpfd;D*|)Z)ESjt@Fw=X%$h3Vean8%GFL)Dx2>BhNkPC*9^;3%W4n6VQ#WX=m+%W z<(ZdtTH!2a;bYQ+Ds4AAWNYyIUy_?vDP}AL@>aAjXQ}D3`M>^3Y%gz_T_%GXF3hg8Igf}0#--p( z!}$Ee>K(H>&|Z-0jDZ|$?9CyXuAWBhpU!GQjW-;$a|{t*mSPM7@O082Q8=Y|!^nea zKuyM|yMqB5&!tf?dIqfArb7)M2h%wHfIxuXBPlhrkVf0pH+i62SY^2>Lzo1L5ktX~ z0)_iBhnI&~|0qRQ0A7-I`@>pdWApti5+lIqTjBmZ08WcD&S*PV^7Y|GjOGTfuCLJ- zx35~t9qr*xp;(1H<_l%)=C;Aex69>&v#!LOEbSu(3TMctk`lUU46sy(b@}2<>d5i&w7Pmw3`_8=hFO+ZcvU{!YoPwe1@-o zSh@TdF3LrCyd%23_Ls3f|Mys+U%<@RFO(SnypDf+xdg7qxIf2t3@Oe^c=tGJ+ERF6 zvAMDP9HCP4uxx(RBWkU(d;1t!bo-|%A7q#1l&pN)xvfR+juv`3J0FWk_zn>zVtf9! z+N|xU7LU%b0?PxL&d~EK-qFQw3Rk2>R@RYtPuOavWQ~i)w zUW}kfxb;B4;uDuo*lVn4er@9b@{PNx3fAxw-`blb_DEQWM!Ox;gzL`7&#yZB#cbD> z+>z#*f@A!SMKW&(4ChPEzj7y@-fIeEZpf|F@fhFCxLMp1yt|chVB`)CSn4$HS8=v` z_jEK8q7uhu6%}PXmFn!K|FlLR>>v(!1PzI1DUeNJ|3`v}?qwqnuqAgw=Q>5=et9mLV_-W(|zx|ADj z$YeBaS6-ir`XFDgN1-dMgU*cpdgBMz6smQmY1!#a-!D{!)JnR&)^00FgyhybURWa& z466tWMUF{*%=R2h0%2a^<>E#aM9qRbsKQj1a4t@3g`M{21F~gUCQkznkSod>JHbSe z&UpN@5uUj5JoXVNF(|RV(0yqPDT02tPCEyDP1v0eAsCfT-Yr$lo6nS(yC{?=tp;_r zGePJ_MDETT0(FcAFMVQ${C$)DqZd}Q(W`OY#caD2y4LY;7!hHP0x(T0p6`jj?mTJy z!)5+uM3;?M<1XUFmUpJ$#ZTnq6rqca>7-KbN*GYY*zjK672|e>K%ZeGk_Ve4E;sg7 zTgMHHHEbH8KbiCU?CVhH9L zY7badZ00aZdO|0`mz=JsAMq(sYe3;&PHFGPUFzY(z#mx*OQ*HX{T!*Q0x_9j=t>rY zIA64J*LWn{N)xV?CzfsHmMX@%MAxo$*@td>bExrfHq*I|dM zSLNA*w6k#VRTe*l1Rt3`(NcmG-7-6j`A{Hjp_$J4dm{3CB5ahC+!dSlhcJ*sLMvW%dI3mfIGVju? z>CIPr6JH_B7QpIT-I73eO_`^*njeWo+`S+s&wltEgF?=E`KMUkS6CZUR`r?;_4Gdc zBAwo3MYK{$9t-pEy@Tv{hGNokOF1N}hQGnD7Texg!3+RF^Zgwa4qkoBVT*^Ft;> ze~WG%E0O+I^i>{6nYXns$s4S*zdB#A`Xe{jYAMVLS-YzWo^Q2YpDmTuxWHj+pCrdd zHD5mJX%F=(0naeDeSiNusNvsC>K_L7kwDAEI>KMs4Vdz0O9^v-wt>mod)4s3pAZC9 zg|^3&Vbg9>yO;5e4a$gVQC0AFyusM`9+NLU5W+>6{VLwQ6oRw*Cg`rM=F%JQrgM%k z8?1!+CLFHW3%K})jzx*hS1U-jo?p9jU|8)>e$Pb`Pe#pJ3rsw{{VZm)$M9ZpCfI@U zmR#g&8(D@X-WTMLOtI|{Gd2CK7?A|X0N(8=;6MMcn=f2rCfoZ4bER8 z>MVIefoGgKLA56z)!4Y*f}x{J@fIp+6kJHVF6Xfrb8eCA@wrU}xm@2!S5GnxcY|oo zePo}YS;YupJGhATz)0<0c+H2dHdelw87rRaE2jMZ((i|{;rHO9ib>uGJ6EcVd#wgHjL^D zAoyn8ew~-=RLWKc(#a&=>c7}BFU@>+NJO`mBXBa5Np|bh|1vP*d$E^aGhH6%T>bYr zWOn|G*+SzF=Xbjb<;)gr83XAKiR+1o!_=6EYRW3WIus(#7Xa??V5G(LHLD06OG}*~ zbY?eO6oW-XMQFSW(lA-nB9cTy0&wCDwNiSpie%!5aF6+qd#}5?^5BB zG`nM=(ipCrOQhc{GY<~{7o>cNMBNH4=I0VZ#KnC5TG&tUd9tzDGRr833UnrsQCUa_{m8`KU7g>p3`F%F zbs!wz*2t$b5Wk)|FMB0nrkIHz?+nELdA0UzHiw^zT7k{9`Lfq=x-VNej~_2#nu!w+ zOO$f`d#NrWeZb+J_!7LN>g5-`W+5F5VxyOjpTBS#+c8~#ey(WDu^c{@GfHsS1fh}r zVN zX^+3$lKkbs!I%xwsu8)HO`<&w&vV#+bpdX#?uT-jZ-Ien#gB}rjnHD4fTx+9ysjV* zn9Ln%bs?%WBI~B{te*M>Ew6{~uF+#e10`_}@B-o#{Z@Sa2biDd-&SftzPjDPS87SB zOy-n@nszSEv**Bnq+9=rD%%FiUY=aDsgR%0+zrJHMClpPFJ@dv7K*;K_I+E~|j(Q6XM-nob z<7n&k$ttmJCfmL4jDgcQ;xM$n^rpNrxIlyd0N*20YW!P~L{O}CavNXh_%D4i@dl38 zIOq^%X1wL0^^|xKLr5C5bkSR?S{cZXwy()QfFx;d<{esizpxf`mlA$HNNEn&J z@9grVrU*XAt9&6EK8X9yawX&qA=E&|Y};2;6+W)@oj%fWyFCdLc!uC$b+64O4&z@6Wd(>q;}MG;2{y9*2-X4E z6N3O|I5x+fdug-rP!HDr7!Pa9nEOH`Vo%O4F5gVq&g#53OwMyFsiQ)`dSk_#kxl01-IM5EprbVL zp!8tSQSIMs!C$%eq*ajdZt_bH$W~ktsFW#fVKIxEdeASbCNJ>kYdYqP$LM-1e&rOK z{)bk_OnAetNRoE>&)|GC^j(1qO3-rgdPT?&j{Tu^T}{uasL0e_s&82q#uVBuZ?4df zB{#*X7~tdfq%T|n6|zi+Zg_l^m`Ruh(oK@jOujfb$)nJvhQU&eO(&b8<`nwx(o+SD zk+#rloBfn?Zm(w+9hR!mPnr2c8$}RZhnf$YVf+x|2B8PiO3~rfwPg;Q{F~&V>bxwg z{VK9-r;RoR88U5$z8<~f!z<;mdmXsuyMeYX(k}W< z?C5rS9NGkB6sk`fJxXR5_J&PDl{rbQp)ly6+Z>#LH)3?^(d|eYQIO8S=YTamH8Kj5 zd1cZ$R{MH%Jo@v**Zwgr#qVK|(q-qz>W%FX4Pb1$U1;p8>vic4n4E}w`ivjG_KH}x zzaQ2U-R|CrGo@arRuB8iOQ@%xmhf+}0%9%C-dIa4Tq8X4cAF+JEqCT$%sqkrF9cQYP6Bowr=9b zl6b=P#}5kZRz*Bf49y$In#njUk%s#DTY;p~^|kUyJl=Y_(nbmdoVR(RTWW2M3_+MO zk5lYx)aCU2>ihse;A8%E6DNu6TX5k#VNAQbMT?03x-ma6T>`lM>DhM-L((iD9aJfS z=F&kohGHpY9srZjf@~zR(-TNs?Q!Ra-3>zfG{VND>NJ?01@w!LBWm64Lt4S$#q;sQ z8|V_$+e5B44Fp{L>2um4S0Cc)D>dm_BcW@c`CV3=>`)QPi5UfnI16jEPM#^tLcOa- z^=4D-Zy_4KRrlnn%v#k?GAbQ_2#>y9W`O#{NPjy@UNVGcbOlfz#OYR ztyc1tPW#vJ$iWy*Gy5WE4LeOP2aDdggV*2M&K;r+*ASNsCI7MjNnF}h8MA=7*?~1) zhpv=>_B0_Sgax)jI-1?l&ArYMzl=#BVC*^56%!j9oOnl%!Ft4iy5mdKalkX{Lm*pE z2Tc^s_a`Y}2$6K~ClzX^J1P3qwJ&TCLT%1~9BTS#FQn0hHGz^$f7N;$&R8&m1 z5tD|KO2tPSYE~!|hrhWKQD$r1Cpl;JxR-QHV_5b62PNH}w%%1%{IpjxODW77n)ad< zgW_Vu-*Z@u#JjRYBeIH4+Ge=tCASRR&1%(iHw5Z{_vhA zS`z(sijsg>?|1x+>7~vzt70MWV}*e4hF?_mUrmSHop=9m+BU1&^WkIHIV@)5NSB~H zT7)mtbo87r?!RL&i`(&k=Vqn*r;`DF0(v{wp-K0P9(S*uk<&X91ByvJYGeJpuCT)j zZ{of?>z9JN}sa7oAsh(Chk<0c02ZIJS8zY$9Ac_NekV_(Aa-@R$?) zAGntu+@~19MZ9)Un=xMi@yA-PWhv&t)ZW@(Eq@Krkaw?g{|nHnl)7rK1TdeXRTH~Q{X_J>!oMV78FDg3Au*;sCxN3ihbb`v42EAB$em9_aH_c|BPd6dN6 zDm4Fd_t_g~wTz4wu1$zJYyS8U9Zvc_ zet32v-Zr}y{y7UabyMLXb6Ahh_noo?gHUg{~(#vk3q@;Who zGm-zE&*knD0N&%gKa|FAxBwW$aH}E~1o+&8kNUA7P+eXJ1^3L)_Y(&8Kr$OelHh$E%GL{hXYS_I3m6k!Pya ze_S&O>0M2Z9RS@FxuJ{oi3i3P}Xk)?_T9m9S@Nq0ZiNP=W1B|eNx*2cv=gu8Cpx0d~p&3?DO z5XRKc9ZOurWNr|mNvZY~tnJEQQ|^B0*f>Jz3iJU0n}=sH(AuIW zM$^Y9C5ipl==|@>pt{9eO}|Z98hhX0BAGxOdr5IOektOTEBFd^0EPOtAja^8rq!4T`yZ z|N5Q}l~{haV;DzX2XsOzJ3jDIq~S|h`Yr%*g)g(ixP}q;AO{B%EY=x;UQctGsnXuX zxZIQk`m{HQwNUfbdMTXMwf1k($@4eob>rS(r`T< zSRH20mgirEg<9`^w~jfzi-Th9eTXX5s$4j3Hk~2ytH!aWC($3OGTpyQ1VEad$>ZXR zsQbUFn2vAmV|g?jftNfjCT%_u8T6mPm`G8f1_#PCXDu0Z zy!H710%8cAl%%%rJOja(*>SGw{O)%K@n@OKk>{p*Y2S;!qYiOH@za#l5&fB$JX)wX zMj!ju`KMrXf)b|1p&jqd>fM@`Yvj8XrQY71ag@LUPUGpXzVFmWccU_*Xia6_Yi=xO zvCVAxZZ#4v;;JBX5h^~dN`eQpym_oYl3pK(j@`Y43DkxsdEWePy~A>$+>JsGZ+UMd zw(V*izl3=|rkHBr*stPv_qMU}N@t?$_U>%Js!5x&MCF(7CXot@E9q|M{gv|f!&y4F z4cWgfkq?zB>p8*T1r*a*>95Ro(lFjTw@$^*kv9M$vWfVv`f<{W*46L|ruwrQwI0P> z24Ux%dlPd!^(m&jj4Pv;>=GvnJ@j^QmB$C(s+X$-qVQp;D;@CZYLE1iOX$r1KZMk6 zb~ELWRE6S`CdUX0O$Awb$%e-b?J73tDA+bBwD{Ma(SNgN~SeqsiFx-T@FEAX%oM)>k4t=cro=`ht zczt$M;%gE^#43)?u~dlG(#7-HL8k`m7A`Z$YP!r1<&Jh~7e#ojE-rKREc9X=Blz~P z=lnpg`b9#}(**MOJ>%*GDn$Z_vq1)a-ts63EY}c=z(X9df=Cjx5dw)Cf^4D9Y z>nz&sC$4WVrz?rI> zE^+>S@p%=;YT{dr^$Ka_-8wAmd4zsynKZVS>Fg^{!(~miwdYtBDP?Eg|H5=Xj7s=# zXa#X0^B^5rTj=a3I9rgU!d^m$Y4;9YLs?pG^uU@rnOaB+W`AXw&hpE)n%FIM9aW50 z7!Lgoj;d&BW+LS&<<2rNUEU*@Bp2N&-;>>O5G~fEU2bh$Chstn-F#Ru64m|AG!?VL zzWjH;6TK&nLe4Bm9dva?S@Ppm^!Fae{rDM?NleDwjM5iX&Z%%j#ad`a6D0k9D|RDp z|2{)eTh{r!i1vMkYyI70Zix{BDShq4%pf+<%iB-xeLJU0(e%rMXKarYmBKNH6Pwk( z2n;!0Bd=Vv0$(S54wp6}vMcT+AHZnwl&RTl6_;~qlig109Uj)Y;%{K0XQMRu0jL6_ ztNRR%;wry=<99Ugz}J`NmGq-}$tz#GYDg z13iQ*X)BF(zQd(G6&JESV<>d&ZqAF|&ij%2O!K$7c}}9WQ|j?Lp`_Vd%X`4AD0@A+ z^~R-Vbj4`eng=;BFW?GZ@6evvY`Sc&w4Ei(fo|Y;?x1OjYAKh=UlRclk0ZN&H_=(* z-#26F73*uznZJ{c^czB_FWQvBad=$w6VKZX_Ic4{z{Uw+FW>yKg4e-cmMNV{2S%nY zzNm`m)eAeTbSJmpVHBH;ClpH(f27#E;xXrDxLtPI`ovI3{39P6X3=hPz7jcifX5ot zPA=q#W}(Jw6@h3>7(Z@M$_!^j_Yu33u!Q3Wn9{; ztDfBAoo6Dh$pgEj?@zzc)O%w~JbM(O;<-HHRHL;)hDmEAwwwOR$9A-tQQLGCs+2pt z-|M0<=N0Y|FNAYf6G$Aq4nlF76rIK^T5zOO@f~mC9&+b2gBt1nSAc@C;*V}debsG9 z!~`Jbv|a76F2UUjnr9EP#tEc-$Q;qzjy3QRBrIayE9jLoH4+nUWK1PtoW?uOI3hq{ zQpdqW^Lev3ZE7kHp!7Pw%Zl}Fb<~xwj5V@wPt`&d(M#8y!MNYD@`Bc)`d4}GA3-wq zjUO)4Ce|KwbM%_G(yD?#{fC&Qux9%799ifPpH(mH)3KLI2H|YvBs>DWGk(9{Pza(x zY$Jtfi$e^^e>ea4%7ae-7vunsPMY{_RIn4$;^@ZmKa;lW}5KGo|NtPjk zNYz8`&6_QQxY6v*FU#DgBU?Xrf zcCft;dBmJ955##5%gMz++0ZLtP%Vj@uQBAR*mXu_c75oz%3iVgQt31LiXweG$Hk>G z;C1)z$@dlH3V&;Oek^jz=@T?&`uOYgi9n9Pb26)%28Ez;vt5TSO=B`M@qyV4ujJ13 z6}WckQ<&yTgIC1y?CZsug|Rmqm2V5F$lmv0aZG#zrQ#4Y-;KIPM&eCmZwJ zEMbuhAQLxBx-zl3;sWd0=Q__N#&hwj_?~mrISwg{s20+`)i9`m*+w0{@0Yr5>=5;J zVA6L!|Gk|5+CzIhpL*|ogC}LneL0B>Eg=b897x_MXg5m zV^O=IcV|VxD(uR1p|QB_{z^1js$%Qp(Veg-d_Zp5qt>@`Q<62e@xq0+^6Lw9wb7J;=@Ck+2+`Gr7-K9jXm;ObCfMRYc zzaBP(2M0yIi-Pk1Of6dL)Bp+9z1F51n}CBhM$n&MmF@>%2b^G$D1y_k(SsrX35*zL zWz(2hsA*V*hIJc8Fo##i2gI(Sd^=d)vLE6h?rW(!zEe7WNh8C);WjftGS?Pr3!;kC z&D-;QoxePFPGeAR6lDm$whV@WqJDio<$7%6k4O+L3~gMT;-(sKe0g-P`2M1!ASKwEvok0RN{TVW0!7&)cBxaoFDJkTdr_X^S0l#|CZOp zK>cIuf9~f(@CJvMp}(2P2cr3Ccu}d=s3Jqz=ch98@xG(SMOPE8XU#*eBb(W_EF;SP z^nGIHtCr`bK3juf%Nu9xfKX2%4M|s;i+k+HPT%1D#(~-!DKb*HzwiE@5om)E&|X?; zl?s`3cQGZNlOs#j_4oz)SCHOs^a2PAri{ZF+0b=IMAxX}oWJ@V;CCwEV2}7z1hnlDJ1QC0CLC8n5~iZA}_6 z>A6Abk@iA(Kd>E6>moToLI$hJ&|iVV_GXs7j*#l5^@T(ty_t4i5s&1eUg}~~;%tok zyFl5YxTd}gC6Kit?G14kO46#BBV?1vlSBfL0MRL>ZBK{{`eGQr4%@$o%$eRQ_d4sa zDK$G77s#g%0RdiPMqHMfq-y=aS5SRd2w~ewQk?ShXjdPD$)hoYbORRFGRm3e1I43+ zN1n+-_bJ#UZ1lkUw>#EWBLBrFro;drhtu3bXOQMFyc_KRyw#0q+ZzUzK;(LaOZi4X z@=QCiF7d!Ru3pn+UkGo-N&T2E39$|dRj;te_F$yJ#V_4!yxN#j`ZH|bdHaH(f9Y^O zwDlCu+x-U}k5vZc8-6o+xXwg1LIk+|qs-m&@8KCF@axwBiT}D``{#EL+4uK6^S?rr zkzduD#$2MFa&W3~>pPAb zk~S9D03%=T?y=|!OB}i}2V!mToel~2;C!U3Y7Y(F_1lz^Q;-`~JShBg#+{{6_&ytW zNeeRC1R?Bb3@LQ+&)i@sON`dhjw@uFNJboqJ+TlPmvebh{?Ym-B)QdAlvc%(V^nlE z1t0H>K9Ky#CJG2*GZ5e&`vxQe&bHXhlzfwA7zsil1jAsBk&SxnEF$HR< zyfm^OJtSb9+jiXB#5h60Hja*-tk9^=j zydzepGTb|6!S%a8c>hu46va^PD^(F{sP1$uYM5p6hHLI}PxH+Dy|N`9h*<9vZ#c*N z$_&7wd4nf(P>k++gI8;a=>MYg-9s)}A+u?0f31UqDcPVqE#@?S&q_u40FfU2YJ-_Zp+OYE6rE`fZ9Kne;xRZhtDq`03=QL=hT4B!| zcchfgs@OH#U~~sw@nwaWli>cgi_QtvC4u0I^2JHhTYSy2w666bk19%gizV_^@7WMk zVoz451Ia~iR-q$MR;HMQH?)&YIjHJ~AXDVQHmOihgG%h|Rw8?|DB~O9Y6Pl~?vEjs zLg~?Rk^D^ZrHD{FR9bmhk8rMGvFgkeAKYAxLTY;9AyK*k2{xby<4%rhp@;&R7?Y+V`%WNR5JHw<3Cpcm#?2(+G`mhkbq$PAy)=73=0iym+r90NXp}p8I zKXPEP^6G><4uViq@WbB69HLsdnG0FCe_DV=<~I7C0T5HtvT{C0Uay%$i14M0W$kRs z;!p={{p6oMNPMs|%lAYGUjpC?iOP;4TJ22k8{^5M)Hh=fclL)aBl!Li=!5kB10wab zFLS##befs)C5IPGcWC(h=b|-r+0*Y#Plr)|Lut4Q$QhA$OTBHb1yzQlQet9_SA8-l ze^Le@72)6#q2y*4+=-Cx`4%%Qj=AH_p4+c?wcDRVv})Dw4Lx~3lLveksK(s6Dz+(F zPOct)c@K;vx0us30eoX96*6)xI9~3aOpbUMyu)>|(i?d8ufKZCQIm(%m%Pzu5qW2F z*0w7bs##(wVm#+tobWQD|65%3B#EHecBb&BPK^NCvJjZo!nynD^HI%Sddw2F7Ixy%I{J2Eeb&*?& zuSsVqqBw;-ZCw?OIB*G^x*G-F+juC{P|m10kHfZP-pAhHTJb@%DjxL(dGT4}tvWB) zohc3~Sir6^KZgm?Fxzvyl5YU4w;F3u%r!)fhNk{t$DCOBxZ*sjAwlH#eHHtl**5Ya z3MldPjprsnJPW*BIJuT z+JE|<3z-+SOIFx#++LR%JL6f3`br6NyqmvqIz5i(MoxXD)f=`ob$7% zHg`3it-)f=N2?IR-^d$`hGf=00aKTwJ9{rEOq=5>-}U)~TOpv3(q+Dd?Lql7=kQA! z0lz?E{7)Z?N1gmk$oridrEB!8M5AsHZXZULTA`wXA`mg#guq9=6jSlUlsi0SfpAXq zRfU0OTyvj7X*K*BE9&Z}LrzC%G~yFt(Lj9*b2l$05#}uiVIOEbyo>0Aka}_XSno;L ztWZv~p7m%}eT9mo(Tn-m;%NTbWZI(tF%scaLG?l5nR}UucQ*53D43Mwx%tc+A|xcd za4QI)qR~r$4F*5JVG$TAw_n zRA+L9<>y0YNdi+$Htof-lFd-4X(4h#cQc9R6TA|DRQ+{?c2frNV8O6c7#>$0!$FB{^p{8CB8r& zVfm6v&fOcFiqR(JW6Kc~lD*H?!7QXL!s(6+#mE037Swm;(}8UkKozY|{bsKfDA< zA|wyEV#F`vXW}dz?2iZP>gdmba|v9<=MQr0guKQJ5ro$6Xii7ybx&tt&Q?|CW6Yq% zb)-fzWpnrM4kijCbkoaeR4 z59>Bpft8m-hpHZTW}!-G|BN_=GYVXgh=ZmhQ8WMx^%!1f>6Y9K!$0osgvYh!6$A!< z0^c#lKPi7WQ^Ir?w0O6&*pOd7ro|{^2ZQ;3OY@ilW%^maG2^x`8Ba9L9ytD8*y-~0 zE6tg3E3$eu((A`E`3nNVv3<7V?A?m``3$`29s3f!$sx%Jeu zXr(NHa8MIbi~o3hL8Rt^!g|R<+e9t;juoCuxxLLe=^sVhG$;%jK>w_YkxXqBsfuxEl01rJ6393 zbffV)fM+%b(e*=QjkTBJo~Vi?Dl$jPP8l5u?b*;)kA{N6K)STQH>eJUow?C#LtT`aI~WAz1G z_kH!7v_^$va|z$&VN%b3*EO%3Hzm9j!9*&++-%ho3OdPw;yC%N68={hqj zEqE604}KEom73hx6I~NdLphP%nuacv)>ART+#w|E7@_5L(Uae^%S54PBa7@JItG(**7n(@^JA~$@roXNW<2(S!#GV@R&`qZby@=!nh$j}lS<`Q=r@(2G%)5# z?fhVo@-icKen@dyc$mR)AMSj0pUB^Ff1Z`ZwEep0;K$Nxg-3~e!#^>>N3>Rs`-OuB z{prdi`o~+!!v9ixV3Wa>A%AK-*(t!6<#ECEY9UKsYB8E-EVL4zc+AnJL6tk$+xmSw zrtUz?3^U@&*XsF^<_x+(j+K z9&`*jd~Ku`^vYi4fsv2=}78RP>`+nf2b{V&|Vb(Gy$Ac=>(d1 zX5~acDak@R2DhH@bNldu8 zsH^&{-eSQnVx{>bX} zsBQ&72Y%oC8uI2z%(J!=NNoX3<;&BH>b{%0!<*cqTYb1-B!Stj<pU%)-F^Ke~_k@jpIH9_utGCB6~XG5XQD8-}RYYh9K?RdDZ|{rJ=1NMn8xt z0dB~bM%5Q?FL1Tb8e`9MLl#<_s3wpS9Y4|S_0k0N41Z?V|D(97lP+>+PjTTeVScS5 zM9ul4&t||L)}Z=fF}fD1!dPIUe#Aq{Aqr}~Uq@`AM#?ZFoVgyo|ScQ;@}Jj6OI#>Om3L40N|Q5hdYz?ri!OHi5k zXG-$!&|}v?2yB|IEkBJLw+=D^%xn^pV{i9Hc+(;Sy&0Z~_PQY?bEvY{HM0d6@LlEok>ZXcKNG6hjZpBGyc0 z?iofQ-uk|b#qqU+zTsxunO{9`PwWfqHs|3EJ!X3}YLKqPyxbeJW0X+{RUVue3pvmu zF>kfg*);#379ghsA-g%VEWE`er`<$}kF6nLs-(|^(cCGGG2~FDr zY9mHXCZee{H5nUbV~sIZ#l&tl!%AGTOz^MfU7bglv*^Y#Jg>?_R{qeh#zxXqTz6#A z$v;xA@vOrT6C6BvT!#oCy5e6#O&S=@-_{=p;3irVy13~4dx@rO2QV{VY;}UZs?shb z4yFdYM?s|K{2@>)fNw{e@Iub;Pv!2S3>Dp=>;Zc|n^~etZ8oj9QUzwnrCU?K{X@y* z)vIh8A~N}gG^r*Z-?;=3oEHLXr+rWwBwEh$&MAL*GtnnPi;pFeeQndE4T8Kbb!|-K zoBFwe{MQT{piD-nIZQA$7;&!Q#V0mZ;6{BG4O-ui-YU*XVjIXp{j+3N_HIggY}|-* zG4X83TiSSRQ~KWIo^@|e5jCjH_|$Ka*HB!0DI%OSJZG;bvX&WD_Z@|in}D{VmLByMU8dkr)Wav_D=n$s{jH!8Z7Zr>ij*M+y0*J1-VSe6bAB zhvWpyW5+60Sa zAkb)f7|z4y{eY~iz?s`)`8u7_9LeLrgG07uBWSM@AWFo9W;pUZRRaCQ3WLtdk^O|kBu_EtPiN8o8SsUpomsCX?< zbgS}1AWK(%onnJu2JI?G17n76T7`jHaaMNURWv=vC;YPVi+y=;`;LS##*Vd%J(ZB7 z65gJpA|uUV#6Cz3;^X{!zGV<6w`;?>Q9;A(#v3UZcf`)>5T3GuIQf+=-`zK(e}JiU z&S-gH^Z6}9CGDXhOP}j05+2D`eWuY>yVL9cmAQB9!O`!6pf=o0kiI@t%qS$(S26AJ zh2NStn3^&cCtyA(jN^_ztC){<2+4D(M`s4YM-@%xq0HDGx#c)JA9~L2bXQ~M{XFDV z!kWJQbWJ{5#xNN2g=0gvHY@GD)-bkGfuL;C>vpV>f`!NaMl3$^w_+u#fQY?H!yMH8 z6+0FqSa#7p+2l#7Q%cHRId~kT{nN9w4h!$YfGb-iLEC!VbeiAA0+8q~?$@RW7 zKN|CB8J#xYRk|C7?5V2VoOlhsld&BOlgm3lz73p49YI=aSlKK`$3m-y!^A+X-nC0p zrOXAQst%^fc_Js{i=uUrL=&5M$2muV3vOy9zJS6R1o!zBT+#F&%aqK;@4hh*Zp1o^ zLKMP3_M&Vr4(5Yf)2H5(_i!O5L(r^J<3seeQcCegB$#vgp`wAqlde{%bCu+`+E{|EO zIW7MQwEMdDM%GS!ANQjS{QH4)YHu2$t$I^qH7Ghq`L_#7XX!C2u1s&3q527EsLc?b zk>0&d;As^W0w>B|eJEXVI{&;`cce7V&o)o&?Ao~Dov%HSkKfwA~%@Tpr)HF5%1uDvE%Lv{IGowow7%PZN{r7JxaoNgIS|LuC0k34lM9>f&&c?dzU-;nt&-b9hJrv#YW;28B*h}Xn-`g=w)>|Y^HCz zt}gcd;dTAf0J1D-RO&0ePzj43K$0!{00AZ5ibwAyLI!`=tEU()Leu!+(Hv{RN51E? z=AQ3|P^ZDipAPBNUGC9L9`xpFyk*Z7lMoc@ce3N)o!3*J!8W1BE`L`5Pat|WkQ;E(akighXAR*se}vvfwsHD7hem$1A7}@kU#KERHJv)YU00Z z;--YC`q8c3&W$EcX2;>H8vdxZ9baSuF!R6e)^+!>dWqsw=kBK8O z{>urr5ihoVC}sTSs$2kI;4)t42J z5(caOP6<>scNw&=ZodoL4)5t`Kp)g&D#$eUH3UV&5BpEeVr$E>0YrDYjeCoMqGY z;l*c9m)*FHHitcQJ+q%){7A2|v?z>vx`4WWe__5vJnP?D_FXf7fzO(}C0&1DPyJ)g z;E!ud9WH~H|E)xnDref&(q^_EGFR*TjrckW?bLu;`4+z{UwU)pG9emW($({XHL(_1p3w+_O-3-4OXUkMgcT3sSCHcoaK}T3ADM<|mp# z(;h;lBTav^4dwO06sCN9X0bE<1wV)SR1V}xVf-sC1~Y%E1&i0BCFg0vC$12$!LaKt z7k;})>1?A(Z&wOpJ>6&3Da^&tL<9B{#pQJZDW+E>_$z;j{2G+_A^O}UZ$xJQB&sWmkQzW=4)!E=fsg=;=Okk!Ma{D$!9_N~o>k4l#jLE9s zMO&$;HL28}yw6gVP@GVQYl%88-D5`^Qe>8ibLU^okZYXlp8AEkDl)e@B4w~CTAGc|D)$oHW9iP+HGo){tgur9*k zAblS-%0(G|@DDWAa^<1kYMfjXIC*dd6J|H8R};PSzIUsQ^4u7CptdF7bLMg5+#epG zJH~~KhOyt?e-4MMY-r+^iP|sY_(n;S^cGsQp`)@;zswV4S)TSxo-?Fb8YUcSCp-eE!i~=DmWYH~Ry3smSHXpaA(jOyaW_~y4_)C^_8O!}_$y3N z0hT)kVQaljmgq+htITpxwp+V2>drff*D|VMD(9B+`4dbWAM(4Rccxr!sS6uEnJh@` zO@yA)WllvS@80W;0}sE`i4~M09nV%Um;(hNRec_RGLVevHB3GcMprTSiK3yQb!*r8 zpfQJa#wykEZO7qs2klHQ^Q)#(vL6LVeIG^Yh!PCOzO+YU-1^6w#z^-# zmG+C~{CAC5u%KS(afgSEo>a2`mIDGkD;t1ZpC9fgj5kQeQ#f*vY#yLaF&l(1E%o22 zo3v?DKg-IWW$*@i^$*s5K7u{nkTV$vS)IpH=}?+ct-0dTIulWtT`Fuitc)&Q5eyO1 zgo*r78+6mLzjm2~>wX-3cpnSEKTLi&7LMvK!kJgy^;sW5uboXgyR5*RQ=D=(>~ro+ zz7WqLJ>|m3@A2K&4t>31#U_&dWi<7zeVj_=4EE#RkzD6_h4E?twN<+@=7M6fsbA}l z#2wp;oxb7Sa`#{#R{imz!Su96>q4jDdR3OSPyNslY8n5(;OpL!T56yIYcuk((R})OO1d z_DkNUslo~!2{oWU`rO@&)vw4l38GzZM5{p+;0t$^s2$pVidjl=re8YhVRj^t2K?$? z`$6!tX0ruXC-l6};H!u-wzQPvMF? ziSEdbY#LozUyEWmL7wum+g#C!5Zv)*g*FjVml2Y+`yUjr&W|2RlZHf?Zbat0YR8gcZFq zQ|33FL?@|OGD!uUXP3(|oiztt4-XHGCY#9MU>F7l2Bj($*^N2Z%00IzV-^NRbT`Fa z>Z7$Z=Id}MI(xPl*LTFULfQS~M>N}aYj+e18(lG5AO;;lM_^jZBYP?tzo6K~)7U;F z$xWB^WK?3VayW*73!w+YuqHkuMsLGwd5g*0B3rKUJ3Qz<_I%?JVC@j$E}nzdbV-c31)&p6n!8)64%qNDg03AfFS2UOXm2>~>9{DXc73neQ?SAX~j=D{bsH+Nx@QIe>aHZ$r~AM!Nu1vl<2r$qdL z9sweAL3;!jOmB^Q;l0X6wyH_3;D;PNx!_=`mi=sH5!mUwyI+8EP2U|TH1_FpETJg-eCQ=7~H@8q0j&reG3 zN!9itr?fLZ@i3B$6`onXov@;@kdG!JBr8s?!Hm5+`h9+AY~Cs^c=oFT$50RLhoPp` z{IX~~w>Cp9{BI)09bF}ueNx0I>OI zL(87u_)jaOAXV?(Z>k+gQgMc^P5%tZeABVP#iZz9B*Uv%Tl1x6<_=){Fz~W#67-Am zC5^)xj7mONWWfM*JC^yHX#MW7T5tBN^f8i0PV zD9eLkE+E^ya4pqbth_`wG+aXAp|`s+&kj#_0=DKkudISL2yVQy(dR3AY6I)&B_$j? z;4N|7Z*{>~Vt<@Er)ZR56c5&_I0Af;*P=B6?Q?yrrNi+Rp#-~24ipkW-Is^4+&l+& zA#$46i*Gf&y5%?IWVc*{&OVdLiTx}->e+M9MK;o~w;KH;P3<_QPLzl6%6S^{2_F_fd&b5& zT}tOqUC!5u3vGhr)jEhLFt2qxSD;*hq}a#myf;&i-)S?b9-6DBmJB8F7Z_h%;u9OL8{Ea@klQR6QajZ--3FoNsLB2%qZslBVin#cA5d{U7;Svi;Yq_sE6uZl{wos6zCb!veannCY*?m2V zkkRd{FtJ8WHaYQagVC@Lg~C%+8sz>=D{25D@iSURo3ml>KxBS?;WZUUB0wx+3lw&T z(SmP!gHc2x;^GcB2b%|?~LSGH{3 zKqdO19v|&XOU~u&2-;M_VMo=$j+-S~hpwf_XgBY767Fyp+M|!U{6UjMV1jpf=CeAU zcf~w+M1e__v&(8Y`oNi^vQ8lsU<2aGg74xAl99SAABFro+=?kzT|_4lFSFUX?%L`d z9??p}VBM(FeZPr~T#7>1DGl@Y3z5=bZ!zG&_;CxBpPWPCR714}0UMXdGn3mdIzJi? zvg0Ha*Z08>JWW+W8)40A6eH_oFQ$&U1*QZV?#}v4g=K3fE4|wic}ymFbWK8$M3IzM zluS$^zvk(=neE`a#EW%5&SPE-C3EJf-}Rc?v-L_vDO-M{I3YZ|D6vIZr=4@UHtAah zIs3t+QE?eSdyO7T@YmsF1*kZdW_jx`RB{k$_P%u#&2+WcXacP!$ouV2UQJV^GO4Wq z{0!LnZ~Y|*{l)6z%&X%}+Q+F%vM+J0Xky)b`n27+7=1E)09XTxbistt<#v9oR(s`= zpN{^P@`?5e@oi9M>`pMjFCELRj))mL@?HG*0nm#Hb50Vf}1aW4U6!X1# zQ?Xkl9s}dgMk9P2?o3E&l$BcaY5uHr@xfg1m&EC!tfNm^tkoZ7xujwE(Ux~cVvs`o9HcuEW1HNm>K*BYYB?$(N zPQ?FcG;DHD^4s`w1z@Js43QvZp*#X!IQYTpe#hR=H+c$74u9m^gm!SH6#%Jw>$$6QEy;UsI8X z!N@-}6QuO`1DTt#83Gnko0nw#rQ?`iHs9Y&HtIK9Y^qsIuvfDw0x?FRr}F?l0#D4T z&UrA~G3P?h*kyx4UBYZ-aHIVD0HnTR&y`JaZ8K;bmCDg>~6Ubr+Y6XGA)cYInROvU>}#V z+5^oQ()ovDNH+Q&R}DCHrGfZD6pEkh;3x<)h?Jkd{8_(_muD;*0ja$5~h&x;_FE(;Ao|iC^JK> z_BaZ|b20n}@_jeA}Yc){(5f~nU zC_V_2*9zNpT3jv3m3WijkP5`&Xl}qy!7ARp$kr~;d~PN&qE8k+L&+!JbSusXX*T9u zO8XswS&G(|u7w`r`4wL)G7HrVh>aswKNuKBHe)-AhWmyCJwv=JFp!AOTpPS-V_)03 z3hH2&sU%5UYR8lUzN-pb%>;3*>mzmdn~kzqNji4ZM=aoQCEMYc(gG zfKBylZqZ;qE?A>vX{0KUI@&h5-wZR8R?boI{K$&3PSy?jkNuLP%EMGKExA6-*B`|& z9%@s@6yoDy$EAW>IdQy|?!UnBK~bna`O4|GSCrGip%opTk%ksLW-uU!bZ!|@JhlW(8%Jq2b?cOZU z;&bO7n&{kVt|_p~qEdD5BYj)-s0a(7^@}3e8m7 zhgi)82pK43)^K~nOc=e5UsW`0_V%THa=!^nOZ>8JI87HV3#Onb!E7&WsFicIj?5f4%uJ4BdgOxw!=_7F6xbrfW(*$i`h<8 zB7p-$<_coL+t+9iyJ@pUmU!3Z86~eOC?}d%nGTw#pRBS%vfn|q#*mES08I{yM!qMN zfP*HY$se{^CAbNCu3yufjaH6l~L0J%u+UlKSZ)n+@3 zj4c_KS9})sQa%MX8&xlfU-{TSSHgI$iaF5zrqaLfaBJHU?O}xX*@=;izrk*z)KiK~ z*>?lM+S4!8{{<3fmJSYbJGSyg5*WSTg@W4Ez|+}+ui7J6b_2r|pUwqdf2u@Bqkr#C z6=2bqU^j?Z>Me&lG-J0W%nW2{EEmd~&zartEwFOn;iMj0PjjhThn-El{ng7H&}&+; zocI^yVJ5sc^;CXAlE1%pSP=E0%a{<6d*Fic^tEx+_ltzY$JIfs zUXOtX!pUa|*Iw=g#_NJxGF!O-B15;To}R&2y|6yZ39Fuy7ZL&A&T=!KtlcC<<`VCH zwwRy&pHp0>{TZ8}>~}(N5H_fSCq5JoX^-i;Ca7#aqn|a!x)9SFc9O)?p9ZOXlN(&6ytpEg{fC7}P!sPGQ|br%B~(of!_Ivu>@#S; z0+ZqUtvL#<=)(a;Nb&uhuhqyyZbXqqYj1G)rg`d-_9cqM82A|bD4WuMFOe{SpoW2? zxJTTn9rvYcGs=#}6_P}C*dBaU;o?MUy3~t4Yz}WA=*JhoXlQiLBi?7sSq-$hB2yMK zstprNTIUa__KuXB_Y1YwJ(wID?y-Qvxeq%S=pg{M_o%Mq0{azoBHSgA4t+ysq#J{h z>kl`;-gaC?X-|C;uw8n;%6WrM7gX@k)$dN-h#XpzYE3a|0>Ea4QbPGo0WHb*I`(r9 zi^hZ4$X8R@OzJwqB*esL*j`z=EcR{J&&e29F&~1(cO4JeOv^nNQ>hN=Z2%(dCW(h| z`ePq%imKBqR!56V(Ptq&y-^A^OaUw#>?kxXWsGv+AS0W8#-F=D9~0q7hcTcd>0tR; z9-G+3dB$kFU@EJ%a9X|fX(_Y8s^ml_GU?VLoRT1Gw4|WUn7!gx@qUJk?;Ai~@hl6? zzmy`$cRtyE8fE3mtq!t(f-rT=;>eDlX8wX=Qbi~h-P5fB!EvBFd!=s59^U^z>jbpP zgI>5WUdw&y>P{B1-%*PeA9sp4VP9PldCOa482;QZK~a0VGvp5g@#=7`Y~>exMJJ@X z`~Ch%iWbOppcRV))bZ3<dbbalEClbAdc1dqS}Pebs>2PwFg*joG@glP9TgU~(1pVi{IW%%ZD zEGT=~-FH5EWbNZ;oY(YS(c70VG9vsh2^LFc{QSW8FK{2|^?V=pd6z5=+07p{X%E{Z zsAI?4c|-S|degO9b-fLG;Ngr|i-~8Gtv{993+|ye`3&ao&oo)zhb9r}GF)=r0W+#5 zN3BkXWft3mVk-vq8MVGYwmu3+(-j7%Weeszj_gVdl|ZpJ(G|9}jr|X-^IzAM$v>+4 zsUfgfP>-YQf>+Abl`7aL3vdZfmV1FJ8ssUgIiNn z_;bIVwK;SJZ-1cRWZ^r|zuGNxDa~i%6H=vh&~LF@3J#sICl(#;z)VD2j|9B))SYPq zG97tFF`xG4zFmoqXb7 z9pCXecj)Qj>AvBK3qx0)-5qQLyv#apG2gBZMnTZTUqj$pZbH{$X})0d2h9f`&fto} zT#1mbN!?(Mx=Th#Fl5jXdHp=P!otxGRu2ym=IV5dIO9$rgxn$p$G4j_;7oUNY;iP> z(J<$$TdS_aY~Uk~i*l%Q_~ncSf$@@^si_zO~XP{hnL@{l%pO%3_G z{OH>8H3hXV^{LDL_nGX4`1;4+iy7&(N|6?#4uy&219L{Pv9S_TQWV_tsjU!lNapIN z@PmN9nDfTKua+hkSN(@&Hkf5BAq_y!t4-ddN~qcAub0elS$Ch0nO&JRA0EFyR&(C) zwB!hJR}r<*lTKM;(Q*QJ-e(C-yxNFuH<2QW4}Ut1Vuv`PuH=>#gMPsf$KI5O(n@rM;axlTv`buMt!80(f$gobA33^J|U~4T@3FS57J~D0A zLHQh_&zrJl)Y4ZfhRT*uJ zpwA?fNd@MEOmtXQ#dd@QE@v{4v(8DccQiImmxw1P;+BYR$l~slH?xCZHK3hNe_5VG z*V6G3$1zp0|1IWaas?g7J-Ujq*Io$$*-7}d1u|=A`OK+M*9U7-wY+(pOoQ_8@WX75 zsQ6K1!#@X$>yuTJu3C^vIfk_r}OLYIT8ZB^*RD9{1nFvEyfg zTcaBdSyRQ|p=c83 zdA^X=!Sx|b;ld8DqrsblBugv$nM&JETJruuDM*UlLd2( z1=F@#Eqp>4)-Oz#xG6=>a@V<}gngONKJw)6j?VQA6#tTw93xl84vK4^iFZTl@}O^U zu+6j(wqsv@z~C|Va0qO9$43Q0Wla72d6Pt>GKEPmH~k`;+&ms!bL=zAbJXlG4i~A7 zwwCc3t|jiqc&f!f>LV#>USml0?ev8D_o^W_iB4t=ZXD%sy_8 z)Z|-=WMVP2ga&SSr|D*Az2_Z)zKO@=$~R8QsRjL>d+ww2`lYsn0)rT%xBISNPY6jZ zz{lb7aL)!oBN->b!imnn7>E>~CXJJ?Hg8V8H#iImO&XtR5*&B#OYLs28%M9`Jr!rZ z?y$TK=FnWyzoc7u46-iqLd>sH{{yuEyk`-tC3i#=dS}fPo_y-*>3_A3@Q_LOr-d4$ zHG(p{)xJnw|BiOx#FrdF@hfB+gzA9B4F{;0_E%AUTgv=+*Z{RomE6D}30frO$inX# z_%;sTw?B+TduB2Eqzkm@#APYKEZLH~yqgk~S6Lcdp>o1`h;a}R+hYW-_@CnEo$w`kH$ z7OPSJF(oHY?bPzBzLcDN=TSzgaF~4fL|D}`L8b1NROd$fP9Zsyuw7&#UL-e*Q1T)? z$bX23md+aR^JZm6*40dxs41d#&mph6E>Ro|mkIZ*da^if0`Kqz|AJJ966_(W#(jiY z#gdR}-40(+hCl}4Qj&1UHKnbGi={XLaw;*$^Vp0*J8EQFiwzuz2bPX+?EGznw_rR|8Kwdp1KQ4{ul#@t0_HN?5L^J@}&Sdn6m2N`LW| zbX9+PdRDC~{mG0(M6XT%+oz0)}x*uDp4if~P5Owkhs!AAME=O?P)s37^hsgC5Q#E>nQ6O1oa2 zX&a$?{|OC1(oVS;do@PNY8Z2c@rw$(d?Tszz&soYl6O4+jl7$5v1KHJuD1mOeH`C) zU0PFKPoMU|i7msY^$*ZDBHvQcHZ#dK1W2CF&Zmr91S+doQ!~1Q)fUQJO?u1`7K@~V zTjObWBH}bbb_CC)6~rXuTYitK_+Wej6QJhZeC^lpa~cA~!k&{3`hNS>1ap*D)z_>h z%bjxiFY^LkW~o;uHoMxD>&`jyY0#K6yb1*m1Z++c;XlkW%m_=STann;iKbE&B&B4! zlW_r_2cyiG12GmYY%8(Eu3SOiAIq`4DF1ok;}Nhcmk1tD2V)|Z3J)_1HUd7J?+#AO zQkj7v;yl@1^D(f!!FTP7FAH>%c`KUK@Lvx<)XBzpJUYulyn6Evlx!h+YV8l7e+VB% zR8`}3hSq1Nth@VdC;Zw}ZS?(Xm>C#4oH}2u8xH@Yz2-;CDA$^;Nc$rePSbxCw{ede z+x#oOuoJ#jDA9f}Mo~WTzKwA-8g~D{?ahr9*PtudRNt|uNSDk@_zRum@E{ zt=H|Zt)5K&^8$x;g2V_+{|5I|A>K9L8h^tWb%AnKmS%afRt1E=P$G5DMZ@Yvy z0@_10kCY_xM(#f*FT0ga&m?U&Y)Iqi4Hzb&9Y)d^k5y2^@__9-`fi^N-AnJ;=`kaBFm~3B;*EAY zD`P~`HSn%g3h~K~;#nP1-DJFqS4ZVJNM@ZiuzA|H`sfTH*nd8`v`}C7JanqeyM>^Ss z4(g$9Wrou5O&l-Aai97ju(?wu+I@m#XAAAmmfJP9NpcI!=63=ni3T&J8PDmF{^d&_ z3rhT}&gPHCJIOB)Cr}XbnI~eiA?~UntDTRBl2;1>8?|d_6~cP>tsFtUU(?)Hq%pN( z-+sK4{U-Wl?AOdB<*hKIf;L@sOLTp|8Lu%Uc(+ghvAPUOQxRQOQT)xy!Ts_H_h5hN zea9B}#HIgKxAojU1EZJVl3QF!0C;FRYo^MJb+g|I>RwL@AR(BsX@SlKZfS0WY9S|7A1Z<$Z}=F@G%4_O=y~MvSTRi=k@h zg`({CoLD;mz(2l1=Ouoy`hDbBMkVJk> z{3ZrE?nl}%WlLl6Qg?i)Mhw+RGx)N6dYcp}lNe=wUugrJjnSq~f(b4NC3j@oKCj7gT zDEoBUM8dR_Fc{XWBTVTPICTFDwnEO%bXgSFb$aI_i&q+d}AdTgWR=uv>O%s z`JL~hJ%z1m7HuIFKy%c?05f$4wJ3J8a1PVk(vE<1Sn}_y!q5xO6ITARqvc~s=^`z( z8ijHt=V5ctDkafME0wscw0ut9g%}Om^)fLEtF!7_MN(Q;6vg2N)f?Z(q}$^R(n4YCV2JOasNorlqZs5;^5At;;4-xM(2iNrsgMm8w%2WR8%7o zS-)A{i=gWd=;DKh$n&~+hv-oUo2;LmpI*h? zemcJ5b%~4V27DR@_hijQIp=BbP13JoGU$fI*K|@M7>z=UbZgM@(y36*DpW*{v3f&; zn(VN({)CT`YdjenWxo!Tf9R`nU1t+yX>6ClJ;k9uw7v%1ebss9tS9x~Cw#FT+Hmg8 z+MLc4T3LIv=y;wxZAZ} z;v+tFp~VZZ#d3ho3onZ4 z-jZDfgR@yKrTP+_J?XuD$KUg~Mk6IS`DD`uk@hf~n~q99N)%qRfSJ3S-{Khh5_B=H zakX&?h0Ef@MU32{2D(S#~}pm!sUUUrm|R)sd?goAg_&bA|<>Bo15QPH~l`7bUZweT;FV`IIXUc zKaw3Wz3FVS)_gs_le z&rk&s>W&3GOkS_v!qG6*hTTksRjZRY<8z%ZdH)I>m2XB+Plw5mw!%g2{-Kz<}Sbx-;hFzMh^3Z;u`D;e4o1E(}N8DLZL zotvJC0K6ZjqBvz;^zdJVQ7sSNN4o1cTS%Pzf9bl|SAJtJ#cHrA{i}3JWlp)kR`j)K z?lP(;T{W-ZdmUQ&I*y3zkbp|NCJ{{Eu28*TINMcpE= z?2)01@XFMD5vooU%AgKH^25l%hPR@^lCNoY*O!QNY55KPJo zVWfqOc$T9QW4{^J0ZzUg>LwOm9^_ayS-J~%Lx_1>aY9&9oi*_nIak<&-A5aL`|<>k z#o0|`8e%>fWx-@LMX8Gg0Q^0JFcOjwf40nl@3iwV3Nq>9hUtXDR8Hq0W+fSVznL%G zX(eGh!Jvt|@f|>nhsX!Z-8bA98&8{q#rPEyK;OTD@@scb#^gz$-gR5att+?Q7Bd2- zo3FTPPsnRszVWP6terG-bd}R?sfPXBBHuJZK?`iZb!o*}=mP#>7UZe}N?1s{)r3Si zgGfaT9?p)*DBX!E$Lqo7%jX1tsFj(T#*KU9W4goej|~4vTjt3bHGv|``w9(`oGIsq zWa_&tCP8bfHZ#0zTpamT<;4DVt ztfEXcWa$TG>gB$$nfeNki9EqI_ABBh(b=Dsi40cwH6lcxg7hdM4c0?KOame!&hERA+vU~o;RH>0@ooho&wH9- zV#X6poeqi`-u2PwpG}yu{g8W8jBn4ELWL~fcQz^~kESa5GqnqA8L|I^#_g9#{vz&* zbNX<1{+I<{4kKXKKs<$Q3#rw!J{Y|hdUgfQilK;F>S1`c*vA5$D7A5S*MHyqrW8w2 z;@?rlLK3c{k(&)whpYC6kc}$#-2E-0=IHePHmn&+*T0jJ&5cqwka9Z7YfvJy;a<@z zmS!24RAJ9qu0&2VCz>?DyIsdGqN6qHLA1KN?1tWED3e{*_p1e?g!mcnoPe|FFc+3*JVki12Y|eD`)>#% z20q~@uVg+wY#}Uy*xON<_IE>wj8)aIj6(oB9fXx46+l5_IA2_I2=*s}_~YQB{?ZBmnI>-> zDN(87QrNc5M2!W~h)Bln8h=Bc#*cpnN{dOn;ei|({cjleZB&QKX5rKIEA%FJW^!d{ z;PC{{0u_X4Q83diU)+fE!7_UX6lsm~D#K%I~HRi@vrTJ8x_JV?>kPhnc{OUFT*Xj7>Ngn~lZ!QM|pkm`>rkjqtQtzBfV70^N!*09o^ zFQPWdhCP_2Jcxm9kBSLY;S;C1EXtbNTKP^!Yoen6a5Vj5Pb%LoCr=%4}QMawNL+sZ!Kvof_rvHX*!Sj(IRo z^YZfUMmdrbh9B2;k`U;L0r1(SDXQ>t?X!sb+BnsvD&|9E?$yV182YIe#YUwSB$oc> zkHz8R);N2WDQ7_Q{eP4Mj3(`B8B|N{P*tj;_cYoj-R*g7q!R5jY}HH5{1;k=BWtZh zY`g+b`KWLv7tvAsI8*q;_=DQ}istAqCFi+nmLSpG2tad{K?6F>4y{q!8nmOM9aQSA zg`IqgV*l}PqDfrqXiBO9nP#~U4%pd*b!WAc{Ehvrk-}Om>MN>nQJTstm7ZFZ$&^YZ z4c+Mb%!QfK5b%TQxrRser}&Na;QOwnM20kpilaCnnQ>7y|6Q}%&u5$>2FyGY_Cc%H z99r$T(oi3Jik@Q6C_UEhr;3jzJq`%+V*$GoE$QQ{ary7nd~GE;c0ywJztBY&2TFQsn&w zU`(P8eL$*d3W-kii7e^@>cdKolsv7LKC?ly0 zI@R^>kZ(GAhCBr^D$5pNCeEIO?W+cD!-++u>&oAviqjxVyi|n1N9u8QUjh{n+6v z?iMNS4lo?1QKC@+Q(Ti32CNS`gIPEK=J KlDf99G(WQ%-p&bfo~JEH=B4DeW|BI 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

    $x`~4I}(Vwast`)@8uU#T9hnmJ?z=y#q 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 XuCX^N6Ejc&0S+-CX~7Bs9pC>06!Smx literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_update.png b/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_update.png new file mode 100644 index 0000000000000000000000000000000000000000..eb09fa6a597c9d6db6592020d1e753063109edd0 GIT binary patch literal 19683 zcmbTe1C%7+pY2<=ZQHhO+vu`wblK>tF59-*W!vtunPtBE&Hv82Z)WbjbKi@#B6F>i zx$;EB$vEempS^cRDk(_9!{ERG0Rh2FONprf0ReySKtG`%z8`-O& z>f&Z1Y35*O=IZPvXXWDh-K?%ALC*#BpW8QwPrna>2uNB?Sk2SmBHP0i{cydtmb$Y@ zR0KujT8gzvNQfwq4H%vO)r5PQ)C3$Emj*^Mp6YQ}8Tp|s;;>K(K0jOtB)=633JeSc zIwU0If`@g7(B~TI*A|M9_^}SHP2Z&dI{%Z4pqaTpDVxKR4yjhrD;EVqSZz;#LZya4 zWnp0T{}Um%SyCKh9A+bK_M%!w*As6-A2 z*oCk9pL0_hX#7BVF$9Et%I^?`s-6^krgEl7d6wvJQI=JYL4qF8vIC*Yq(P}bPrKKp=KX(4!w$r=1+2SZx>d@eBnr!2HMkG9q=dr)HjX+oNz_x*GDx~ zEgH(3c%sK-^%S#VXYIVHnQ_YEY`&=LbA`9vOYY|WJlpul1G-3%n8HGht9+lGRa)W? z1urXo*?_4AoUG`mOjQtuvO+;jBooQb$ar7)|nB z%3yBcjf@IV(UbJ41hNUD4-AW}+Qjeap%&9*$vk`y(v)n>wFgL8 zzLFSkOi4vXVn)~q9xH1Xw}ei#lt8C;!9T(uQtE|0mKaSF+zLDZLsEv=3{;;av(?le zmuM1V&zu|F&a$Zq{1tv$`7r7Z1YB)JIc{$miDE6OU?@L2ETWn2mSKv&j%<;IEOW<9 zH#6v(H`z??7@*kHO*xw}TqrRXk!}OEc7PzoJXMb%JE%PZ6@~8PLP3m8sXxKN4I{Zj zc5!Jk_k&X8ieVDqoPd_6jB@6yQIG}V! zGhVBIM*eEwi7w~`VQHvlTE*!;giT9~w;GK$2f}h>B5+`u0YTKfKi00w+~Z4H>);lY z&zqz&lJqruDaY%|j*1~iLJZJ6YjTiND+|VFH87gr3|>WwxbP%YHTb~fH=S5z4WMti zYtBelcZiTml68=4lSteGo=uqWyZmF|&0iMK$zF z{z*@gcu_i<&K^0pz+sH2q?jFDYE6WG{23ABETALw?;OX?Vi8fU2s zVPVk^N*TXSkQM6q=XIju(y-T#(&7$=afUxqzJlaMynZ-f)MNA|5Gz>6hQ7o@gJ|(O z(oW7Jxe8p$T_{4xPATSeDLzkI(DungRJ#{xtb*j=hq0aqOkaV}#nS4?z4)3S;uuJT za#?*Qv%HMBl+^I!DpA&(Imz{AoK_|2^oY;j(Vh4%bK3bhU$Dde5^wPsF=l(pi^>70 zUHZDs4bZo_Vl04j;-#Mx+h&NX6mU7hGzJkPUEn??bao5qLq>kGxGgaqd##9nAW{@- zPsr@4AQ78X!NssUS8KJn`(nSpAIe$&?+`y17#(s|cR!E8(@G|-O}EHZnUj?@D5uEe ztvTT1Y1bc_F^wLY$)vPUZ?9-U%pl|#Pur;>zveM@xAa8JtHgLH^IKw`vRsi@P)73A zLwt1ti9!p)cz}`IYlv+XP3aVyDsD_UdoG-PJFi<%#c~WbFoR5$Jd#aML;Q3DmrE$k zR-z5Enlq&2Pq03bId@uOSnD}&=bn<<{3iT--AEE8OE2!eV|48;NT+LX9+${rMxx zmPMjbfY2x59bVlRqb$1h8e&*AtYOf3FCyV@DW0LiNCsl76!4g zG;<_m3Bv5|vR8eE+817g8;P$4&MGX%97bQ7oj90-bs~&w@r&iVY@l^(krggE5BB}d zr4G3gS_y<)Eukdih^>&zkU_+j2C!8FiFpZyRgoVr`;<`P8}liDtR^_eb(;J=1rcM% zW8bu6RSzE3DNAHol}(6iFU3%yi{n5EyVsX0rm;jA^pix^ub&TPMcfYq(ZtO*i?E>0 zx&O)7sfQ-8ZV@xGc0(67MTx8i&TK&#hLVd5*;k03SZ@Shs-|?O*80CINmDz&dXYgXdlNwqP?5hQp(FjL( z^<`tGL{kvzUB$UZs zk_rGu2Hr;<1QycV&rE}CyllI|qEZ#UKa^kN0#t#XzsTQV<4&bc%m?NOi9QsSmKyI~ z1=MUz+GMGy|Gq0!=Y4kS`oTL0riJ8!KpJBkWWx1xwgdP=KN?LAZ|MRGvq|5vdCN$| zMF*L$6EOolUrq?t2~j5lHGeaWrtHdil{n`? zwZ6fnrmsflxkWbic1fTSTfXYVf&&b;=gBBooHl>d6mv>MI#Nchn(AOwM=Uujf7A}O zx-CKEsW-Gtxa2&r`y<}o>m^o635mCNlpxr`3mw`l$K$K94gJRKWnCSa_E*X0_Tm?UbfQeZ$)~|AimmS2T8{Fg! zT+pInM5;^J;*-XzS2g5aTC4l>Sxc$;y3<<26wLkPNzyCwqEue8c176K#0F&^)$Ukd z-b3XCFellt_!1c@;tDj+z%)`27uC*CcUZi{`{tgNhu}(R{*#=U8h9NaAS1VV3ROy0GV~~a{i&|NNP{SQ| zD3tvIj>+MZFI#DnWQCd~LbljfmGYU%f4~jn=LT__nn^QwMc6Oc>H}8>is9mI6=8?5 zbkp675Dd;be-x_*<1R(B*s0;V3};qbJ%NPpGYL;yFH^5R%iiNV=-0xNcCrkLSZ<(? z8}&UX{CQ?AWH*OIt_Q&e77n5iZnIXM)qfKmRjBBb?1(HzYCQo_rXDVLZCM;ap2&r( zVbJncFPqo$Hn{-#m^3O$>gXEju~zIRo0UTkA5ca)%1ZUN1Tl$ zJZ{%IPoqZGbxFVJxx`pCMl6Pq@Jr5vGDp@rb=0eZKXu}sgI2Fo&blo5KplG zHchO9&DG*TFyQV&HqSYc7{z}ajSM*7OXGu>Af-n>Dk46%$;*+*sYk1yYhK;Piau=i zsYA4mzzF$zE8>FmG9W%XnbR`tMlZJIztd1M-C96>K-;SayZ9mqKD_0Cf?Y^ZEQ6W| z73GdbP9Gr_ zN4%3ae)#mzkVW>5Qm~}fY%7Wr3x_z+Ie~FR(Zr?mIK9!GG*e^hC|FqG`ID_GwdPQKRsmE9een;S*xHeYH> zXSn%XRys|d?_C@5xg;(-$YqQ882AEU#(y%#P&KVWY!-cYhaO%K@CRs;Vs+{%4DzfJ zoIt~37>!pNzc^D;&^>cbTS(j-O`pZp@bG+=^N=px21l&tqfe_sCelt0yE1^fp*Rj> z0RvYnt7bV1+)-~G@dPN`Z~Zbt-mi~6ix-_9;W}QSnefh*jmAg}^s^+al7N>{G}h}P zppNiyr(DDRRZc6DE7& zOaVNFA71)mI6It4^oH9K?`HRv8Pw}1?{iZ0geF&UTNhi6(OLLwKPEGWRX@%lw^?CC z4yBH3qnW)(Y~1ZE9)qWR`DoAKzhE>1e!!KZ;h_6#r%I14ZAsnp^-wGp*gPG*XC#U< zDdsJvHTcneS+PS_qwMSh0?iTvP{vkE{v`xh(E4}`hG}h>L~`p490ne zqgO81`)$D4$9FpF*xUP)eto)QuVr%lYCloUxj?&dS*poeVrw;q_ zJiUDAHuu6mr=$j6dWgn*L}!wjk4?WdVG{7Uhq!Y(>DqD4?=L4$$!kMjdE__l5{#2P zqvZRR-pdD0!n-{)0=rW0Ho#&ouocdu?j1HwE@~}4&Q8H1m^<`{(S54!L~U?liDNWcR|NLGS;&5BV=+7*1e z7_;LUjz7*48gzhwGJi!!v>Pn8uJr!n2LJROU_I+bP<_aj5={gp(nG9VK7 zjmCqMSCBhZ_bV8An6cgAnaCTlE!=8jVs`wu)v$}5Gs~DL!CvsgOIyy73+*~w&g9wn ztBDHiRr(#C9S8r!pQ{zeg-%NByLDK&XeV45dzq)_2f4O$LO4H5X6X2s0*B{N?UVPo z(ZnV^oBx-cY^o$cHQ`)pOA51;BkS_z|yelS;tS!Z`1k2H|2^AAZBb@8$QVNnJXW0 z9G-fEm;Y03#2)h2v#I#mZ-LEbMD!8n{R7Bv1nKS3tctmW=`T&|OsKo5(Gy=vEmzRq z3}uD%l8_8FE{pqIlP;z;G>UwuTVEY>@RmZ5YE!)#Gho6FtupYEEF4fJG?i>M7?N{u z*AYzEvn`Xj_jj8GBVIzx})Q#VQt&VVWnm`g1XGDDmiU%{Yp3uR5b!r>` zJpHY1@*dKV;xYy!tJkwHfG5COuIFRYFbAUdOpzxQBhkD2b@o0r)|Q%I;;}^4RpC?u zERZ;HR}_x!{ltX>gG-41@Xz?tMLAzz1;XQHQE}#}haD{$QPBp_FU2aO7vrH?#bRsVykxL}9>FH7_dw3(Ii;Oze_;%1fq2CEk#<AaAG1ltN&(W4SAd+8dQaf=J z8s@nLd1NWC&@6ZlyG;J*RTaZXj*Qm>IlJrbol+<1Gk1&#omWrKw~=Rieh`&-B%~7x z@o!)8gNCf5H16sZ!%-Z-zpZX6EDH%{NccGu6FuC>WLT71uk~Z3Rz+Ty1^>2WDJW6B zSpY6u9yk4TaR-Ushcd?#1qA_>!v`ZX?}z2j$^rB3O(7oVqNxSf?TqE9_&n|fqNP1@ zTB!Z()R)X$Esd7tNxSjy>F;OedDrlz?&0qP&Gbhz^`a+DGz^l zC@Z3$grfQx&l@67R&(ATwA(@*%i0U%iOg{RImnCs%Htg)hbK<$9w&Z5LH+nc#;)-h z@a>~6o&cC8kd#R|(u*UX6GDHgyk1Xr?z?@9&!x2Y=k#2@k8;6NJsA-x8R`Cp?^~LW zRj4{523_o5Jzaw;i=oZGRrn_Pjm12z<`$!#SX1aAi+l$1VPa5YTGRj!E@#{Ooihaq|`!E`?ogu$z!z zIqDkQx(t3>tj6+z-!EY#_L-nqp7P7|;SnPOQt7OxTW`a^b0 z*u%={VlWUWHlU?D`l;%eScc(@a$I1&fR+nXkN&RX-Dcx z=?JV1)U%nP;6G=WN~*{((2Oph78__p(xgE}ED~y}$)pZao`3lv=X0%~lN^x97II}; z3K*7uKt_&GAdt!I&SfU8Y%*c_3USRlUb4_?JkjKNKgY1Hl{ZV`j?6iRy^XV@6#QcR zJq4+#qUIZ9SAL2YV=I!hE*$T}lZv1C{L^F3?fi#NwX8 zAifIzd?K&~c$s;3OmAf$4bZzL9e+$nVZZB9h0vYShyP<14bL5yBNIMTzHlnxXGo3C zpI4XPtmPr((b%fJrVm$zSu}k89oHBMs&6zkQRpA3$BfyyOI98$BXL{UgDa9BzcIz$ zijF)0^20O&J=D9tkUe-_24Oa|%cn!nispAi$>Gvg^I^!S+xwXg+q*R_holSW(!Yhy zR&$3i+F7@7JA<>@@y9L|>zzyqXmCn3dj?<)ZTD?w7nG6C7fFSA#_EH>bjVwZ#a#tP z6vdTl4cJpagrxS(7x^b6 z4vgWY8CsHuK2P7uPMkAbZOpdPu-MLa_GEpnZ)xa37{go~uk?nu)a2eo*tL6o~ zUP?0#4t(u=aGHu^p!=;NcwkDW*WTSWcy-+wQ()3&kIXH?RZAo-qE;y&fPK%YQ{kQwYm{{G;JS%;kulyV-HqL^F zv1@PjY67(YN{Pe8*LW=cF3jv-uTFrwh_d15aryBx10Z6QY zQGi5H7pqXY2?e7={JI3R*qM847h!gCEtllaZj z*ePOdOA5BV=O@+^6o3^#>Vgdqao9n4j`{Oide_SUqt*{lh+tn~FP;DpGVH>!5M>M` zG3=zV2s)66!PZN;i8d*c{dK1Wz`hjsJ8LvTPVbfT9v6nK)<9F{d5*{MJY9W{`ce6VqX3&`GT<S0#PJIGDHBm80Cw%;s;&`EQb zouA`?B!!sM$ys51D?Q4fo0B6r&v#%InU$m-P9d!uO#-AcKZ7S$M#&sU<&|a1jPaK( zVe}zcw;DFz$uj(lt-9X{#Gu@O4@&fu2N339gM(hgCJ##A90y3Q)!S22IRlLYoR=(( zDh*r>UGQ^D3+<;vwhRGx!Rz;H=44de^tZnFi*hbcFKNm_cMH$!VYc77hmCz#!7>Cc zhFITIKRr+8<@Bqmgo1i_|eDB_=MWMu-(|vPZMm)ZdVZp zuPEr?HVaSMbsPcn2fOdC8FF`=Kpn2`^>eg#JUUtd=kqrAs_&g%_#(|HarTP)u_HSa zjgzVshzt#WH6N2R`Fkqw&IewJE05P==*AZRqii|b^|Pw|E`JJ9+5Ww5si3?3r%-aO z7$FoSMgL|_&p>hJOI1;7h$FI3`<5zGuBqtA^hNU@yvz_AWyq^I@9Af!;bk1j{Om}Q zT8F4VZ|2<**{1=B{i~_v*oH2Ovn!KAYSlzyo(ve}_=?kpgD%;=tL+kL?N{CKlU4L58uj?sSxGSksf zo$_V(GHiodiSXii+>2Nlg%y}eHL5aS(14c<#6 zNjwT$Aw#Et6up#VabR?$T+bj%YuzjK^2-8i(m>y_j zA!N!!z=|sL@M~fMj#40@*NHQ>N#yNCsrdWvUVz^bDQs99!PQE|CPm`W%q5t4#c%`2 zx#3OjoGJ$FgGm37Ad12xjC^vj0&Ml7Nw+i)G|>-+EL>vKPgl@is6t}cj-VRMNp<>e z)VOmXOSTfIJ}x!wATk6cwacU%z+g=!*;JkR#U& zb$qA`KUr2%{(SJyJ?046;KbvQlbY8M|48B`8e$vap+mO7C#BLDoJtS*k>yIycu0lk zmsHmpEuNGO)!xZ8Ga;-JC?TD7em>YH2qS62Rv|5_pc}+J617Ym+R)>sEDFmU&;=JP z`FA4szmtLwiKP%#cyqFN(f21f?_M=1u{v0(-S}P*x2Bs!HCc`O$WT}UiWT05#X@;j znfJjdruZY^e~!jIF&{1k%(1q_@B>y%XbmgVPhEG;<*?S$OPaxC6fcZVn>0OXFR66G zC7&OwGcA$S!?8}`=e;-n^!!|r>=~U$NkCEY^xfmKzf>VKJr%&{eIlu)=Mwu9+1^e) zkel{rU;w4uqUmNM3|r3g4A-3&h=iGcH68O?>lgnBHZvAH3EI0i6OTMS=22Pu^~O#MW>%7HGiEXY(i?ZtwUg8 zJ}>FNX~Ngkf%_ZK*&N}s@ZwON%P5bxw*3N5;3z;LN?Et$X{BF6&liPd{2RM$AR_b^ zE0p;J+On$~f=DgvL4en*<0q6MspJU0Nkc}mi*QlPZl1qvz@uC~9^%};6jph6P(OFj z(-3~QKb?>zC-{VlK!xO78!!?YD?id*b4FG3BQR?HQ_t*eiL795394% z9^E#WyfsS&vO`QOU3m=si?xVkC_P)0=+l*PG+k{)FZIJu6%^hLXF& z{$rnL+x5i90i$nlLm6!Z3H#wTXX)(qYUk#BC$68w6s7$|<>nS$0%^u6%aN#o zWn=6Z=Tm`d{BBI<6K+N+j|m@t4bN~TX$`TN98av|j-m_}@HlJ&B@l?RwCT$aXIhL{ z+)~InYn3Hl8&2WK8Bqf_G+}ilcUuvG1*GD3-Eo~}B6C8a*}%OIDam~$op2Fb+2jt% z1WY_JM-WPP;>&0eE7V8Y?bd(0qx@#hDk0v%X-86Y(# z&Ogkr_Elflv2M1Ei=$YJSc=Vd5!jtb7dUupVZK}t#co_^pJDF+5IIx}BRwx1dM~V& zF%Oe#^kao%$f>Zdx3bC{@?PTOmEpBPIBVjtZuex4+ZuA)ZV9gDorGW&7bhYI{=k!2 zq&Pg$c@ia3u!xFq))F95cY&Z1l8cStd@=$H(HW7xuw<7_bRtDeqKe(JUHi;(9I<7Q z*yKKgAlIrvH@&E#If?#+9@ug<@Ts3|*Hk7$LPwJWZTWweBrLG^v>lXdP`(WT%FmX$ z%mfw#jaVGHVoK)v@fu>oLF`#7!efSG4c(fFzwlx=8xXtumv8sq2eg(@ zS^@-9s}J|2V3zA@_#XQdtF+o<$PEP~TGPy%$~2qL)x@k9bBU)K(?5lIyxid@`n=xj z>IM9~hkZ_6(V56td?S8_68cRKgFu!Q<7u^L@aI@nX~?`P0=SHnsn(OHHHwL2_sPBv z!N*a5M#LfB?mR)%0g9b`+a)!d${5sBAB~AEr&-3Agqv8X(C7O3JB2txSXxzW5bCUv zFhG=dElVi446x+e5plpmeB%WQL2YxU^8!gUp!VHESQLd+kg`amgtTb!3Q>^Fr`+jD zhrGEA@XmN3^K_79wyuk;{+BxP$se7>zyF_f)31hY#cQtrbl4kaA@3kV(T zTQ3GWrc=@hbL4;=C~AVW5Ck&Wl7S2&<3X58iSDXgU5XYdm@5bYOsLJpU@+`eL?ic$ zas2=`1+yM`lh6n!e!JD3;d$|NUhQc5`P zc;e=_#QF4*Ca>ZE-yq(7k(s^rv_!m)#hHYg@`-aBuZ2AIPj=`j^C}pES0+EV1UMUq-WU+q`oMf=#Nh_b|C6E`-+UJW4 zUkg{FM^8Xxsm9Lm1U4qk-uZLs8BO60lZroo*2j5aB#KUW4Od}2F}|yZeP75rFY*$Z z&_Ja!&H?EqeK6`^~=C z3nAX}K5W52@F-3k0-;S$csjktt4X9tEAKI<#n(&>>-c&|;C~_-U1-$`12tO7gQ+$CuF8(O}c&rX?z80){UUm)B@PS^1ZXl9bn3egjI3JHun0IVE#!h$)=K!?lLz@S6;X!GLe-nmFMgkk9!Fb?ITgwQLZ3kU zdI&J?Unw6dmZ(O|hpki|O^SkaBXoo$gx?vV`$qaU!bVDr!$YonvOcTDG=fh2FSn9_S3kq zdR}2f?UCaAiiwAfed-`5bK_6j5F68QO#RC6_gZC{KJ~lk{!iMn0--Je4-fm`b(dr* z3yF2O2A3kf*s|as53lm1K-OU>D9hN4y<|Y5;wi_mLC)a^*jEjGD zL)A)qlO;0rYWQQH^zj`>c#Of@|$!A z+}S<4N*GKg!SH-0b~1gI7FWsa{D})yoE7*Ze_~Y=$QWkzrn5&!Z0?U_b4ZI6USQQZKN}~LpxDP8Rd>kbC!nxr!Bd&|JuXAJD^wJ!2N;zZ8 zKA+81)=-}>Ln=fCzvP;q1Ru%gN+UVbKBo3&fAV;}%v?~1yV%37e$JojK?Jl1y^b5k zSVO3=W?%Wl6RIwZP3uflc;()0=0S`GF76_m)5{-Dyy>8DzQfO_Fq$syX<}daFB!;4 z?M7Mwv|5QXFVI=jef?DVWw?_Y?ek~F-x_~)cbgbQCgoi(#N@5I`)e)8}!7kn( zpnp(Hbi~p*4drzoak0b$(Zq^G?pAR4N^0RQ3P)oI_$G2D<>*$-DNykRvx&9-W}ZM_g}&zb)WGoMQhC*!+~6I zWiePw{725VB)Qc+L)>=giAo>U_0V zmcA*CY_YZPs}?c%Bp%$sn&$x;qqRRpR055TMhrooLl_C~cQoIdYmc5=N*yvk)XU8Q z-vg&W^+Dj3@wm3%&cU62K#X|X_v(vwlUqu7v5{IooYo&$xtYk;gbUhvT<<%CjMnSs zMBMrbNg8A5ymKRbPvD5S(2|<}Qch`!HtF-r22#=7%`BF!9Q;YnD~=;G$IR%-rtNeq z3C`;hJZz|qH-0nu>h?U{aYYd8b=Cxh09)KJzC)d8QIyX633l1=hAL$|l6$|+PX;1% zNh?koTHccGYq)P;zO6$O1%EHziK-SuK2uGn1d^!AO&15_C?Ux(-?8@LKHNbN7NT}# z=GyH^HHXlQ>Uf&GNLvMKevSWw!_~;qP^gT>g*M zi&~jx(9>eg{y9e)9ODO_IT8W1%S~ktJ6@DO$e>0$3OXI>{wpmaAR-;`L@$FdDTEpz zi$k&W(dmZvg<9aYl-yYsp*YK`awpO|CA`nO=hbM`2ntoNVP2F;Cp$x1FHNjJifWEy zARdD^*7hxh_S=X&9+p&X<@E>r65|k#R&?`wuWF_Pvcr|Fh(+^AAo64_{w;uX-ku-l;{Yd+W%mLz0QJp@HG>A?6je z`+nhLzGS5+=9Z-+8Z_~D|DDN!2;g{&R;gb5I8^TEo<3{M%|Bgz^E!O9C_8@ty%2wg#=1HS^t>6s;rq-kF zR>PwTaz$2}2ePF!IL-VL|D(Q*2Y|*BSwrO9U5Hc5zV~7$X!%sF| zP-$|o{!+!oMM%Ha+LGtS(gR8P^Y1|eIW<%5ADcMU$hm6sLV3aVih19zt5XqIk{U^xCv}Jf!7Bh~^t0`%Y zz%cAcre&zrN_uKh5=gIQsnBDVLXEuRpgGQbsRQFc8B1@m*os{d)>b3Y(BcP225mDs z-1tDwqV^eg6rurM>5zhJeeF@l)wBf`rNI2)EifXOh@3Lfmc1 zw~KaYzyyJs(z>77~kDt5pbUHrQr|+b8@pfvc@aDFl6Piu^*kAS(?7-(OKe z;B#oI5pL%OW_=#X+*CRK9C2@Z64L84spKDd_B)+eiFKj()u|U6cIy8DXzT6DOhoQ$ z)fvMt*w^@M1IsjOWnfRhdpwbzWrcckZV3yX%cN+e8FuI%c8Vm-@!=-4EZ(9ufgy8;k<3d^o z9u9kyyTyS<|J>(T{Hcw0>mGcV1e9m86-TR24z~?wgVmC)0M_r2bM7CBWsj}Qhi|`s zSk&$xm+nbt-&5mGJgNB}U?cHvq*RkvEi7f})CcLsH@;Ly3xX`6DmkaUT(RKDNtsO? z$$k2`zy&qL*X9HScW>?dco}|pe|P0i>Aj&5#0296Ef*khlT@&nSdN{<(oSvD6*LAc z!^`y+E4(a+9yKYM*DIM<&z?4mq{w;wEOr}V6{HPzaA;)R|K{B_NY~xPsHhN5GdCJd z-It~s4o+_qM_zo|`=zZ;v52V&1mV_e6TMt<%O#vGKB&qA)l#s>#(L?9SW1v^Lvx)y=eWn>l!+Mh zBX!NA*)n3XI5C%f8f7ZX^94g#3$U{)VY?ACqB@>5j>-dHZ`j|Nn-g zT!()%lyEN_M{=EG3D=X@Pm_`D7um4=E_A$?@84#?kas6Jxa#L)9C`RX_unG%$p?1T z8;4Zy$es=RA;lcvb<8EK^H_bSVHqgMM-uU-z?k+l#Fz9>sY_4iE43KLozZjMY@?Iu zqQ%<-L08@d1pTQH@Fc0x_uo91xTxr7Mk6tpX>3nK9AMujz>#FlFY%dGmd8oM=xX06 zcvaklswx&q1nhi=BAxA@z^_=bK)H$l-Msj0KbS^osM<>Pi?0V8LSh9-{Tt)tVA3o!pwfabryJhnVwN83%QG>4*od>oC;bSX7gnBZr5 zJV|c#LM=SUGkxeqIX?jOLtYv|%S1ccXUd_twXqDp z&;Y80-y#g*`jnqC-OTWoU?BDx<5dTE9tpvul@ZQm1D#rM+e>? zMEd=?LY6B*6;K2J6}&nP=?3uce(C=_RZ91fCdn_lAJS+A0>ltP1y~Re^U5;#+A!6S zBY1HV=S~y9?-ygmw`a-!J7o8rN&Plo^Beuo*ws0dj|T_w8>!QB?ODZ=gtf@XjoR?0 zJ1pn>xukV$`ru`3F_5)*&+nvn8ip5D$-4>!{~N^Z(<<`cBkp|+ z#3ec@U4+j0>`_s*f?4bK%zmpJP5NNdr7elL9NRBwb@uG0i9pu@n|G$kujVb?+ z2vi@|*3Yg7paM}*E@wFDXrWjnq6&iPG!VG87pRP=ItRqCU!Ga;{IKA-D$`D>tXT{~ zY6HpxTO6wF5mli$)WO|gr)j#nO8=2?*UmSrr-wU<{;Z6hW*KbUF3=)yBI9t=HYB~FEzRY#HxZApA3EbBs&jH?R1l#M`nH{M+4 zw_)1N2`x`8qF@;BWx*^(Y0|aWj~zB)6-!8&tUk?8H(6a86_{sNCFn~Zx*=B z1k&`8QChObLrIWU>-`rp=+D=+O?^uly7cGbEb5 zBmYz4D1tNP$XG8e92vSQXMm3d0lt|R}1MenNB?LyfT`BW>yN3-9p0Tc0mCA;W(o1&cDg$MS~_v32l32p zL{$wY$ymu~!C>ct-3fYbCW=xcF0zvVSnpr3#YGU~@%egf(AP0!a_DtKMii8$P38of z#WY0nQPgrn65bj^h_*h92ChKHUGQzk@KUGv>y+-iPD2It1b^`Z{5$hay z@U$sm0`cuGkl;E))_j<@2Vu)faaiWMV!Rh)Iqdj!{HQs;dmv+yv}5Q6;DtJLh(xza_St{{TzKY3cgEKqF`j4XoDGo z(irS>3@+|eqGuDlI$+_JIy(Xg2oC3;{{=Aa6xZwbdrTOC6aLU%TyXLnA%ETb#fLTZ zl@x|9!Cl&OCbE9-z%coq=l85>0SB6vceH}?@H&j_ui>f)wu za~d0uLqo=2g+ot4GUo`4vu1#m^V!Ec^U+NVpBw@#&)jaVfSb87$ovlQL2sz!+}0#0 zeXQ@3I&V7Ag1-j9J#SL*Q{_XTdP4POWKC=rQGL-z!hb$sGW@7DoGP^ zA`Xg~#@R#(~6Ma6OdS1~>{3Qq$z z4IS~Mt*f4kHXtQ}=HsR(4S`nEgcn`d#Dnd?z|-HI*7uz`u2v*uh&iw$0QcwnC&tCG zXxDM31eueS;sJptK|4H${h;!4KcLdo(|*6wvNvPo+81CC7Q{hXM}n?JWEz7Lq~Qd@ zz6aS3ts@pMUVE(<5KZ5mAAtjX(;NKzDAHysX_puU(!92?`7uiCy&Vv3?7xX3rbf=VGdv zCbY!wjvVGv$_|TF_-(Gp4Nc;MCD<<@M>ciX_7`@YBmA2t9Z^00M#H5Yr?HZ%7qN}{ zELbefTg;FfN2WX5qn^#WfFVyDzBG~_+l%`d+VS<#9lcf2b7`pb7M7qf(g*-1;s=CG zw3W+-{KQGw{}V9@&i3}1Zyjx(FCD{(JPM?-O!UtObB<=>$TITtzeER= zK2v#e>3Z__6jJ!f8eX|)ApV7y>iFl#Uh@R=9{m&RHfOVQXC_N##UtS})BI*lHU)bM zDBPLBdykFBHyc!<=e)Q0WNSVLK3&cOy{@j~oP+M=)%SBK+_#tAo0jp^ltkYIWn~0U ztzXCM|M47ud4DarTQhj~N6C%X(lTTcXEfMna;{z#VTs>9v)X5$>6P&T+dADz`lv9q zO>F_o-~51Whfh;c`GwCu(|ssIdj>R1GjK9y;eYW_<_-!AcCvN-GM=586j7CB)qbJd z-RgW2T}D65yBYZu?a5)y;wkiK_-N|rr^(EDfr*U`W@GF#o5_7XHB4t_kuPC#B2*44 zqaNeKtV~uc989mdOUTa6Ve97CNRI>S&)0H7$1`-y1kp=i6V>e}Z+~~jrzW8Q>hLti zxC_WTt`mvTMoqq-dG-}7oI8`rcRk3`12vcyW*V@t-6%Kn;BTL0*uH0&F<}zl{o`3? zz5YCN5*ofdAx$_DV4P&rAOFs-tEMqUp?xOkbz0Fnn@`a8vut;Z^I2Gxw9mGXT|1Ro zV;jnE+bGhf!6#cjwOku+nJ-|G6QOhPn%j}A;%N~xLG%*Xk>X}g-XR92jiZ~SFfeT# zw!L{A)`-k#<0)XxichIB0MA)U%j$rZnQ7!cw=r$tLH_r>A};D)%D1j&{n=EekMpm# z31z~G0HcDU%kLUNZ9YNT&$``1pHH!}D(S^+$-d0gS!0O-Y@=py zhyDp$4z_ZRQ^=fXSq`>3oZCds8mSp)^NU%CY)Tt&B4&0uccVUQ?W2n38I%E9Vr;) zyVzC!029+Dk~ruywif!FDB+AYDu7`G?L5MoX$Z94n3pba$v&KfSP3dkkQ3+;uTyo= zjY$M<(RQM#MJ5{TGk#ic^9gJ}t9Dn0&kA`y!@{Zrpr6QMi)%TvZl8dAY8^RG6*t2I z6qqmJ2%Ce~$c|(g&tcXv6GSJ$$0zzp@(Sv?_2D0oay*ZMDqo_u*k}{hOasAeH^x^5 z>^POe{2z~|t74<~v>!9C&wh3kwb`xOKsu;>#!qW)KEbeRcdPU17FH$SflJBCI>Xc_ zf5nXIY&L%$c{ds?Un~imgV)ZEWEIb_F%v{3!8=lPit`JJ8$A-&t^ykGeYDtU6V6Nn zL2WnsF;@P12_+MLNABKTY*^fv+~;3o!@0;Rkml2I?K6H_Yx4<;MY~&`&%&zY!{Bsw z7AN`*pfV?$6V2#HgXT-q_gqD|9K42hB#U@jnWzNOi&!EmxW2^B;164VO38yi;;+r> zNdoq)544|5 z$M}2`j{kfI#|Ah0PwqnR(y(2L$8Z*7e{&Viw-3NQGtqiUAjhLEoQ-jQJC0}mg!7#v znBTb@t#`vTX*mI-+evJ1t-`tVDCX=5=zi~}6o-*ih5fa6aQ^jQ7_-tEwi!rA3$VYj z4CmAD;#_tN^S){5e#4X86{BZ4_Ltu#W@!oLJu}gIgY?+}WKUnTUpzwHlj&$^8Jvai}i9tVP*h>f5ip3|YSkvzr7i!1N&JA3~}(;P?q-V-jXp z3F-`RCgEK)8>6QkOa8U z(i}YZ*CS`*ABkdf6sntMj!~e}1aLbsn{rjz285E%N5WJ73Abq$N=fNtF z`{I3Jwr?ANQHSJin8T2qUp zCV~@i15zi5HIUp5ni?qvv#SCaAUQE(C8(|icMZ~|qu5@~MsBM8l6yCKAwuGNVR}xX z9;yNph>6GSDt#^Jk)4>aGQMlELuVOI)`C3_WAsS0+eTvatVZ5-0Nb0H$bL7OKp+sb zA%VYn90c);f*Gtxm1PJsV{ne2PmD3s3hx*=D%pcCh^Oh5;%1~BkqEz7hdhi`FG-3(hbw_Ab)Wj^?!~vIYBe1I*PhJ3Gbps)Nu(pZzpO| zI(p9-I0hIM$Y=Uc|LRl>M(ZZF-u eKp+r&EBJqqllBY4FSAVm0000W73dVdR)l;n3##+Cu+!tw=t<~42YR%(~%#1Wlcj8SlvwaG` z4YnipRE{#>cJO^xCzE3MJ_fqJytw>hKYl-Yk*4?9{+N1Q2L}gNlEd?;HRfomool@+ zU>sgIR0EQRzvmpD!zX88C8YKHDgaINe=c++cl8KBjYUQo)u(9#IUuKd)Am{uA5TlO zoE@jA55@oV`sf-olB(6BDgxg4Y1*KZzxl~Mi@}tFvnj!s5(-5G=0Dvu_voasNdG&( z5Zn?lDg8f>^ZN=Q(u@7?-vfsKJva!F3`{d4go2 ztHu2FHZ_WuxGp9E@=x;dmgdKgjsrYj%`BJw|L#19)$E>OID1}h@WFDNhBYNuSOF*1^eU#BBZt|Ll@!$FgZ9W51?o z=L>vo?nJA!ZB3e-0MVu3%eG*=wn({Ns;! zQrO#=uw$CM5a)F{$C4t}J8kgLIB!IqqZ&Mzm5sotxCwvx0N+$iS~MjK2zV(b6xy7b zIS9%1*qH;>gOA7VQQRz@Q&Xi6B2S6W`BI9e)LPIdZ9lEy1*$e8Nsu$_<|?$B(UMX& zKf!?2Fk3aO%FZL-g6s>%uDLOv#f+u3Mn4gvt4S=h+9I3d6uT;EvK%?~E1i2=Z6BIF z#J!WMFxV})_`nC3zT83H9X#8-m;Nf0SqXJMG12GI%w$SJ;Nms5x0UYcX>>>*Y*UTQ zuc#nDkhMR!*!M_G9Zo{_@=ON=gD|v5kGoRA1)-h&kFu>@Zd0rWyJNCQ2=v@cFkjM? zZC*v;p(>Rs0mmek#nIJD30WXIpA%vSqjnb>{4fApp+wc)vj1JdNGgnr=%c`L;qKHAXB?MFGZRX!u4FKdwPsc+;8I4&OD^AUvnXbDO|5yuVh)_Yp#w3 zH`-7yPLaJ)@bkCue&F(wTLZA!`zCgiOkDz>vXy=w95ui|G2};k&L>e(qOV2LcO6gs zihY#Lz78s9=SZA*ZS+Ack=gKAMsVAT}%>ChK z1l!%R-pPW@=n`wOx2>a6!+T0$YQzzH5UxwuABIb47ojA7Dfu~{6G}!?N>w zLn(&;%soS~vIV~2m<;u+OGxzkFj%4eW&e;%^p@kg;)5qszm@H$a2tV^)9?A5$JaN6 zD85tx>cw;G%#%de$fB5wBCc!hUs*C^Q8U(R85+V46=FXIfIDJ>0lD8Owm$bir){Mn zWEe!G_tesH(CEAq8Lb*Kms)-4h;?DCyvGuGQm(Wep>AzB7iC)Mw*x678|INJn1FK+ zTrY&PWpX~koWER=@}W~5aM@sxa17G-#ep?`jxf}pQFf@|8+_8?HNMT_Nu}YGR*^=) zFdG^Q0US?y2)N%89|u0tyt(omBUx;+S(=Z$P2LKhyx3h$ZziTA$|YuRtF_T zs${kPbI6v>BS0mFZC|*0&MNQV`1?&hvpt1P1aA0wCq-=1@{raYy8orAQpR|{l3rJ? zZNI%4;Ry;b?@3Bef7HaMf<@u!(#k=)TIyem2n1p}LE5|P5EH)^aXW^E%xUL1v!m0+ zaj7RIihWQdImAK6tn@ID%7mMQTc+A}A4A~>X>2TMwedacuX~fW6{$BF%k66m@?GJ9L8d+X?Am~%?4DExlR>JAuD-DfJ*l}%>jg#APiA5q zjsAiWo>uQH!PchB`Z$6$6Uq(yYH`~Jl9ztwZ&1!`NanrP3WM^cc+ zxtGQ%II7Rh&oEYAdQNYY>HsB9PUCdv^r+_ahez^`5?qF5>u;Hr^>nHeQbEy^35N{( zMp-2lCnQ|KSEXRB0bkg{oUpNck9zfL=TiSQ&Ampss|klJM(69k4D%2X#u_EkbTT48 zb_+~RbpZ4kbd7Vl(Tfg?dVQu>wA(P}xjrbJ`ngMB6yaF3vq~QWMEIecq$9Xey!r9a zg$tQeG+%J-C(wOV=lL_eU}8iYd4b&}|%DVYn zT}qe|8frpe+$EF-exi&ZkLs9Ad?T$*B^i#WM0JAhjSYPyxG`#ed9vrL0KUMLQ_BYf z%N{c|V>*MCoJ#L0gA88*OfS!u(*ODb2U{bqCy+2nm@cbU{HxN{q|4m zDMdwm2@#vW7akq+o`?0q11Xdi#^5uVmoHuvemNOgR3((A3=r)FYB+hR2*_&tt(U?Gs% zT9`^h7uq?Vd2~{2@xH zl{dQjy;XQ^jrDBTki*>$u#_US8^-7&YApmf2yJ;54?$gG@A%KY{NWm;KqMjMzgbdc zK(F@xxIiLlb&Od$JqJg#sRL{g%x9G9nNu{yoqaiT=*}kd?Y-$j0UN|muZP_MWLyQAT% zlR%-L1!wY&3HaL%ue`$v#0GCpUNa7WtBcECH`lFwW^eT#k?pjOvoE51jox6a)oGMV4ig$vvP z)293kGMinE@OWYCJG>p#nViWjr|)yMRr)I1t`RR zzVU)fSEtO(GsPt2DJZ^sF%ftIQ6)>J%ci+MWXB6mGL7MT5#W%}&ez{5T!`;)U`Xg4 zxhO4R#zskZl$$1a^ud18(YZ7|ZyKeH*QspMU9qBXavI?9-u}`_a_(1DSx(9HH@FBw z>@51lZbc%3!jNs7L0_X!^>vK{Gmnf4HBW-oRw*L; z!jY(37TtfMq}Dn*%v3lO5@NiYtNAu1jkhu>a;V-EWvqE?KFdlza=rgv&fnxa*YnZr zDy7VJ0~s$-GxsD)bPa#%HeMG$p%Qx9oy^zZ=?vZ+CQ`}?qFGTW{qpVdrw|L?P zjZyDqwDRO~WeVhZFNhN|elFyFqq{$qsKfWdV8N5%30qeVRX;lRk&hW|CRDXQkm{1# zWnEjz)|XkaNI%|(dGb(DSl^xXEl3%&vnqJBI%jhrWKEejE-EbI9dhP-NeM4|cSvFM zcqSDVB*-60?K07k?o>*XScA*ZPv`mlhny@^>3{)!KXcKhaT6<41a8vcpx#hQFy-(< zgy{`Gat(U;@*dUmm+FbUUI9b{AYlrI;Y@A3YIiPe3O&mgCY1^1iz@m--2vje)L!w- zUY5#`)m6uV#6fIeaNDdOCH?Qw0XBu{0HLBYU5I3k`{^OJq|)zA{{IHhn&l_m-Q7zn zVnm#&c3T4aBIz5w*<+{mFc0hTo`h!^x8KU$_pi;KTxnEW{1y-r#c#C6(P-5}IhS$H zCFHB%v9-B!*LlEK4^~{<6WPv+eKrLl`2u9|a3%6im@L zJ``Z~+K6>55@^NOTJ$d9P5m3#c{%!#(z9{@Dz1@`zn*#rq%$Vm=Nw1Xl;c2^t6@)n z_@g3&bL4r+^4I1n$fEFJeVIXCL_FU6hmn>xTu(RnZX##qbRH@V##lW{;PS(c%cYm~NX&or zh3mtziiqcx1L7GSMmeFz&_hWb_k-Kl=Lk-n=+pUtB*vmuj+Nod1jlDZ(!!I@^AMGY z4!>n2>t{dgySq;>$52nD?kQVb7*)-c@EO(#*BM`cd~X)lng@4UGN7r`u>t6C%1-Bd zH!?&sUhTgDdhhP8bqio7OdiLoy&S^(OTy)2e$V-H7#>4jek*quL7E238F@^ zAog<22iB;rhV<|LV1<{ zMK%1so}T*9Oe;R#<~pxyJ6zg*_6>**d&T2U9??;7-&xD3q$aWam129!k|bkwiKg^I z3X=QJDz>U8-{Ry$boB#o25LO`xH{gWbx`c(g~Kyt3w=)qBQ_5rOF}Jk5HOKaQ!Q}+ z1r(r(gxt;F8HOkEo#O&lP_dPiR27n({Z{OttO)ic{OGIRYVtH0z2bqi0?a8z&ky(@H@dLPuw_PG~L3}E9!iCcArrck6y@E$;9Y$HT{yRAP zwGL>6HvUQIzPs%N>`M$%RJu`Tg(yA5+b~ZO)fUIor9#N9^wP}b%iWnmu{$rQ(MWw% ztv(5Uzg4_&mWWCeAq6EMr^ z$YK^NA9GnAMo!I`9yUfjapx7+i2J-pvh1yy_WuWP0(O@mOUByGQ>pkKhF~x!;bdB`Xy!-Tg2Hl zEx4);l0ql*F}Hc1>iZqg&hv7KaY~5HAX@M=K7kbi&k?Ls@O%c9rYD!2O2-?Q%%ID6u2UXScdAOhLOQ%wMNnIM>%QlAX{=6-4IrXu+*i z&+}iN1D^OOiMVPxQs1w0Mri*;#2TJjXxj7SUDC4PD(y+MySMw%908XVnK9a5!;4ou9WU=`f(cc!T{Ou`xI}OSD4q!gd`np#QERer-2PHJ;nvGdFO=l=FZkUqW@}%4 zkgRsQV(D6$TG;yWan(HJ)?Hlq5v=JaHy-NvuG(8{fD3UmVubX)P+JZ~74~+xlM&e^f^m54<&>8E?y8m&O za{s*{fmVOE>aNwo(l>1O<)+hzZ++VVjMgl``=Jnz`_^M1;lRrX;u+jzA<1w75oUKg*e1aPuGi8es^sy zJPChXM_o^ed{(_fq)Xd&^`=rZ`<#-SeGaFer-wk0YCRqK8q1O$iG9_(x5^4uf>;-w zsG2-981(+}Q-V4d)4238+7N!c-K(;Jf6@s?y!F!2%3XtVkRutM%w%CZ5_^_pksM5R zBh}0L|5*0^Nt29lchk(lfVvcD=}g2oYVz$D+^gEfg6Ozpra8-pu8;0gG%ymbM636>MTlo}KJ z;>>bH^UV!@^(?%HWdf2*7{2P53{uY7j-*I-PF1`}AKKL#;)#t_kIxn-?dek{L#%xJ z3ya;|kxlz4O!EL)^xZ>b_-{YrRJwC+@9TR|OjVO(QTDHObG4gJmK!*`fik_v{A6h) z`pq;F?_Xc12@|`+^zZZ|Qs3FcgYEno^(B@QKy` z6knN^Whips3u_HHL;v!yF)dLJ+`thiLA)3@(5Y@C%41-5Zx8q*#CIlUqGwdDEn3$X zr13>0FWoHE=ZHCu^)pX_MA?v%V;y#mxU5xhykfX0WabsjcDj69Q*#Y2Vn5YX1it>` z8J-=;1Dt{f%X17YU)Yhj6S=sgE|t?Mk5quTvc{*>I??(NsRGzeJ>l@jlh|zj>CvN}7K<0Cg<%GqJ;wrGp~A2KibStY?rRSP;7eh7cJn6AgqW2ca=Go#Pu_Le**QBN zox|eR*{x1caDB7m7te1x&2a}FX6%*d|~ zye@%nV)9O}4+r2b%>aeiiRN#xfns~K1peoHNJ(#|1iYxm*JqFf7Om%ybA}L&%wCsT zqjD#DhrT83rii*PFTY&xI7se!8`CU47+=RV^c1npq%^GfV}NTNA$1MZW zYLzefUaQC`btIGPgGzlxgUS@Uh$>S{Af(R9xlkyeP-NsXTOq^|3_W)jo5JkUp95}y zj@xD$3}Wi;>ITWISj)H3@n!a9x^$bcMS>ARy9%wI4mUnjsVzeCyts6r64~zr;;Le*F>-g$;JGZyQTq$qo0b9AD!-JEG z;g5_nfy<^loUPGk*PU&W+?3zlucZszf8wS;qdaeZ2Adg}7Oxo2vCof?4{%T@o?+iP z!ouHxREtSm$l`pl*IJBTXLn`}@Q4S>udBO9n_+en{#y$Gtgv45q|=sPZCY{&0lp@K zDB&{4HfjWsTbKD#4|wwMs=RXqz%fvjZtVat5Cs3S;@2r6@^i;lyf@9PWG_ z8AO`KTC83D8Cp_7f(Egt5ysisgb|}IYl*&LfnQ)or2E7JIV&uzw9ML&1bZGBzxDbx zb0TZ`5gnV5^j8g^KhikSIEC+7?tEu{U|}WK;ctjiy~sA0af}~z0gQ3k%0qr2*Te;L zX3BS0HX}aL9P4XxfRJ79f|b5(ZM z+w0*3OORY3gVnPQOasfIv(3cjHk^YT7CHvDx1cV2g*DF7LZRH2HzFYv7MNh&Z4GOp zG*+?WTwbWLjS0nFQI301@RCIw%S1DnzzdI@E7V1|=PEAlDSF|=rX`YE=E1?wIe*PD zzO!V3@gn$o(llMkpWFRg_@Ia!4k|3e?+V~wG~BIDl;u?4Zxui$RxfJU6Ht6c0FkwO zi|cc22_CC6wGKdPO!|pdi7QVLbJgqfG;qNJBYe5amM#;aqe10 z<`0e``JsM7{#UkvNq0y&g?obuAf|V7^zw4KGXE|(K4T?4g57#SdbbGOhqw#^kNib# zMX;x64d~jp^}Fs`X}o}ogAh^dsVSy5=j9L0A9M$_mj8nh_MUCZZVFpu=~QMd)Zq!0 zw7%%a-TzcfVnC)$o++sbj17iKNH<;$Y9)KP<&nAgXVIinjq(SE-SWy7@*Hrr+Q@X zM%D4gYVwfFWhd`7RsGP!NXXLr=j}UR&aSfrKEb%-OnieLrA7*67P~*t6Nn>SGe742 zG>RFR6S5z+UU@m%#)tc0qa`)f7LB881AdcEHiG=90Y-F?`;4HA>rY| z*vN7xJjJg@6*i-Mx#91vt9BE39H2a}eSNW=SJAzyW`C;Udb(-mlF$jjPV{{TMfQ10 z#QWMj#W2{YnS(1C1OyKQW`4R+UT(zIEbgV7Ee_)dnQpm!j#h(@PwchJ?2VC<<)YYZ zy%0nKci8#`*zi0{fX1A;DLQTH)!gLw9GN7kge*oAGXpvNXK+h6^;oI{iO*jW>~(dF zuR8@3`oD}!sWrI}>8$1E6my4$(_8AQzTR;MjB;0FivieJ{6&)q79f}>y3OY?KAYG^ zOeYCr1w3w)sKh+A?53B!PSpvP)bva?>D^a4B`9kCW}HGjPo|2<*rqL^9MzN7L&TLu z+U}W@zmcUd0!&ZjBaXj^PqGqNIqFvCLeUDI%c z=xA(&l>f>{@SOH!eQ-$yA5{%_L*-jo%dL|ey46-v8&LVRr^$qper9XVnIPPzZ6_(3*wN^D5m9NQUf%l?2M&zN*l}HtZ;5Yr%Miylj92A+m>sFI}-DnlUL{jjApj zH?tu?6^)l-#F-T7 z!yP+>1A&s~v_j_|s5dZuXKqll{c#^cC6DdY9x&5uQe5xVZ~ki*OG>0zB8A&)&ufkp z!Dy1tDo^(j5fQ`JegB)jfP;mOd#-I>oVs-VQj+}q4atoQjxyqSri#J!;aimei`f%0 z8*7l~axJ@yfU*;*viDN~zD0%;7ZMK-EH9V9?=I~1^37hmF!Wz3^Ac%k_~iDn?00Nm zgQua?^Yb{;yCZ(i+nhhBEo2B*4S`#C$Oy%Nl9kLQu#oY`(EEua&{P%usoQ+HZ3~AA z3Qgl8i+oljzHBuIB5SJg$903>D4UEU+oWZ1x&>enfpYwJLxC4-wyi!t+v0LPT9Q}& zMHmi?N=>J9Y77c^bimga4o+xSv@6oQ-aT1nhcHsxii>?u?u3B5Cf zyD9z$o9gY`g!m{oD{nQYL_)IbD;y#{ZK&hEKEz-GI(Io|aZGt$%8-@8u zBVrR@$9PsglH=s0Lc1HYwj>#{odFX$8%EdASgM9u?nu~>kkm!zT45gR{&!O8DVYC{ zY(!zV{U)3rf}BqqEEkj?a0-_p>-9p%@brg|aPV{->VZcLy##sTG@5+VwW8gYB`g1W zOH%7v&EZw=^rytS88Q#yr{~+}Uv&zrU7vo~pB2PdGpUQy=JCz$?3yw-QIR$H7Z*|0 zMN9RM49Byp>zgy) z4@hOx*6Rhp3I`Ami55FBQXsIIA<{D=twgh=DOLy&LVk#~*ykHtW2yfJzzR`ox1ygV zF=%o&vu-^>F!{0j{j6f$o1n7_b$+0aXFE69*-g7G{@Wo*Ry7m0to=Pmzm%G@z8C zUUsQs4F;G`^0~10KRp%ORmU_$%^2bgqb@Y__)wCZ8D3(cD(3~4x&x^TXmq=iCa4FP z7nTw7P^6Se4GX+RiU}2xRc+H85qZSk_l- zqteq{@p2@udvUQjv{7bWL5|2`@qed%+{V$eZ2frIz^AMGc1{{NHs}kwud7J?u=q%K z$97niZTeQODL`7b-hlLV88fI%ITV*u_%*GK(GYdQn!GaiXU!Wa?h6%gHoz0}rsV)e zcfyG5$(XQ*XB#Bko@-5A+&Zz_4c2&N%Xyyc8ld#)GWPb&NrElAyd(6NFXH80HGV>G zyUYEGI~y1r;ai||Ji+e2xIs zt8QuIdar}Uqi?Wa1#;OwR2;UMyg?8Q%28TsFcM!t)k5Fv_kycS<_$up{oE(+A26|Gb+=8XL*vXSoI4Ww9;LKa zS(Bs90E#SZ(-ZSk6{&>8B~*e@_toGxq}U7o86!L~r~{YVAqgtp>+LF?<%d&{oQ!QA zo4hBnjUvRIjEgAzUVm0rEC8=yBh|SH_3xR2Cv-9KOiJAGHm zv+o{v2&PO{Xa#zK{eO+_XE?@s9aoJ%XA-uwzB0_ zRYiq`p|rKN>;FlqXxMD^!Yt>9Mo-oMgeK};PwD93ySuwHG&a^}O|fkG$PNXC1_)$j zDi+9qrEvDo=dDa z8n9^LKlHAicR6`!`P~<)`YFGI`%(Yc9b;mHg zmgJqDbAb7I_6g%nLhoEMlBfr|a7DH|5^7^U@J&@aRQ{P|V5Z*pgAkfDAKQSw58Vr( zKL0jB9gAO-GN=q-DBk~pA>$JIkaN6fzvXTg&bcf|58cv9EvIddw09z?iz>3%Yy0ZnuC3zr5yu4WAPLk1e34hGjlqUU&NU5K{x|1La|z zxzk3(-X1Are65HV>esnKbno@2obd$9zSO#N%(;^BkZ{^dY3crxh3pmX9H8~C@-&`e zv%nf!?6_J?XQM2k`LyBk_S4N@d#sVSrjg1HZ5>~&uWDtzawe^9ZFYPSQaA&*>KdU( zX7VAY|KYe`Ce9c_mv9DEc$A`2tOY2RI_0@-0@nh zLW=23*t-FLi1G9DsSoC*LzBhSu?qd=ml8ux*w?}DwuyX{{7Kq4G+0o*MQrRf9GOwE z(P$8&UHm1eSMhRYc9tb+Xn1@Uw;+(sV1IE@Bg?R&(rIQ^kMjxAF)xWCa4n*z7tlFg zzR5nFF3VuyhWK1bZQJ;G8^9}k16>Hjlic$;QZ;C2$hNV19kVJ zNf+??GY`+jUNFP9rA|VE#gMgl2*gqg$#6$_piL;LWdxHW8o8IBV$}@-A$e0O=7Uvw zy}GqOY{7x0rluw`0}y?`Aoc54*<5V=R4LaKH_98ka{M1T7xMj}$^OR10ek>XnDm=& zIU5fDZcq%*OzJDr;RhYwAm}2jTsWUMjtK@o4tYW0o{uRcf)y@T6K@q8g(af#0N2L; zsux6p#dT7+eXkd5H)wIf&1JA~K`-^pJ79W7z95Py{JtqgQ*fuZj~&!=8_Jl$>#g^S zs>`~?a7!91c;1=%g1=YmVum4_jl)4W`!G=Wx(=BbX<>SY6_3iLHz9>*?FzX)mzSvE z1rb`5wSMtRjnxi>8fYq!6GAB1do0P!x22~9o8COHvcKmhN^$NrM5`uZq8B;^7GS>e@o|AKkuPzDf#C@nl_R>vgC$4Q@3zXBx=Mg9&vPd= z7(;;-WGIZ{5+WXPpuVckSZ)|TBo%ofrRd_b+wsrO$Gl2+T3__XC93OR!Kb6jDqUfU zk1;kbfaf{IR6VhkpQq^wnOAIXZ~JP{;*!D=^^*3LBWd-A3CG>xh4af6a4Q-**CY(C#ypPatTooKh7Pe+MeStXNVes`k+!-g3keZ;vkuK%h`{ zQgoYoPiypcg7;=io&6*Ft4(h%4x;z+4AfCzV=4!g(KLEdIxWa+Yjrz+QL$yPCkNAdHL!@N)vJA* zGuuBB)DkATyCqUetA87)m4((_)zn00URqKCjh89bM7{@^4%m%8^NHH-qQ&|GvT$C% z-fcn_YVnRZnS{owN)PBAjp$a?p0OC!zey;ocGRA0`uO-%*3@i|v8`K})RgFGV151i z?H`M(X%_pNol`Z3rz&tsVuN1Yw(PqTKRY7&Tt?FvyYTf!DBD-}n=jfx;!vj4Lp%bJ zFagP$4EDR9H{rGctJ1j36b#V|-v;X~twYydv3BxvhRKuVwd!lg)}8px8|`*iWo<&Q zRnk4`wtXp@SH^bwVm3?qJZ?hcJ5$nk0|4oQ%+5rI%Jse=#TlveL?DZBipu5HZ+-ak zwNK8WeUj6y*~@j#vcxBmZ06=Ad_1C;bZa_Cpc)W&*UFZtx>MznQ*Q<;%D_xIPQ5jk z&z?t2x#XcoJwH0yK<`fxC(jgq+iCmEE5Jp#ZQ-3~PkHM#4+mz#$Ga_NvqlGL9+$S> zusq(7>FwHB)WhuSa#|n0zyRfxVU62<34Ab)?0F@TNBuJbm02keM}-p4LgYRDa1aAc zRiNYx(As(_`g}jVG1zGkF26sR=b3R_|7dG13=+N6%lWv zI@J(wYX;K#!*9<#HOLA!GG?lk|H(Bf6M!@1UOq{OD=Q#wzPeoeuIlZ3*wB@WsXqO( zrsehLgsg=486mQt{8p9qQCo0@g|}3F`3I9C3bP|8l5{ZH%sO`QjA6lBe;~cpzHUsY zi1PX3D89n@6VOYreC)PC5!8b1IN;DM8nCekp`6qaU1`Ax6DV;c>N0V@>#11<#0cbk z_nkC&-rkjyJZyk_G*Ra!^Oo7hx;)s154s%~8miJe>z3`mn0%kQY<42<^4GbTJSvOT z$h_gR{(9HJcF6UBJ=MTc6j6<2d=yI0*#1I-(N-V2*C6m{P`=u{rB$EMFn_w`@>+p9 zfW%5^8k#=Dd@YK+x(FBd8rS+Bce_W^k6NOB(aSa$f|o&^#OY3D%R>Tv0VZfl_l30$ z^vq|dQIep+{6+gFnKfZ?`)PU>^2egM#iJqiaU?5JYMA=5dc7+{#i}D*3#Qj-)ZM6X zad;!5R_C&!-9po*`P{qBCuv;BLCI5(C8l^I1w8f)DCa_#=NPRyeu-V#6?{0Xf~Dc= z>O1aDVA+R^$YpHQI-x|V-eqo?fIr-21p*N`xM0W8Bt9%qeab&_KNN zv7RP;N3he$^g~>Vleuy%^(;v_hbt8LRrYti3aM+A;LXHlE(SnU;~H%D=XF)d-Mu}1 z03fiSfP5gb;asQhAFUb>Sw7D#t|o-YkwN}%6uIxizt$znd=Nn$ipX>X0y@|Vyjm)Va302El9p;9D>++Pb;n%0uUCExpQ z!jPKAoRYNl2ntF>7)?B|Qh0gC&fh&0hwfC@j9Uch(;wY%0x&a7^^($qsVo@-+u4VQ zYl(|jh?DAEI3rhVlb7T3^(G1~&pazGtk#E0-4_Gnq#+7FTTOCbZ5eW&zk~=&))XGi z_;N%_@2l4&yN<{hfK?(HEbt>Kv_FNPzO^Ny&4+f@ap5E!IpX$ZxA?F>47+oum~|7e z2YGFZz$Wv=WA<3%MF?&!TbSyt(|Ia08nvvGJn~VRz`r?k>`Rkz|41lplBBS(+r;)5 zp}v@Q_uzFVa!WXKStP9cEdMZh{af|G+`~80N<&(C5OU?}NmFXXdguDw9!wO1goH7# zL-a7|5ng-;&@*w6Uine~IKZAWWc{s7B`ry^$(lYu>#*;#7el|awvM|&m$s{+wcq>| zMePEF5$~t0k~6e6c66Q)Rr1?=)4A#(qA85;;rlvTgH^;v3W3pNkR31ZSpE*9B#3}3 z;W3gf(|B{lqKfiveDw-J9CgpmU}Ycg@iDR|j#Zw#@~P;1`yo$y5;MldT{y?d%ai@w zyGQG6)=Zxl@BI2(^_Up$lcrOdT0l?QwK~J{;BrO=@m4%knBwbbHG0cn-K$%x-|Jh$ zF`sl#a9hWp^M#l$18aQ~S$c_R;Fj9r;yotvKY?Es^l4yP&6f}VUoB+nXO@8DttEoH zNYeBcBY-sfgoU7Bz^nf+YKjT*tuW8py^=A1TDjw`!+ApHj>`u_xL*t>-f0eaq%}nSJcN8%HI{?4LHm3H$*L z!c7+tjuOck)bzP;!^?}u)7@$4N5sp^%j@#S=YEfm@0i45^TNfF_5=F&4+#jyuis`S zN>FksP~!4~vZEfS|;|MB4& zLbwXomm;fQGycS+hcmvjbEE+6*t>o?4t#wXOA%Xd54`g6pkns=b~*v2sd3-+x|CJk z5zZRsB#$Fw$sO%z@P0bh7IH=w;3{l+@72@Vks`NvJ3Xmf3 z!hME1LnNna#O5j)j-}MQ$kGX1@Tt=5n)a62Gb|@MZJ)Kwm`Ib{Ii7k{Bp`Z<&i`0# z`k3Eo%z3s4P^;1@M%QC%nJJ6J)I;jY(;d`%N&W_x!ffAFs)pn3s#kO%0+W?3q$tuR zEDpLtu_<$QltK@UK&Ou|SfMo*2Dfp-wvRtNyci`PO=As~f7RHsFOjF+=BO`S8I1al z@75O4%koS72itdw+ITq19BlSX?0pqrcYh2g><#6KPQ4FFyosB`wJiZco~Rf*0xehV zyD~U?>}-3vLGDJc2Cu6tvEn{{pZ!Is2a`K-Rox3q(J=^6rgX4y)kkh|i`5l6tz+mn zpu+p8KVpd<PrUaGuiFXn#J4}vgU4MHnSMo{u{`Tn_!C@5rDn)^!*euFBLCo@ zX)%E(sfUrD2FGBPW)7-_U^sn)F!D8~I6nw%_ClpmRp>N(UV|SY%fV*ER~AAl&2v>M z_kgin558+sEz@pG{@`EZv1DOaR}RT|8olScQ!pB}O7F=WQD)mMA#NU?p^*`Tfe8Ev zxQ{}ehwVnctu5nR?got`5k1b`xXj|_Lkz5tsdL0L7psFhMp#-2iHYJ&D(OA8>EduU z?Gf^z2{0B$AkZH{R?B>@xmf(VLevsYX&3(?stDIisU*V1jA}f!4bPbE)Llp*ayvE74LXS!+Z6bDc;Y4(;wk5jbS;P0)9S*KaV3 z{C6A?7>)&!w`FePT#pWpsBbK<=x$`B)kdo_?d!=u5$n;R{;dTNzfHjSEe#`gxEQBm zKmqG`z;okrLqtp>Xrl~qBzjv87jjIBRAYNkv9M=7@SlQ)lHGrM}w%O%5FqTISZ&Ch>*U4V$^wJTHK zF8;ZHELq3hLzQ>HbT#P&OQr@x$o| z+w)5N<&gr@96zXN8ML2j&h~!gCCDK0fe)Q#cFPT4z1o|u*Row!$wvK39g`)GUktT% zZ*-X?v4hqk*%BM(9L8K;`(E*Vz!V+VXq#e2OGJ;i2E8X5sLK-jyB|Fva4$RLB(%E) zd9ItLkfyKF7^gI8uhkE7`c9V7@_nWWd-~1V;@68+w;4sj)iRKS4N`ZALw0xN8GmUQ z$>Z1tH?y+x58JxObQ3n1Z&zoxKb(4_O_qJahui*6S^!d_S)}HuxgwWBJdMKwR`C06 zq72CNJhUvKHok+ohI37mv(s4tThAU&u8Ft5fBmAcsqXC`u z!t`@U5MQqPWFadYolDx4D-!)437MUYuwKuP`*>t|#&~S`n0EW{zw3k-yP90&`Z4WO zKzUc=^5nNkx74cBxa%`63dc?8eFnWOJBdj+=HtGGAp|x#G)IFw^8|t3`eJ{0{ZZL; zQ|M?&&I{iMlLQjjs*Gloi~P%)SHgpXcO2^`x$(W&uS0LlQSP%rUZttkI5zTPq{ zjxFdKg%BXPyCuOTxVr=h?oM!bcXubj-Q5Z979hCm-~@LD*V~+P-h1Es{rGqw@GxO! zy1RDOszdFTznU`C-qjnb&&VIP zLyi^I*JEn0TsWQHktY$dkEaf!HCeKKLlWf<6-=PW;S1anXRL^1H~^_Kg0rJXp3;#1T? zMh_>Np8Ak@>%-`tcqJ!{nAWU)B!w5;H1X^)nId0)rvOnTiCLx6GN(d051?PvuE=3l znh`d)yGJ31ISPgeL2d17^7aJNVxf@`Gs$1n&wcbFJ60KOS;Vg`$qY$I1qEcW`3PNG zGlnX$c^?Dod66m))BlWDh|ca?XfDVYk+glyVutB@*g(Z&R@mm@vv#A}Bm=*=HVR^v zz#&}K8Gqv{J?tDWjO4=gxZBK59y~}}!xitJBo~}W<4F2ddnle4eLPrCsWnq~f!tZ` zQkJzjOwK<38WC;j3Esr%Xr}alJtL_)q+?SIpgbkk&Q95$iP-4=JU&ql{}r+dNyN?> z|7L{V(czR%^K}n8OZ$cui`-+JA!Bscu<<%4?$~jtdzH=Lg@1X4poil@p?Me=q2V)oYJ_X}9Sp3YgV5s#@qD4kZvO5Dy zi<`02nX0ICsDN&mRobT zJkK>kK3_4G^SU2;r#9s=pFtyjv@QOXN8nf2x==s|odVa=(#~B&WUi?haq%##*%wix zz0{2uo2Pt&4E{tR)hsx#fc<+x4&iFDOY_6Idq3*fdR~r)+lWtB#~PCLHb0WZb)a#b z+>OeC?ugbeA6EMP&HiADI+8L1D&&t$Ibxj{6QX9`Ib@Y7=pSvtvW>q5Mg?@{ z`Z&Uk@K(-k=Yy!m&vz*J03GN;itA6>Dqg|&=O>!$k8p-0MW!eMov-vL)<@$jB$~gc z;_-}<%|0Bj;0i>1E6K7;$n;-Z$=;Ah;v_NFjg$3};1f1@+;Y5O{L1^s?+&?p?wjh# zY}b)bzzlYs)oHA93T-KswCiGnTFr^4B8gX0^HlLty^`EU#{~KqyXu+qaMS}*@d5O$ zM~Y7;HCf^Q5cNC2V2Iek5H}q!uq+n{^=D#qkgC{Yom&|Lg9`)pOj;qW>Q7^uus^_knlakRsRg;_ zKNyS-CfDy+hP8^<`&WiWB!(WZ6}DSnylkFKDrab7SYKq|{=E2e2`mDO9QXQIlM{A( zGK=+kA;`z~Jb{_alN(FPOXS|2ZOZz&nhk_8gKRMKr3J@_D#*;23wKu0zth03SU z)M`r$qD>MyySXOhp48yeGLk$H_m!!Uv%D3mYKLvhWIT~&i6}^KxI=*~v6JPz_T~sL z8PD0)v!OOC7%7Tii379VGxCy!Z}|OA{cZl(eT5yEI#o#vx$uKsT3Vx&YKm^OQ$aK~ zxs|xg^(=ufgUm)|9H-%DBR^DOVouw?X5qohW&RCf`T=?2%Dme{yn;m_>_?pr1ycM| zg$+5>oD!?MuomTeC3{MME2_69;gUfMdxi=Vz2DC#;^{cSS9^7a9_G2LzdNojCwx6< z`GtZ@N+R@=>*e1*Z@k$`rVztWiBV_==K^yry9p5y+*dtV&C-clJq^f8&7_N&0Sn5j zL?gQ)+~3_(t}OaSbl%HlTpgRhY;?C>aNpy#o9l7UpITRk*Bmp0-uk~p0z;j%5MnR+ zJoH)%zy7*4jH&I?DhD}jzcgZ5ExCnX4*ZP5BN<$*b!BGePs+;OA)`|tPY#u;?b>48 z-Co)yez+^FWfIzRV{YS0t;o>RT)9Pr8i=MWbEl@<{n9sG$)%=R@zwU7U9Q6GAlw&? z3ICwk!@Bb393-M|kGZ$gKIc&NB;0A^7jn~`iK(-huvAP?g6YB0o~@rvl|LT zQOtzb#(mZAzWlyx-n+|zCH{q+(JZD;3ETomNs3OU<3Ci7S2q8wuV=5UXz%TEOQ2z6 zyLcyR0>!JT68np$-OCe6st)~IChYwD`SambgA@V51kObB#WQ$BBVH5P&othq{ia9o za?LXuuPu`zO!H!&Gn{MUeT~boRE0CA#aWZm;P}Rn>AOYnlTl0&HY9yByL*bKfLmI` zZEKB3lTx?DBJ}z#HVf>2%Kb4V;XRR|!d6pcSlCBu>Yi`o=A%@gG>LR&&xiW{0uIV`Y8ECfefn)|F8TM z)XcVo=Z?A*BQ&-OG5G*J>DY_<;7Q@weQ?EVPYb{JdLgZw<-yzg#RdY59>X*3tLff95D$kGf&qLJ8E zwB~a_nfTUT4Q=Ij%jDgzg;1obji) zXsTEj_HeCmw?n3y{TbG+CG-Y*8#3Ci*4IBz zt%2%ocnU!PjY&;p30GhySd^eHGpyw zZGZL|#>wVn<=?%)e(R1`;xMYYZ=NKLTvSrppE!{8j6av0Un>2q^Ce1!4BR&c1<(S@ z8*-%8bPCP@lHs>l7pq0j49fNUI2LL=h>CT`sK-aw-ImZ0JKxuF=~ss@mM+9ay?RcX zJNSu_JXv21rykyOz7M^Owe3l<O1ogLE;4zx=XPdXCOYl_d;L7`>26!NDC#k$NZy|Gh zn$Xn88V9xbq$ITjaBqK5&7Q8|N;yz-CHuAX*1`yP#Z)$D_%<{jRI}vSQqtpKVystV zq@!dwoniwV%v&Jt%m*rn@kzjWbVr`!gUb;A60Qp&ZxC&)04ON0${ZWB`w54*u(JsV zrQ-%pfIQ>3QD@S`Jx89i4l3-K_no zMssu_KtYwZe<+k`*K`}hkrJ|F&`(%DTg~p+^a|8D(4fHSZ!ZVY$RA5#4FP&iFwMvZ z4xPpoL`f7(=_>y-{+%9*3FO_^+n%QFk5yHhM5~~+$bJQ z!fKsfWz9c^eGlhPeIg$$l}Y^eh>72IM+IBDd-u>l@UCj7UXPlE+@1st8SNGa#Xnh& zqgP>SgE~)-c7(cO6xuHj9Eze^(z_J867 zyrcd#Q#8eEp@^+USe`MxEnkI~wJg@EGpTPPzAtB+x$2eYV8}r~Wl~=f;;tr!?a-Uv zbx{2IMu^$mA%0!H*D{je_Kx`YyeKC5=|{7>E;|%!(TB?>>V-_vlLM(hViftTMCtL} zVD&E)_{eVWvt3*jz3Ba?XSd0`8Hu}OMM~DUeSXdRN?+UuBHt>wP@|pg^Rq^H2GF)8 zD>+AZZ3dY z{m14n$=aVi%O)^z1uL@og8NJr-JDG8-E9bcu6g&Ln>d)X=tiIRs5;Yb$O5xc z%}H1))I1$7;qQ(5O?1*3GuBQ>mmJO$I(#3LP;%x<4jvX+D^zJS^V1xeL~PIgb?9%o zfCpjn-)agq*^z_WLHt<@EqfaIt51Y?_@2Ax6bf1K9;1&L!;6cq? zlEbzkb^S{t(n=wY6=dG@?AH|$t=y_%lS`{L$Y9OLmiG76VX_eFh>g~cHbP&hC)(Zp zm$$&7@@Eg&uZy1MtXCu{!x2=xwTVw6N42ZSuX0@M@)!byk~t&<{uvB}8+&X|oqLqEVq!UD z`SKrudjGuNCvKw7gOsfdFSWN@*t73eFI_W2=Sy_TvseikiGvkYR4j*$j!GJx&y!cC zSU&^{_e@n6fk0KV*3%`B+}_0eS*KTLvk`ZDdl2V+r}^#of1jVccRzayo<&cnU7Tq7 z?rj||(P?%?wv2FqpaApI+wrW#ki88j_xAj(D~<9oruX&TkcDxz9b7l@(qCuaJun#| zejq2`Ls2-3Iem}p6>xbqGaGpt%_I;RQGo!VUfFo!#HEF!kmiv0pj;8+5DMZjtfI@` z*q^{81WBKV?b)G(3m=gLeOgfUdQN8DXM-E@83;uJA z?J-*>4fD8&_}c>A47b*6z@l83M;TC7FwosQ40nwvJ8_(Afngu~k$zfFKH*X(c0Kc0 zq4EqLji6kPS14~T-_mUOXQUoS@b*Jw**1L{h<90k9>!V8oVqzZYW z8^tO#^M0q``Jm{|6+KLQa5Ja~Tp3e0*nki|5n~+~d^uew+O>WQcHnWOWIsmybugl2 zG{R}mPxUbst?M$0)`b4=-}COR##|6#NGa-|y?xN|lEE7FJ~#+E9#N$v^gD_!^gWQB z^%mHp6}IeKCkF$5vXyS zx_^!ulhvktf(C?Y^UsnJD&WLqqyq-FS^KU}xc@^#t0}p8kqdBg02r@CiQf48C(7!u z)K}d8M=ACi{WE*I`6Gk`4g~m()SplXgmW3m{P&#$@mCPMq}=avF3iIQia$XR%YZhB z=hLKgyWXkN;+3!E`!u=nYB>#5+9ODl-(wQ5N3@JKb|B^Of_al&eM99ykZz(*z>+pa z!N$s33vT+wfqw>3-x)iTmAYSfY)Sez~FT5Ul z4e#c_AHfd%y0*(u-8ES!)RiTFi-Ue2j?@|)L7K=Bi%htDS@QXdI2Q0Oh1rGix`U6J zirR2yZTqeKg>nHwWI>S%3!uZjf)5A?Z8v3r(f8&@kw4m zdw@G_(|KPNDK86iOto(Ix5BBQw(=wr0k0UN@5pkU&(K;ZnVnVYuFf=St`IbiiYIK@ z6(*#T(OPp|w!DCe6Ubs8E*3t%Eh1DGAox-rrWBK&nv((iGF719{r00R`$=KJit5Ng zvhv{!qgv7?hzVJSPoTmCqbj=3zLZ4rpzy2oT;t{&!v~zIm$ZM9;uiN{96i(Nwfp!O zhjA4hso{?2?3uej)@G)>S$#@`j1H5{pybY zZUZXI`$mHfJJKB*VXI)?zF<^~VUVyFsbT{Uk;mikan|t1yOjtQY){VR{d@u5-C1^ zso?n)#?l(7UcrIPPPKBFYr%sF2xRbc4N^d3qo!V60Fi@e5lvGjpiZZ*h@#(FQ*BYj zQTB(wWEl}gaFvNzWkwbv1=%N-{0K4abX)!*)Id@_f?6LB9tQ>UleN{795##OD`Udu z>ZB7Mv>&?-d^F6HY?eGRS0f&u~4G@Ar zJo|oXB93A{l#rZ+(g|89+DaHkie8o$b-%9k0v@VtJ50rx%W zJS}xeTdWArF`GQqF<9CY+dv)6JzR5RM&h-;Rvd8*rE+U1!Q}^>8Mg<}F5w+^3?tIy<`>59Qf+_aM??pQ}P2n30HN4Il^@>|m@6%q=@Zr%HK zDn|$kA_Rp5xjO=j_U;B`3u))`hB_ur65Mn+1=$x-t0 zWdd9gv*|dYSS<0FIElA%Ia`7xIS^lk;<3bT?(RRcvnOs&K=-F@XUDg>Q)akq7MOq| zeQ@_m58^ACQoC?k={Yi23k+eSPEN;@qz1)J`l%v-r|CHuNyz zp_PiHKe4gRt>K`f_a0SujRR^F9+v~z+S(c!1;ypXAc>N;c9dAY{&Kx}P;fA0jnxwK zXM<#uFMZgg=6i*2rAh6{`f$p|q2XDs;pp%fq3g>oPG^{yAXYqNW z6A+9<;jvKB(0u0P#Ell)t~m{Y!!TQ@B8tRepa9|p1_@tV4O|M?hk@{5G8{mZl$1Qb zZGyh4O5=5BK0Q69(`jGKeJ=C3KAfu5;&@9?z-0qw8r~w&>uxg?cv2mY19HuJGk{5) zA$li2=Y6we`X*?*u6r-EAiVjt<+Zg(5g6M2#PT<52Z^`CDYI%|Pa%liHX!+5?hN0w za63Cj7L(D9(Nq>fey`?b$$u{`eYuRyO!Y4MY~o@PjUqa7JY_9VbW7^4MDe^DuaT}q zx!+W^*jvv;)YlIy-`n>=hx}Pxru0lQ9(9KsUN_{{zYRJrNSuxJq##C%IRg8G4vvu_ zFjbbM4^>?OMRxd7p{a$yd6ZAD#(G^UM{=^bjSc-^EXm$vuE@=`mzUQ*sEL8Z_le2#=J?Z> zFVTIWDDlAlVkA%-J3IZrA`X%*&dNLx4Zqk2k*_4t1%odRNImyXJm{52>^(mg2F=k z(-kh@zm`@0yOq>os{kE~#UM`!WYb(h~*g=jm$U;UX zv(dD2dD)dkNJxkZ6W(MZ%i2~++4_ssV$CK}q+j`5qg3^hRn;6mkLxLrctYI4yS29K z{PWeiXQm<}Ap`$bx9qtSD(rjEoi^A!%r7?H$X#Q5FBePETjgpL(bYb+ruI zLKR%BFb0_m%vu06mHHR6pw?}#&B>A}j9q{A&g7O3e#EN3k&UKuX8$M^og>defbb;n z%ur%2vUTKJMKXhd1dj=Ud_(4V%^}vPX_IdH2YHPxw?~SK9nq8p#JFyW*V6e}5mN^{yNN z9zL(6BrGB#LbFmqL7|7|tX(9YLMALSa=Wr=ZL969({N`v(XX;7Va}qm)wbLprXznBc4+o&Tj*X|zG z>>hRZLs_c0p!+pg9A)KMJZd`+Po^9-{rx^>rl?Y0?3B+oOHZ}ZUb}0$h>%mRdF4Q; z)NjR}udL$>J#*j$9CCX{$JEg^vMvXFN^@%~v)SZFbaZq-EiFcvGz4*+&FGo|xCX?Z7KS{5-sRw35e|nD zQ}I4AT4x1vT{AB0SLa!I!6uF1)Fxr&RIFnLyM9a>ol*Z)Wvy1XkFL-_95zCltv@6o zd_eTA|EX55?01|yzOg*5_5cG!G(nlk_iiWejV~-L@h&IJ7vKp2L*`V*^f63q?6~yw zkw$Bf+rvSzM!gxDM@JSA{1`y_UT&~F0e7^wo2|8Tefsq2_u!x*EB;CG*qljp)%P|< zAaH=3CQp<2RaBJADtQDj<1JKu=e?d)0%}7_R1~6@xA&Aq19C&54+;wJIYe-9uzIDc zSTz0{kUODV^|z+YS+Xi}JzFCqBilGQkWf`sZNRcQUTJa6;C7A($DsUWG=#29gM~pM zt#`K8fxKP~q#e;7Qd8!-F?x!Q=A_pXT{5-Z{Ok7SqU}5*|Ah**mrs{0-CR6BPmLpkhj}`QE!Itv%s}LF46T=wX;K z`L!t&=VuD_ssh2eM&`a>LuO*q;#gBqmgdBXw7S9|*F5i2m2$Oe3LxKT)R`#g=#0ma zOTB>{2n1|8y{r8x=?qRZU`+7x@^Z1ZPqpT`Y_l(v#cGk!!O@Y+X&-eYnZdOr(y5M3 z`}=o17867tAD8hZ;qFuNCdLB42JBng`aLkzkbzrJ$ZL1%_zwX zkgd)_U%$SWknoK;&RPF~2PA0;}77j!dsIEAG<<^tOWBNc2e8c#dTA9 z)Ogm(cP{ZNIR1palW(4bvI1>agp|dDq!X#MJFH%-R51W0E9mao9hFGn=TGm?=GYrh z(0hyb*M$5_Cp~?2#TXss9+ShNLe)OKVYDo%oVSEO*~UN`j%GuYCYW-3*y8nFNl%XH zO9`io)#l7$aB_&`?7R@x3h<#EUv}en!WY@|0*mfHQbdtRT7e{=Yh@qA15p(&=gQ;qZ{`}M7RvQYW60%RadceJ#% z*!*+z_a>x3J48jW>d$3f+{exfT+*#uHA$ZVYW6WLv8_UMVHi2%;X4IFKE}}Rp$@pS zr3jEC&W#%}YOn^H2@ZFmU!!nsIcTfE2(9QVz31i6Wc~m7$#S) zlO`4Gc%>AH?=qkCIpPL-UM|Kfr6@8bE-W1M&?XhXoav`!X^(p9X7z6nM4ct-CeIa? z;*9lS1T1y!@)aF8OycEwUqhNesSEPMqYKZn{bSg&C-TmXDfHyGv+1M;4(BZom`p0q zP6Y}cg^&wC&5TblKJgB^H^1>eZ8ImJKXa3^J@fCKZm-Dxz}}qk36HOygd?frHgonL*J&EiWMjs+2er_l8EDAHyol5R~?eop@6tA=3Hsq;XkqZztz z7`M=WjBQeVzOoPZa*M`Ocwuod1_{a8n;`7`1Lb6UkSWhp3g5#F5{a0GPh44Wm_BA7 z7HwuJwBabK{%jh3yOxU#-#8?xqo|8YTq~|d#w++tl_1B`u9<#72jx}yY$TbgpGG{a1XH zy2q$mRdCtJ!k&m8>ew;Q7VG=>?-x1#9I#xWP9}U?D1V-;kzmy9K+eQ-(zr)mO!ziP zd+iLcQIxpH^z1~a zA3LcV9eqlqR#TjT|8!6#Aw|;9*xO=bd5E5$wO3Xc@+ZVrmrBkFFb&0~%`lUwlZNm4 z0yD&)fBAi?uGKpwGbl%Hz!DB?-BPoiaYQ+k+@p8ZL674A&xG6lp)I|4I|5|_vXsok z;2S?vo;%t?AliprLh2b9N`k4|6X$~nE+o}!SRO3-+?tOVG0^O-(~t@vLLb{bANA3J zT@1I2nHTvo)7Q&FD|1X&Yd`Yf@8XwuF0qtaoxGL;#-~NV^#J`@iN$9;mRz*p>0UJ2}Myycq*u+td= zzH2Rb!NNlEFh3E^UqATs=N@wchWj;WAnQ?f^8{H_s?|`MLjh2CuhjR0t*vd5Z00af zH;-3D<>gTwcSko%i?f8QUkw9|4o|ly*H{2^`AII_dam5eo&;-P7F2L=?rP1hGr$}z z+gg%50R5zi@+iKUZJP>-*E!?_|06&EdexH#-5rI8g_T?^2mhkZU(1$#{2rgudKue6 z3``Dw$3a6AQdEosNKdCDdx!r&H#lqE;+4^tT)j%)W|uai;JUe;AFN$k1(aFmpTM<; zX(SSDt05+o1C4Nan#5~a@r*oZ?<(Ypw7tZSJ>lyWBSo}$2 zP9OD;fW_dA2ue_pQw$(J|NLZvRjh1tC;Anmgl1z43+^kh*TeU}C#MsOSxVP~y_tN6{Cy>)VOh1l9Fw^74N(NUlGdaMX{b2$ zS@b(yidU#9S}lq7={WwOVm{Fb(;quxwOz|7&h|;m$@vHXS%AGGf-s%P+L=?c?#Wnw zW7)p9xfBWo!eHXy)LDbrljy%&oTnNM zf1!DY6q5#tN=4m?k|}%5>S&VOfWNkfUzX=sC81|3M>!W_c9j^WJ1*V`MXV+28CT`% z<0B!2^FpoiC_%VbrNRFu;8Ol2;PBZjegj;QtdS8J0M_5e$9G1OrLYrGw{CWpBTIE< z3pxhE`1P4+k-0NX-rO6qz^PTXZeA0*ZR1hW&F@uo3U_St{aiZf{sWMxTf0~LF>E;m zo;u!zTk?cN&sVqnaGd`1ap!bPvbXh=)e^+^TjR2JJc zUZ5ws-xGKZU$QdkkHA7U1b}a<xZt{P?Ejuz0eX^E=?C2Vnxy0u;C^KY!i#X;<`ZWLwe;Rg;vXWj%8oe zue7X}e)YecwYT#E1h3h2K{y}o&ej&t7k^@4i0$nac5t-qsL|ia>&hi!BXEwrXw=iZ z)R7jL=qxIDJNfTdK7ic=Y&#BjE@z=u z0v&11jrplgx1Ln;KXg4(oyD>3S&b+CFc&Y~X#0_Emx16^r&c)0#ryZbSyDfaqk!Ev)U*n)N? zgZvg9>$L?%B|fHvTOf>kmsnZOM`|Y^l!@}pnOKL^`U!ON#ZOg)3*LB+_^#~4p95%~ zg#%%b)Z5)^J7fwKxs2TZ74#I6pM-j-DB-bac6|4$-efj*E@*SQwR`$iO~gDIb&k#@ zzQ|r?t@$5fh0gfid`eql$|s@u-sj$QL!Jt*c;VNVqIBkiR#0W|js&V50r$r@mKcyU zQiQgzl0-Z%e{Fpq3C=nn-$=wkgIaAh+p@g80M|A5PzsqeR2-Z^E!&QMfPEbtPNXFo zm${&8}24zK;vi0OQsq6wXk>HkH+)dy8-9*;(VBo@fYW0~=jEB8_0NdiSG%z}b~ z^Owgn9@qa4hH~!Ia6xNhwVh=%H~PG4FE}z(07>gA*V&MTt5td^0zjbxNdF)A!{Y~( z1cCX>&k0CrfUtxMzUNc+dI{tEU@XD)-jBJRU_L;);+`A$w7clG=v4Ka2MC?^G;*iN z&!nUP(ftmPDgb6CN1o~fBBB#9jG%=D4Y0$*c780s!S67%@zt9zL4eK_Y9iVZLIu@J zw0yiIO*2?QR$lwmdJi$|fdmP1H25+M8H^5e^u-E|d+)69`f0>+=2iVog zqidi$rq}H}w$ttD>1l3j1KIBF?J23Ne{*qRhk`-;2;{D~IP?%?qKKv@*M`)|21_*> z8k%OO19X6&EGa3$hvLNk{<&-(%HI7i3mumPRR>gQiU788{x@x6t*{100!tn464u6e zFa#KF@R+8Y9t}8fZ3?=2n3ysmWtr;1FKx5wF zc}wx>6C^+k{QC6^VzJGY;o{;#I*T_okycGnLqh_9G!OtSUD^q_)mD6fIqIk0!IFh0 z$`kcM$Lf-8c@r2KUdrm<&8Y9 zFZQ#2A5w4LB~?HEu)mql9@Cw*W8RE!{rNin{CBv=Xv_7IAV8s?%vR^?FC|NjLmQVu zZnig%Mct)TwY+kcxL0!clbaXyUY(pEQt@B+w#OMt3r-*zsC%EY(9Ow$%4M;LVEuXp z5EFeY3E+1OPIlS`Eh%oVn0JmufHIih&U4MCMP5?`o4G( zdz}jb%#9qtU;{!7w3UXEZRb4&kZZRS)pUe%<$ok5_FwLd5X}P>rmJFO;X@brGfwBz zu#dCS?Nb)&4no1Poeu}tGyL;L>Y4pIf%u{Sm97~^6M|@ZY&c=T-t=fwY5O@TG({%( zhd`>ut1biA?en`GL3}ylZx_d=)K&L|1}AgpZI;^sk9_GLz$s%(w)6AnW!JZkCwmXv z#$DHsXvqK9!MR*{Du{Eti#+kasQ-~T42>NUIubE6H0%J0Q_>dI>t#Y4LjKxqK?M~} zOOG-pinW9Tps$nA64M1P3J=wVLSH5M?&s{8=RGV`!g*4%vh>WncC8{|foYGVXtg=T+Tjm8=Iu|V6^!5&@GhxuNk&*m~ z_9`l~S5;f-mQ7)lUhT(Y@xv|!s{OsULgW5vatY~q(j!&lbsJOlQx}-6@A5gny9Ctt zthmmBQ@)71nXc9mmaRoTvf?Q~NPc_2p|QN%$l-~f$)2z=|Jr{y8}uf>kEida@4KCy zg-b^XR)S>5E<;O})k1v!v=tbe=ABcmW_x2s>^T;gzawJ#{Baw>LmO$nx;o!%ka5~Z zuIL7g{kfW0$}9{C&)9Pi&?g_*e9c-U`jg{El55M_yQ1Idovy8-X zKXzi|7SeGBV-y!;gvNI&w8hLa)mm12>Kz|pj8LOsPUK2S z=KUrk>fQaMTtCiy=(y)#q=HP(J96G?@>gD!=|@lnKkn7FI(WUnYUrI6r4F6xd;O&| zz2U<^A+6Yk?k0hx$#q__-a_vW;ZeaM?<~~D3k(K_qS#dy(wj?T(c`nCic0-}tt6Cc zJGwzW;H zYzqHkD$=ZJuO(tceQDEo`;f;;@7jXpHtrn=@f+VxyH^!>A~>SW=BSVVSu z z-LxNYcQ^|*{;zXu7(Mb(4^k%aZaeC|28bm|1{T=g#Z|)hQl6?d{qzz}ogU}R*-M+& zgM?719S8kbLi=J@V*1Sm7aZA#@&~5J&AJt8Gs;ki_uLZ49AznZziEq6a39vDJC^G3 zW)4*O3$!^dJ*MrMN=py~D#S}I`FC5^M1#xl#I~|cx3sU`MY$z3kIVB3q?bj^I`UR; z-1D7Ng==W+U$YYy>dN0wZL5#6^Nxr)hI2pQMrWF!g4pn6L^iHd5Wg`#1f8kjsRAf~ zK{38EE79E+yk+WZaQ4$$d6ww!_7?=Vosm#Zvo*&7K}^1haCvUXzP}q1@T48FL~49NF<&LuTykMM%L7Jr!l>GiYy0npuass5y3($ z-DcNf^0FnxVbPkE@&0@?==1&@2az-MInR?Y+FjQT3em^<}esx>D3%3zCo0vT)ETTp^uYSpGM!yYH=(V;zGzvcfgr1%WhW@v9?Tqkh!e4 zoPjYgD-$!t58LB!E)8;t==Pvu_!v)?dc)B!?e!R)(3LROxsa91v}>bS)wSlh0+GgQ zAckD9vrT>c_;`|H`S`we%!hhn@YV!8{(aJ@@FXyz3p_HI@@YJ`IM7-Lw+s=SLhnJd=t^_lN6t2rPr-KxIJ1!j|<8tWm8 z6mB?MVv}WwP}{bL^8$K{_ZAk;4tsF<6drvb_IIZVML&X0t_B;b!wv#jVHy*|ACq-U zu-O53;G&;ro>^NgMTHO6;0S1VntPRL(QG*rxXXc7Z^sV945LYr!GvxwmK_^mf&G{W z=IfWpUQsSHhIARL2uMa$=1b$a))c0$tg+7I-RTS$KC~Xn>_pi*i54H+s)iYAuU&3Q zN9+3RCm8$i$_3eBE5)h_vDM3u{oo?`Uk;GhDwU7x^K8f4^^eYO^rB~#y>smWaZ5lD z?7Ps(el&-n#`slJmC?IqT9uzyfg-`-UiGPOCpHeXF8Y_d1}5*TXUyNKUQN*a#A&!* zwSSG&FZtW*oGCa{XB~;p4qH~jC|$!n_bjEQ8=jeJeUr%&2c|iv9Y>3|w+G5|H=o=O z^Ml-N*{yR{v0O3Q_dZ2r;fV}U5S(~di9i2P8WDO*d+Xai{iYsGa=^BB`aRW`BLTwr z*hN#_;^SGoh634h(v5zLI=p5byR13Oj8_e!w}WoIU!xQW;*L~F<*C@6D9p!1My2=j zA}#d^m>UsiGGWMJc;9$L=-Jxnf}9Vaa6cSmz#H?_H2$4d#u73sR{j_;d1bTMNSDi1 zgrc7-xc^a@bi|AX{?Bk2p@>s!aGIP}Y?}eJN;bXtSbNOPPs-2+D_{S^t#=u0Ewf&i z^fH@jlWRtPf0({HQ|~PfC!04aZ}YZ8fawwRlM#9FKFB+A-5l_!TMpNdxWz9Ue2}$5 z`VCnE;%an&n{Q=4?)QIYx4K8D0p6<>eZIRVGP^f(5C1KheKLKag%t64$mg^!_mH$S zqtEmQ-VWVxrj8Y@AC3utO2`Kbs1x)uBvBo4wN=?tG7@OAV8E;QT^J$DFGiehfY`fc zubOi#pl608u+0n$+mhomGjHn7*BCOoTEr20IltNOok7b_+Q&$9iwJ6y@&w{`8IY{r zj5kr>Kdh;IgN8+DOo>6*`iJvy7kPK2Po=`XQ-_uvNA4 z;x|=vA0}^N2@1r8U18&2I`G9#?6zBco=oTxJ}4t+B^mE4^@#FuI{~7oL|y!-mm*Y;&C2pZ-B{1 z-Fm9i=Xk{Q`?X|eDCk&q<}__$)ulWY!a}G9w={*5*!7wi@EVY`nws5D)h_W@Yer^@;O+x1Xw# zY{!IGa^bPj#~%h(b2+inFq$lDvUgR6l~A(=X%XJerVK<>vLW$gX?C5QRjOkul>&TL==^_5sGU;ozAs$pDA-&EOQfKdoyiX@zlzrd7oMRM4)|(}AkUMYq zTm@eCK+=lzK9us#2A4?;qGB-)>IjZ7g-L&d=H1qA;9tns6pX~nBaIiri28KsR6SKa z)AADW@01#_!Cl0m84u--HZ(oK1;1(}XD4TR$hBek%a}FUItR?iRyx-&+K)3OmA%8( z4T-x`1?kde2H2YMsYPs}>e23IVmB0IXruoR-tb75KP(~lcK%^wX+ z((iuwR9h)T+pU=qdK4E4Cvo_V3RFtRFrZ@biKYRi=SDi=m+y?z?%WN(mCwjMYiCb> zcTONnaz2AVOn(zy!Auke?~(#N!C`9FE#hC<?^xu6{SU z28+H`Bd9%in%7j3@3-q1;Pj;eUGB69HJiM~0apUb3@IV|SIg$Hbu@vE_J@n57~Py} zOl#;G-;T~RazJ|e$2=rJ;A88htVv4F&sw{`EeE4nPt=y{nxNm5VOG0IqZ@F4azwrK z?&q^tQeFeMg8Gs}Ud^TXa?P$mr8GtTt-Nq1$h_jcs|2yk39SC;pRd%QDSS?v{MuRR zumkR8XS(78K|FOw^D~WnLkucJIF5b}At?Mo2zPSu|EcS%!=mb}<$?(XhxxO?>b-RHT_z4wn1JsfA|oU`|ecdhqb8Od8* znGYT+M%1;f#L1Bc?6D;}h|@NZ_OvHhqCU-39!kUKcC37r@sdB_$*l-1eZZZKfekAh z-EF$_&Z@St!w-}pwk_NTB)lz2=Gbx)Swh8O9HDh=#oJeYoRL92D=h*qQWMWjmJ_a=22dii+6!jG&2k+0ajGeNqNw z)KvIIXzX5msdGn_QMy zEysiNi;W=%ag6uu%^ioA+~vJ*j$Y-rlXHDNGiys5KShbI9@)MFl8%Q7@c~S1pVrK> z?(3iXEM{p!JdF>9iH?i{@3_OZ>S~wZ0bPhd)q7T?qu9LB;0y z#=ZwXKk5}FPL^2fi+e3jtkjV1wd?l76Ks3OI1?^sPKDr3SlEZxS^{4j<42xI9=(~M zC9-x`g*FwwpLN0MA=@|=8(Sv8%I|7YoHubCR$aXJmiGAoq~)RO@-~UDMxlxW-|>0= z~Owl#Oa* zZvoU9A+S0UlhflK)pBW@0;BN1)fT>vS7n*mb5p#vx!%eQjx0)5(Nl%;x5uWJQ!TvD#=N30BNx4_u=vImc{SOhW}s;bGd&~7m{2!_yi6kn3KaDx1{y6JcT7uxg#vH9G4FWO5hOah=W~@Y@*C+U}5{T zV)$~NYIbli>XLgl!!s72`Yw<$uzGa;zMjR7z{>U>@d~n0PfBJ*EU)#@c z``$*4Ccanw=o=ivmqpGct9O#7Svhw8h!4VXP6~~a-Fs_yAH66S5DRp(3wBa3vP4KO z7d+?B_-Vlb7mN&Xj39uI5+`4)U%wc(VVA9MVn#@I>Z86LXO3i@@p3iiEBmyYx>2Vc#sItmkFTb&P_3B|kVzjgLCv0HSw~?pD=ow$pAsvb zsr2(z?;8S9_tW_!PLar$qLPaj%a;LSvfutL@i+d81<9Nl+m4 zj~c@%ShssgKH;>G;IkYxO2l4!`FbI=^GEmXXIy`To?T*U?vl$#4$`XIo69(MV_98d zWUYqs_6!r$Vz`VBBcRU*wH&c8iX-~3)F@#mw?T}sF)g$(R|w&4$fJ|xh{dTr%3XtN znZmT-x}a!c3D?P<;ZMx<9iS^-K~7a|kq_CkeSJJS2r2|XWf^pJ{?M%YI-IBa4q0Gp zdM77mb!au}LI5BkA-uF5t5F5JiN;@rpN&X@@#{k^4Jq+!RK831u;A`+2#v@$NukV-G^w)s+_%ioLsuzuWbO z4g?tB~#F}eZSLfo%&c%zU?2n~dfeRDoImXZ=*Yxcve60(^N-fzV0}7NzEi1t|>I^#A zAV%ujjo>tV@qAt{yHVq__wr$(q0i~p?cp{J8lbb^Wi2&utlHrvXsjlCpZ5(E5AC+b ziW^grfem+Lwla6on%Xb@nC(-ME*193&9}7Q)0G}~WSE9K!@u4t$k+Sp#VuCq z^-+E(c0kd2mG(0bl-a@?8f1d2hc zNjl0)IO$1IPI8@?qWT5&27q=}m)q;p@k*O?Cn!BVy>tR6Ze-_cYwMzlYi~@7xw$4^G)zo( zhYe*6JhGtN+@YGqa$-;3nL?r)%SH_vb$`jNI9acTtP8szf<_nFQ2Oh>>D^|M zhvN3mm_OZQR_sn|2vwIa(Z7r0&f{!+?fx8Ub{CuTA@qx%kI&`Mg{E0uTMpO2XASM}1&C{x)v=~iYYv=c|Ylh34;awhAT$zzUQss6f z1>O&=unDvW_*de2ep0V}K*o7AD)cGS4$eVdGfy|$t#flgj5Ml)azfk0Uc4e%gRFq9 z2G|Z=Zae!%uxXoia==+belum2}3>D`g|Q2U!hA=+&XWTU3e@53I27)U={6 zX@XT?lens@eD`gPQGfjcbcEdGawQrV4<`PV3o3@m1K#OKOcqdeAynO2IV9gz7*y-@ zDt(~YZ$XCp9-Gp_C8-ooKz_QQQO4N>Oo!Y1hzc7YCHF;HS(zFGk*TR^?P71V z#eCA5Rbrs!p0XTEK8&ho_^@Z4WXLxmH3KCqhgnJu$1)2QlHu_zY8Q{hBNyokolELL z-53GC0b+CGNCKGs+T4eiI_l~hNrTZLA@{7_tEs3way#9j77&=eblnC$>rUL8qlH-- z6_%bBW+OlLjWqMMYNGjeDp4alTXv>vfwChMKCbzdE06S%@*xTjoDB{MNh>cOIn6-=JGt?a{bGlAH2mYmT9s}ZHsKbD=Mi>vxBHDN zoZ}5u;a667G+O=FGFJ%GURi_yP=uG@I9OX2ThN7H-P+$K#LL z?c9z6ZIOL~Y>OWY4ba=SvQ6zDPcO*fwHrKygd6d>=k}MP2YC6YDR!Dhjej8FM35*) zg-XV6Fm+$~or@9CMTO)^0W1Pj|Y(g6{-W3P8XiBt}d!It|Aws^7e#u#gfey{1jw6d>Bxx@|3=Gtv~Njmb(1 z_FT~1eJETp9g=1uLvN`?ai#@Y{DZ^7j=SUsOv^k!Xd6?ps2P^2gI4=}!Jdu|-Kk0& zzU$ri@vp6sE zySNt@7pajV9pG+Y+j{ycoamS5b1q)a&h`zZ9({U2>-6ra;sKa>#N@8hj(>PkZTxu1 zkWfIz*BO3|trjnUc#dWwfa1??vvWgcfv{Pl6^KwTeK73>wN|BkEie`TVNgAG@}|GJ z@?<$N@viRS5amTGV4}1qIn8vI^a^$X7ptIh9ObIS$jErLZ3U;IruN_3GDi+GiDvll z>!)GYRa+9SYUlgj(QO)ch*iL})(n$aA!RE$QjO1U{ zuOLK4$>rFwd5&Xz#HjB6xv9C0cZqkvVta9trwU-50|W}1&>S*t(mc=W;g!l*upm>J ze+<)S7Mw=<2n860ns3d{-T3T}AddS1hXzcJpgEh8IBX0BA062P8w3bU8>Y7!iC~pKASK=K z&{S0oY}HTw`Sa_`!rF(xuNxRpfx$s-Fpi5qem{ONsH>~fF*1s$_kWIyTgRO{Q|xj| z-xhq>oNtx#{!tpMW6JU|J?tSH%hin#*w&S1UBb|%Dm#j~i5-O2GSh4rjR#A>5k$n%Spx!b_L?_czm?hUct&nH|Zm_2GYU@J}ts5|*AReXLh!0n= z$~Ro_5-KuXeTJvJ>p z7Di@mT+2t32^DF*^^_L9d42ZvgvVzJnpL|Cmi&(s$I30BJUl#C%gk^Q1wy2=hg#Ln zZ(}-x(E5s^;dI8${it7ZX=w>Om`)`*pc*x=d%Q7>Jm~2V1==^`!0H10MeZb7KxK5E z_a}BQUzyjuwc;oyPOUoQTGLmQ2gyPObXe2RuKivq{dM2-(_a>5zZ_uLJq}iL6E$sC z&~ih&J~?*`87U#c;b6PdRY)Z?LeK3sVy)2gK3HwpEBcAI*8~>{+WQH!V`CjiO8fV> zk+Fc~1gN%C@Y`!ITCu}hX~|}-eSGk1qIs&^KK!L$k?}g z9xrXSwS2GZZUZN0a73C&EM3tp+8(JPNc|=kI@caFFabhd3h?BA61XCOJpj1`DkdH> zLNh#A>f}yJHcS+~+aC=!BN8xdVeY{1K*}EPznixnAJ;66zxvsY(^VU7(oEU9{*&N4 z?n-@La=SUtFTTy>W%*<6sjN;wmJ)pi=^fy#s2d+#D@{cUbgMtj!J_umVyaqt2o{PQ zh(+f*LwKF{o&aMDNV)&HrI*kCs;_9vl)JuPsq2pRH6xkvcm^)noOh3!PwK|$z5k!# zkULW&u08>>VkQU(6DFw=B?lJq;tS2y3LLqs>Zq6)cHKq@kQ8_=CWZ?7L8sggySHZQ zE<>FT{>@Ws;Qw1p@-&=K&vX(r;XS5-4PC?d95Franod6$6424txyFYv$})L+0PY*| z5wA_xaDf)Tp^=fFpvN1j=RrzJdIwn%rTmZy+Nc{CkTjzpoj6Lqzt@py_3z(AGP=IV z!1904a-#nYz=9(|h|s?RVE_HPMQ+7yR))FMfan@iGc<1w^`@e?Vh_e`LRFBi5hWLy z7iA@M5ueV4-~?|+{5**>NISDh)1i|v?bpJ%=Fuaa9aqGJgxy@94m$NuDiJZyh{aE< z){_aSH3|zgDP1J@w$oDPNleG_G&3ffJbpe;=e%a)Aa|SVh}&g9TxI0pi36-!R*)gl z3p4%wzCE2)#u6r?LAx%vF{i<8!vhlbZwW-Rn`BjHvX*|R@0?$3XoQ!sDuc3|znB6c zZ@bnXN(uhXvm2+PD%dNlA1;YwL1;#r*UuW(IZ?#q-^`U#f;edj>@*y6j1*ug8MLaS zDl01+3l3!yT&Sy?lx#L}ytUA9Yd(FB)46YdEQb7RO1~Y;R2|`TipEu&38t*bq;aCo zWR)x69QMO{u6s}R=9^uBfCXv-lKBdfAzbsDeq2(HAYh1Ci$46lw^t#FZbng@WCm|= z`9_xr_;vZ;dS6T36}d2CFk+8h^iDzs?XMN|_CvQEsA6I6(k{C%lmVGIRnamtTV{95Qvh68S+f#D~-3e*E`jx(oTCTvTo+ z4~*QwLHySe5?`b2f9p&kG63m7UPp&=45=9kEQ)v!==^3;svO7hiyRrjEEP#bGiwf} zw53Y&EzOoO`hCxKTw|nheYPCjsj~)s;1hm-{@{lW{ZMpLNT{;YwoL%D&5?DCx{B~Q zV8rPnYsdAy=>Vo@%+;FF5|II;rQ3dnRc}QNa#&?zSZOleU*v)yPpJ(8d3^ZxwTLo6 zF;Z)`hyXN$F23JmXL*JX0I|sU_}{>%t&bH`spm&izl(+x0d7BqOAEmt9w^t0Gu4L= zAAlOlKwn=Y;4p(n`=vrBy`RPKHz5W-g|xFXw}XQNa4XITIj%Vg`^sW4vvSTOdstL%NtN_Xcf&_cMhuY;tPCI=H%O6O(S*A2;5@t@I+()-;7a|=D_ zLFqG;Nj1E|MO!aL4$cBBTL=-e_7=HaGcH$3Zt`K&{{za{*uG^#=GlNh3+Uz5PP?*7 zN(2DIpx7MAKMY6qpp5X%6>8vRDrQ{YMWg%;N3VYU z1tCfazs3v-7o|VId`iNnC3@;Tj>Z#RoUS;s0Zg|)&CvY-*5@H>dw3sDr%ECwo7>@)ijqdH5USa|nml; zw?dor#NgK@Fy2$i!D49m!89^3NqrZ?gq$zqiIPoV&r1$K0X-0pA){%ar-1|&G?|Dg zJdCy^`<;dr$H)peL5>wQk%0ip*+yO=@`apX350w+y_*PjDi`s9KS3VJ&9&`ftUywz zf$&T4KgjX^g7J_1sZ7caaXSZ|vi68U>npnD8rv~5JnCY*fr$N&U_1Aq+Fd`GQ9DFi zxvgftrY(!K8?nXjs$o4vd`k&|BSumsFwi`- zY1QYwc-GG2~^7m`WkLHK%od3p$@Rob;aQbh~pFA;D%DRMitR8}zryJl;)VYVg= z1h}pzTb)34h@P3*`1aITG9=iq*VuKASQ+z`MQ3I)gqA!4h7Jvcnv2xM-x zClh8sIK^hE;{o9AyaoVoaL7U3%aFhR_pFNVHcla{Xkh50B-GV(UKQy>!zbEa+|=wN zmI&RY9Sdjo+w+peL{bZK;^iuspYMJ)?tH&m`Nt~`g^UqGx1DCK@uI&JBX#OH-)Zra z6b8S4Q(2s<>x4SJ9;;^rJV>uO04Yb2mY!}?GYzD3?qOrsU4x5C2kHpO#Rep_krPa9 zY>In{>J!wJq`Df~(q+~I%Wt3C*R`kBZ8nS%O@-#c4CeMY*J*o>nNaK}^XX_qqAHm1 zub4VJJApYo09sLQlcnnUI?E`IlP4hyhFH~{8` z10rk%LiGIipVH_om{xIy0B%euj^xM8loNRWI6HGTH8ZQ*{u`hytZviZmGHk$QP8fy z{0ii93#%y`XL>W*rwqQ;p=ntr_je27DDUiWAtLG?jcZCgPVn&ZUhbpFWJ$(}Aj?MF z$~^ouikbPxeg6jrV0Hw*5&%q`2#^j%g48BDiO(r5cZ2>o6C`bCle0GxQd0K--t<>= z;=@lr!>;J_Fg|F(*Zkx{3rhV;y9d?Yk-aZSGVIqvfPEiIcPp;rc?5D>5vrRveLkD6s(Q_ur<`TlR^xbW3PX!VL~I#p*R z1hEAWkW$Eqp6c0$@%J?8%XK4}G(wn`=6Ek1vv32uD8^hQ{(otIM+u>9ByG(q-%+6)8lm|69H`88VZ zJ``>3>nZ#Y93)8)vogBUZ8UI!={SYANq>mK@nGL;^_9)2s&|@5q#(C$)M^<-u1zWB z=T9~Ow&oNTwwrTadZ3W;Ife!W-35%CIy+vc9U$bjACB@y`bdW;HZf7!Fk>}5g!bmR zE?q}d)aTR<@bJWmwORoEEx1)5g+ET#f@j)=k(pUifiP5Jk-mK%%JDCz7J{z|vHxC4 z(~^Q?oZO>*W248X-P07tLr8&7Mh6yC%$vy^F3@GZ6R$WlVcUoCAnFx*J6GYN<&UN^ zD@O3R*IYwI4;x9R93=Z*Q>VYCHn^T-nJTA&0K&}LP!0h|b7Q-Wj$8$Xhlf3TzePp8 zhQYE=Z2)*f^vNHj(*?B$NZ>mxEDR}ZmfpX{P5^2lFcXthF#RP=Ld?i0Q^$G*t<0Tk zVuy-#>H@=5C#%Fe+wYyi`s^4db~ zB&LjFa$r3B5&9fVWYX%{g*?@SA5PE_gTWC12K>90_1F4R&1Y)kii%jQ^!CG`Tx?+A zlhL2pCV*)bjhoL1_XXfW=@=MV%sK4YO(~LBvjm+brp#VBR|z(9cl3-t5 zQ~b&$38t}Rr0>N?)x!oc7pIN{=i16P*$Kt?ID+F~3yL-s9CH)rSOo$)qGpam!0H2J zSRWLyG#!Rj`~m`gdR#g}0Qm~ZycG+;nXhQL&Ogm7F8%^Sf19&CJwSJ?JYPwuI{5vP z$9fLQa1zNI{)#~03xi50@X$uT{IEhvSnmWjH{})9OL=%)2aBOJdOW8LV?~is#4jbU zUMS~UoGQJm=@_*~!m&-z*P@LEV(kMh?r5P9vtH8%3lIXOzg-Jy8^V-PewbU;p)@x= z6RPe2$E8`YA&!bH@AC;O~dDcjn_KaG{a0 zu^ko_(@5J1K!uc)ltwokkj@)6dZA1?FNPg$41a34O}WaIc(aZ_ zf0jDFP;HHuwDalQ-QOf6Czp{4GwuY689@l4){kr+PAUpuJvER3)M6f>T%Hyp>H;3T z_=e6Ao7pDWOI=!@g0bXMvewz&n`;U0_K0;#^=9tDDDoVc(!i1*JI0D{k@nfu2sYa# z-P*ktnmRGMd#}xU@Fk4Bpz&hp$rRCta*tFXd_x4Nk;Y9v=-xmd)JEiuoZM**767>b zHhb9cw?(u!yxGv$uHW>ai<6zV}AyU-)Iq=~VmAt}VF#6O1UN(GYlfIAhe+^a^KJ@Js9- z8YlVLS90oGzC6(tQ*jhaGXW8?tkhCDNKA7H2jjfHrvIij7X^0Wv%h(m-`Te>$i{;p zrC7#ghKW6W-9sl^jm_dZmzN^xJCdUYgll5*o8fbsrx+*0w|B|@W#E2ikG{qO+2;M1 zgYUcP!0lZSrTOccW5fx@05SgW76yN`M2P>@3i{r5RRks#H~z!D8jx z8iri!&G5TD0o1qP(*`qT48RK@I($X%{^s{VI!Si;5+=>80YgQ0GJ;L0ZISj;@P}H} z(44WKp>^LZF!R8j(NqIK$>Z@&2_{xtqt*Ga+6FxefT%&X3Omvzvlx)Y+JVw}_iB%) zZe0~A)x%!-i8@l!#-(wp06~U`@0U*sxja-yXt?cLb7TtkDStA9p8$1#Sz7 z=VMvm=q8d?ffrjWSC_}%6&5H(pV}C=5L4*O#1)MkA`qtx0S05WpjX&oArHt2m`{{; z7Rvm0F)zV(szQbK%5s~ihSR3H$KA5kjWI~z4A{XUKKUJeoS^R>incUZO}6E~^+y)A z;5i`0A>+1gyc{DT?Pe4+CLl6j@|9s$Qm%qJLA`0}m|{W80g3HC4D7we5nnT#nub-x z=iQWbFqLVN*r#U>i{AvK?lHbA4VpN)*v&G9Dch_YOV6{&C*ik#W~*6ih4EoK2a_WG z&UZd+bmB|?fY%W^DUpY;de6DVr2DlePhsfl@T0DtMD&_Mv$jxEC?-U^uAq(iwg4kV z7WDzWGS~Is)%B*%?MC-kpx$S+F_eQt#(iH!1YKJsSmP@Ibs8{d>1QqU zW^9O>*^J5;v&>H(ncg*)k1-GUs41pa^kppQIU(WH6?ap1%4`qB;{J$BddfaY6T7On zAmQeshp zOarc=gK1=*f_yQkmj(f0iRx}cSEnf(Og%k4kU3+js8oTvG$5a1$no#Lo|6Zg9&9hq z2R(3>7jLk`AD*};$bG|pf)EhT!Fk82$Niak92f{26t+=Hz47SL^<;i80Lx}n+HxUw zog?Dgq%gjR&4pMl!iv<-U|pNv9oD=zZfs)o%m}I%kkzLuN=TVG?ZhWI>V>>@X-eJ4 zP~(&??}Ax}wS-ot+h9!WqU358N`N8sxitk2~}@mvNI-8C6eM?t=UUC zQdp10u|EBm@A(}lp~`uKJm@jo$Gc9`4#clsy@DVww&C`A7YNNMXlOuL#Qv>yM8hFP zs4b6HHs{OwvThCatrV^l%)gj3dTx1f$gSlSEe|?nz}e9144{P(?br4;6pcp)xV3nsaaKmO)ZpQ=_KTY`sT(ppbHw)>TT-JkPUsKg19b z%hZoOV6%Kj9j?;5I91JIy=DS3Eo5mCVp;P@JbmAuF8|guFr1t(jqV;GrXQBm=N}h? z;Q2pr`l;ua9ygZXMm)0bU}OrZx+Zn&@-Vf#YEaldB~pv$j1cyj#&~2I!S`Xz&>NddM~`sJ4hs@X7jh>%^7tif?h1G7pO%qbN>6H+DM#llPtdY! z*{;e!4HsV}Qn@Z|`XOD$>*6uDG8 zC#|a0O=ol|X9mlfVZQK@-A7_Ikrw$JHaRJSZft4wiGd#b(sDI95x0$l=3<~4=>1H{vpVLVMB;~6d|(mMr`c;RVuAX!EhBx9PN!e0UB0Nfe#pi6J4sDSKzKwDa*NC00P}*!tA-Ndn@07h3sG{ z=;gLn>u<@Jcbq5|{I)zDu3itdIQ>Fm>4937dq1ogm9bE6e<;4%opgdC-8yDh)FM~h ztsl~xI3hgiWFeMMw>MO{!S%o+`+vOQCSB4YVAc-~jX zprX4F?o4)l*^rQ}dy5RFZn69O`#sBo5_2OzEwHUS^*QVub=3Nn1M`2`s2%>Dw7r2F zquRG5W~ko!WvIZ?BQ&`nkLBn+uWqWU)z1BUD^=e6Wp*uF#IKPiM1tzxP@xSgcv<@ zebTvcL(D=GbJqE9JNivyqFGi@!T_oVE1=hFyw1%@Hj(=aP}Y6^RzgBTG5>uD{PqT@ zf-v(rZgmU|Da$7DmYwkn*KBTY19f2(ui-+)yy55-ZA-}e@2RP&p(rU*ga4T}rvDy&r zpmQ#}63+jnO6PWOA~BnfD`Rs~Qc1fis%v(3@Zv7SYzjziOGrv;bU}V7QeLqNK;9=+ ztqha#9d;#NT^95IT+BPa*mGi^t&Q(l2zTFnC-;3O_IG518$ZDpPn$>tdHKY^pX8{VkICZDQ|X8Q*q!%!EK#V zh6aI9zDQDlSgcI*rmG(xPko!e#Q#1~N6j2T-i^?K>y2Z?5hJe5N8pFnzu_{5H%Env z>swMbyTpp)eTXWAkY~QeJ+JaK_ItV(4j6?#WagKQ90x7CCKPID`GBW?B=0#QTdRmX<>urU0PNf$E02Kn(u zT;coBBkZEgyXlY#>Gb|LW$KUKpcE}U68{23cqG#MtI--?7#R@?LjiOQx?<&Ce3ROI z2>C$*-k~4%UAwS?38g6Hx>s)q_-$*!5;wQ_!W$0eD?_8=nZvnsm!2M-FCz zQ~jIs87?1G2n15pHhlv*3@CvY)UFwtPgWDUj&-uA2xR4ZS8wOd@Q8mI=B2k|Pmy-ZTD zI}WADqh0SQ*9Za=ne>e>R@)8-#&37h?toKL>ZU{!kKk)--2#&rY=@(RCfsS5;CSCj zG)L&h+GO%Xk}*5$evg+OI0%^-eHfsiHD0~Fvt(7cBGa6PJlLTapa2bED{|qCG@c0} za77+_{*FlEQ4Stn#^u$zv}{EI3OLqR5KR-R4tLrauNGYG2{kTvzy(LW%2jfPO%2T+ zApcwRuK{}rwGo)|~ZJtyPmnh`g*gDiQ$_1Ox=Cq=bk91Ozl01O%i50^Car zMoA;VPz6iG7b}O)f#?$^y$W{>;YFGg)~X($YJ{MZh$h1%Vpwc z-$l5}u=EihIRi#GSn)eGz+*|Gw zOJ`T{JjPTa&!`SGqL1dT7}uP#AAxjo`(DZ1H{~pM2Od@%S`&5qM`x>3XVpfI%yv}M z-&dyhaI#c2>yqCqI`vH!TRpxGG#)!!uTz{!Q{eJ^=s8296k)LuMxzTTB*$~!M; zJC(DlS1rZx)ssBz688ivRj3ED6o@lWQf{;g0pz>|yxN}MmWQC=h^hlv5RUKh^b*c- zv2tl9LXeTiNcr#Z0+imPw)V`wCyUO2kx3*`j0{8ZSJ(u_Fc&Bd z$V8>4YJ75Lh@iTx-STLc_DFcgH#ac;Mx7h?uwX|PbtLu!L*De{2gaP?RMWD&*~MZ( zo7!oX_E}T2(z*#lIlh}oGpm-HiM?P-$W(*r2{BUe@IZQ842_csJ_YMdjGCHtrTaSrlp zrL6r{M2k?o1kObPtLy9wRMlozsVeExyT)Ds#;Hc7{l(L{x{Oab!QFga{ZwBgX3x5N+sZ3rL zE8-OBGgSX6hYihq1=nN_sa(se?tAqdAI_P==oDsp_QpPAhF&YB$Ltwb28TT8r}`oP96NaRqV4Y-Qgp*J^wn*U zg%FN*%PT_w+B%=Ij2h@g2+bzU!x0+QI6YPYr?Jmk3*sy_V=Z#c2DSkck5?6)c9W-j znvIU=&~rS|b{(TKeUTQUYwGVZ7Ciuv7~Gh;FrPkt%=4b97V#PUU{j)Jq#z0V_OS4C zJ5KON@Sy7o6%Ba&*cmaCqY>p$BJRr&++_^(j3zMLNpCk}77;F8h`bi!X*CX^0=)LK z9e?IAC5axDE+w}9DgQ!OV5Bt{ZB`U4#^zrAV!4Xg4kok_(t8(Y-C^%< zTjvln`<^KDIpn%E1yDzrDrcnNCX%Rif=1{Nqy(XirSO^JNA4jDW=xf((>-_p_jq!$ zDir)z`Bz_=vc-b0Js!w^5>1aw!C_sJ?Bk`jjeHpl^6=NikX^0zF|BpaHeuxsuMujm zi4eXkv}C5-X6y-{UWa_(Fy0jk^1&Gp%qYzzB-qJyU9T~(%x~{gJYS-o;U5YlWu;e> zJ5l*jSgGra7X_uYjK{h|A#0RJf0NFqnX7kb7#$Y(1(DPRa8FHD|yqDzO=I@{h+GLb*zI-0!;(Ux@HqQBY1}P@k z5{uuQ#>#|R05R%|Qc8&l5edq@Tok-rmC2g(*vWXe%GZh67xwm3RoUTwAn#ygK;E!I zp)5&uZax$R4`yM`JLs<;?wI1Q7cJsab8M_Xo^&&FDi6-1`1gwV%Y=7_27jVm_CNjv z`Psae&;GnfB0nTqlUu?F=UQU-OKk_83E$BY40 zwj9D+=e_zUzN0#_mIM!no=g7MoQhglSF#%kwnM~8fcGrHv=Cwj&cIlk0#j;vK#5ww zp3cuBmK#mgB4dI`-jApH4c9h4O_db(f`B?QT?tr%ayb!%eti};u49;$s4cPlA0{+X zP#__S$2r6g*>cEk--C7T>AyUyjetT6Qju!L5j0`=DNRSRi<@Lk?|nsd1-TrSDH_e8 z*LxF77FEL~K7_O2SULv^mqFcWvw!-yo2;O^Pba@whpeV8Z6AlMAt#;cg=~BgO{~Rff*{hg2<$h z$VjPrkkElSAr>DhKg1?={qUUx$PRISl7)w5uKny`T&T%z%C;}3ETz^#yd1}aGC$36 zevczW9Ew(j)Q)hihkpBr!l$divPmlxg^r^`Vhr;mQ?WmtJU0Oa8w<~CnpYnno zpnEAoh4oR;0oE(uf>_ObT9WG}&4l_3IonMsrDoqdVo6)B%*Qv+N8|{N9qLu6(?(@@ zdnpL_ZVVgsN0xVHP&pX4p7ZYpkQAsPt4(4UUg^#`l=vYO*%T|deO``xD?b7e+#czS z1+4%}}(J zK5AMD5vpIeR!CKN{XG@KWvVVCg$N~XF)QFh+@|2Wm{ll8+pmzw^BsgN%D$#r-%2&= zPv3PHMFTt}H3M@6@WT9|o)I9Sl4i*tu0D5L-i?SwhupIO|8wiXd=P#_3iDK2uuVG@{YofuyWqp+&EGYs8j9eKGEU@ zq=kherN9dV+-p;KM~ceT^~;0L%$Vb}h*)7CYsn=ksKlPuktsgRLPbKXC{G6p?urVk z#eEZ6o4|l$|MWfI4>EKfJOJYJ$2f%(4OG_5)u*5kBvt74bP|e#_-qXGaW)}bYmGAO zO9N9^-&Pc9<;)&MeE z2zr!`eq$bcU};%3?q;@OxCS?#AfO749QEBE^LX^Ee@w92XW!*aY#}Ru8a`o?9+fH& z-Sul>YWavsA?76eN$3ZI?hH21sS_@qH(lzqxE4^9{*h{GZFroCf{I7&C}(~I@ntLK zGVUb(WI$qhu!PYEJHN_d}eN1qaE$;(r@ zeQ^uBp!}{a6p0ig!B~0COF9>jWZ>g0Zjbka7#UuNTh32U^VE*{Jir?^9_DqwTJew` z!}y7iKOQeUG(|;SWOTca<-Dte^U1NUUcbGCV5BtJm=H_6%Nxbuc#e+==48_th)<>M zERrx*vq2!dpofsibY%-=&iV-$yNWG$+oAMvQ8Z`tmMp&&lW9LcK2>3qJH z2!dSRrF2mVL6nJ+!X_MB1q9{PRm?C8#Yu=1 zBb&)}$*W0Vyp1Chou-z6$jf-D$2xE-SY5CmsIm8j z^|=Vl)!a2`EZmQguul;EGno4o&?5;(g4!)<9&_GNFmLgp!g$@1Qbh}%?=zFX^Z3TN zfH@{H?%-I+JB9};jzX{DAKg6$uOJ-yOp74P62r1bv(F-yUO$WtX>*q0wX2*@Bp&6pi{VJ8(t9;6_E@EGXFyS2jnMc!*z3z5jrbZe2Au8yQPnL@q8y+L(c8b% zEAQNil_w0;3l`}N#@6|^!b4{3PY+5vrz(IyQtJmYqw;wRMNca-esg(qzC=>)9}Nv8 zL&7WM!s>8c@WgK)OX0Rv#7Ezsbkr7g$2E7e|Mp(&%#R+QJgj0tj(xUicw+b4_c;}w z6?=%#zO;ZgraJy0lOsJhQ3||J(NhVM=!NXA-RJ`)`bt@ZQz0KU6X6f|VvuW)kcj(S z+pP{{MD|Fi#(r~t?qmkhi}qz*wk~O=4%B(WX zn1t&QZ0RZ4cMV6K$E#Qy)r-+FK2LufXPpS$Ru962Wa5!iMYK>Jil_>t(!ePr2gH5N zuvb3x{f5n;q!>do7n_X1nlZV@_d4e}JEOh58H@oO{c00%)K3w(v%oS6>95-^ zc_)UTlyAPR^z#5iwV{>l@|ojG>Ep!Z94h$lZ#t>z$ilvia@Z7W@#I#;yk}CFfg}i+ z`kp~Q_$*PiyaLbOOJJI(ZzeL$1dFPKwcKTm@l3mtMcAdt8%4dYN)lt;gplblc%=D_ zA=0`%Tx6qC3w~rD)sHobL&ZbvliMPJEyzLoGv!x&+IM!|E3Fx!F}1lWDO**LPy{qw zDS9!--2kWMa#`FOS1JbVz!K^X1Tv^)*OF{DDqu#TxR2w}q23Y8hl(^tW^Dc3w>KR& zDA@d?%|a_T3m#ruM=6adN)YYWt%^kk>!_g5elQu~5by{AdUoae7~OBfgJ&UxzC3+} zRi>L0>Vr0aJQYkRG`5HYHFZLC#ct_3p`k3BKM~}KH zys8k!Bcu&(`YWy6?uXd-VR)pPt9>qKM5j&Y7^&>}>U@%dQx>dgvLSb!p?I#M2*OG> z{sxBl)v@tDXZMZb-e*pTnLA!*V>9JA05}+t%{Q#lY0eqWu2URbXV~KEqADR{AzRe! z5|8~3JzJck21&4)`0REI+?#JJ)lT*D!qj`FgA0Pe#rcY@(Kl*4%{}U0XVjbIo;oEy z>S%8QXWmY#wNtzamX{ZQ%|0(NUKXcEF11HX`W$?e)Snmq6-g}8#az(u_`c(L{l>g> za@#-Yl_X>fW8@VxoWG-wN|#M*6mfwA6ik*6UCY**F%)Z7E+_EQF#_H^977pTY8AZZ zDMXiCp!s0gt6Z!PRO>&(TZA1a>t8bL&$G@FVd$1783v4D3N< z&KBmDc0gx7ir=`vm-}DMj1*+QMeNP^DAZ)+$%L(J4anFS*cg}qqRu9cEEN1mWW2We zhCl@ovA-Z*YJ3#N_V(65Mn)$mCk7{01}j@5MrLkqZbl{+Miv&piv+;V#nK++46wAL z`~~p`L&U%iY-?g|Z(?Oh_6rlFXXRkeM?vw@PxkltEUaZ@{sC`k_g55N;=$+)vSwsv zU}CheVEktdJ9|;b7m&XO^ncZ`Q+mlNGAbC@SvlB(4MZIcEbS@(8A2cY4}EI~Tl3%U z=z|#z%ndAFMD1RzGXIN7aY-5Ze`x#)fsu)Y^>3}0VE>Dxy@}y}1nXbM_N(W&JO4b8 z7xjPO{)_bAzW)|}k&=-Cidcaiehp7jgpcBveW1P-*hC-r`_{mKo1K|mp98?b#Lfa> zV`Jt7fSC0_045F&Fb69Oh>M#E{7+DlmUi|aOR&K&s26YslNTIrHcn2k9upIQS&xkw zzy>m81#la3u>ka0xw!S2nDn_gK-~WXA!lpy!b*_&Kac7cl>Q5pzCIT_8!IadfSbec zWi34nwE(?Lr-=o~$biw>(&)F1UjYXS$xHH4 zurM(FM~l2U$lmZpfsaDk#L~g}KRT35EDRLwLBFEO%*oEm%*n#R!p_3Q!pi)|&~H2y z16#WnCjP=?W@2FdgZpb*fG^Ix1Qzs*r!N41dkGY_H2~RL*(zCCne$Qnf*|{)`J3Kk zyniM|!o==H!sQp^|Khx&fz6-VpCw>!^1F+S>^E(JAn+d}b|6Os{ojUO^!{{#jX{=1 z1~2RTFGBs@Zt{PbEOvGleLZdteE<_Dw?2T)fRz;h;$q_hfI(nxP7W?E5C<#AzoOe& z8QMF6Yz>5rUOavA=7m7Ny&-%1JCwBlD(z%!@GDMCEbK2904yv@%uGNgW*`$M9TN+X ziHU;of8RxJHWmXeW_<&I0S6}=fX&eGg+zLs1^`2SF7OM94D{IlqVzuk`2XHTW>z3G z%l~&SvNEx8aT;Iqt1^_lrE^Yvbn;i_`0<&@JzpNhv5c?nc{tvpy!U|+#|5q1z z8Gr4~fAf}?@&Cc>KLY=>nZL~bpSG8W#LF{>@gEPJzi9C?-v7<(uNC#bX@ZRG-$wph z@%?wW{vEFWRs{ZA!vAL1zr*$4iokzM_}}dM9}5@Ke;iv4EMMMbon8*5aLvrPF9%vU zJt=XK-$z@BJK-j;mpepj33a=dQ*igMA7la@8sSSLyuGB1DEt9D4gxN~-nV5F0)h-e zQbb6}dGUC~DgD*XM&HHQaP894(a*@EfYmVXFKn-s%nK`%3NgZ|FOu-ErKXd+3nkeI z^kiQ3FuZ$YM-XY!2ET={wY2}{H|f%S#j4Oiu}5^(?EU(J{Hh$TtsWS5X{mQrB>tM|07=i)a6AkcXj}*gdXRE4DPKp(s$}np#k=8Olg?tJC z7w%7E{KLrRqK*?R2R83(kjN;0UE<-r3ZJy=ai71*G4W*j?j2V;N1pk#Tym$9c==l^ zU#%vQJRt;o(fHt=b_#HM*FDfa0NSamet-!`A2C5 z7f+i>TwBXQ_=4}1VYC}?pT*P8A2*qo@oC{(+I#n%Ntov%{pGQMp= z<*a|onv0{H#>w_25Fo2SZ!}CHCZ71rqkMt8x#dmpZi`P$3A6b@>ch(YNvGs@)X*b9 zx(Thq#&V2byxg(G3PTe)pFVWc`)8zCXWY0g^NmuOF0FiX=Otakry=QmRnpD?h3y&k z9B0eR`GjnB_8uk3COCSt&(yTHcugqx9lp381sj=e2xuG?zBS|KK$D@ucOTzG&eM>X|qWBJC z`eL1F|E@$MY=-DAm68loAR9kw^SS=jP5p(l+itB)%>8?q&eay*bxj&J%f6~On?@~f zNR{aE!Ml0(8a3sS`3~UwBb-hCBT_EAFN>X0`13;VN%>JFyMjq3Mc0b{#6SgE#Q`Qq zO5v#dR9}-X2eH+WQKc8wnMceIHINgX^&H>dSH}*f+g>j}QMdjm*jy{E5+%e^7RW=@dFn1eSz;I8U8VF#BB3YN$Z(xWaLaL%2M_RmFk`&;8ONSZAU-L0}mN|?;Y9cBg z{woZmtcwm@G}+=C$Iq1RvNSSLtFnp}_-l7YAhDCChF}n|lCxQ?Yi-y2q%USMqwq?K zDI$zH%OkuOwc47RhdH*oBfQt+Qdva%2|fayn+a=atK|^|B?&&Af4Lx%{Bo=f(>yDp zfJ89mV5Vcps57aoK1? zG6}9fw1{IV<@xLzqAttMrMANF?$KT7WZzcH!K$yt^aui%@+=sB>Dtn>njasYz~HtB zId|xlL_>!o7(QVvca60tBs4p%Z?qx**)1sGm)vZM#{5Dq0#f89#3x^ zyWaOkG)EiZy4}w8254rU^xV5o)QY~*0};ZZ1wjk1<@_?%kGWwM@R;P_b?l~?b+o3pKD4Cd0wbE6J%BLa#1U%2%o+vPKb4P9r?BqjX1o<5c6xD zDrhNs;YQ!JfUqQkHBE+HroQ@~r9Li*JuFH7<6d89J9e5_)M|^w1%X?E?LrI=2SeJ} zu9nPva(8aRc#{X#*WIz~ce=5wH8gy7lQzlns_0z8~)Oxzv81UTL~NSL;9TTP-L2q(yK3K}$IJ z6+xYvmYbN{;@IkL${|NG!qNN0XjQT9(hFVA@O$Ei_w@s(&O}D&Bm<|Sbyt_o6sKty z6f4z=3$4xsH_LZ4`2e+%QNB{2Ug8Wv?T6OK`&PI5{qC~2e!pqt-Ua!Foi%g%oBi9B z(V*vBO2tsGo{$w_G{I4?{Wm}_Q=$3=aBH+7MYKI6$7*}<3a)cBfcJK&?R+_LX~0CM zol!iO<#3a9t7RZDg}M zgMM?j4pXohw(nx->zMxTq*tX~Pnf2|g~BLsOGzx<191=S$Y%^Ozb37Sv1NdwJ%%Zr z@T?_b%67Bj(J%O-d_8n&b*u8=s@`$>d%A}q*34CJ9b9zDYP!RyG1eC?3yWtcQ@S}; z&}P~<5v+Z$d+zik;uT=a5JL5LIyqJw>pQEn&B$k-EPbP7Di7q_g&EGuMi<(t#QTPC zU}(Ff(LD14QuBJxP9;koZo*DL`kECHr5B&WSu8zW=jliq1Og2XtNHeU{Xp<;_{Tk4 z;qlHSj8Z;{Upv({lluws-lEtm4~DiVlXCv<Ilh-$xvhJ6?R;}Ngr?e9 zWdp)baWX=eAkeZ_P~lu{SoIVNGqu81g>4t9gb6n8zahQT_R{_ zlx*S%@)H{69g*yZ%XLRW9knBmF+#kuwAcn=o(k3i1Kr;mwOsV3ssC&N4yFXUiXrxt+PA zJ=lh2$@jOjq0&EiWz`$Fu80`nZs>7$u#;X%8U%-heyON1DN^rVT!G)gflil2r}AT1 zuWhBVyFVzf-P<2>ZgT~YTCDVlf~*gu?f=Xfi?_&Iog4hN)(4l^FrM*J4OLr3@O+CU z8so4zpCk`w0X9A?Y`WchFA`5z95le(1ttR3&U9(k872<*V3syUr?Tgb)B08Q~)+VxzrYV_oTmI*$wxK*cEZ^`MPhr3FY{z?{fUdhu&3g zAE(TEzn9;Zcarw={2TiA^WKS~CHc*}XaYAXuZAb_N7#P63$i3lw&2kgo=NW2{4cPE zyf&l$q;JaU50phm@Ku-!UPO;Im{Zzs5&o*Ul~C zpdMvyl?A>0{1W4)Jur+M&m`i7d18K3l9Na<-Cp2={^?ExyS()$IU$`HqNus%gyc1m zEt;y1D+93|R(mZouX^~?U5ouOdoWFwOG3g@F`@<>gB4T;eB}0Kw%<8E2gk>2AQ)vV z%4)MCN#IL<5A{2age~!#PKzZj9u%X;+`aneC$Gw?D#WhWGB#_h##!d_JGP3G)##9I zAxmr!&_?l5nJo|N_S758R^HuA#N7t=d38CN&UJ|M$pggrH+8hRwQWgzMrD+`y*8bq zoVMC$ES7j|uuM#lK|@3BHc?E}KL9H6Dwv`3Tzr+UzVk#JdAj2BRmF`%{F#$EquZYV zorhQ@9ggns=kztj#Z5z|Gs#EaBfTY){o)jYzW~_C|CB$mbK58+1yYpPV|a z>3)fz_RNGVCYJ*S;LW~dK`gHxADmk)!+M^$Hi!mer3qW~0>3neQ0L0-FVYYRM&bZ? zI9Z=+b>vAx$*C8^hD=`G1wU3+@N=01gXL=>GvUH!ZKAJzK*FW7%__wVZ8<$p2oe>875 zfxw~^FHZuBMA0``9aSf1`=uIdXHBj=n0KHVzIV?Q&s{c4z{2x+$0g=R_}bbm(xdM^ zAyEAj3h)bTvr1JCSJWI9tM6S502^JJBDtPCjQrNfTbA_!A*3UlF@#onvyC50tcoVh zO_qf{!e9f1tRLtt8&8;P=W31RUf&hRVw>iEF-K10u+WoIhmG(l*O{dBF*H4D>tHby zFI=k00HkqLnp~+kPP2KqbakRBsA|a7m%c}2pHp1IgF)#WIl5h9eCobjLB01CMSIH$ zDyAEn|CSejzbhQ?&=k7o$r_1>%z?35e$K99xxPwRwt4a$gtA4bhDz67b~!ogYIMY5 zn&zi-|LJR<&!VfBnU?O-E#aXtQVq$`4ZTZ-&hwr6yF-9So$atSNek)7=j?06Oy^7G zTKuA1Ac3(2;XuY5I$sI8R-GL@UF|pPCsZeE_w1nFN2ui@$u(J9WcF(3MOJf0lCCIM zv8@kBeO6E9@RBx`Cq)!GDw7cqQZM;1ueO(O2Zvt~JZhIc9^e6udOS)iDlA4&R@JhG zB5;4S-@-MLr8zS03_Lu^7-(`-KACO?t+q!{BB9l6!qkmz9n{@e-x(Oi9-~&=R}Ty$ z6OYYLNm+~RTx~7&ZAgXBCec@Ufm@3L55{=gn+Q8K@2}QuKinMqMGn9PcDV#cgLHuz zYZABZ-X~cyn?AUEG2;vwiH!&a&({U%(Mi4+0bfW!SLsE=C4kM)tNSf94(7d?0-JRH zL~{IzZb!V)kp&z{ewh!Lu+fxlAN7=(EjFc;aHDq7lTfI8Eigj7r_dBD^>F0cZb_P; z(SYgB{7I3A;#Wr4w|z$6w+sB$tId%cx)}BjV@^_dPS^*{ijyCQtKY1QXQ7|DMOX?v zQ_&>7saPK=aK4B;u|H7~>DjG8A#y|K*3jN4;uf-e98sJ6F}$9?w0C(Wu;%U714FIi zn5($cS2D^Qbo9W%x)Fe0XlmY`V8;tCD4<7R?{Oeib4f7WkSRll`Yy}G^)GI%1ht>Zmc@lvX(?yPYyhn>2eW2YVRqao7VLU%4B<~GB>Ji7*$)nK4(z3<^i@iA? zoGP#S#vi$sfWCeIbL+O0u-)4 zmxe#7_g&zIZ!~vgTqKv4#wJ!#(Ieb!W~Y_Cp33bmcCE!4GtSE&>r5` zW^Vp*Y&NX5B6znedQHL~>`*QTwsXeZ$t$qg3XtS=zak88JmY*7uzQ)b=g9K5Ar_zR zgXD<=!xn=;fWI}YViwU@I7?jQ&&EoN4$HFVF7|KqZb3!`^l$Wmv_y{hb0}xtCdN83 zIl>-V++W{a)n8v5?v^kZN$fd_aCe%gUcp82KV!C{d7Q&`=IZJO5T@{ar_Ic&iST{o zEq))#NYA)gzL_&ebAGysl#VEx?zPZkKW2SCE9{luAdX(^!JBoGt;9fZqbU1UwjBZm z%3Q7L)tQZv-Byoqh>b4@Z$29iM>ebbD9aMU35$}k#kZ`LMcc)Lz$~@de6c=+b@6Po z=fI9h^+bQFCaZn#dnxXX!QHeMtHXsX(MQSf`fDV(nz8WbK*C4#KfEiNSNTyP5fq$EoZw=t)V~wEzzDc_C2w6#mr~sKmpBEaKG6fDj0%5TLzP_|ar-MYQLjl` z#@txca)4yi2bP<7_&~c z+uim=jlEe|9qjH~`?6J(#IieRN9(o)o2dNY!}OJ3Tj~b6eDj)LvRUAO9Scr-fL(af z`7DQu?KlHY4?AHhDKiGPnb!bF_u*>?)A^h^crwgN(S8=Mtj(Rttbo67u-N$io0Yic z0AhH72`FXbC=jeNqoQ9{^nBz~kICLCyl{;Is z%`L1MbbXpb-t{Nu<`oD*pVaP0zjC>zkDzis`p589z2@J3`|g}$=Bp9rA#?B(v>Y{; z7iN<$$ahA=1$+tr3Z*Uft1Ml9WryVn#yo$Jk@nJP!<_aIEi_WaWA?0yFGv>;F5jej zrwiBF08Eq=^#Ggm0ON9;f?kNIuB*)Cl#)goK`7j|ZOZ>>4;fKAp)$#5&s9bUK zawCvkk`LR(Rz#OJQhlaux4{l>SkKj5y}cov?y1eGXUf>z60_;5$=RQ@LU38dlWjF6 z+Cx43@C}pvRplqC#+l9n6B(H%{eV(6^qa~y+_@9w~#fMP|t%|WIuMx31q?dbrT8N)^iQ^M!CbsIaE_v*;!Np;d zS_v?Ka|4|5>_Y!#-$?yNLSq!}^B$^oTdoi}>CPilLM9dzD1)PgjH!UKfV*#ur-CYz zuGGW=STNKnXkDSk`Od&N6m@3UU=yQ|B0rRAEq1Y^55fT0aM)x!6pz2UfC2C`A_i2u>R<(CV{L zMay*`HCuijpE6%0{=9-%fYszqPH3jeY9&h1^% z2Zg^JJBraKzFUn5J{OLVt}%I)51E#Bn2LXpY+6D1;D;#-Qs~=vw4dvp_ZbUO(?D#=765Gb_&Qt(bMu396V{GkA-l*PUSog-Fl-)pT(=_SDn|&D}Nx8;4 zJ1`*z{hEZbEUxRT*9w}`F~@H>9i=G4j9NRc#@f2Yhg2){WT?1_KfI+M%qeu!(VJr^ zc=;+(4abG=UQt0_LdXyaAoRR?RZ~G;eHK-Jlw>qfZwTkr^!zbVd3s~5+4r*eyR_>M zTJ5Y#yrdjVuX$nnZ$X9oY6`Ji!699B_ zk0hU6h%H`eRGKy~gTTm$Znyt=5dD{QS?QNV18yM5*FqQ1edjeTN)%yE9_*0uNycL{ zq@J$s5~lf5x2gGOleWY5jf-^_6yw!lbNO5#TV;?kZO%EEM_MckFA>5T6SYaJYdQZ{`hOiF$}#R>zv3J}f}fFFFwH;W%#J zmc=D=?07gj9ZLmqkxHic-St=@sWs{n$UW_FE07S)eL6H}l7SvN={yuAkG1OpACUuqBcM}Q9O60M6X z-_Gx>ap&-$xRDLt%GN=l`OrmXo6GvLE|F8JY0^4!T;p)S8#RvA*IQI5gbCqY6^O9! z@x=Ufmlj@F9kDXmxd#rx9D?e4!@-W+^u< z)VDpRE@B-!V}bz=170p$%&~fWztcQ)+!{UZW9JN~o;ZQ%5|WnoA8`|SzvQ!IOq|V( zx`mwGaq{Ea45YzAn=>buMw=qPp)zoIAH%JguijOkq~*Sc`R9UB(SRw)CL;YHe^McXaD&Z5a-w4`c!Qdh0+rb5XuOzz$cQZCh18x%M)!P-c^H zZ^tNqd|Qf~TB$?D2`KELO_XW8cyrv9CfC~MEj3049Ml~WFRv=3O-a^8DER7t6iCCI z5XjByvgHxh(Za*bdjrTHyN#BQGB0+5=Q5eD7<+(1+uy!rNvNi|?7T!cnQS)KQW8_S z`KV8wKUMQJX~D`6uXpJ0Zvo_bR_M|KSJh4s=vC0qW3&ibX-uCkA6K;GJtLT=}_0xAo{dcM#)CUm4kPfm60l1 zik7h00_gUI_LM1_qKRF78}+1*Cu(>bRfiHl$WQG#ANAHcrQ~7Ip=j%80ZmnpGyaae5K{Vm}0g^j%WW4dgPO6yh~ zzNskNEUfIO;)=fD z4=NTaKB|TF*y90fWkDa)Q(^dxeQK-<`j!u*`rtBWyd& z_CXpRjpzMaqK*xzJ%2^<@vrs73_*yf%EKDk9g;@r;zF@u67?yAgYTfkuxKKH2@EMA z-PHOq`!xuJ6Wcp=1sZLqB0&U2W=L3ZiQ+bvaE9H~49sC@ceEnDAU!Na+PD4W@33C} z@by6w#6hBJmd%tUSOZU)=N z#4luSHNIZ2pcFCqp{KS+v^jazKhmF5|0Y9%OvKOzz0q-$hP5F0I@tq$pfDb*ardt9 zs}*@`g}`3MWRP=|Uo^3(Z4=g|!ZHjr&PCBl|Cnr_h4;%=nu60I57R{~KDJR{qp-)T zrx!PnN&^>E(MYQSKx-nIxIA9 zW2EiwHoN}iK8yj=1(Ia7@yy5=uE8t-fjK%U3E z#sJSUn@tkF3CA0HO>@%@CV1Yk3wdPXj=GmKCUs4n#6>>zc|G(rMtW&9B~$N7C^ZDd z^@Rn`ZHo4lOGFDN{-Rey(5ENd)wAd*(reD3Tlyb9bfvWFw&pUUKM*M(G(? z+gG^X%ijsZC&;umrh6(AuA33-w0%qW$Z*||I*jp4T)5|?CQ!iMv$$ zns+;RZ<_k{tOyI^jyy^3Xx}RQ>y_|!vWZoppHL(Tmv3xe zg@lFzx3@ZUG0fVU!ovDvM)s~SLqzP&ak<4Jx1I+u9k3dQc7WT&zM|XxuTbEWXGJ3+ z8Ir>C^YexI_Z*M-*(t=AY#s%;zlaHHGT`PHse>uR-FkNHfi_(B!ho2Z9@Plz!Y-lh zd1Nxvk+9!?Sa8}+ZbY$qtFNeRbRlWtKZD9q3k@vb!J8fxa{cC`NX%qga{d6CfO2+2 zD$zmCy3yq#ijG4r$b=J?4NS(9AIp6~arcWXv=jW2lkOC=F3ql~aQxXL z91^Ew0dsdJ!&;P)b1#AG+&C*bM@yZS_vf2tPFNIdGzP_5*ldhzVg!LZ{OkR@($WuL z@D@4gjcZG)FO}`9N{a`nG02NM_g^*t`>L&5FI#Epjw%Wc*1g*E%#-zl>SoQwt`ToN zTu0|6CnamHHaz~%?D6${74FQBr-t+2E`|tStM~`!wS0P+vsZ#><4UhL zH%#M};OhtM{lIOJI0ao~fpVHeuG?qt34)^_{f1|Q!ts!BA=MWvC9N@sSP+`N9b!O@l_>QAgW29Kw zY(aaaot#zZ4OEsV3LOr#*pY5z;pM3ESkQK=^f1bJs!!B`?0f+wvV)$Hlv8smg*ySZTCFr zt5;@?1%W97J7*;~js_!3W0$ALHMx$*GOp8NnI4aP?kjH5Sa;!T0_TW6GiMjwQdUex z!pW8%i`XM1{LY)6y=}K>bY_If>>Gf|s3RfcsUY6#^{r-h4>&0^y@RzP;`|~!J9C6; zkGq25TXU+Nm{*P4)OvX1nhl{Tq@JCd-ywlN=)29-ju$J!#jJ1+m_fT^wvR-;SJhoHe5(b`E@W)%{nRI{ zaEUuResF9#AkbRRwH(>C#MySp(j3IM!lE`1Cdb=d+)L4j(@jj_e`*chvGJ}t?9mC9PG?I%HyqaUsFD0=!@pYY(m6lsAa(no z^DL|NUI(b}(Rxh1>T*t!scFjkS%W__XJflMFoBob29nsdP8?T>?}J&+?n?ZraX0Q( z*M$y=-}`LgoAZX1({c~GP24h)XQe+h&L6i*~Tc&7r9865{-^+B4Skr{f%{PHK|IBdca+FiC4XmMyDZjbDGv0GfPd zUUL0ZjzcUdcGAXAD`k!){a(WQHoYMNhB)&A8O7Tpz!V{26z8k3zLPhLxKi)k zc{g;4Yay3#O1Dc$Ym6qlqAos3a)ydEC10&S#B16CV)jk*S8doeo^M|n;dEd}J*F;` zKy&5oD0@DYb8E7mzSC3X>yz=ivRNGQ#CfuTDesBeTeY(_`H^RwdCc5H2CRV=4m4u& zx@yIQQ?*Bejv^JgqRF#}O4fJa%cO5dtBXF>^7A^Ad3>aQ)<-*$!xysc_BFWb*svu2 z`SuX*N(cT7qCGI3b;FrcS`#%AZhis*uEGu8eSk=A3SU&kk|aJ+K}AK#Q=3|Q?}oX; zR8gZb1zkV`rKt+fvolK40a~PRp*3P90-)P?0j^c4s1?;xhUGC!Wzr%~O%?7YQTj&V z1I*{W=Sl3z>WK1O4w^r=IF*ONg=VAR|E)}Um6Ag;6 zo2${S|1w~j6flPBp#1u{*rd0!Jtsa_(y4k7!}V#7jk% zD7uY${R3kZp@xHljv!Z*)I(^lmdZD-#7c9g9i5_|v`Iop;QbG20j1rfl^4BvF&QZc z{|CQ7K))?J*|xg{I}{`svT((wk(UEFuc za)W~GR6LIF=~!g9uy&)9YyR*H^5UDAJNe)I@xJN2@VB!FR&A%Erjdwk;EhXd-DjJt z*jipq$Ocz*0y$Y}wCi&Ut|Sj&n(h; zVF#3MuZ=pNp@$ z9>>cQSr-hjVZmg^-1Gn4XViIQ z+pXI)SYO4Q1qCt$2jhNb}D6MEBX7+#&OHH;|MB2yLsWb`VBj*%L(avIkWQipj3Af} z6Ko61ws1Ji)+?U6Jj4Ko!_5g-|C5(@0dAL4h#b7%S=4P`$w$i? z=s)Zvye^ZdE+=wYr$*+!H=B}SBS;C>Lws86C3pc$=Yd@irU{{P7=II7`YsIW3C2{2 z@`2O&r8|76xt1-ZRm5aulN$Z~^n8bdRZM?9$c2CJh+}jNPpv7ZdtNlFR?nug$Ibj{ zR4=ShXI4-7RckQWI+?lM$MF1VClW;ws~3C*M5wQ=qB#)8aK+-OTt%o`dwi~a2{6hV zM?uaeHZ)ii7?7NICSxu*6*Js}g_r!5x;@pn{Sm^pjUy@nuyMO{IBW27W|r?F&lk<| zdFA|g>|h>wu(h${NzCBnVS@-+LH2YhWY)4uuIOUo@FsHVX=6CGrHlR1CrC>&9-3>k3^r}T^>zw{NJ%0HXY!@9C7KFDp)Ex|twrcGVS@IPKgdoTPb zV-mBsZl<8n!02-sKRNddQlo3B*f5L5TTL!Z%OF0%O<_?!8v8hkn=0-YatiaXWOf$2p8=1g-cp=6%W9X8b#nvT@nDx#K zroH+uYca7SK^D&Xm_TwDh8oHW-G1X&TtJ zjbR!XZZ{l1_{$fwb}2;K!MRsJ_f*(f3bqN^`H+-!$Ug}+*Ro|x1+J8Aa?%s|zGh|A zFL{~q<#l{G^)04v4)D@HK45n^h(EN0go1nwz;q;1kn6w(!aK^zE%ISH3~6|K8zwZ zrM1Vzba}Bt(9*DxNAJ9c=}XpAUQtOya|p{0uqUvK`0N}Ez~P7|KfCoJ1G_g@P``d9 z3l=P3gOSPAmkcHv8^h@(Ho0}Gi8Csec8P8b)4=I8F|9C7{vdVL0m_#zWd8hxvK z#|doNUCzr7+`@#JD<~_kpspo?WqCMx+^^{2SL_Mj?ObaCPqL^hr#e(9_D=zWNLa8=cMl2 zxVB|8e`S!$c5Z&1XL49GuuL~uMLkG}@$5~JDV;8$CE5f`;@XvvA0Lfrc<6XZFJfFy zOh*iZ&uveXVSvL;MoB;7ydDZpzKB0B-^k=CuaMm(nskDgK+VRPytud?+sxqk2hPLc za;l^pgS`{co`b%3!->!5#WVnW56eGWz~)AiiY=?LZG++=7jROc4-6jzMxKJ{1n|OX zXTqFMp}Fmxjz|ca{a^u=@4=&maK+D{W+9B93=R{94u|ZVL#|t(u^xAFHaY1D-&^>= zuH~&si~0FAS8;rwR0w3VXXE`$UUoVCqw}a)x|U$1KLo1Tv@Jppz?ECVws&d?3=iX^ zmK_ay$Re7q15Tk!|JF`~P*W7guegilyHBKFMm&ZcVaN7`eBwEWE4>aj+F%?|QQO#N z8bi)L@AK9R6-!(HpORikcP8-oGbSgGx*eBuQ(Jo`$h=qQars^UpkJPshLvx!EV8%t z^M%Haf5$97ZFdUK4j+WGd?B$88w@XL(OE3nyn*nLt^`|ZD6O!;aFEft5VNo!rwl5= zNrbTNz-w>*eDPn}SrQ%NB_-V;v)3?A&2VEy!kDfo!aEM?ByP(drfFbB09BQE* zo&6jU>UVFaYpSw-+fODww2qhU z)=mP$m&NgCTtUB~TloF8&u~(=;(ZOEoMLvqUqy3s5O zV>|Qf`yU6OWydD+P8-YbE^tx#*~9#KWGB)*K6+gL0K-*2j%hKeMVy>^@Pk>LKC12H zM<#B%0*^lc-Wb?81ul3Ae6g+Lq0=6O*MAR=nAX~12h)r zZ+jHlA&`Y#OH6nUE zSN-gl%r42nAevf)qb(4CMeo7iU+mfEBO2wPkak%qt%YdAQKAs2!x^_8!(_Dn;qE9hmF?wP{Lq_!HiY=MrB z{i|F_5;*Ko&>sdA9{a%iCqP3Ac7$D zDMuQBoK#`EY?T?Bq@afm9{F4lCu0)9hj6k<&+PdTzWV`4{dyjLVm`5nF?7__arzDS z6Kfa2had=o&^Mh_0f-*aX>M1M)B^($iFTh(ROc%H)zu7ZfPQM)u zjdZhf)4SpGdhz=FL=V{AFcN5F*`kkWX!jGL%dtzD);|B!8KuE9yOab z&^GEc;zHGIt8tQ-Yyt^_tu?IPQ4igX)S3oyL6MU;USB{={ve#bYO2h``QFTdbXRU- zLt~V1&33fHvzS#V@$uYu2&5EX?W(21@8-hur_#J;A)j?Rap{f7*^?MQFcn48=x(f_ ztfm3uj&ckGV+q!5WYq=*V^=Mmo)XRAiF@Nqh&b;ni+|e4|nzxRuc%2F@nJh;b zM_vgrbxT+wP2`foAWIf3A{3v2&7Q=#5t)>iuBR=aQB&2-xY@J5{7a{6G?j0ltW~G8 zwv5b)rxN*OE{wW@kr`$-zW)Y}(NpPMyNnKdDzwy*IpIvQx<25A#eN1Brja+OguEn+ z$k~D*2!bF8A^9dLW3Y9V@#5kd0t1Y!t1>Y^1>1K3 z03ZNKL_t*R{1Pl}TX<>lW=0R3(z|zqgseLlJb65M<`B`BU!t-p8%eP+VALc=#H(np z{);YUJfl;WQ&Z=~)Uggz<^U|-b*RP|1{L+gW-(GUPEw3ZZE#t~9V8Y}gY+@6%laANxrMtUZB!nRJQM#^^l$3N-UaO_0g-Aq<*A;}m z!s&F10OYtAs#qu-mCuJ;m(%Rk88+R+=EddcT7-&C%h=qk6RUU9?6aW(MtclaMFK@Z z(KWPC7i&KJfM#PHj;=By+6Y3yFb2C51E5(PSe15&_-SjZW6g>sIAooqjJz+MtZjBW zF)A{$q9E%UQB@_-R>{hxAE8K4Sdek>8tw)QR-+7(8M{Rz5{V+oHtcoHF}Z=toUm8{eIGb|ws+s1V)eB%u=$DdAG@3`}5B#6mwN0FqSo}i8j{<~xoCYO_@ zvL-SIerfc98f;|wl4S&K@kH9IkqQg3B@Dr^ZXHcq+cBmUW7BugP*cN-B_RyRr02#U zt1_`pCngbmoRl062M&irB!nRJ@gU@ANJvN!i75zu$dN9?D;A&q-%390enf?H zAemMP9nhm8%6BzVG+`n|L;GQozPR9xb~du1-p1rG+IH@s zDXJq`G8mW@L%*S8nLcd_Mg3DS?yGE@kfVM=!6@1nRO-!k8z~7fqz|9S%xRMuQkaAN zz)SE~@>zK&;kGhLTU^A)TRCV`x?Yy}LToiF*sS%ZzXv)yB4m!3z?8u;Y}wX`E=eFs z#Ka`hwPOQKfiT`KFWpU_5lAXz(u6T&IwijJ79>fi9XqLrBr{>kB>Kl2(dgMYEi2x~ z;!o?zF37@?nopiPmSJP3Fm1|s2Bx{i%2|RS2!bF8-yzD~ci(;gcjaV_Mq{5@;YC+N zcmon?DaqI^3Z8-jQfvyH-XJO28N^t^tX;j4=Acfz+e21{n?OJ#BO?)657E)3k~yd! zalvZVY}i3K)=i=#f$aYM$uKptY}pzb6$^4eq5q(PWM#YAw(?`vY~D%4o=9qf3t0k5 zw&7BmSg~>!mh5y)5lBl-K+%G9_#rnhi>zb|TR-VJHegL5+tb@x9PzQOtOcuD$GWY1 z=y%HL3`#c8*&ZMvCkK~7$Jg13BPAP`%|Lf!8Pb5s3{5i9xP3Jre7uS(zl({JM_`M1 ziCB`z%}OL$Ze;ngmF#Xe(!a0(?~V;@-Cc*#okLQ33NAfJ)EG}nj1`HVWq7;2QPT7K zqcm<~LuonT*gR4b<4KBjVG6dfsws(6$7f?Q#gQH#X647r*u0|-dr~@XLlB?rCe7m# z5%qUWI2``cye@Xr7K9VamkpgVnM`8!HbFSS?&F7ZQtgEPouCD1>(p__*=XPSKJRRg z%lzOtPw>HWtnQnBlX|B*kt#j*(u3Z6Ci)Rq9kuD~J_2 z{RAU+LKlRSgV+gO5KgZ9_~D2-Abl;&pIt)(HTqnKhDG@?JY17610w3}@eEkt!t ztO*P*%%W!1OT5q7+&m%e&^M)g{TzP2xIb^)J(6#FHCi;tKd!l+@sB^vfb_V-KHuN5 zjo|Wcl^h z&9C$GzpkfvSPlWDlIrB2@`qWTZ*sxZSCmrI96-}SR!k(M=aG{di;PNR%`U3yJ5V(p zNj4Chlu2Gz5=LoX=BBZ#l*&dwnl525*~uC>2#@VZ+kG`w{rO%ZQ*UST;N;JhHPN7t zvU)%HIf;lB>4k3)*3#YHjnNr{#c+K4Bt!smgv@5MNCZLnAB94pqxM?C`f~nq-?eCy z9^`>r&cZ1{q;?BWJn|-&{qkCrT}yfVi5Bkv{hg$`?9Bi9lU(%TqnHjlp&k73mk(ha zcRnLLD%+de=wFaccJbw0jTHc0*U)-q>$jMY`ZPj1S=szlhjNmoNOR@c#)oI_@U{agFKITJnX`pumCA! z@#t(eEq|1T$lg4qBkj#&nubQtCc3IdZ{F+4cW5CtFM5;@;(y5ZvSIg{_jux|5Vt&d z2jg>`>{#;}f7&*NJ5P_Lar+V;e$vbD|9A)a$h8N(bicp7KK1wVs|$T}PK>l-_IWEoqPynWAg%MmIZq&Qa@qJ`%Dl(b2G+C*N`M zha25kjLQD!9QYo+|KFQdk}MyW3&--+)HTjzK(ZMmu*9Y@q-YcwMMWf3p2a7f zU0j(GkJDx+F3xpOA*gj$u|dt|!P#dq(5)~XK#x-T(QkMuas!V~^{{EdUwQoP-K5x~ zZ#TkdVkM97fS#7e%8dFsA6Q{NPWk znE%^pfQ~137$Zg|p$^Pp`&)O?6+UE{VO=6);7~@5h^IIw#Owz)(%dUjQa*vYgr&Ly^G5l{SeC2J=AKJOp>)+U_vr^%)ab%xv~uyS_cB1=z;lniNXQdUi#LT^@A?7x z@fHz;oOrca5;Jp&RF+d#DUp+vg!MS}gopq{5QOhMEgE3$oRwU5$K#lT@3OS2j)LUe z-oHvnKzsFi7H&>p;zc$jzIe`toG_M~N*40x-#^8)Q)e=D>>%tiJuQF|bT*ap+?*)C z{@sHl*(7w6jmA=)Kt}>UeDeDwN)7z>#>d!IJ(EElukuz`KKK0M91L|Exc|O?G3wdt zQNkax&ixvX|1Jl+RpJ$2E7><($E723s9g9WfB4UGPJf`7e?RjA1>b*?a|_LE`uFY3 z*>Vck4FDM(OWrgtI&}zJPWu7h&x#jc0O2^0u*7)Cm1QccDyf%qNq5`6{j&V$7m(zaoeSn z(L+J34l`S28A*}}?|zHrNz?ehAJ4`Z4Pv%CNxFOni){V)(Tyb-+qUw{2mj0Yk33FE zOqln6^&?i6k7Se{rY!#yUcCMc9IczV@9r1be$giYVE!11ppKZptN+~0WyLwjNObIahkI^mBEjxt(B(H%l${7&dwP$Iuzl?u{_^q) zB8j8;#m$#8<@(<;VEbz3&HX#KFB!^1x1YcNeS)Pl4W3A5Vk|}lKx2=t;~qJd^cWiw zDWqC8)JTZ>b!%AuUKbBnu0qjNG1=f~7$sIz9QLH=lfYNVWGDnf{}uk~{xK7CFx0_ro)h`J$D5^aK9Y$SyvEb7sfW zUbBV2J@YDCrVeFnwtN5UDiZS^xs%#d7mm1WZvNqwc-oe-YWo&;Jo6w6O*)Z)lY%jz zn_$veW64T#V~`=|f}2Qr>@VDQ*BUOn;W{Q1*n3Yw!#eC5zPIFe+;RIl&c5acoLcPc z8CIq1=$cN~o;E6XZ{qKd-N%~}M1m=tBCF^aDH)QE+hxV9#u5_~z!&k;(6XDX;+u$f z_P$5!XY8ul!OoW-W$SC8MRXEpO6VFO7AHJ0n-^pmMV5Mo-5sZ_Edmfh5WeF=toqOU zQ0+;CAHs30>J##|QB_%w zDItsWczYi?F9XKUg$Q3#$&w^wG_>CA=4Ft$=B?DrFq&DbsCqY{KKEIgY_nZI4<@`rxRgk%{Ak!kE?-n`XJnkFF|OgNmj z11kMG;h>*zG(sQ{LW+0dH1(_`rB<)xFCR5fSeT98xRLoaMf}oi*f(G+E@mXB1#ji) z`A%kJL};@OC*zCCYE378#%0LYJgub27?46 zQ4E0~s%|@M&~YHeVIwiSndPhM$;fHqFYoTcaD{{#Y-i!qFEji0M;Y#0#4rB3jOTtf z2}y#+@?C6GH9lMU9PCJ=|<}><>Nw z5{kII@bA1b=S`evj-9oYszVhy2#BfPt_gYn6TeVT;6ChYCN8P zh{+mG$&gfxvWz4fNli?|Vu=!$mO)xZ3RyX6>|d-_qkR2ptV8?ZZ3~f{lgi%efkc$< zjt;szI|(UnPQUD21}4WMNp?JO>Exs)(tpSh)b<8iyTZh!=91>Nl9rG_cB&HzFvP}@ zoSj8{d?v*u*>p8F(A@4PHYJ;!lo$-L$s}dw5ZhbO8{*t}va_(6jUdS+q$ZP@nL^Hp zVloVV8XB7k;2xh?m zjYJ|}__)br`r7yQhSK%4rVK>y4iT4|Nla`CiJ3XX85F>X+nq*MiU*U$O>9~=2`(Fw zWGC63PG)jEx!L{j)$O2sPlyqxok~G!CLXn(wzP>%D$K*3kV}rS9$#z@NwG;-yIN`O z@L`J2WA^thp*T08=Uyz^@kq@yHnreY?M%AhJc{#EF&uaq#&|rQY*L*ERtAjZj2=ru zw4H{=79z$tahdb; z_OuaKd=^s&g>~~nEgZk_19+^k*K3a)qTt8DT;z5^=y!&YC3YToCojt5fuH5yRM&! zx%YAC8LlDeVcxmf!jpNM_~`bbA^;KkoIramWwl#7^jf za6%G0p&z0rRX$V90ddfELLPe+Llh^4UGoWW3 zWeGaUR&dYxqZmDEFyk(}n@=j*(V{`t&3%&Mcq>zGyqo{7YXKyPcCzfB_b_GZ3}#K7 z!tds+CKwSTyoJ8a8k<6f$4X;G877?0^W|~QSs_-IZRNs{oA>8-a^~O(%x{;FwI*Ks!=u!Uzm->?ole;c7jx5d zAM^2DLwV!TI~o7%Chi&8#;@`2IP{JlYu1Z zRF*fHBD#B?g+JJ z17~E(G`Fg3>-y?-!I2=toq*77LJtuoWIWVTmEc%xcBY%^`q2$_PM!v`Qb8j2x? zvFGPea@o5)am^&$p?7;WKQiZX#n}_N_SvUUx4p;K#XGt0fqU>cJe>B^$^7p28>t_a zz}ltNOdbi@6UT7&-(Kg*KRwNiLN^ud$^7b$^F@=g(5D4D8mMmc;mOIza|Dyn1wjx5 zK{)xGu&ZG0)$P{_8YL2sa@{Br+QX+ycaSq-4EC-vHg0JoYwRh+HEw59T_*#J#^AB| z*uG{hb=?t+P7fo74Z>xSXs_GF<{h=*aN~^l&|@^h>qS*nk*I>uM;z&jl_z`vvX`bG**p(H5RRRr5rAl#hNg-6Qi9OeD=9}~8D3RY z(RDF2KoI%@Ns@ElPerBLgf@)uiH$9OfWdA|q8HPHaUW2z{C? z%SYTWAqc|pakPR4u|JR?oET1u07Q#wytXCE1?dI`m?XB;tE}oeOkrqN_+g4docN9i zf*=TjAPB-ybJ7gKIv&E_c0vXRPD|gNjH_!AIy(KhVq#E^Nm54XZ0*Dt8;|YKhAK5k zYkQEGgxIf+eDx?DEiL#p6N#QUjK^SyT-D!2d&ERSj75|J-y*RSx*(h!#7^jfaB|(p z4@Zn!I3nGwTl5xl-k8hWxpR4A&K%zPq>QH0#cZx^>w^ndMQCkkCIaYci2B-kBFAjV zyq6Vo-(>d}-DkY@%$vKM?!$#JjhlGuz16gOgB+`&zP^gp%voL|zRH3i2!bF8$C+5P z|A;skKIL?Vc9rwD*FIy`b+bv3Wm-0@CmIUS)zyWpn6TR{$fyMTej+LuEmo|i{YkDy zg7^brbY#pn8zu!pejnl9=UPk(k$|6ws-tQ;MzaY$5+S}V&5y9bb)?!hEWpoZ}VRcv-EGCDz@AA{8fkpTWs6iGH< zwb?Kb#uwDE+AK(#N+1-)Vm1&8h0s+MO*Ub-nS0Jnl6&6U+l{JASZsDoibN#nBM?@R z6eBj96`3#rUj$88(NM4$WkTTy$VTjTE3%{!^7{!zH58K-yG1NTD+q!h2!ilcl)LY~ z`~L6B$r_EuKGIDqAu9@s+R4VPEfkI}#Hq-5>o)N5<_?T{H)~g}!;+ncv27>sd{j!P zdk<^3wUU*ehDnk@i?VCg`;<0#>1u67cDXTjZs)y^Hxux+uyI>6Ss5NSzxf<1n-qeL zJ6OJQ9gV&y&D&P7rq#ueEGM<4>)F}R%+?jlXp8MfV#j9w^u`J_S*L#ehwKQti3wG) zVq+bSgm~Nzl|>6ylaZIsuI2Brv8D@OS37oh3O17rL|OmZ^L$tnLFy`F(ZbbqL_&1d zf5xh^F#WO;s9v|2)#Yt;?_GONt0@Tf+Mr8VS{x zva!)bzhs$BrOgZ+S%9@C1f%}56}-2m2F+W;C+llSNKc}9`)WRGmPk%bCf;E|3e@uI z-##E==wO^$18@CjF$o!NRxf;yTE9m9mQQGulS#Ig^ZJ`R$QzQ2-rdan54Mq$Zf3#X z|HiIP4aI0BKHh}_gqkZ@x?v}ZQKx#%2h_^xWZK(V{PrT6Ln_sqR?=xpC*Hi9|9fU3 z5vxqu`VU$ESu>$XC##pO!jN5n(^tcS1uOA|+gP)%0#9BJ4ucp<@O6d5;V;eWVq&=< zoLC}}FJAq{WHN~%Sb}hZ-Nz3{+~JQV-9TRPNJf{GFg(XXc~g-3?OVtiHIkxH!-?zM z!OrfzW1n=?P!|D1JcC9KCq33e?S|E)4k%*e@R4{z71Rep=t>-;i$*ZEqy(#GW9*nw zoHBMO?G-hIFpxT61fxe5QPMw-@~RFbS;FATWx}}8Oqx1`_NoSAQjP1uGX9iFj43H5-m!nYy`;!w4=ABz!VC%=0dfb7VsyzQY+X%+f*q9Z4l#Dj zc*ai{gS}x3+dF)0uT(j0@>s@9sIWgFI9~kbZj`P{!c@zyK1)c*dwpgt$op}=tRO{ zqQ`OUwi*c$j;QEb&vix)`CQdVh+y#GH2F&2QXYTk2|oL>f>YOtgn|d8Y3P9WJovK+ z217)m>b~+^)x?s^$2eo7sVd(_GK(QtN0Vg0Wi}#7Jxc|uQBeKu?B1{jpTmrll#P3D z9b7gtVEoxgTQ{(9-X;c4K9z7sD?2u?!&hg4m~8Aug?6JEtHFRI$r!A5YzDcf_eEC; z`pL)U|ZF<~^wU@%}YYWTt$s%*im$Y3yGGaJzDP%(A@03ZNKL_t(ll~ACC z(oa`VElXq!FTi%_nP?gj&49zG019@ifp94N1)H_VWEYKK%j$Kk>}(=;@(idi$7r>q z0J_P65{;m12Og@jcWVesOdJ-I@sO9*u{c~9fr!z7q-z8NAxu^qGN7335b>g8z+y9_ z$P$ub#^Ep`NivG8ps5;>u$PANwJdA2f-{>;yC^KbEoyr?5C7z1nDS@txw@EdG8nGA zxgIH~Vk#WYtcltHN3JEcw;j&6>NQUN>AyMkqN#++*W=ATpL=gQi+J0SUAN8c;ndkB*yJzh z<%u@)(u2RH@K;YV(R@5U$aWU|_6|Cx-Ot4-D@e<|irYWf%rB<)N0vZ~_<8r?37q}L zG|D$UPR`e9rnY5p#u+n7b$&_N?C<2YTZ>td`vdZoAUig0CTrHs+;rYJ;tYNkJa;88 zG>l_fl0;qUCm6=u%w1O$@$nOPq0hRPvxcXN*79SPp~BSf+JzdILAoaf0h+4=dQSFT6M;+%TDtLS6VnI+otbw`9#C&bNt%79VD(hNjrDnB;?k z6!r!T2h0RllsM9?EmXC1VY0MP<#%&NteL2xiES-@1{oWvZtf<-<{&*O4u9qdPAQ0? zyUmBg)PC@ZnJlElM_IR{m6>@e8!Mt@508hM&sXA=*a4*Yp5?!tBe*5mh|QQzw|xWlQX8)&cU>9DfQ=!Br8^;X5CWeZ8mfB zHDf@Fu?eQ1-Fx0^9Bo6R}s~X6kT{T)7-7BSX9cufl2IG_7-n^w3V<5S>wOQB>8Rr^UnKZ zs`s+>w5$1kiHB8h{~sT0ZNZ#6f@?231CQFu-2W`Z74K!m<|dSwEH1j{YWl}3v{tU> z-~W1-rl8EgS(kHBaR$3r&STDppAogDbK%vOFeqt%WYE5CJ#SSH<)M-clp2|mG2>bK z<_dm1xgRkGnMl_f7Om14m(@F8vU@lGc=2_1w*@db)4AZPYbc0o;O{RlCElj8t~$Ww z=M7`Yip@;R8G_SZ$D7Z;%;we*iYuE-uegL9J4nhfF1-E*Cb-N5e4Q+P=0^UqDxIH= zOF)vW%)I;u+%&+Bzw;D+^8I&cIcq%QFFlW+{@*%g4ob#q6d}m5$xbFb=_yoJRa32H zl9>|2@mhaUe4_tTiEJmgUn+a6oaVT6+;%e{VRt8!;xLgha2y4CIrHbt;lnj$g!lIk z(_XoOx8}`bU4xUcxrrne&Y(c93B_cR@3ErT-1JN9Eo=<2WM#yo*m9XT%*N7%%jr~Q(lZhKmNdJ6jZtUT-{2}w4Pl97zTWMTM}skCnVkOj+jF#5EK#M>N< zoH(AQ)$g-#!ybkd55Z}&Q!-;Zri$gvd3_$McQvCKY~~EQtEexAD6?gqg<}LUX z&!qDhnjm9{Nh8~1J@|{NnDAs~kXJMarwmHsaL$>S$jSwCS+&Q_DdPrXHD@z%q?1oR zc$baU7Dn_>z+fL7mCu^xSl7UEoJ7FH*x9sbgJ5W!gt-fhYhb|jtTqQJ zBfrP&j-^z$_lyNnI~u8}sitDbI+pHv z116IJMbe1sW=ufM#y9!bt~jo{Wk$#`NTMytttfRqv@=7>q`YW(zL2hmn_F#Yb~WiRwB?I&JkeR99D0y7U8LXOs{Z zYrz>el;IT%sE9;G20VrVy~*JwD>H>iTMf01UA>>zu_t;!{uj1nPMMm#@4xPTV{rHW zp3-k5DF9d)I^k4?ey-FskU4xRnZpl!(8S>Jr!n||NBWH(zwd9O$M!zimBF-0J--%B zK8>P-UO0hiNxg4j&tt;ap5ODwo=$%6GZM%2oTW9TkXh#y9vW4VKX&@QFXn)8r|i90 zib{IlKQ4o*XJ#C9lp`sh)6dC28G|1N~Xl@JGaDwv7A#d_Mqow44X>Eu!D~sT@w5Gk1k^fQ+qGL;OfuVk-cYJIFW;s zB%5)gdIQYF0!AhFK5syA@8=8o#Z$;H7TMw36!C84mD1tde_b;A#gn+}gL0-1O#ag6 z2X?=Q;exXnnUjo39>cgHc?T89l2*g~PbJRy(cBp%*4o!r{WIc;574Ie%mq=~>ZvF%L+h@lsXIa>=q1?g!{Kybv3~U{ z)o)$G3(shTD>o4=yoR5qVjmIr9iu0=A~IsL-RC>mrT;%#Eo zh*svkKA)-6Pi1thg|6PY5eA2Yg0UGaeB%wGQ)V!AgdI8#eAf`m|GgM*Y?!&P)X-kj z&W7?egwLFYP64M~IEgf;jB84N7S;O*RDQ&#{ipH#xM3vqZfUi9{%h>)j$`2)uRwb} ztxIaztzN)zSpqde*Pc@HhJAnkz12N{GY1)X{mm7e|D$YPTdOkpvhh?u^ELpQ-%s7{ zRjgbaB2d*xbFQB#ap?Wd#cLZ6f;}%OJ$;bd%s{rn;?-!eAylWRkI@rEtEnBZG!6^Z{ zjt)rZgaW-yfzc=?v$QYhHpzz;g(@l%lGIZOOOk{lYsal+ND%sDSsV?}P*Fw5<{>x1 z-uKQg*vPu-RL-?nk+%(hoRLWPp3QW2s3gaI`CyaSj6qC4 z^L+9>HxgqpB1sz2u$?K>PvhKy=}4T*()mZxp6UnfAJm`Y`TLd&pmLcutr3WXY#aJOc|br1bpA*#6&Ad z4(!I>0!WrY2R))98x#(l#u<%BjGHixbEc2PB*DekTW}kDpP=hRyZtz0_E#=7%}BqA z#mH~}lLc>%rX_PW#i>T-1Crj&+y8i)rSfd23r536`A(0dB8v6z&D%S}lRv*eEt z^I^={{QT;vc*`UFYRwmZQgk=3BRY5(iX@@y5{2WYGNaIeI(-V#6_@c@^LQqwn^2qv zI=VHH`Htx=RHduAj=FA%w9FJt%JCT-C5B)LeV!bj!}*t8$&8{rOyV0W95kI%lqFji zrPH>pO53coZCBd1ZCjPLQEA(@ZQIU1_wVjK&SO06h!_zk)?DA5Yg})dhVW+3Ebc2| zgy0K4j`y4Ax^;B4^QF>$RW>-&Z5|E6Z%b=idxOP#FpEE>xh1W^N}gw`qov-~ZAlO~ zhTe?1Qp4o!T;Af!+U((-?DCvH%6smEIBT#^+{c70J2EqC5{)*rTM;YFd&{}8MFBv= z+I8JRxg5+8Eucb5m>ckKZEZQTsx|osN87>Zsc7ITd7^POs{IgE8uQ2mt0))W6nxXoD~ zpa0|NBFk~keA26fc9F;?8{QZWM<{x`KN6kiwPIYo$+O<@ zKR;hcxy-ORObkOMV?*T;hl%tJkLv`lI#PJkLI1tgDdxm6!3v(p;DosqUYUX1+}!}Z zuGmY0L17O0KJtCUJ<{UPcIa{Xd*&oYzl}a|JHBMuy5O|V@u19YF?C|AO|svv1MZuq z5eP#Tq^oQ(C(Z=|EZJKul9#?^1xiLja6Pw+tG zgH=k(x#frXRONiY(O4FgWdv1TcY~%4^l2`X-iA@!6kqpmw7xCoIvw}q?nmhT1Cljd zOzAP)1p-%>x*;(1H;yD5Gws(W9G!Z}o^bN>iFRX!EoAsXPQ%C@&?)`N?&19=qUMG^ z_?KVnr!_N1CAOa!s?^*L;o}TP$*yFiN~%+`8%UF`w9pr=0_$0bEHCyuk||)p>`(76 zhOHU-lZ~-lXKHLyR1}z;XpQ8qN>54hMCIR<^-)gUe)NdHpE%uocZs@pJfiKNE_aS4 zTyEd(2>0wm<8*$nO=$4nqe=zu#`<$6}Gs-eV>;1mSy&cKE)C1th`hrdT0?81@Ik=y z8F;iFI8;^90e%7!ptB2f)a;Z@q2IO2C+~aYp=4u&+N46n+2g#5$2AD`-D9KGzoJRQ zpL)Uec&P9YP~jj%g`k88j~(%|O)5Wqd!U5C@)^KULVr~X( z&{dU}SgIQ=PRb<^*0y1j)kTj&>BpUqaOjx(%yxz>&^TZjm3P^*vdKIDS>w53EU$Qo z^RvxtZ{XSRGJ)0606QZBp$^BV84jI${FE^?G>qsX9R~CvbQ8^ykjW^i@r&G6L$113 z*48XqKEGFsVbs8aKRj}L2>zyf+49_YO~3HoaFy18PXP^Ki|1Co`gAm8{Po6sj8DV2 zQd77>XHtn-To9Y1sET>IfVsm35h}~>S0ZGo$qgyCCcCH;Xdi1xWIO;BzcAQpzs$}q~ z=ds+-XSOixmX(qUg?g36Oeg~yO0q&1)y6wbHY9u8@la=`!Qi;Z+2?Ixe@!h-Me4vG z=CC9IBm1g#zwpuN2t&oa7j)Ee7LJYw&(Bj=zy&qBzc}DRGyT5>KI%|BVCGM{Uwd`s zedeuI#p0WsU8#&HF~SWt;6JtT`PnRBqE!$6Rykh|2Nfm#%Wo8FnT*Wo;a?2}w?hAw z8{b$s#j=C4DXcv2qd0rb=8(N&|GFJgPy30a(#m)0tF-p&;w`43*38kkZ=CY&AiQ&n z8fvx=SA(w)G&c0y@oCtY;s7ISJgJDFKqF;1zO3^(5^+HO`>Kx0$nKumFIbqMF!I{l z18~;Ru+#9dlgH6tZ7{$?*s`W#;ag;?tZi9?JX2a$|L?vT%dPteWMKg7aNI(Afrnep zR>K~WMRJ+|Zy7058uO!@k4p1Xe;L1-ek>G(vQJ`PFon1T~#>(M- zgZ{QKV|vH}W0f7)x372T2%v<50`c$5hkghJMsR~j+j#~gV9nfiP<&5CSB^0EUM{5L zfs;l>eL|ZRo^k6md6lhz7l`^J9c4BrWOyN9NcvBkHmgd?bQLiq6vS3P_*7(ahdYS* z^wGny3HYdTRSWW9r;l->IoT$YMIm}aP z$$}_sMN75^;tjv@onvmltpdv$BJh%-x;pYe$9V_ZxxG zy2E5@$5+%0}oF#!@4-8DSM`jUyV(HD73m zywz+C6tjozcPr0@Rxnyu8lm%lnoJA5$3PbQI?mT%VFL(z2XCVd;A_|Z9p3{UUD>E( zh9kDiib;jRMAW3l&tzhdib}N_o|8K$JpR)3Xm!_55ROcLrsPSGrR)|2m~()IrgP|9pAX;H20aKG7`_J<$=s!JRkP80%W``#PFVsuN9@d-LoZA494;PIdViJLV4l!)qH-C|~_1R4aNk(YW`$F>I_p z81q|lT9}z0c_RZc9?JZe=s93vOrh2D+JvG1RlosF=mGALF#Ydgo>GrFtmmKk;YrUA z_E{KJz10IQt=uxxm_-5LR+TvPyAGa<+KEB8A&XOB)cYVX3PfLW{WE0NfqQqBg_)Xx--v6@s;p}vBz zrBp>NSrIb2DQ}7IeGvvxz36V>oZ6p_pw2epQHb1Lbn$X)Kypk!n1k7B08a!ZCqi~K z&Dsm0k;Cr#htpjBk46V-r3DK4P80~TLe(?FqPAkQep1hS!vL|=Jv3AFIn`G*&$VY< zgI#w-k%CuEsi3xX#qMGjy9*lPsSrH zahV$?edYrl8d_SMy0wu>Mc*A9+-cuCkqAz+rmQ39CNVS{xR`pC-@O$_tR*oGXzu?N zu(4nwkY?3V2G3wg*v39wG6-0yc#*aZuQ$rQW?<#+aDkKaY zeh!(r-@oScyCwbA;aAn>6&O$?{?(ne4h)iJV8U&|{ zI?$Mcmm>2o;{q&Uq%rgW4s~gf5-AHCL5Fu1X*P0!?+7(US7Z2ElB0xz2*8!Az3mgj zrft|Jgh{kIeBJN(TM&M1pY&HLgKegq>Yl9%+(!@{U^(G8huCWemp$ofZ_PFSoDV)PlT z(T|75j`FyIKO(SOCKs<4K8SVIR07(4kehFZ8;h>y?w0(A;vAbpp`L_I8+`lC8{eb2 zgqSGzXpTR*IVEKkxPA+zpQjZ&4HXqpsRc)$cWylggf}+Ct2)z0ZokKu4H5g+^DjV--&0ebcUu?crcioLU{)3nV0EiDeYt z4reeOS1zn>!`fd@k3KvMbb%qKq8C7uFDV6-jivbAbX)U-x6#2fD48(q$Dm+Hfo#Iuu3_{7+{b;xY!(yb!I|E{d(6 z1KCzZT(KSR;KI+=obo?#Xft+p+A*eea}CjE-nOdD8&)l*q%G`2<25WUE0b7g zBN1)V>$4~?%F4(Ity5Y<#bf3AjvnU=Hs5?^4GXq7ZnXil%kdqi1}8pkTwF%~+wvCs zB~2sFn<^^O5AMJ21L)D*4=^=yH6_&z_@KZihq$el_naj;9_(LBJ;3tTT1(ws(%T$9}zX2NN1J2#?hk}8c+wWIF)hDqt3(+ZKz zbS3mqQ_?4MKb_yVv}e51x|Yy++V=s(k&=i&e$HQIVxPnG;PB2 z6lCL~QkHt$>~;e?7eEgWr4I)e^hU8i|JD_f-#^fl)H@7?0sMHtFK4@rb%ha5qVZe~jG52QhR{)cSI$VNnDWs) zf#IX(`vp~1+70OqcJKJY2MAfSrn9wYbOrP{(&zD-oEY@^bC`MM?Ws#c18+l3%2-@S zIKF&L1XD;*;I4PaCEmVXcch_l{At+AGva7)omW%IDXB_IYC#MNee{KhbI)JpCV>S= zYYf?2L&Qh|^>D}Q+Vs28cWI6fvvL&~xO2!%NVVKXoJRL;MI+p@N!&_df)4SC>9Io_ z0wxVFtvX?*7b7V~_iOKaBkqc8kJBh(aOrZ_+p_b;?qa!I$&~7}12f_IdDRI>c~+X6 zpHZ;b9FBM#dQ3q&(mRDh9|eEIH`MR`^>j`iO1~F|J>Q-ea8BdLi&%S-k2TxSYHmbO3VD0#)%?6!PZOj>72uv0 zgxtR3(PuE>bddJz@*856waaK2Gn?r-(x18V?AdZm-(sO06d-5vAH3bW-!~{n$W4-o zd#C-Vh9H3ljc%rIx_@&H>v^M^v7#-k%}t-D?HIj3tvK{8HgNjAr?=WHb>3@%CPAF+ z$I2Dm2t!uHPC%_uvuCmU@{59{sxCfs9Ax{aC}~d9 z2brg0t;q@#yrc3KmpA)4yjErSX{)z?9>JAitrs0N5y|r;-6fUwa5`+eprATaK|yro zDQ9d0LZswSe~p3w4uk&#!6Xs%1DTzhxe5>i&bz}^I57Jku>y!*qWXT^`ThFHv*_{; zRZjhmyiEIVgE1_nx#2Gx@zL)667@0P7qLs_$?bUMjiUA=n4QfzQQrIQP!Z}}<$j`) z5hIYWT@ectu%;SN2$nilAkcR#ISj08U1eEh-ZeS-Y-9yKqjM2l+XbsOgWiRLfOr(xmEyA=*f+jC~w^YEBLF>xnUU#{rC_8WH{a5_Xr`{pDx z>dLLYbPrO$uzyz&)*BG*8Z8v8ck%X|;%wOUxyCn^f#Q?o5C zC9AqJ-v|C2T>4@-gBBP%hNl55lAGQCYvbw&^4oOd@$>Lt%Ffuv9gH8vvxk1s-9O$M zx!KRB_?8XP3Y43ZTwL+U!4XuJyEL=h_u@3z<_4X1UvA)^C53S7M1#i86~*5XD~f+`x@{oe~UeXO)}$8mk|c z#ZEdjHJ1#6{zIr>77HQ5?-o}s^eLTJP+;#Z-Omb{Kkfu{8|?e=6=2?URT}`~+SE2` z{3{N2y52i3C|E~Q-bh>tu6Yi<77g|D7z(g~o>?Dfv<5O5Ebu=>*%hWitmzKQz@gmF zpqUiw_d`*n950B4QhBrWwZe$2E2eM^3eZrQ<1Mq?0~QBT&FfpABah`73e$CCF~loz zYe0}yKu(mc2bUATFq-AZplKqQZ z6jF@ba*eL^bL#}Qix&Nzp?}xK6Qz`YjqV+)_0}LNL#opPI4Tssaks!od)(^ZmtVH6 z_l_l5EHSvY9l29>U2!ug0UZvws@p`CwVAwL=SW~kN3_gVuoh3w`62CP*4Bam31s2J zVY=}wi{l86B-=uUzag~6O=b7&85Qo;qK3g}tlyp<%lZPE54s=oAyYN`w94Dpd&KCI z(t+xM26s-jkXyz_9Wa`rpn^?8$PywU_MmOA3^*3A2Iu17t%Hz)@sj!dnhgM|YB$pw z^-gL=W5tWM*72(lfkmz^ugfXGD=KS+>C01$FDvJighGLXx^Gmx>c2TUhUQ93*=16W z!9)%PZtV>kJj^Y-g!96}2#d*@j0dxvu28_2stP1KVN(W=VzVYQ8I3R+YVc`BxH7^8 z`#jAGAki5k@W=7*_(2+E<{GJ%Hvfw~FOX5%srx+c_8NtuJq)TQMw1i+1mWQjl^iD) zgeGm+VHpia8@!&q8H-7NoWJ+UPs-`m2sjwAZRLmY6TUJp7^8@1 z*2m(iWB=XMv8MJ%T*5h#gEV)LF`@bX%9_S%h#*s@l_Vh{Dde=;Xk(f8^$_YE5l5s^ z8N@jwa{1xAQ?&@;;<)h>49pKyd%3E&l*Sm5K&oOxDz7@Snn(I>LJ@A9P@qT@46a?9 zX0@#pW2rs~!iuy>hdmTdN?b*oa&t>gZAZn@&9+cE=sDJQ{~eBqfehypAMJ8g&L~Yl zELUS(&0C`Q@4&9XFUbULXzl|0*`XZ#jk1fy@QHKzo<#|*3n_~y*Ex-a&|N8m(^)*c z_ON~%p0XP#q}2G4Sziae`^m3l%*&#JxuAVHGl?F~@hHo&>lMf-v?BKjdh0b|dl!s` zt}+ZNl9c=)7HIY*1{rb0|$)mZ5#)UoP)ce^%~kd)|6>Seyl@15(w*w!Qfm z#AHl{hauZe>^dZGtxIe+t?6YWi8TsPRyPDW;DiEZyX7JY?q6b)EngAeWpDj=z-C?W z$s9R$>X8u}v`VvBweVBw{h_J!IIeQD@$4g3LiH$VGJ;+-C(!^O3 z$`%-kKXbfMeANWn=V=U{sjxul&;-OujTH0%WkaIxiJn}muz>_-m@z)9ZpSKU52r+S3Fa-xD$4MlDj2DO-=b<`_!dRXS0To(f`N_Ryu`6M*#*3wA(^$l2Jl;?zpcLctaRxb`H&2k;mu&DA)9* znNFF9S*+$7D%0biEy=9BLRXGD{b^}d-)p0nXCY>Cohf;SDRGezDA(IL$eZ2Dh|*$b zNEbzQrw@zNpaK7Upm$>27)|{2O=lV6X9>7fc`m=Cw*uQ!N15ar& zCLj?nj}5LGtgfIFINI7q&V4j=y?X!e+o;I78`SBv>Mu6rE+s3%CsP*cYF~qiYBo0ZBGcLg(kaA;iPJV+nl7+J@3rb zz7HH|QU95UBo6n-xiWtxjxE}G=L%gg4xfk+Yg9G*ezPw*C}Zc~PUV<9B!p#0RerLt zSAeD`;||~d&=GqLhe&ww=?gkgujH(x*}xtn;rIg3JqSvgGg5Ljlf523liQ`00(!5Q z_3jmBwo-9IFX@%L;b%tMHlnDCdDDKQ>Z+exVY~x+vDHT=WK@Q{T*V11Cs+IDq0)x? zpe49WUyK~ts4}UXaeD(uJ8z}o#i){`%)?>w^rQeewDxv{+-t*@jf5h*V;C1U38JFs zNJ!u{%K;K-b3wnGU`^mP!y%HWQ!Rgga)X9ZsP;(yyn{7w z0YWH}jjK`r^B03r3^Ywrv|H5qXK^<0p-@$YJ8(AIE)z>Z{tDwhlGE292=+{nb}1qx z5%GT0CVlsFkG+!3m*gR|^DV%>Z-|(n}t#QeJ8Iee< z*l7|04>cr`32uGfK4P%vaiatZ6p30?bPWVFgeq7$g+RR@nwUVHhN3YtT($s_KhZ|* zB`)?Em3Dl!gjl$~!~hZ)sU(o#aK-4UR=7azNme~jJCRWXwVwTbzCMuZ)s;OA3PvTk zB-$)nih#m^>5b-*DE#Xz8EjjZ=}en$lzFhB$4{ngh!%)yvP85(kTCMTFXw41$k`O5l~|? zG4Fg`t1f&{L8JsajO1-slEW9|`Ii+V$vS;i1aAnhi|c?VkAK|?&=A6>p>syR*m27Q zg)(LjK!NBEDQ0OTMAibQNRVM5W<_b3i39t#+o`B{yGLhlKY{@7yd_)F*_WKc(r#@V z3^+Ckg|s?tvR2tK}%YZ3nbj!Y_1`o>%W$UL^6?q#cM)HE_1Me3ih&hA1 zi=vbuAx*HMuhp&3s>a*AnE##+IziaQI>00y8PMG#O z7TTrjQJ&Q)mDHdu&toU=8R62<#oAwY^p$qRgH&+jiEgJz@lK4)t-B$bx^)D{!1|%) znL8S_jc%)!=hSlWE-bMbH-wRZqX>IiRhOfI$`Bvjf9- z^DNS%T>yK9Lu*`p`1lW5jyOtqsC97dJHTkOCwhAq`D4R;%OMjd6d4GgZhj(5Ulfkc zI6unhBfhV7x+7PoQYxVwJXfdDQ>6wGv~KH8g~9TPhs%+0HJf2tDx%Fb<%EYBobt~7 zQ5?RGB<13b;cF9ayZ=O9O%}fAiRtQ=;39fiI7QZ};Z#yukicb4$n;}HUfI*e1S_Pl zG%o`NS>NssY_wanuq#hA&%eO19DJAD0R! zN+u<-zE6YWIb&6~-AlU49;Bc^zN!Z$aahxY;^8wh68$CoP=E{uZ6*U!Zej6=>&C~C zlMT-e$zzS0bQ93t&JB>?dfo#1$d9|8DG|F{121aQ{dM@JZ8d?048$3O^2jN$>j%E8 z3p>fl$xDE^3;-X1RJ3VeO=wKN5L-y|E+8NvDu@fpba65=Z(ms%qqlFK2>>$|xv61< z@`55m)tsk@Na&JYQ=h8nC`~@jZ5oY;H0H50ekrN_k+hO#nYz;Xpjd*Y-*m(+7Dab1 z;||^K2u?G|yU=%PJ0si}8s6t#*E%n^ydz9LFgq2CbB_oo<5Lk7v|#gEzA5T@feY=n z`$B>n5I{n&cP!9ovfvTzh$^#vF^q~VsqjWrjnTn6B?>o&n>2iAzCuICP*AWV<6l_! zn(>;LXMzLOSwKd=WnEf0ybGFp*b=mG3=Js3#cB^VN4{-tnq6F9cG7uvmXo(I^)lid zGjRQrFh&Y4y{fYzWM#xAy9ENGm*8q<=!ga|fKO&|CEefO+qveE#Y)?D2A$-7z#2If z#C?2%N;)_Wz{aYbC^nO~?xIEU@s zn3J139jN6MPYH`8XU4Z=H_P!Sib4zssT5_$BJj`6Awz}cmXI?bJJ^2GO}T^MsC9r3 z)S{qX_3vzpL{az?E!TUegq@{jg(yGFZ*GbyfO?6b&F#hd;G^q#{h}j?xowpY+9pa! z*bA?S8;&KaV?sU!MwFex4|c8%9YMmZbK_JiENnw(B7sOV+_kYO*eWH_w5BW&5h;qQ zNma8>s9P0@iEVbpOGuFLj88qr_#_65f89?MX60x$TrIGdIxCLJ!Yn zfjV|l(a`*&p^3s~F}-~~hyzFugb(1EfANrdxw)MLWMpJ~p{`n~1bofQ@X^p)P>^xO z9#Z8gRYIAJya`NK-WcICYUY--ruPxm6TG%nAEOec!VF>J59kGe$YuWaX4-X2N=Ze& zCCbXk00S@*n0R4ELXIsW+AR470GO#z_qBmJRIqx$dUS4NIsPMlxQ>{>M_Wkw__n>F$jNsSP>Eg6KaLZ`3G(H0`GSRrK>~o( zDwn+P{&zAZK>ve;xVR+}7aK-oZ=lXp)pbHjEC7I^@tSkn|BfLywKD$?m_kDW3%K~# zlS8FkqM)eQ_w}+92S`m&MB6_&ki9ebzjO`^5&$1bDin8j=XBe0!Hg^bBvgikgmgZy zTZI?A24yPP{qMMYA47U70Ep$NRQS>5{08E^Gx6o|o8Z!w$HBn?z#Haxo>Ng%Q$xYR z3ahF#)){4Ll7Tg-h2Yb^Ncgr%q!lIJlqV^db%%9nFiH5;Rk9M^hrS<)?sS3W`M zC3cX#HBwQ|o?9KGI~d(ntQnmKh|C1dB;|0Vt0{a95)uc>5!a&cB6OkLofg1v(z}?%*cO{i;l4|CF zVnKXXvpvF(_a0I0&#l?_%{*{x=$|3@_CWMmHgwemCLqD&+EEn!yilQ2ZlXx2&;U{z zsIszl;PwFGaLPpg3d_e}RuN-SK@keHc_7dMAQ5QI**WJRs1{s7B*1rVliNWff#2K% zuIdUfuw*k)gnvFN%+ouXqELdYpP?fOc88diEP8f6-2B0xk$*`wOAqICn03dUD;ggy zQT7rfVwAnhem@Dhoz%CVk7f>)@#b%;R>Y>9T0isijqLL|jHB*#lBaJ$FC168^ z^`fNBo#9`?-E9T1;BepH`MKG|K_YLrIzW0SH8b(s>M70Av<#D7#+mP#d z#~QC!24h^i+l#bjqZcj7vD|UlBqNWjF|KgQz00@GWSScvf8;Tj&*KU&#`lvXLkoj2 z{>-REDXQC0#a9pL75+~wRHyaVfuWvZ9(TO-X}RW>K?g-s-i?laO6{)fsB4eFhX+*i zwI^)(uI}KnS4L`{g0~^N8VZ_CLpAXvRFE+oL9KQv4^gfZG467QJ&BRAL;Sa-(JH;c z#CB{M`8uS>%iRTLo;5BE0RbDjz3Nhe;?49hyBC7t?{oV5Anmu^1-e%2n*}~|%JO`r zYpa61K)90;-l6- z<_HhV7)F!{GVS+b!={l{elITHEnNhH4vgOCM>6<1u~b$vvDls*#UVrC5t<^w)EeIw z(5R*IO8a*w8Alge`+Aa&Q8f)v-Nz%mP8=c=r* zQt4S<+6Ws+_Z7cArOB&duTSb?a5=3;DUUyW2+Xz|ISL)CX>+{@8R)H!`mmu*eOS2! zk!sru#wO9I7%KC`rb+15J-lUjUBT3!9qKN>VzM3@6jf-w)A-($p|NR@plbL0ehk#d zCkyU zo=3s;T-;1fI_F!?YISDVWP^HqmRLDh`GR#AszD|tK`1sS#OH))XbNc-OUQ|lq#7aV zFhU~t{K}~KZ_ETZym3^ZF?wA`(imYXfTd9P_)02vZnim$o%j~XMv-k*n0Dgtiqfej z#&N6K?e54G9>WvKa-%`yeWo3{Pj3`m=fj51 zCrMzz!V}%2&Ti7yU$vZ!@H7 znCQJdp>$}>mfEjAKaNUUe*${yt;1wG_c$&J#-PIt9*cBf`tM-bPeZejPv8ozPJ|+H zBR$Mg;sgtaQ9^;mFiq%=tTpZdUWpss9A6h6pCmkebN$B>spml&iD|5?^j-b=La;*b_OKV}(C zNNi2gn(CJE3v>Rfb3^U@)ay%k#vxHEON;URhrjP3GkIz<@i;tW2d-`0_aRX)xa-AH zj3Mvt6dN%(W(mT{_T0(D3GE}UI+p7sBMdwZ(NrG2%bTi?6J7uTQ*#?=m$SC>w(3+AtV9)8+R&hp?!N(^3KU0 z0>6~|R|_~?$eiXzk8LIt1O~S+T4Lf6xv1h; z#G>`*U0Uw$c6_C#XOVxuKl^bpbY=JK_`=ToxWNNIC}!e4KXA>qLxUOxcj;m}W z4DfDQ5k^6ceqg*q9eR7#2t%&E2qn`0xT%84ck_kGcED&h>GNIS`k3;vayhK?_(7(m zz_0GJNXEF}x4aR4*i4UGsLSnFiyt#zN6xLnb*)VIWAS^^K1t^QZeI1}W@{Fpvn4tk zFFD!p(3g>&th%@>%-M_JHMtCg=0;kY?Zy3X>j$KA`JX`_WF=+AYF}7xO@29zfI4IF zmMIHO@R+1fcu9p4w|!DddbkdkYrVkx0pZW<3E{Yr655d!;s=Imxypty`H+tjL%9`1 zW)$1z8uOa?UvU(eMdq8mw9&RFM7Su&$0`uCbHjr~4oc{(;b;eF+FbtJ>8iOuoWwEJ zexB&}A9+oerqc&EC@y1HS?OgBj?>;KBeKL(7Q65Q$wM>4*)By#CbP9hWZ9BISbm;* zRV68Z@fwzOihXCq*wy>Xn1Y~N!g*=B@TU>lHvrZ(!DtzBI^uKOe{cZjNu2pb!Rr$& zD!v1$h-ezqikLE?h_oaL4OP;6 zn-XF;+}XwDSDWFOj6C_KA-R4=7SSnA;+Cwp%4&;lC5g zx!pos48wiHTAzu_kY7y)dKTjZaVL;Tlc)Ba-KM33`hC>=R-0aPvO%$1Kt$clZ1j})MwHW6C*_Ajs=KqYi^Z8Q} z^B0fDZBcQc(}Pf9gU+BuiYScfysG?B*40li*qJSPuBbyY%I%j=l&++@`icR6%f{7+ z^^3jEf`SXEX5#Gc+=l}_+C#UvZQ&oVhA;y|$HmV`gWV@j#E8BVdnMnDOibY65fNiABm#2tlBXb4 z2_!rmA8*QU96M8g7W8RIF!74XMB%%#L;O0jXSBfKdU6-^{9<64uS~1i0GdhoIL@TJ z-K5Y0{BRt0+!ngzUn)MpmjByzPtN-o7YGQJ!hD|M*+pB|KlDFm+5FT{AZK+X*m8ZF z5vzlTUWX!Bz<`qV?VCv)P&vz0yM9)3dZg{4=g9|(5PGtcZEE2eo}`)62?l@uf%U;R zHDUg*z~w4m0s;%ltI)6WH?*xX0~DUtTx2Nla07YGlEt-ZJokFpaz?ush!EJG@v+Mo zT3TA>HdZ6J3O&aO+%7z7^<{Yv9a~8lhFhO*WmXS!tp_a4Doyt;HGHRA<5@q|13%f% zQ7qkg7v!xhlLOJbT?t|(KnFKc#tel!R2SRe|T z)s;6%Ssd2aiu{fyRTEmX45HC{Hn{f#DfLfrAV3t`3LRim|E1BJo}RY%xh=r)xmwd6 zJWkjei)`M_*Rn(8a-sLRzCO6Mpet^k9XCz}7uwUu)Hh8i%4f>tOneuguyH-Vdh>bn zInBVKCjDD-Eu)S-nyBOZVzu6YaB#q4F-7|Q31L7a@u=K2-1_R=zxzK(twLurrSR023cB*BjWPdg86NKXOw`YBqhW z5nDN8y;8|JMQ7r;w!RjeiaGOP=4__oWyRtBC@tO^y8f*Y(f&!&>|s2H6%tPAzSLoR zlvTu8i@Le4F7L0u9eo`Od43x0$pT%|=-!x2hA%xfvY^_eSFWpINe~)+r#T$Gvn8xr zgCc%!v|z$348M`D4mr#Fo4Z{fHFw~w+2)YUm6gfEew?QIyo~WS7X9DZ+-04M)k{T- z9o>F^X$BJsXRKYbufP|HEN`yrsGWjE98qyqHUsQ|bSB~;^qXlDoy-^=;Zpm)GOSd( z*YJAw?Cyh7CZ>(C`(i8T!icGD8G1s(seSN?vMZRxRQ{L-aTAoXo#`+_+R`O^X8TzI zS6W?}kyLJSJ$Lf&C27eV<|q|ud})3S0f$Vnd;d8Z0^a!Re(1b>>$bj%#d z#x2%{8`a2lYmMq-IWBT?J=h+?{4RVc>HI=aZf*c5gfQ{`M7g31yHFx%O&c!GG3wZO z>>eBvl72HgcnDU|(XoL>G$I`i6(}MkhtmhX)Trk5W-br5vgrt%o!c|CUQH&FVnbp3 zNS3t$_}^DBUq|U>ICHOv)Lcjyduqv&TS28s_TvVHK65wvJ?VjPRtMJXm^?LQWY|o%?of4%jP$9;}S+}GJaTVHBTD( z2y!KT+;mw-Ozth5d6{CF^S-H_QnM{ewb@ zkR$B1@bC(6yH!fuP=7F#Bwg9`CKh{=;`>t<(dq;-tEMA;$+g17%L8GNdknp=?lr6n zN9WIQT52gz{Ky-YIV~ZwB$_d?qDX{j{7k25{kChfym%a6=%T1W>U71{5bk}>CU6K$^#?z^<|i2kB#$jWrn zW561l2#P^0EUZVGYlXEuo7#J+2KN8uy|Ri9_>Z zfoSG8)P-c+XMdigpg7yXCX|9>^Sj_!@#~CUfZxfavs>svwoh!xiM$Ko75MYAL7N2- z0$Ca3)a{`tQQ}arood}=!Zgm|z56{+^K@5Ge{9T9wUoXDqY0rvb-n1SpefR>b{s@= z^P627VT)(iMaP;v;^Tj;dO?DfD-~e|2%N@)P!&;dwB$7G@XHb9QymZmUY|TfINor* zB>Rl(THQ2t(**EEAh0G#xK?=iQKlfla23wvdoMe0Zzhko-WmNLw!SgAv*-DGV>{W{ zwr$(CZQJ(7w(|)$8{4*R+fJT*e^vi?&zoDfrfR0@PT%h7nLcw)JvB7cXaxsa=*fgl zruzF+_$zc#B<=W-lE!L`yFIIJ13|St{!-1Fr01sF#p&ni3O&|0dxOV)^&>3Lql{N^ zBi6T&hQBM?V$1p?ky5aO6y6i5HDoAg(~6r(85vGJM-C!ENNn~Oad|FtIQzCM(?^W5 z154@;@urmC_HJ=SWp)fKzh@Ldqcc77MtHZb>ZYWW6H_JdEu-6yyf!K@p^Qv_euWRj zHk!)cak_FUgv3kM-UPAbxX~3Ai<*^Dc9`W^j0feb24lAC5~gH{JQMaxXe!zF>9o|} z>K111t%6qHA}VM~TqJk8!Feu&f^O{|EULY@n6fkU2mOQz5_0)^`r&-OJI&pVcYJD9 zb&0dRV_=?No+}-gHEqyh@nPlVMac=t5+ul{0XX=mV4{J4YU5nT*^^doU6hQPl4ea& z({h&4%Zw1AVL}Ko+`kSl^xi0ykL}HUDuF3DaPc}s7egdSG?oPfG^9wPyg*;|y+IYN zKw{y*M{CF`&p=EXHLF?^G1yG&qJQ6?{S*DyeWg+eZ}W@DsOaXJ zqMx3L0s9H@uXz4BbX1|!jiyDV*a$i(C~G5JI%EiKYOlGT$T2O9r>`0z`h#rgc)4Hp zB0u&dB#N5KST~63C!eHRNl7s31>mi)9J-)RKv6Z@@e-5K1m|tfCen2?r#MQUNVVp?om|kwY>@xxCs|fTXR0zLvPO z6L+vSf2>Q3C?R`fV5raY_{aM?p7DI1FjZ7F$1^i`qUjCh$y$!EIF50wn?$HgCI7QQ zHpYVOOPKq4Qvsx)(s4od9Ca)tYo?*-yyy31>>I9JVQV)OQEoJBag>OmvcLb$N3(aDKTsow(`ps0``8;K%7p-MlwCUdBn`_rOS zung(+#Cu6myD4LOTRWb8$7DfM^JGj65!hP`uLg}e{cg~XWl%5^xN=fbEGp}8Q8OE* zOi8^Z8xtU{&bv?9avkPB1y7cbrhvGg&?Aj5<@jM*+QC(8PI^K3rhOZ)~ zcehqFnz4MPBPP^3njy&03zjD*StfQsv%&MY+J5$*1-L9uyfCLwv`>7&waiF?U+=Py zCU>%;?;F$ic}0h9!0(jt5as*zn3L9%8ODrOm@*|a^w_f{0co?Bl{lI22ieqiqEl`& zV9(b`pSx9Y3v>8EP(&_V@mTYzhiMP<&@f`U9}!6-C^h`e+n*U8osJp?=?~Z5)#&u< zrLOH+Ypk}?$YSr`kM9qIbC?xnFo6^iA9qWVAQ=wPwgTk# zz>4sd3|P8G6Xkq(5lx?zE>q5C2vWW)MBt4Np7z~#hsfJDjDKga4GZckc(-Vu0=g{0 zX{-J`o;}jAaE5(va=c+f;NWx2r_xw=v*N8uou(Zw!uf~rguC5k-7EN=it}4DLV<`A z=*G+N*2rTYE}aeT>})Ltw_>J|TE`JgCKFUs^Jfnr@|!4G!cX_}1%c4~htTT!Qi6UW zIChHI*RJMhU6k4q9(zG;Vb=MA1c!D!z9U{3?)Gz?dq9$bG1T;^na<+#6KEa&%Ji09 zdi5}N=YbC?od1eA=iP9LTWKBV$;ZzkhZtwL>k*zWwcqx5$M$RH7JqHZmd}6t(XyTP z)JK9OF$pMsc@o|K&5CNViyVC~0-mxbe* zii022yMvVX_-)oSf8%Xw^@IWm`a|&@5+YV-$cw<=9s~q(S7#mW4}RA5Mm=p)KTA&! z@(F>5Vt8@%`mRS(Dy_fAL)MiaSYtgrG|KXP^O2WFOw^4ZsVL4*X9Avi8;)l4matZt zfl2?JQ%l9oEI@PAZY<_a_h_KqN50qvy-Z6CjY#C|`NRzvB0O1mn3o5PE|@3E797u3_+b2?o|(zDcz| z9vv>7F*ZTSW*Sv+l0ga)HVmmO{E`59koatI5s))M1yfy|VS$rXj&GfbD6AAe_POBx zEzAA(NScT;0#xyG<3`5AiBeRb7<&#~?((n5xgGT{GfG5!G*=-*fc?J8Zwy?_RZf^o z2z(^+ii`@9QnG#eub47*7A6+@VB@_SYIy5)N=c4~B7bmqpAU-bYn$nwsd{lMLpDF| zq|Jn2%-`yL5ckp;u1AoChsJcALi_>aV6CmGu=XY-sA!sxLOq#qs|~|SQ&u+ra8h49 zq&3euI0=YUdhFlyhT&z{=yLj^@oC8$t_jve@w{Mn6TvoaPlUvBm$1Vj8_t5|E!f?7 zpcJQ!=X3&j$6w!lf9~)#ZB}J}f{laVVyrRlLcBYvIwz&1Nci}mt|6(_=)S?)*VfNB zJ9D{hido5Vjc(u5B}w>YetNB8+&%j%?1gbeFS}>Z}gG&GXwSJiYj|pJgQ)w z3A^wfi`C#}L?dsFKcwZFFEw#xLv6lJ{xF00Hl$5&e`U^-UF=?_eGUFQQ^883+bR5h zN5Osao1Fj7kW4C=bKd(Aupooj?(n}|!$Q*+Mlx+AY|HfpS&o|$?w?+p)<1{^Ygfn_ z&G!Gq$4FNkMz@zYzp!5~%2f8W6l3hYlNx(wOJF&Gwrj7W|Eh-ZJX)l$fWh=odSh}F z!n5yw!aUCwMXlvdfw<<)nk!NE+>a)G5rH+=`}U8SY{Xw0()qYUxj1ErydOT=tKI6i z{{F~@x$X?Ib=EIJWM4nF$tSF0KAY3#@D{)dbEj9<^UV}(4>CC{Q`Ux0+wf-g+-2hP z|Kj|e>=7w(K5TE_62hX5^zC;i>~L~HLpc<4K5W~pFVaRc;(52@B6Pi#Dy7zJcXO0g zXOU3y2Q1ZS2~exWDoodnBgebwBoa6Ns~`w4tT5Gi1MP$Y;_`VRnfq=5f`VO|;Qu-4 zA{#MKr8S_B_l-JFVSJTMb=B6Get-4GTe;QKv7Eb`(#G{6MWw#=D*i^w3CU)&f9c=V z^QIMC{si(esd}7rb;Er9n0DhO^Sf$QRv~gfh<{^hhQ=L`RCgfU5lp|A3p2EX3|?v_ zt_mtEO6|FOh(KWpi@1D`T!VGBzyHWZiQR1y>do`4pE0n0jqW%udyDG#B;N$8nrctc zUrXY!JJ~$LTbJw4^T;P13|MXSB1o#`j|Q`+IT(7MGF(kor*IPe>-q$qDFaca=Lu8x zEJe1UFjQ8{(|@-K&Z#?JL8IDwH_bjPm@1p_(X*rOBnB?pF1136x>h!rk4sMeTzrO9 z2>>uYQ@Z>Ye{+r17c~?V|0cy^v+aNytsf&=zpN@P1W`oJ0Rrp>N^et zY8mUEK}ZZ3y4i9O?AziFN?mz8j+tSx?+|>Hw+zC#g5L2iCa2`__Zs7mou&^xFIIJ= zPTIEbhNZ)hA!QEi%MgUB*9JbPCw7w8uM5fm5#d)}L3Et*^Ys-G{x#8i{oNZ~y#g{b|FP?W6cir59 zDs{Xa{rTa$XJ_R@IDe*s%0I~_qc=x~z2f-2?bkw<6^$F`p_t57AAcUt4ev~>j|NWv znTh;}8Doep)~#Mrm=Vi1K9ZD(%@WQJa|5hB4pb1hyL4rJKPc>Q!BPsSzP=V%Jz)9m z*{e;=pRQX!W3EvBZt3+rZngE=YU%U7KWmd+yA#^wM~(KE>2F`msXd*X&^y|Gnt;Qo0Oq6s~B^sd<$tT296Q5SNh|TM?*Qk*qP8tx!trZEGXI3~-aw0>5 z%q67;Go0pgth_)cNP$R(p}G*fR%oldmReRYk(kkwW|Olc++D3y5*TLj(es0S9v!SRw3-kq|d zPR~>|-|sfP`l)16Uyr4wV@Isu>0A>5Xd+-^sM z_-+r6f!a#5E402HHTl!x@hk{ha;m+lbjhp!VL2or28SguuJS&TW2Zy+D=lGn9_c)F zhKsNN8Yx-Anm-3GQ&T{5SkR>O%0=_-UhXTXl$#=A4H;sT=p|RC^1BNm{k9e$vpBhHU= z$t1{zps10+4S&twHHq`(Z^trL;(6n9eb*;kS5}364T6v|RaAYQ2Pcqf8Y!VsXMV8GKa08V!m`wM7~^@tcK=G4ez zI5KL=geqk*#Lr&sWYr*VeMVglff6JX@N8Fb&e2&6#m-s&RSAk6UL8a2{RM*&Gd}tl1|E&!RZq0%=-aBC2!6nPy$qjlu49?OwbQ z8APVxwOF@`o+N{9i|-CPCur_m1BF zc4Lh1aA23x4&)|0VK+ox&fdmvhhE;SLO}yC>@!p^5)p0QF((Cd4-Ozv(KR=9(u|$$a_IN zfH~(^O=w-+_g<_rn8!WB!r?$7@PZPH;kf#Z_`7mo`f?oiQJ-ce$@u)6Z_8^~pP#+Q zFQvsAS(?0TePctY;yLM>*J*hMkUIrfZhJ*Hjg`R+h7K<|Z3D)7Ykox)qNL4c+}nS^ z^t1c-<6pf-=uOAkCj|351PmadyNCENHn;+4;fJ4#{_z#rZktv^Kd3PpV|tNto&}aM zJRXu>*v*ZMNDbED=4FX*6(UC-q}@Q5)Hj7i{dF1}qb|3Gzblf}Gmrlrknw+50Fu_6 zuzIsMp{KXrn@dx9QCuO*MwNvXizYjYvaYVc@(>ay8);1y4WKAV*HgL7Ao0W#w>i=V zay04EzeQvb$WMRG-AN1Z)5{b@0`_RJDWtbsTF+} zsWcjfl&0RG6m%GiOG=XJreA+Km@*W|bJc#H%UTV|kO-?ga@n#hUl*7Eh3aV>wtn1@isb1>rO;CLQ~Mw z6Y5Q68h8$Aps?cA_j#ceP4U)b-N(+{bCQ$}D#zf?8XvEywk4u~=MI_yM-Luuf3=x) zzo-TnK4zBK)G{5&QgcGXVvR*pRrl_GZwCxb%iv=kxX|%95!)FCm4$hM@7K+A- zkQeCk!Iw!MK9%^e*rSvNOeK8}{DFl#{Afsje-Qup%wyf~UM8_?Es1H~`b5{q4l3W6 zA30BxRZ;p~p@_vnbefzMMMrSmhdttbNBZTpEre{G)N&GJ!=gHfk|kUT7`##1I5;jb zP$t}u;b%T;H21tq82lH#7$H#?xM#Ft%C7i+7u|8QfUKfTvQO6%25;%c5u$q|%5EdublW_;$uIdGHRS7`J|>6jNU z+`9edIImYx0pr<(aPq4~>$n?9l4(1B9yoOGnA_Byga9Q z+>H`Vb^8%VWsA6|658*5KKMTBf9%iNk3^xh5EXlpb7t1J zBW{@qYN?Uc$)ka3Z+SqbiOixVa`Gs_OVNPQR_s`stw}#BTlDano12<$G6qB!&|T)`58Bj-0OKWY3?O zlX*AYmaWc}k)59*xP9x3TGL5P=?;aMxFOw|EdFFKTP7_OW z;dje~1SpJDKHpBVGc=es886cTI1IH>!8Yuur;7>-SQCgSN0kQV9`{{F$ly}A(_h!T z4-h(olGBq0{vpwRBYn5GnNOCUPS8u{%MWX$%6mo|Y*S07O@$wTig6JjM~V==>eNoSo5#8&6`Tb1i1xawy@2&s&maAYjaJasQ3a#u*vo zl5-Ulzz~E^s}VT$!b{8LLVO>cJE{~Ls{=TSeqCD`KBc=^oU_-voWehJM0)*SKdoCrVTl4H_VL zmIcr>+!L63&*;HWT&lHQtF=fq+#dhomNEK8OGqOT&_X#9o z#IkIoLzk7yYB^B~lj^mNm?l?hDc!8OEl$o5Wo4w@8z4@CH%2K5gz$by%@rl01o)9# z5=u(Rp-3r`ZUR4>i<4e(Nd}DMSjq&Pm~Di1_o5o@aNk>_WY2qrCL7MXH&0K8ql^f} zB1rcO2@XOaV||K6!(7J3HY{~R!m%z9S5;A$b1?=g=>2>yf?T#&f^V2!1H}G6qEA28 zF$>riUppjE0U-+c10Nwm#Q7_{KTvomOPb_&sU;^&Ny*R3ULx1%$D5ptqlKfONWh23 zPTAcE8|o z$jZo2Yf1etpZZ@?_0tH6=xb&%5c+$7ajs&>bgc(u_0_0UI2JOoORybW}|? z{+q3>hr!@n4PZCIhm1@>JE=6B_`h;Pc2!Qapz5exr7yUfI}IkL<`5f^+&_6?8MU1~Z*68;`VG*V!`lOtx^cQmSh3Wt--VK>CUN^8qs&DOugY$@qKPMNqinezZ|W9uSL9+}op3i2$Jj(EkRgb5!5kU(&7 zb#Am1c?i;}8q9d&PCPt#(tPf7Bmg&Yu`o0;R~poc%1WB!GTIz2&4&MZIxZq&n1Qil zy1li52s-vFyr5vcph=Wm>V1#vq*?GO8UvYh|06HcQKY1z2#~BH$Ul?{D%i92^(!fei;Hj^IM96l7(WeAw;WIk+PdOBh!mA# zCMG0s+G;mve}Q~nFLWO+7oY~W2e!QE!w^rVDE5puLa?mL5ujYqf(#=ZIB(e4i`H3% zz7Q)nBZXOSUxV}8B_iU5n1vUXmXIK`^2=L__8np9rS-f5(v0YK3OLXs9WPrSTj^(s zs=)8qRg|}Jgea)4Ml^^vxwa~$fZ4E1`9lbMFwx{=wENZdrGx1s1bUC6Na)sRW9Ly) z6hQ9F{HAKmaI=Ua#_{`K_$p`-g7f;olr?A5`@vAW_jx9!S#^t=EYQJMiwD~j4?|NW z;yUM%AO&0-(X?27xqKecY}Va0OsQBVoj~6n0+EOf4kV~A#_agrm{Ei@8im)w^nqNi z{Uq*MfBw}EE8IVq>%bcwdN*ZyY&?)|7tnVPW})G82)gQxlox9!<~9AJrMIv2IC+$9LZ9j&q&qpwiIxEm7Jd?A?a>IHioDM}1o=3?0sxKi#!l zc=&m1t2`w=p9^^{JwTWqV0cq4f3s{o{P)8i#PeSlxm2j+YfJ^KzZ2H?i>y1J&w<%j z!r|Bu%eH4-izD^dDbucvfUDyIgvvUY3MZ_)4zWMf}}A9N@OA<49k8DYqCN-oN@|oz#>|c#bG~EX5En;nayMia?6;|7kwSPygSf#m zB*!hvU~KuzTO8upZN9}bx;NbfE$!)(-jI;SQxFJ}We-M={B2eDC5*fXWslyzGgvY` z!`)@~HPoB4IT$ud(q`|&m^P`n#;ZzR~H>tnsF`n5;hK!x(fu|Ib;dqhU)A7})hUXbv%x#SL?BBM- zw5YM-I9q{t;jC)#V>J3*?~_XI_li}dgSirq@fxCwnmCeH+u=_hD!y-O^=?%OFC&&H$`giHcsu;GXt$O)+Lo+m z{ygz;!QoXPMVs<3FIZJRq{Qo91}#9!bdL4tNsTsy_p??jKE%TgS8-|6*h#J**THe{ zxa$N;ukef^xdu_z%3J+!lEq>lg{+~NiI7PKk|2ygx3!lZKm}tH({f^{#_EY!)(u ziV^r!u@UkJ8UJYTxFIrAMK-L?pW836@VWo5n}~p2KG{2(hv<6>;r! z-lmz~D1l=S^0+eA$>N8=R(KOaJ`bx_RU+qf#C3amk`@xaHrF(t3v0t-t<#ju*o>p) z%KYPXve{A;Y#FJS?aMf;{-kdv;jPvuqgNG^><}%e2nxjJE88)da=R(wGek~ZNN#U% z5Xg+a{b*0x4E_F3EMzlsPS{4PJyOCv!ZyW^>v4>bi5H?7Tr5ATks7)jF8w4I^zG?P zC`8$9u-i(Akh<2WAKbdh_{~M5^={u2D0&0apX3(WKtQ$KtkrAsG2_T=M_yiaX(XjVzj$x56LUK;QH)w+e zj$J_o$xJ;bl31$9y)tYbv5KBOvJNH+0M;g6V%;Vd!@?xT_r9Ozzn~sQxI3gyd$8;XjBieIs4?9E61lipFAa?l5R4Wi2)q+N+Kl4(Rgxpi(ZX?G> zZQ<7!G@s8a)8SkrThsKyTK&UkdH;xMH1U0RdZ*9pE0ZrhT=jXiuiKLb z8+f6|Id{*ONl}r~VujmB<&LiM0D+O|kKx*bt+MW7EOPk91o`h*GE!E7p}g9-9W zLSVxV3E63%6x5?Y9vG;oqJq4M4`PTVQ&A1^@N1V;DioWYLaa@LhRl%BN85SSMa;`r zs^c8FFhUX58%m1PfB2JCO37hkaBl%SxgY^S1!ABD-xf;gV7;S^#v`>Z4(B&x_d7@- zAIdndhzK?c>fZ-lDqp9Q=V=oC2$h~d;A)mbG#EPYL~1@Q@j*W-8Fp#M$ftcR0e@*A zkvN@YMPzwjh#2)K0~K3vG=4|gdM)Po#sg$#qWJAX4^T@QZQ%<3mVcE{`b(xyDpMh% zhviyrq6JHEfz^N+9EsDoHP3BwpzXO)=4BZ{MDcVTosR#yZ~1tt^CR4`(aRZB78Y+9 z{C=P3e9K`J6vtCC(-D6B96MVW+OFG?q6pligZ)zSBu7}fRBIuVa%+{7o~-gqz%H} zg*p7kh{?TG@>^o7^{}`Q{k0uYK#GWGK8*f6?ijOjDS%~Kv!lPN*|`-4)7WERWqEST zEFjw@yq?VrJs#EB_D8F&XDsX%oCj)M!lO+_$f!Ba(-`A7K%M3Co!RQCX-@qEge@@~ zd|6K%hu-HJjQ84mYx*J5kV@fh$Muw=I`jM}MVx`uxg9Bvr?UpBSN_*0jE*5vST`t> z`HH*|b)(+5>YYaB+ay#3Dnm~Tr$-@fIV`yVcBrB;378)!l!Sb0 ze&y0Yf(dbBY#ZK@#n~ zfKM`_0B&14WMt!du&JWr1DU;~Ld6TNezNaK`r!?O3WHW7i70oJs8?LlelRGgr6Tls zQw)0Ml$j=P*c>eF1wl`vT*VDT3;AT5zbWqx-WpF zrY*!MxD@MWUEZodY5Rha7gM%*Z>Wyh!4adRL|lMpk=VdD8=?oTXxglb#&4ou{yuvS z3=IFdkN4(_!>ovO+B0$%`;(9$M__}D&Yo^JtGJ>Hc0n5nu;k6aDB4+q|EA$6 zQW}Z?zJa}8Yq0r%s7a?(rFmkU1+A&VTCLkz|oD)y>S7uac0E5p01hyg$n@^XS zO#-pU?HkJl8`$ot1bMUDNRQ}S%l7U2zeS&$zU`IuFPE#XBN}9)lG`VM1JBu+!J}0= zJ3=aLFspSH^btf+r5f_v8qL61A~lU5>zCuZ_J*O7N{a4UUlwT_s`dV*=Bi-4aQEQk~}*lUh9@4iHu6n)xgp;X{H!^-JQYXLwG3#+{gs;)qA zX4YH*50LmK%$9OR#@V>o(ZszcVP8~L;=N~i%=utW`K~@EAtSl|?b|-G0;2AM+rm4E zDQVR{0;1+PK$3_z@0O=n>{+PACz_Co*XXZlq&4(4o}0MjW$^xd7FU$h&Kkx(w%O)v z?m~1~h``fPe&F(CyNQA}-L>hpmYsAkAU10wGVB{~*F7n0^YEPh>2?god{#Vz>=z;M z??Eh()p|wO9ekA$oSHo?X^#2_KZD>ceI^pGfllbp>=hEeNBn60PR6%r z!9`l8WCzLRdLF480tt;P3m540Qaq{9LsGwQVCP-TjlbbSyw!$8B0@HXeU}!2n3}n` z)v2IiA$cN~XIG(#84iUr>w2;}FGYpVIY)(+o@nIz%}nM2!z^N}3FVDN2$&W~?j7&l zwmJ08_G?oG(k08!b3sMJe8At?sd8Hikg9bBT1v%oiRXH7O~a_&1B6eIq;TN+7)IDQ zk7il*e|RVDd?<3s5f}u>s-7U#=C7#U&8skgmX;E9&^EW1{<#Qvd<>F43mWfrYJ91dhYx=K_n;fwuV(p4tvel+oh+hZmv91z}!^auMa}p7hh?i z6(v+_usfC(V7P9Y#J z%qWbR$G}ISrQf5Uy|u7wvT~=J`AtvB8N^shp9EnNZWAP?q)q!K#N1l!$hoH;#TwU>`-3Sv&H>}>-0-0gdZf~jaO&5?$ND> zRxZ-0qdQG(>bU!jdz9&lbtM{SIYp{V4W-4Xx2giF1+|Yw`UQTKrDtnF#nSZ?y)vrG zqLKiU%uM5wFLaLuyyLJ@5`VnwpQ`2$IgNK^)$^7<@bb(?I6|6mk+fNVavlCJ;SVEo z0WS0P7W#JyyR^Ra+^2qaiGNeByoYe43E3*dl$mjt1pb2vkf<)3VUtUx?n(Y&&A zYMgjD?6?j;IrwbXR5Y{2)&^DKeUTcX8j5n;98g*Aqed~3VSHWgJNNf3J*}+evdRFj zkZb{2Fj?L=)Ay%_=B)t$B?-6Tyj*aE1YG>mkvoMrkC`Zt?pqD{aVL4!jyREw5FyB7 zX;EWGawsO5Nx&t6rB;A~FBtRhG={H#T`LRwpZ`FA6lKatV7vdo-;No|4T3(tTl0cu zQD-!ihs+ke@9|_fnZ^=ecjd$uEn7Gh=|Iph1?&Bu)RelOC63(C5AGeV%xI{C;|a!_ zy}RXT?L^KQ&PWuS?4ER;MTnXJ}fi#hA$w@FcxFjQ?{bP`tvC;ZFZZf%l#nwfI zaaQ1hM6V@tGX^(fYYc&Z1Vk)#*jJVkBj^&~BMuOOw|*{`PuI?UE_q{SSq?g;RDb^I z_OG~Y_9jEIRYqXCgTu=D;7=nJ%df8?J=jNFj<5x&CCpeO);C?Bo5OW%^^B&ymQaQG z=&2CGJIe(fl^z9i`2}vTdr0&ej*g0(_~_?)me<-qj>-#jz-l*XAh+rJK}n}N44{kq z@WkNTPr5yvnI5_i3`mp-69G9f+3;i%s{SegA>z~;PhEgltkSLzPRQV$6(!bQz93^P zfr%ozQN1#_3L;hULTiiR2;QQVQtg9OXt5!LI}OJCgJCk-(Q31bP3C{X0e(dCZ{-<$ zFiTw-_o2QbKW>+}{jcjQbd(hci92TR%ml%<%_4`j2%9##@1UDDf*f|b;O>ScM_W93 zSxJoLeXgqytGP^s&F}xi0-xMT|^nTYmkw?)++q3^J6K45d_wp1Sad<^;+K|eX2 zf$b}>(Hck!VrmKD?GM8e4V7HF8(FMPE$97K-d8{6zH+%E_My>G?k(TlocV0eU~En& zGKp+H+ zNI3AP9zVquOVM$%m)jPnwnV+gxJy~YjfObhIK2ZA?V+|wl$COj>imK+`DbM^Mo$;= zF5Q+$1r8BY)uIwU!#B!x-QYmM#~M}-<1mNYVm+H|Ml|&_=5!w^?E?Vhznr@meAuJyTzKg@I{KGzgSwY+uA2%Z3qj+T%ub2*}Iy`g28F$~|Y64;pS z$*4Y~kh6mOy7|_J#K;gf+M>4J>7!NU$P-s^bQzqm&KfL~x>giSuOkz(`0M_*ly%6g zAO&4oN08~Axdw=a!*k6Gc<6C9hF}|=dPMyx3p!o^KN$0oB2wyehX_$Gbf=X?KrA+` z=VlWJj+)Txrh9+)x2-B`9?Pf{n>$y@{m)Guk`c^5-%#_ZLp^qWOXycU>Y7qV0lO;I zT5v)?QbQ#Un@SyUiwkUGD4;P>sy_cFr!v$L25Zt6((KAMwkQ4(2})W*WxxeJg!q1D z#ZCo#C7moWW@4?XYV=s;#arn!hfzn`h+|^I0B*=0%CzeO#)2jnh7J;1?0YlFa#Rm+ewk2lb z#)>a<9|9HehYV2vkm=}pj?@1`V{BQj=p}z%RW-Irk|3&33%Mj<_kOlRzDq^%`MEX9 zNb+%3Nn@n^HLg}|!C~q^84_*UD0KQwkC%dxpQwP^Ja-!m@j{aueba36qWnr??f7Z$ zAC&M71(}fQD%+*#Q)$lRiXfxU`zUz;ZZmBRKZa1c;YSw%JabPJrn3a5JJP33Y zC1(N<{Z^f%3r7TdIm&gw&~K3b->Y$g!g9p?OOu!=uqs&>B=RDenVA+gHpy^=oHZ7^ z3^lVwj$)z(ON)jkCNmpl2!U>w47l)sm;7mR?8?yM;$mXD^#*eUp%E!~E?;YRt(#WF;BIY^ia%DO^Q3DLJa;$`UJ1O?6(l{@yk4#omd-tTo<+LhX{W=eC z?l;%-sbv^+1r+qiiUCFo75c&_YO4%dW>~EHTSgm-wVuCXNpE$5h=|*i;ia6|qj9l4 zC<&9fyyqC}1+uG;5hmcSiW!fCuuR6NRw2J8g{5Lfn;xmlAytB~Vik->BJ7QBHwGWh z&?3t`VF2n_3s+VoM27i#D@)_NNcZ-gC@H)<=_>!Xf=~UTL`= ziHYTuR3;_zWkltP(OEU0_vy^`SnVh|7ga16K~gRqSvg?VMcY>2Pp|3u*D^s4R}8@ z>}KrFVUmSYG5moCK}(J97#55{6`Kt$h_L@{3K9uA zi=q-*sMl;6GF;}u4VM^)gvJGj>xZ*$yiT132Y&tQ6^t0iX0C2KQ|NG7Nkv8`WF+tbc41TqXZq_B_@ShbnBPq434K#|teHfu8s6B?08pn07^ zSWt$h(_M7AzVTl(B3Z$o$jO=_$Y6ny0mEfRAwnUsbI&zgu3Z7hMLTh2nV>+1w#~Sx z)^6Lr-d|w~3My!-%CoA16gH#i##kY+b^N0I zp&yv?9yftFl?X+GL@@{vF5-V+g#UZoB@tG8{xtlA`~MI$|7-vMyuZ#$pjF{Zii(CN z!zD|6iThoisdl|#0as?7NE}boIT&E^S)B_F42Tt0DA@`AH`*K!=dOgDTx#r3bc@HK zg!=3*G2GNq%Q}TUU7W29MWH)7*VI1cGNC!0<^S|duFaj!Jc0~EIF%moXROuXy5^_3 z%^ox@JHXuwz$jo!tpSwE=h?MA|?f?|XyrrgTr<^1c88DlXFlFz8FzGM7k3Iu;2?@7y*k8pY&4tN<(8pN zH=Xk}peQ0j0>VvR8Ta9gB3w46hUqxhCq3^^wJ^zYApEZ%Zsm|4 zqH8Oq8DPJU%)nx6i-1uRa9z~7L_zP zbvrfZt(w5_^<$%~BCTXPjayYz*f6#L`&wyl)7nLGY*#YqYMhP5OGj4|q|h1lWI6>D3#OFJ%0q2XMmChqZUEI+S%^Tj(>YSM-1CF z7%Ht55-sZY0rFIt&Zitlst0Lu@9~d(n}faWy3#$&xzc20`wTfrI$@y(Z3gXF3jjbq zUj%K21X-6HRZN22@d1^MC4j*=p@4wOow{aPoXR(z@+dHXB-zd*@`9k6%!-W~iE#h1 z`g-Z?lHia){YrhN=?rTJAHJJ-L`!Qt5$z&r3v1*<3jl8$$G?pF&OOC5^*{8_WLz5}RkS_L>!??s z$FU~Xsy=rc{Wguy0~z1AO^oW!r!Bc0@Hiv+^$dBjXq_#e1Gqlg8ggzv;8ut5xgF1z zHog$Vs)tG3x8QB>sSe-L*r)6i8JSVP%Jh9%;pn#qGY4Q=>$QK1Uqk47MYCt zP8X_Hdb)BFXta^#o_mRB*?k7kxwWCJH~Zat{dl~VSCc#0va-_FF}LaATP;xre^lms z{^8kZH)noy!vChPXZYF5@ActA%t^*c5D+(j7{=kWJztJysZSWVZefU#t2>^`wtL=I zL{@n`5;kRUA(pTjobiTs!$}zIn@`_OAL4nDkA%Q?g;enFev;#vWHrDrHm+Mk<~iZNB(?xvF*|G8_POos?lfX8fZd~ za!u*WadymM%;9U@Y`N7x=d9J|`np4Q^Fq$xJk(LD#)=x8SZjVV7{werJ%%5ywAR3_ z(_<{6K%Vq&QpB7O22AthL5dFBG@{%b-35{cJC?gvn@pV9J#D?fwpUJ( zsW2w26Ng)>=Z03-hmhC!<%YpP%-ik|C|PIAWHWq(Gsj|pgNtcjm5DH#cu>%*H8U`2 z4w)&=xFTSqvoju5j6O&~_A1c4Wd7h+#i9MbpJfNa(iu%qQnbG&KTcpgcIUb@Vx)50 z&g`s=rpdW);H{}k88*7&5YF43tgRrO@m}aRr_v`|_;xRJUTLO%Ri{w)X(Zm&l03i3 zb#hUq2)3tF@@$ST6muNZ>5H5mJS7s-$qy-@Z|g%u{v=Q;*VU#gC51j<%nFf020;q= zah=S-j%B%M@qo+nfyf{iuth4Q$p}S|l!Bs!7^hB@OPV`Po{}3u6z`BxU1|M7R=J`e zV0UCFaAP(jl8lo#*x%BM(TJQ$$4Rt-PDB=T5ra;sQIJvNkGnyn>Y$3v<$-Rx+-o&g zGbETbHh@>t1X%+{WYw6SJN|!7on=5AOR%U34#C}ZfndSiHMqOGd+=bv7ncNGAh^4` zySuwP1oyY+oO|DU`(uCf?sV7m^mJE!U0sztb9{iHrdA~G_#-A{A2W5y6arVVWbZd$ zCAsk&42Z)9?M;#AcMj@-)2dq}zW+44mY=Pg!_~K^uA)B8(B})IgSIS%ulCp%yiG&V~aoohI`61usz(FZHd@C0WPUn)# z7h3B(j-s;X7VJ(UE~7@AeviGCe#7}gGay*JQo-J`XfW17%jJtkVqk(Z;+y+N#z?`m z+N5^RabZ>z18gs;+nf=EyoyswAE7E5G;lYVjc8#%UE=nyIJKZQ$qc9T zzM>eMiE|T*SH)pfj(djG(H;ySt!0J`NPR6O@M=^lSW+_a*ROD5GNn-c_^yDVJ$RWD z9e5if4j=XgHOvJ@B55{Z4HTS(d{S5rPE{gcbFFgv z+x&sN#96NNe$qc0LZ&~_1ri*T0HGjZYtA;e($f@3yYm12CS_<24E!VBWRwU0ZW5xR)9WX{kO;t zFV9k~>(?Lics0EQw7*U9a7=oqR@3NhI42HISqTMH$IeO+vRiv&cq%C0Ej!J{8rgGt zbERzb<&3@1bvYSwi~45W%Ugc>UDdI$6GH*Rr=&#P+j|!Y6Y%2F6~u?Sb)to@zb=#; z05v+pCWUlGXNpyiQ;B2uzDmrBAkSUz(|m@%oPko5CdmehIq~q_G=dhJ9_p18##yG( zcmt++4ijz;a@+8IS%CBOTG$)OtF2TfwOMkTZKX}McO(sN?hxc4u6okO_B%xCJHW3K zioHxzJUqyj0@BwBGtA;<%q5SPjNsUo_$Its&#oAXw9215Gddt(DnNp#?}rpx@TRzp zwKb0gPOTF+(a>Ke`Yo=7(ltIIVZDlw(H|-Bnq9LwERMQyz79iDtj;bpm^O(c>9UYm zG+Lg2I*(}z+i%&+cXO`%ZXYcK62I&NQ)iF72f^3`s zLL0IQD)4+VCr7iLxb;6c<283BS^185tpG74<95aK_?$L?fs1~I4RD~=RH?J25O_mD z|15U_bk#~TwM%0;?tG?vdfaO2PS~;RTN0KSg=zJ%H&5h>DJdJ9QG}EnZsRp46+KR! zh{h_Xc}|@mUSry~R3{VIkkaI<^$i)M#6*(b!C4Li_Ez}L9Hkw{?7S+xPR6v`J?^qj zr?#tD`Ci+`Rb{{KEmOy3gOMoanMBi78}(an_w!<^uZ&^vts=7a2qEToRw>~M;}kqS z3byh*RM8mC#2CVkRE{20Kz#gQEe<-Fn`@rhp>QRu;xBnsEePXrRbl-J@tFYv2^f1M$D{6=kXC%b4k0~o5>CcQ4-0eu8*g@gE@xS9-{3PrgQ9y^vp zp_*cztp)(Y=*Vy6eqVW!pf7H$&)fpjRD*V?k|Ng>w&0C}>B5)aX_W(@f5nN59D#bE$*c2x5M#2_2Zv>xOFu<{c-cXX zwj#|4Xd|pqtXqj1eT!O_X-9;6~!FO%p-)m%>_aoAQ1YF3L z?-cG5Q9IYmnh5|CwCzPKIY>sVb9!n#3^7R;qys}G-luj*wCyEJ@Ttw$`n8)Wp9-&S z5>^SQq3gT12ncbsU@@Y_+##P&8D1fAQ7pDbRX6oH60QAd`&l zThg_-o_phBah0O5qHCz)R^T>;rR3AH)>T{Yipv0K1wxO1<-N`7>QnALny$n|h|z)t zJ9jt-&C-6=>pOV1n&HixVWAD=>KM)KSU?T^ty+=NEzh+ve0S(>K0Dy6wuoD`b=|qH9B?Te>xv8FsNsdBGwT17Be_5B%d6jGW`{v0 z>k3RPwwfw_$KU^g+;p)2u%xs!_6=3OP?a0nN1j_W2MAxC=y!6?(0&gsN{q-0bd^Kw zhUnqT7&^Ta3~76Zu^4MgK-JKw>Xcut%6FdsPU<8nhhAIR0-||u4X~&e;ATNW(igkq zBx^MZM|6(k{wtca<_3#^jwpqK0kQxfF_3=+|30g0MV>Sj{x%zWVzuFYTcwpFcGic= z7uNhBPsO3bfI#`m>-{HWW`@8{`C5Fr-xu&ofYO3YJkH_qkzp;SD&Yb)5yBz%@V??b zAq8?G+>i^1-cRDrp3QrC_{K%aeJ(Vkhm+h5Tcz?T`T1d~zL!?Tr{ARaRrCy}id#zl zDAdrl8$Df8Qim1c8a-vqXwp0D~Kpn#=;x%+F4m^^|N1?hhMzY%Iq<(73Szc zh56(~#@Ujlm{|`*!ko)(I2J3LigbA7zyX>n9bzZwz%jcC9I{U!v@UPSaPCb84aFCG zIpeFSzQS0Y?MQll`Wco6C}n_$xkBNoiPV$P?#%+BQjnJ zHuFc+#i2z)2X6QBvCy_?#WG9ckIIyoQDgJRsMcohwkWFZP(VEl{KZT;zvqJ~J2;BR zRJ9&!3D-rXhA{{2P&dKGk2CjOm?^d`@H=A52{RA*V#indFIzcia;L5&Ir4c{C7 z9;qj9xuhO*9`jllBt;Bch&dRhY9!cm%duu(YwNimb~ZhAj5cra(2FtoXZnMLGFO>4 zd&D#iM^3XXTqF%A%F<_?!)tP{K6??`!t>5h_JQfirASBi+Yt(3(4@k$wF5II83tnV z6pv`Zron@|=rDvL++eaH86l1ayNMq{co4>hZP z7#v;*HeFUZY86%p+_w}2TvIZb?G$q9oE~Ac823=)@PFFfYJKrEL}+K+4VoDtn=FH` z;eseuW(9slkmmSOK2K}UAtl}DGz!5copd<~aI4$j;T2IIG~;}8oS2>JfdvIZ2))7I$6BiSbN?uuPy!fC+-k8fxZ?xeST4P@0Z3}3dfIFZ%4HX^N$OI+2r`7#~N{^INE z6f-4y&YSTLwV4D8B_yc!_Gaw_aPIUtGr+L$B61$o2W;~jbRc%Rb`>RP_S+#DRA@yb z9NWxKdld2L7hFbm*R3tT2U5j^6`S;xw6+KT_bpC{1O`$ZyYo$h8RTDY<#L;?DAJ|I z%bMxO-w*Ii%n*<=-pWtHE)*Bvu&}-GxZl+hddKnL8f=Add%LWJ3INh@EmK8qt=2JT z6V|yeMq-1^_lB~%zce*#g6wq=X)L~xOH01gH^T5szR=NozeN0%Vr6}q{CKfm;^e4Z zYq)9fADuy+eVsb}Fz`nBXXyWHQb_nE-^~CJq&Geki+zi`$zW_dc2)%(7-Zu13@8!C zU(#yEYVnhm2W}K6%#Y^ihmgm2XYn{Z(Mb>Q5FY%+Mj>;CqE9uX3W=7fE($=pP1>rO8udhK#Mp=Bs@1(7Q2I8 zMfcq(r>Qf}Bagq(E&Y6}5xXU^_M3jg&wnAZHH7LjnIQ=7D|SxhsU8Ukq>0>l*Z0ot zmRe#6!cr4MQU93V_;CJuvU2MUpDl<(xBkRV=TT-p+Tk4FOs@aHylhQ1(n0Hp&4nRj zS4=#H{NFhV455S+XD`%!2#UJO0(26?l0XsDP01nYuGEG;U(tWsbfmOK)S-x;Li9@~uQ70@&7^R%Cr4mAqRa8c*FICLwz!dRo)_=WZ2;kH zw)TyvMmrh0<}HabcE`#*Jt!}%a%=wA7eHVDq?nWooIJ1}$Vll46~){w1VtNkB*E~} z^EBuFBw0^YrM~OcYzpQSfj0>#^4lFIu*tXC=i5`Cizi792o@Dx{N%c+BeQr-S(P-A%Ts}B ziF71!dovN5At7N?y*0Ad$m`-y<7#(#90m8${Wj8yIO(5>|7G&YvCAO zEzJs<8~o}s2E-s)R|ve|(}~U47oTr- zFIdQ|lSieqCP5b>tZNR2@@HHZW`w9Tr#>uV&m8~ynu86VApe_Q{Yf;vQ6*z8V%HgV zHz{wlsqii=UddUS#>ixigNFsjX!WZumIh8V*xF(53%wj!T5U^!#7RTl9B9b*50*A1 zw&eU=NZJYT2$4M*q`?iD;t+LMcDYg!7LV{Wtc+?n=ccnXms_la(4wp?KJ!?PhJ$dK ztXTT}@oWT8z^N}Z5e(=U7!lhQ61nzhaRv1hVUk9wfH86fJscQzp%+dDb9-Yb8Cw{V z8wgh@q?H!M;|>B1|MqZW$nNrbRE(Ub46pG* zFC6}*V$fx5?y}GinbnVn4-cod7{5QHc;e!N+cmUBnHDAP{)2Fi*ks2dW70vW@;$xx z_IO6I<2!Yj1lq61=~^{mEIFle^BeU(x9<3?bS`=ylzs->h*o|lglW@Aapl?KAv&>b z+UK}>uV%EU>pVe#=@csX&hYF~Xf>!&N6?>t`Wc$6Gu{q-;0C$h0kX6=0(waKI=Hbc zZ$%)W$%y55S|rH?gUTKcgALJG{k5^(N=N$m?`^pVp`~&eWvoC!R64XolEH=u#6V)v zB6>y&PQjnEe@hS!`czcaWyEEe%yJui`vzj;tI}NC zN+K$3)RN~h5r-1wO8MZwXfd*0SfCmyY3Y5=SP`PFKVP= z_(874gulR&oO4K4*%&~M)harFuQ7C*hbDdQ3zwn)Gt8;`;CzIut&C{ z1(uB|k3<0qXo~7WI9tP+w`jF0E?;7*(BFS9(A=lmhzdDIFZAIeV0_MfJ?$jFEax}q zLI9}rP?b*=(Xp()34t zhU&mA_1FqdU+f=$B+we4#J6%bQZotC9{f zN5&x{>-r+f-{F^!tGV@9M>}NOi&(SIsa_OGs z4d^iCZqNVmZ=~1U()Z)Ef}0Dd+GWcNVfVo3`pb#E-e*17f-oSH{G+W#Q>xt(Kxlto z9j`%2w5-#I?$L<(3x*0B^cGVMN;m{#{bse32X|tqt9V%j84;sjrJFEhbe8i$(0CjF z3*_yIgj~iWIh#;h*u}ORzw>C&ZR;`i01eYluqrr)S?vQev&4Q-;born+3YK$9VHik zbqL=@Yj~3p`Q*5F%ycbDZkX3+5AbsToqF&ptC_@Nyd``It@d#yxRW_LDa}R3Mh7T8 zOg3P=hY(-?_kSSV;uxWwQuVz z4}D105tjD@VRwaNqv}c(%xV?eaT<|?oTTH#$>K;si%i)t6pv+7kMBcUzcg-!SQNZq za3_CAT$K|;TC9blFd*z7Z3+F|zoO_}jtCSfed~|=4k;HCw7!4ual;0|Sag}y3o#B) zkySK4#Mp>M;^_|oZ5UYa7+I&5`5!Whq&1xR0$a8SO^sVY-d1= zJeIy3!)IF@vv#bvC6*+tGrZUcz74oiuw|nr{bs7Q)8wJj#l8Al!0kOiJzcdeAZU9u zV2>)$wXtYmVVH3wNb%}+EW$+vBk@RlZ3gH!QWm#QB7^VTVBz?z!Hmam1DpLh(CL>I z?bdpu`^@b2e(!z=Xr3{UJY(;^U($T1^@nQV1Ki|P*aMHpinYpY$ zWX(+i`O@c+RkoV-U`6-n_tMbn_clF#FT~;EuU}hzXl@qN;`ju0^BS)fk%ZMq6WEf* z`o4_Sc%ps|yjmqv4Vr@b3DHs!=_rpDgUOkG9^Uzp4>p@bxLbfCN8kr|l4A3zT8m+a z@ISR2Y!{{AL4mvFU;Xso&iQWvM*9^0UlI8GpDz2al>0eV90NYki9uBzTYgqt6uw7! z%#Jhizr_SxJ1J7{KNk}1PZs@q(La?8BG)c6AaVsdAwiRan|T4UfCtil4Tgi6&i_=6 z9`L_1fbISNuk`f^tSl$QAq-PFgoM7N^oe7jX$U}!LjYwcEkp_b-6-G!(K_eEXRUhcz^*3}Qe zO;}yQA7P9?O1T*#RnoPu=UdAd-oDebz1ELuUV%1|c8q6#OIZJL0GC z?C0T4<}CHoPSf`l;yT!sK#bT{U;z#)FGfpcNGLUz&D6K+3YfOXZW|i{f@?T8Bt~Ib zRZ3)Jsii4l)9>^pD0sXE9&FLb$n5N#+sG$J zX<_5Chu0fz^J?szxv8M2&Swo+YVJ=#e=6^~?lS{m@jP|YtQ?$YXV#>|#3)HRtr*dR zDVJ|n?D?Oz5nrvad>%+N4Y;F63k=7+k_AS-dO)a=w&J$;P#qd}-HsM~-|k<$djG5c z=n7SI@U+Ubb6_c$O}k`JS7|U&&oyD8cr}GY)kTPla=2!l?0ol|?QwPU>tTKVk1N<% zHB)19*1o`b#OfA>lMbeg1Qe{~3z<`Y@EQvsp{CHnL#-5z-4r|W~& zmYm9`hmrEvXCm=JtEWMbf497yHIEB&^vUudsNCG%Ym1!!_Y;GG{(Y}N2}y&`9Ubn6 zJ>4u*`b6F5%Dtd{FKBia{nP0$OFI3T?fvJMG$LS>f6!zA2RL#x8a2mC%n2mFo2deT(e){hA1F(r`Y^{5!6yGD$bhcgUy==A^EBueSSTUORHw zjW`EA);9)>e3{J5C#>z}YPBSFWm^DSReEGi#_BL?p7S~*+Yy1e$sH(J+pv5}E9F~H z3O9v5y;=%~w&`XP%b` z8=I!oJg_4kmz3Lk^iA7!ep*=4Yt4a9R>qu1ltuV>HY`m1RpGN2?O7Yv8U*P+fF*!T z{#R zgyRC`ZBuot5yr6;vM}KiccxfEw5H}70$W=>p=3F+Fn-zZ-I7Ss{Gk25;S=w8E7G^1 zKIPvh-N){@pI-0vh|GpB5IVy~8Rbjgk-dx|;bxAGo+@xWONG5Jd^SIlge)80cy4^N z0@)G;K5JJuAevORB&RA&4X8t@#X`XIB#?P@*oRG1V{=g^=N0g~%9yu%N_jbWO7&WV z${XOeDrVT)Ed*x)zrdFqv?<$A3zsb|_%j_QK=E6o_Zg$$ajD(}p|wQ72qjzhL&U5< zgu__TtY-D}%KC1SSt_2P5GWhsnyH(}a{7w%@?I9q6q`8Dhb`*b`Q zE{;L){M!4%R2~}Ii!CB)L4e{aqw$(-pqVMVxyGJDnJaZZ7kf<;ZPX1nsvO_FXEc*n z%;0y>`Rn;3%TkVY+lkvLL?U4!8x_}(D`GOqK4&?%dN=yC>FKz+2pvJZ1)$OXg40@3 z=1Q6(=BlG98G}E0^eF=jFH%82X;`-VDwY@#MLHEEA36XJH#BQq3iV3yX@DvtN zl+V^W&@LZd>In!|g}k$XvjbC6=I@yf zCaBN-s@NO;mSvId0Q!!eZL6Qmw-{6d~g21DRQZ zL9mZ?;;#AU7&g@A@YiYKOra@_Li$|R&a;V5oN$cMvv%%reERrN;shDbr9gw{Dys`Z zP@sJ4(lVMN^c}lSZ55-Qf@&mgdVdtyPtKuM<+o;6=&Kb5qx>BGuz1BsOv{N5QtyCQ zvf)swX=q$3n!A>uYW-hi3WeiudWW^goxUs~@(y#)-tHA;+im!m!{}|c4onEK$pQz{{jAg^%d2^b#LOq4Gzg){Tg|C(Zjz0rM<)k&t5}^;cS4NN z@1bs_0+Z_=LSr-Mq}L-g1c7NWi@4I_FI3?9Yze8$s(^z5NrDB6RiTtvB0*`)V$6b# zx)!_Dj)GoFF>&rju)LM{qLz>hhk+T zrRYyPq|&G=sv4n-7z(1nVtM~sDLidyk~wyk^{5>@N`uLE~9VW*K7_P%zabfY7BO^n`PSqqobDY^sP)7JC zS*W>R*vk7H@d;@Wqb1?uV5pp9bW@q@s7lYvN{-GVz9P@9kRgJ@38H4kP}u5*gF`pf5J#hc|5oAE1&?(- zlHp&-&H!7w63p{}vT`1$==0&+f#gGtgX+C*-| zX5kRV&lCDXBh&xhc}E}C+?+&GzB8FtjMtPp{JNcH*6Kr<)8k-`Wb$Uxe{B+&SZU!| z*xlxR>B~RmL_Pa0CjaDm(W}e`<|o}ybU43DQp3k%13ZC7<$kq&WHGIy*$iW2A{`-K z=ucx|@kPw0<0!`0wZS`{ak25y zgk43)Ge*qPKnZ8H-MEZ*rXN@P%fG^f%S z5cIuQio|P2YO4XfX%x5n&K$h&bu#53*6i`!FK(G8;QfYGpe z1ia_%^0<#nL6oOuW>=(K-yio`VZjVRentWAt8nJpHZN!Iri8G(WU?wR*ZEN0J?}Sc zNW@k`_r{B~ zZok<#8>!QLbRCnjDsv^IvhE_q{P#`B_mXV}9dRcN=h1%wEcertFbs-NEG70B>S{88 z_$a~k>T%{_Lh~JX`f32-6l|YID&5$7{}yEL50LL{{2-ODC6zvW>t2qZ5J?grx;~6U zlV*bNxlGCp#{v6x$8dJ$!GO16@Rx1K$Be}o;wj<3(M&^9!1rW}fBpwL)Ex~e#s7;G zoRH9EQ~w7R{EuV!zcfP};{Rfgt5RZBQ{grPrsr%`JFrWR+-C%Yr|}mnd;9)#_sBl1 z;M`xvczu0+;lbeT+a)C7oSd9E^Jyze_`%3cN+)>mpYBXLR)Pc0#@*U#aDYUaT|EcljkQo`1r7CAT`YyWxL z{y(|ib3TQO7b3AWu8KZrqc2rB`YU>Ve{{r9fC3h1TtyvdoJ!{KO4GIYh)`aYQk!S>m@2C^?eRc zbz*5wbaYI`qIJN9(zZtwzbilTewl7VctKM)h`$Ibq46hjsfO|~3dU^-;2wXXOOB6E zv(m)TjXw0GKW!>;8_K1cl-z-Hxvc4P#1}AD`$AI#FZ!?ikEL*AX_J5C5~S)I-iUB5 zDF(Rl%!>RnCOM%!-LfKb(F5NYAhy;+i7T^E?UTVt7Z@G-h? z)ilmCsixBP>DFtFX=u+(04cfC8}I=EM}F zm?5=89&0>4;rM9sMDp4aOjUqs31WqBZ;AUoj~;bOOy$73-IV`KP~^ZK9v#^QNaKSM zd5n%ZWg!dw6oM_XK|2Ruhsw`2jFBW}<07w-I{U26Eg-#J_EQ5q8in|j%>vs#y5ubM z{E;K~5Rmv;;P4R&$9?|rMT9i z^(H$Fydy+XHJm*VJL#pX<1$x6_N4e;__T(p*~oEH4+eDHFKDTG`4Z8jyRmJ0H)n*W zE6&+lXMj%cORD6?$k9}kjA;cmCN})tLi;Oe9*oASA{=QNy|!EvIV-=%w|)u$-L*6o>#2Z0#bDztDtEF^NlkpCaj&ZFk7?Ha-oBjC+FGw>ccwi>YE1h`DYEyr zC#5#F1=7~j1UgWYbubPYe7|0Q!#fnOiM-N zvG)dbIk>SSD)6tQn*LfqAlWPDpd0qfL=Rb|JyK1TI#o}VlR*Q5<_or_MyVPd;(9K? zEOD&K0Oyz1G4A{ZfpBAdF3@uqf35H>Bfc0X!kwrkB<8*yML)D;mwrQ1-i`A{5P^c~ z!CXZLr5)D%N^y;!xtUTL_dR`iQBPPQP=77E=TbMEyXSIl!COYA#Q78lK(<%Ffa7hg&Z=<+sqo2@C*_y9p;#`v)WHCNs%le5Qv#X1%fX?Zs^R#I!{V zR9a{7YhZ?&Mq!OoR&u0Q{ z!S|8Q%@|+JF(uOe%vX;GkZ|`sbBA=)PVOYT%KibdPQl;wJ_NJa@b2p*Lq)ECOyvCO zNt4ron`<=MZ>%2DZ`Dmw<5FPHtYA^s8B7WmpkOk%>t(=>MN(l{n7FQ-EIGBmipgCH6m!S>Uf9_AjmkR(_2o z)_y2Iejk>=bs0!`Z|X6{XFYZiG`OYB+;>cDtW{bY@%k190RihP zEiR&#(enW^#!KnJJX&d|fr4|(v0k+(5r7TFl5uamxFu#z@w_CVJLUiO-iGt1q%QnK z1C!R8mYdPvBFTg-Ri(-9z-XiClA6TJ?JL!tAiH{@*9{6RQUo7ffHaQEj?2}hfg&b` z6!kL-$soiBZd+{|!7jYM+};po^PwwT?7BDQ$NQD8jgGpRETsMq^TahTh+fz`vOG^7 zM>~xazg=t)+a2NriBi{h*^@W`LNj~pd!x{pJZ^?u-E2S5Qr_}!Q(}tKidhmPZBBl6 z%;aXp&O2Pi)@x+NPGFQ)95zxrsL?=c@K|-i{54n=e?B+j!)KPv!C)KJvLP%nGc{sb zNygc}R0_Pn`_=EZ!1UQA49T;y$tUpm@Hh4~W#RDd_A33$|6q`^rVa32X(cmmwMVAw1b3hILA=% zV>h`OkOR{q@|IXGC$Z0*LCzb^W8Swg_xkf6VXaAHw;&f9MWnTH5Bg-b(~9V|`>y;j zdlf^2SW5PgB{Ucq!fk{MS_6%cjb0QW%@or>jC7LKN^7ux$1OIkz>i!F$J`Ar$j+03 zp_NqjRv2xKp|P0$FUi967B`uYkcK{E)VM<`aIh8;ty+(4N003!YQs^ZbOT@h;|=ED zhi{h*_n475v8?y<(w#!+<;K`Oog)X@?mpf6X-G&_G!(mn8;wcjsU zO~Td#O+Ui%db^T1!$&9dMs+tCa`#_)wWAuk7#UcSSujnkpB(52+h>PFL}ph8oPzs9 zXI5HbC53`h)%ovU!iR~Xg9**@+Y@??MqeruU3=!C)dDWfYxgIxtt5i_yHOaE}8D~n7e zekm&2g0yK5H-PRB@pf*sbYPe_xazTwweyPBfI33=d~=<4F{Naecpy&PXm`UG8s zZc}Q?V9=3(AjTMsR^*+EWLBJY$f)OXj8&;S1HD_X2FG6`50FlPiZh^X(eul!=)Nsn;#%3cWXtM_th|VCy6y|dn-X290&9yl3wsD;Qo?8ps zA)CfsNnp)A+m});=9GYH?TR~VltlTOd)(%dwAy=`!ft{?kMY3cd&19#xvtluCi&Kl zW>&*3(Rk>BSY1uo^x6h2py7N_0OgK0Vpn3DZL_8egfZ1P)C|+HJ6;K*F^=*{P|Vc{TK?1GMNV@wvTi`(TBMRdUoMV9Lr@Z`HIeIF*dTXO zM(+i(TZ%&FL%DRzIYtp|wkOhP9E^Pa`)(4V4;{SR?2YbQE?S_T!UbVG;5c$JLIV1e UIPFhD2=GT*LP5Mj)F|-(08cf(HUIzs literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.pythonscripting/doc/venv_info.png b/bundles/org.openhab.automation.pythonscripting/doc/venv_info.png new file mode 100644 index 0000000000000000000000000000000000000000..b181e7ffbd294e642c472209e50121c9754c34d0 GIT binary patch literal 53110 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

    %BG|x7A4;kr2827Vp))xPie*&)77- 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 literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.pythonscripting/pom.xml b/bundles/org.openhab.automation.pythonscripting/pom.xml index ce33efdc7cb50..8e4a9c80c97b4 100644 --- a/bundles/org.openhab.automation.pythonscripting/pom.xml +++ b/bundles/org.openhab.automation.pythonscripting/pom.xml @@ -15,7 +15,7 @@ openHAB Add-ons :: Bundles :: Automation :: Python Scripting - v1.0.0 + 1.0.8 @@ -31,6 +31,22 @@ + + org.codehaus.mojo + properties-maven-plugin + 1.0.0 + + + + write-project-properties + + generate-resources + + ${project.build.outputDirectory}/build.properties + + + + org.apache.maven.plugins maven-scm-plugin diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/feature/feature.xml b/bundles/org.openhab.automation.pythonscripting/src/main/feature/feature.xml index 74a9fc1d09a36..9840d182a0089 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/feature/feature.xml +++ b/bundles/org.openhab.automation.pythonscripting/src/main/feature/feature.xml @@ -4,24 +4,24 @@ openhab-runtime-base - mvn:org.openhab.osgiify/org.graalvm.llvm.llvm-api/24.2.1 - mvn:org.openhab.osgiify/org.graalvm.polyglot.polyglot/24.2.1 - mvn:org.openhab.osgiify/org.graalvm.python.python-language/24.2.1 - mvn:org.openhab.osgiify/org.graalvm.python.python-resources/24.2.1 - mvn:org.openhab.osgiify/org.graalvm.regex.regex/24.2.1 mvn:org.openhab.osgiify/org.graalvm.sdk.collections/24.2.1 mvn:org.openhab.osgiify/org.graalvm.sdk.jniutils/24.2.1 mvn:org.openhab.osgiify/org.graalvm.sdk.nativeimage/24.2.1 mvn:org.openhab.osgiify/org.graalvm.sdk.word/24.2.1 mvn:org.openhab.osgiify/org.graalvm.shadowed.icu4j/24.2.1 + mvn:org.openhab.osgiify/org.graalvm.llvm.llvm-api/24.2.1 mvn:org.openhab.osgiify/org.graalvm.shadowed.json/24.2.1 mvn:org.openhab.osgiify/org.graalvm.shadowed.xz/24.2.1 mvn:org.openhab.osgiify/org.graalvm.tools.profiler-tool/24.2.1 - mvn:org.openhab.osgiify/org.graalvm.truffle.truffle-api/24.2.1 + mvn:org.openhab.osgiify/org.graalvm.polyglot.polyglot/24.2.1 + mvn:org.openhab.osgiify/org.graalvm.truffle.truffle-runtime/24.2.1 mvn:org.openhab.osgiify/org.graalvm.truffle.truffle-compiler/24.2.1 + mvn:org.openhab.osgiify/org.graalvm.regex.regex/24.2.1 + mvn:org.openhab.osgiify/org.graalvm.python.python-resources/24.2.1 + mvn:org.openhab.osgiify/org.graalvm.python.python-language/24.2.1 mvn:org.openhab.osgiify/org.graalvm.truffle.truffle-nfi/24.2.1 mvn:org.openhab.osgiify/org.graalvm.truffle.truffle-nfi-libffi/24.2.1 - mvn:org.openhab.osgiify/org.graalvm.truffle.truffle-runtime/24.2.1 + mvn:org.openhab.osgiify/org.graalvm.truffle.truffle-api/24.2.1 mvn:org.openhab.addons.bundles/org.openhab.automation.pythonscripting/${project.version} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngine.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngine.java index 688c44882acbe..7e531bc945f83 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngine.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngine.java @@ -17,19 +17,18 @@ import java.io.File; import java.io.IOException; -import java.nio.file.AccessMode; -import java.nio.file.FileSystems; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.file.Files; -import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; import java.time.Instant; +import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Properties; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; @@ -46,19 +45,26 @@ import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.HostAccess; +import org.graalvm.polyglot.Language; +import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; import org.graalvm.polyglot.io.IOAccess; +import org.openhab.automation.pythonscripting.internal.context.ContextInput; +import org.openhab.automation.pythonscripting.internal.context.ContextOutput; +import org.openhab.automation.pythonscripting.internal.context.ContextOutputLogger; import org.openhab.automation.pythonscripting.internal.fs.DelegatingFileSystem; -import org.openhab.automation.pythonscripting.internal.fs.watch.PythonDependencyTracker; -import org.openhab.automation.pythonscripting.internal.graal.GraalPythonScriptEngine; -import org.openhab.automation.pythonscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable; -import org.openhab.automation.pythonscripting.internal.scriptengine.helper.LifecycleTracker; -import org.openhab.automation.pythonscripting.internal.scriptengine.helper.LogOutputStream; -import org.openhab.automation.pythonscripting.internal.wrapper.ScriptExtensionModuleProvider; -import org.openhab.core.OpenHAB; +import org.openhab.automation.pythonscripting.internal.provider.LifecycleTracker; +import org.openhab.automation.pythonscripting.internal.provider.ScriptExtensionModuleProvider; +import org.openhab.automation.pythonscripting.internal.scriptengine.InvocationInterceptingPythonScriptEngine; +import org.openhab.automation.pythonscripting.internal.scriptengine.graal.GraalPythonScriptEngine; import org.openhab.core.automation.module.script.ScriptExtensionAccessor; -import org.openhab.core.items.Item; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.event.Level; @@ -69,11 +75,15 @@ * @author Holger Hees - Initial contribution * @author Jeff James - Initial contribution */ -public class PythonScriptEngine - extends InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable - implements Lock { +public class PythonScriptEngine extends InvocationInterceptingPythonScriptEngine implements Lock { private final Logger logger = LoggerFactory.getLogger(PythonScriptEngine.class); + public static final String CONTEXT_KEY_ENGINE_LOGGER_OUTPUT = "ctx.engine-logger-output"; + public static final String CONTEXT_KEY_ENGINE_LOGGER_INPUT = "ctx.engine-logger-input"; + private static final String CONTEXT_KEY_SCRIPT_FILENAME = "javax.script.filename"; + + private static final String PYTHON_OPTION_ENGINE_WARNINTERPRETERONLY = "engine.WarnInterpreterOnly"; + private static final String SYSTEM_PROPERTY_ATTACH_LIBRARY_FAILURE_ACTION = "polyglotimpl.AttachLibraryFailureAction"; private static final String PYTHON_OPTION_PYTHONPATH = "python.PythonPath"; @@ -84,34 +94,38 @@ public class PythonScriptEngine private static final String PYTHON_OPTION_CHECKHASHPYCSMODE = "python.CheckHashPycsMode"; private static final String PYTHON_OPTION_ALWAYSRUNEXCEPTHOOK = "python.AlwaysRunExcepthook"; + private static final String PYTHON_OPTION_EXECUTABLE = "python.Executable"; + // private static final String PYTHON_OPTION_PYTHONHOME = "python.PythonHome"; + // private static final String PYTHON_OPTION_SYSPREFIX = "python.SysPrefix"; + private static final String PYTHON_OPTION_NATIVEMODULES = "python.NativeModules"; + private static final String PYTHON_OPTION_ISOLATENATIVEMODULES = "python.IsolateNativeModules"; + private static final String PYTHON_OPTION_CACHEDIR = "python.PyCachePrefix"; - private static final String PYTHON_CACHEDIR_PATH = Paths - .get(OpenHAB.getUserDataFolder(), "cache", PythonScriptEngine.class.getPackageName(), "cachedir") - .toString(); private static final int STACK_TRACE_LENGTH = 5; - public static final String LOGGER_INIT_NAME = "__logger_init__"; + private static final String LOGGER_INIT_NAME = "__logger_init__"; /** Shared Polyglot {@link Engine} across all instances of {@link PythonScriptEngine} */ - private static final Engine ENGINE = Engine.newBuilder().allowExperimentalOptions(true) - .option("engine.WarnInterpreterOnly", "false").build(); + private static Engine engine = Engine.newBuilder() + // disable warning about fallback runtime (is only available in graalvm) + .option(PYTHON_OPTION_ENGINE_WARNINTERPRETERONLY, Boolean.toString(false)).build(); + + static { + // disable warning about missing TruffleAttach library (is only available in graalvm) + System.getProperties().setProperty(SYSTEM_PROPERTY_ATTACH_LIBRARY_FAILURE_ACTION, "ignore"); + } + + // private static final boolean isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); /** Provides unlimited host access as well as custom translations from Python to Java Objects */ private static final HostAccess HOST_ACCESS = HostAccess.newBuilder(HostAccess.ALL) - // Translate python datetime with timezone to java.time.ZonedDateTime - .targetTypeMapping(Value.class, ZonedDateTime.class, - v -> v.hasMember("ctime") && v.hasMember("isoformat") && v.hasMember("tzinfo") - && !v.getMember("tzinfo").isNull(), - v -> ZonedDateTime.parse(v.invokeMember("isoformat").asString()), - HostAccess.TargetMappingPrecedence.LOW) + .targetTypeMapping(Value.class, ZonedDateTime.class, v -> v.hasMember("ctime") && v.hasMember("isoformat"), + v -> PythonScriptEngine.parseDatetime(v), HostAccess.TargetMappingPrecedence.LOW) - // Translate python datetime without timezone to java.time.Instant - .targetTypeMapping(Value.class, Instant.class, - v -> v.hasMember("ctime") && v.hasMember("isoformat") && v.hasMember("tzinfo") - && v.getMember("tzinfo").isNull(), - v -> Instant.parse(v.invokeMember("isoformat").asString() + "Z"), - HostAccess.TargetMappingPrecedence.LOW) + // Translate python datetime java.time.Instant + .targetTypeMapping(Value.class, Instant.class, v -> v.hasMember("ctime") && v.hasMember("isoformat"), + v -> PythonScriptEngine.parseDatetime(v).toInstant(), HostAccess.TargetMappingPrecedence.LOW) // Translate python timedelta to java.time.Duration .targetTypeMapping(Value.class, Duration.class, @@ -120,70 +134,56 @@ public class PythonScriptEngine v -> Duration.ofNanos(Math.round(v.invokeMember("total_seconds").asDouble() * 1000000000)), HostAccess.TargetMappingPrecedence.LOW) - // Translate python item to org.openhab.core.items.Item - .targetTypeMapping(Value.class, Item.class, v -> v.hasMember("raw_item"), - v -> v.getMember("raw_item").as(Item.class), HostAccess.TargetMappingPrecedence.LOW) - // Translate python array to java.util.Set .targetTypeMapping(Value.class, Set.class, v -> v.hasArrayElements(), PythonScriptEngine::transformArrayToSet, HostAccess.TargetMappingPrecedence.LOW) + // Translate python values to State + .targetTypeMapping(Value.class, State.class, null, PythonScriptEngine::transformValueToState, + HostAccess.TargetMappingPrecedence.LOW) + .build(); /** {@link Lock} synchronization of multi-thread access */ private final Lock lock = new ReentrantLock(); - // these fields start as null because they are populated on first use - private @Nullable Consumer scriptDependencyListener; - private final ScriptExtensionModuleProvider scriptExtensionModuleProvider; - private final LifecycleTracker lifecycleTracker; - private PythonScriptEngineConfiguration pythonScriptEngineConfiguration; private boolean initialized = false; - private boolean closed = false; - private final LogOutputStream scriptOutputStream; - private final LogOutputStream scriptErrorStream; + private String engineIdentifier = ""; + + private final ContextOutput scriptOutputStream; + private final ContextOutput scriptErrorStream; + private final ContextInput scriptInputStream; + + private final DelegatingFileSystem delegatingFileSystem; + + private final ScriptExtensionModuleProvider scriptExtensionModuleProvider; + private final LifecycleTracker lifecycleTracker; /** * Creates an implementation of ScriptEngine {@code (& Invocable)}, wrapping the contained engine, * that tracks the script lifecycle and provides hooks for scripts to do so too. */ - public PythonScriptEngine(PythonDependencyTracker pythonDependencyTracker, - PythonScriptEngineConfiguration pythonScriptEngineConfiguration) { + public PythonScriptEngine(PythonScriptEngineConfiguration pythonScriptEngineConfiguration, + PythonScriptEngineFactory pythonScriptEngineFactory) { this.pythonScriptEngineConfiguration = pythonScriptEngineConfiguration; - scriptOutputStream = new LogOutputStream(logger, Level.INFO); - scriptErrorStream = new LogOutputStream(logger, Level.ERROR); + this.scriptOutputStream = new ContextOutput(new ContextOutputLogger(logger, Level.INFO)); + this.scriptErrorStream = new ContextOutput(new ContextOutputLogger(logger, Level.ERROR)); + this.scriptInputStream = new ContextInput(null); - lifecycleTracker = new LifecycleTracker(); - scriptExtensionModuleProvider = new ScriptExtensionModuleProvider(); + this.lifecycleTracker = new LifecycleTracker(); + this.scriptExtensionModuleProvider = new ScriptExtensionModuleProvider(); - // disable warning about missing TruffleAttach library (is only available in graalvm) - Properties props = System.getProperties(); - props.setProperty(SYSTEM_PROPERTY_ATTACH_LIBRARY_FAILURE_ACTION, "ignore"); + this.delegatingFileSystem = new DelegatingFileSystem(pythonScriptEngineConfiguration.getTempDirectory()); Context.Builder contextConfig = Context.newBuilder(GraalPythonScriptEngine.LANGUAGE_ID) // .out(scriptOutputStream) // .err(scriptErrorStream) // - .allowIO(IOAccess.newBuilder() // - .allowHostSocketAccess(true) // - .fileSystem(new DelegatingFileSystem(FileSystems.getDefault().provider()) { - @Override - public void checkAccess(Path path, Set modes, - LinkOption... linkOptions) throws IOException { - if (pythonScriptEngineConfiguration.isDependencyTrackingEnabled()) { - if (path.startsWith(PythonScriptEngineFactory.PYTHON_LIB_PATH)) { - Consumer localScriptDependencyListener = scriptDependencyListener; - if (localScriptDependencyListener != null) { - localScriptDependencyListener.accept(path.toString()); - } - } - } - super.checkAccess(path, modes, linkOptions); - } - }).build()) // + .in(scriptInputStream) // + .allowIO(IOAccess.newBuilder().allowHostSocketAccess(true).fileSystem(delegatingFileSystem).build()) // .allowHostAccess(HOST_ACCESS) // // usage of .allowAllAccess(true) includes // - allowCreateThread(true) @@ -211,138 +211,199 @@ public void checkAccess(Path path, Set modes, String.valueOf(pythonScriptEngineConfiguration.isJythonEmulation())) // Set python path to point to sources stored in - .option(PYTHON_OPTION_PYTHONPATH, PythonScriptEngineFactory.PYTHON_LIB_PATH.toString() - + File.pathSeparator + PythonScriptEngineFactory.PYTHON_DEFAULT_PATH.toString()); + .option(PYTHON_OPTION_PYTHONPATH, PythonScriptEngineConfiguration.PYTHON_LIB_PATH.toString() + + File.pathSeparator + PythonScriptEngineConfiguration.PYTHON_DEFAULT_PATH.toString()); + + if (pythonScriptEngineConfiguration.isVEnvEnabled()) { + @SuppressWarnings("null") + String venvExecutable = pythonScriptEngineConfiguration.getVEnvExecutable().toString(); + contextConfig = contextConfig.option(PYTHON_OPTION_EXECUTABLE, venvExecutable); + // Path venvPath = this.pythonScriptEngineConfiguration.getVEnvDirectory(); + // .option(PYTHON_OPTION_PYTHONHOME, venvPath.toString()) // + // .option(PYTHON_OPTION_SYSPREFIX, venvPath.toString()) // + + if (pythonScriptEngineConfiguration.isNativeModulesEnabled()) { + contextConfig = contextConfig.option(PYTHON_OPTION_NATIVEMODULES, Boolean.toString(true)) // + .option(PYTHON_OPTION_ISOLATENATIVEMODULES, Boolean.toString(true)); + } + } if (pythonScriptEngineConfiguration.isCachingEnabled()) { contextConfig.option(PYTHON_OPTION_DONTWRITEBYTECODEFLAG, Boolean.toString(false)) // - .option(PYTHON_OPTION_CACHEDIR, PYTHON_CACHEDIR_PATH); + .option(PYTHON_OPTION_CACHEDIR, pythonScriptEngineConfiguration.getBytecodeDirectory().toString()); } else { contextConfig.option(PYTHON_OPTION_DONTWRITEBYTECODEFLAG, Boolean.toString(true)) // // causes the interpreter to always assume hash-based pycs are valid .option(PYTHON_OPTION_CHECKHASHPYCSMODE, "never"); } - delegate = GraalPythonScriptEngine.create(ENGINE, contextConfig); + init(engine, contextConfig, pythonScriptEngineFactory); } @Override - protected void beforeInvocation() { + protected void beforeInvocation() throws PolyglotException { lock.lock(); - logger.debug("Lock acquired before invocation."); + logger.debug("Lock acquired before invocation for engine '{}'", this.engineIdentifier); if (initialized) { return; } - logger.debug("Initializing GraalPython script engine..."); - - ScriptContext ctx = getScriptContext(); + ScriptContext ctx = getContext(); // these are added post-construction, so we need to fetch them late String engineIdentifier = (String) ctx.getAttribute(CONTEXT_KEY_ENGINE_IDENTIFIER); - if (engineIdentifier == null) { - throw new IllegalStateException("Failed to retrieve engine identifier from engine bindings"); - } - - ScriptExtensionAccessor scriptExtensionAccessor = (ScriptExtensionAccessor) ctx - .getAttribute(CONTEXT_KEY_EXTENSION_ACCESSOR); - if (scriptExtensionAccessor == null) { - throw new IllegalStateException("Failed to retrieve script extension accessor from engine bindings"); + if (engineIdentifier != null) { + this.engineIdentifier = engineIdentifier; + } else { + logger.warn("Failed to retrieve script indentifier"); } - Consumer scriptDependencyListener = (Consumer) ctx - .getAttribute(CONTEXT_KEY_DEPENDENCY_LISTENER); - if (scriptDependencyListener == null) { - logger.warn( - "Failed to retrieve script script dependency listener from engine bindings. Script dependency tracking will be disabled."); + logger.debug("Initializing GraalPython script engine '{}' ...", this.engineIdentifier); + + if (pythonScriptEngineConfiguration.isDependencyTrackingEnabled()) { + @SuppressWarnings("unchecked") + Consumer scriptDependencyListener = (Consumer) ctx + .getAttribute(CONTEXT_KEY_DEPENDENCY_LISTENER); + if (scriptDependencyListener == null) { + // Can happen for script engines, created directly via PythonScriptEngineFactory and not via + // ScriptEngineManager + logger.debug("No dependency listener found. Script dependency tracking disabled for engine '{}'.", + this.engineIdentifier); + } else { + this.delegatingFileSystem.setAccessConsumer(new Consumer() { + @Override + public void accept(Path path) { + String pathAsString = path.toString(); + // convert cache path to real path + if (pathAsString.endsWith(".pyc")) { + // SOURCE .graalpy-232-311.pyc + // TARGET .py + int pos = pathAsString.indexOf(PythonScriptEngineConfiguration.PYTHON_LIB_PATH.toString()); + if (pos != -1) { + pathAsString = pathAsString.substring(pos, pathAsString.length() - 4); + int indexof = pathAsString.lastIndexOf("."); + pathAsString = pathAsString.substring(0, indexof); + path = Paths.get(pathAsString + ".py"); + } + } + if (path.startsWith(PythonScriptEngineConfiguration.PYTHON_LIB_PATH)) { + // logger.info("REGISTER PATH: {} of engine {}", path, + // PythonScriptEngine.this.engineIdentifier); + scriptDependencyListener.accept(path.toString()); + } + } + }); + } } - this.scriptDependencyListener = scriptDependencyListener; if (pythonScriptEngineConfiguration.isScopeEnabled()) { - // Wrap the "import" function to also allow loading modules from the ScriptExtensionModuleProvider - BiFunction, Object> wrapImportFn = (name, fromlist) -> scriptExtensionModuleProvider - .locatorFor(delegate.getPolyglotContext(), engineIdentifier, scriptExtensionAccessor) - .locateModule(name, fromlist); - delegate.getBindings(ScriptContext.ENGINE_SCOPE).put(ScriptExtensionModuleProvider.IMPORT_PROXY_NAME, - wrapImportFn); - try { - String wrapperContent = new String( - Files.readAllBytes(PythonScriptEngineFactory.PYTHON_WRAPPER_FILE_PATH)); - delegate.getPolyglotContext().eval(Source.newBuilder(GraalPythonScriptEngine.LANGUAGE_ID, - wrapperContent, PythonScriptEngineFactory.PYTHON_WRAPPER_FILE_PATH.toString()).build()); - - // inject scope, Registry and logger - if (!pythonScriptEngineConfiguration.isInjection(PythonScriptEngineConfiguration.INJECTION_DISABLED) - && (ctx.getAttribute("javax.script.filename") == null || pythonScriptEngineConfiguration - .isInjection(PythonScriptEngineConfiguration.INJECTION_ENABLED_FOR_ALL_SCRIPTS))) { - String injectionContent = "import scope\nfrom openhab import Registry, logger"; - delegate.getPolyglotContext().eval(Source - .newBuilder(GraalPythonScriptEngine.LANGUAGE_ID, injectionContent, "").build()); + ScriptExtensionAccessor scriptExtensionAccessor = (ScriptExtensionAccessor) ctx + .getAttribute(CONTEXT_KEY_EXTENSION_ACCESSOR); + if (scriptExtensionAccessor == null) { + // Can happen for script engines, created directly via PythonScriptEngineFactory and not via + // ScriptEngineManager + logger.debug("No Script accessor found. Scope injection disabled for engine {}", this.engineIdentifier); + } else { + // Wrap the "import" function to also allow loading modules from the ScriptExtensionModuleProvider + BiFunction, Object> wrapImportFn = (name, + fromlist) -> scriptExtensionModuleProvider + .locatorFor(getPolyglotContext(), this.engineIdentifier, scriptExtensionAccessor) + .locateModule(name, fromlist); + getBindings(ScriptContext.ENGINE_SCOPE).put(ScriptExtensionModuleProvider.IMPORT_PROXY_NAME, + wrapImportFn); + try { + String wrapperContent = new String( + Files.readAllBytes(PythonScriptEngineConfiguration.PYTHON_WRAPPER_FILE_PATH)); + getPolyglotContext() + .eval(Source + .newBuilder(GraalPythonScriptEngine.LANGUAGE_ID, wrapperContent, + PythonScriptEngineConfiguration.PYTHON_WRAPPER_FILE_PATH.toString()) + .build()); + + // inject scope, Registry and logger + if (!pythonScriptEngineConfiguration.isInjection(PythonScriptEngineConfiguration.INJECTION_DISABLED) + && (ctx.getAttribute(CONTEXT_KEY_SCRIPT_FILENAME) == null || pythonScriptEngineConfiguration + .isInjection(PythonScriptEngineConfiguration.INJECTION_ENABLED_FOR_ALL_SCRIPTS))) { + String injectionContent = "import scope\nfrom openhab import Registry, logger"; + getPolyglotContext().eval( + Source.newBuilder(GraalPythonScriptEngine.LANGUAGE_ID, injectionContent, "") + .build()); + } + } catch (IOException e) { + logger.error("Failed to inject import wrapper for engine '{}'", this.engineIdentifier, e); + throw new IllegalArgumentException("Failed to inject import wrapper", e); } - } catch (IOException e) { - logger.error("Failed to inject import wrapper", e); - throw new IllegalArgumentException("Failed to inject import wrapper", e); } } - // logger initialization, for non file based scripts, has to be delayed, because ruleUID is not available yet - if (ctx.getAttribute("javax.script.filename") == null) { - Runnable wrapperLoggerFn = () -> setScriptLogger(); - delegate.getBindings(ScriptContext.ENGINE_SCOPE).put(LOGGER_INIT_NAME, wrapperLoggerFn); + InputStream input = (InputStream) ctx.getAttribute(CONTEXT_KEY_ENGINE_LOGGER_INPUT); + if (input != null) { + scriptInputStream.setInputStream(input); + } + + OutputStream output = (OutputStream) ctx.getAttribute(CONTEXT_KEY_ENGINE_LOGGER_OUTPUT); + if (output != null) { + scriptOutputStream.setOutputStream(output); + scriptErrorStream.setOutputStream(output); } else { - setScriptLogger(); + // logger initialization, for non file based scripts, has to be delayed, because ruleUID is not + // available yet + if (ctx.getAttribute(CONTEXT_KEY_SCRIPT_FILENAME) == null) { + Runnable wrapperLoggerFn = () -> setScriptLogger(); + getBindings(ScriptContext.ENGINE_SCOPE).put(LOGGER_INIT_NAME, wrapperLoggerFn); + } else { + setScriptLogger(); + } } initialized = true; } @Override - protected String beforeInvocation(String source) { - source = super.beforeInvocation(source); - + protected @Nullable String beforeInvocation(@Nullable String source) { // Happens for Transform and UI based rules (eval and compile) // and has to be evaluate every time, because of changing and late injected ruleUID - if (delegate.getBindings(ScriptContext.ENGINE_SCOPE).get(LOGGER_INIT_NAME) != null) { + if (getBindings(ScriptContext.ENGINE_SCOPE).get(LOGGER_INIT_NAME) != null) { return LOGGER_INIT_NAME + "()\n" + source; } - return source; } @Override - protected Object afterInvocation(Object obj) { + protected @Nullable Object afterInvocation(@Nullable Object obj) { lock.unlock(); - logger.debug("Lock released after invocation."); - return super.afterInvocation(obj); + logger.debug("Lock released after invocation for engine '{}'.", this.engineIdentifier); + return obj; } @Override - protected Exception afterThrowsInvocation(Exception e) { + protected E afterThrowsInvocation(E e) { + Throwable cause = e.getCause(); // OPS4J Pax Logging holds a reference to the exception, which causes the PythonScriptEngine to not be // removed from heap by garbage collection and causing a memory leak. // Therefore, don't pass the exceptions itself to the logger, but only their message! if (e instanceof ScriptException) { // PolyglotException will always be wrapped into ScriptException and they will be visualized in // org.openhab.core.automation.module.script.internal.ScriptEngineManagerImpl - if (scriptErrorStream.getLogger().isDebugEnabled()) { - scriptErrorStream.getLogger().debug("Failed to execute script (PolyglotException): {}", - stringifyThrowable(e.getCause())); + if (logger.isDebugEnabled()) { + logger.debug("Failed to execute script (PolyglotException) for engine '{}': {}", this.engineIdentifier, + stringifyThrowable(cause == null ? e : cause)); } - } else if (e.getCause() instanceof IllegalArgumentException) { - scriptErrorStream.getLogger().error("Failed to execute script (IllegalArgumentException): {}", - stringifyThrowable(e.getCause())); + } else if (cause != null && e.getCause() instanceof IllegalArgumentException) { + logger.error("Failed to execute script (IllegalArgumentException) for engine '{}': {}", + this.engineIdentifier, stringifyThrowable(cause)); } lock.unlock(); - - return super.afterThrowsInvocation(e); + logger.debug("Lock cleaned after an exception for engine '{}'.", this.engineIdentifier); + return e; } @Override // collect JSR223 (scope) variables separately, because they are delivered via 'import scope' - public void put(String key, Object value) { - if ("javax.script.filename".equals(key)) { + public void put(@Nullable String key, @Nullable Object value) { + if (CONTEXT_KEY_SCRIPT_FILENAME.equals(key)) { super.put(key, value); } else { // use a custom lifecycleTracker to handle dispose hook before polyglot context is closed @@ -350,10 +411,15 @@ public void put(String key, Object value) { if ("lifecycleTracker".equals(key)) { value = lifecycleTracker; } - if (pythonScriptEngineConfiguration.isScopeEnabled()) { - scriptExtensionModuleProvider.put(key, value); + if (key != null && value != null) { + if (pythonScriptEngineConfiguration.isScopeEnabled()) { + scriptExtensionModuleProvider.put(key, value); + } else { + super.put(key, value); + } } else { - super.put(key, value); + throw new IllegalArgumentException( + "Null value for key: " + key + ", value: " + value + " not supported"); } } } @@ -361,7 +427,7 @@ public void put(String key, Object value) { @Override public void lock() { lock.lock(); - logger.debug("Lock acquired."); + logger.debug("Lock acquired for engine '{}'.", this.engineIdentifier); } @Override @@ -372,46 +438,67 @@ public void lockInterruptibly() throws InterruptedException { @Override public boolean tryLock() { boolean acquired = lock.tryLock(); - logger.debug("{}", acquired ? "Lock acquired." : "Lock not acquired."); + logger.debug("{} for engine '{}'", acquired ? "Lock acquired." : "Lock not acquired.", this.engineIdentifier); return acquired; } @Override - public boolean tryLock(long l, TimeUnit timeUnit) throws InterruptedException { + public boolean tryLock(long l, @Nullable TimeUnit timeUnit) throws InterruptedException { boolean acquired = lock.tryLock(l, timeUnit); - logger.debug("{}", acquired ? "Lock acquired." : "Lock not acquired."); + logger.debug("{} for engine '{}'", acquired ? "Lock acquired." : "Lock not acquired.", this.engineIdentifier); return acquired; } @Override public void unlock() { lock.unlock(); - logger.debug("Lock released."); + logger.debug("Lock released for engine '{}'.", this.engineIdentifier); + } + + @Override + public Object invokeFunction(String name, Object... objects) throws ScriptException, NoSuchMethodException { + if ("scriptUnloaded".equals(name)) { + /* + * is called from + * => org.openhab.core.automation.module.script.internal.ScriptEngineManagerImpl:removeEngine + * + * must be skipped, because ScriptTransformationService:disposeScriptEngine is calling engine.close several + * times before. Specially if the + * same script is used for more then 1 transformations. If the engine is already closed, the script + * "scriptUnloaded" will fail. + */ + return null; + } else { + return super.invokeFunction(name, objects); + } } @Override - public void close() throws Exception { + public void close() { + /* + * is called from + * => org.openhab.core.automation.module.script.ScriptTransformationService:disposeScriptEngine + * => org.openhab.core.automation.module.script.internal.ScriptEngineManagerImpl:removeEngine + */ + lock.lock(); - if (!closed) { + if (!isClosed()) { try { this.lifecycleTracker.dispose(); + logger.debug("LifecycleTracker for engine '{}' disposed.", this.engineIdentifier); } catch (Exception e) { - logger.warn("Ignoreable exception during dispose: {}", stringifyThrowable(e)); + logger.warn("Ignoreable exception during LifecycleTracker dispose for engine '{}': {}", + this.engineIdentifier, stringifyThrowable(e)); } - logger.debug("Engine disposed."); try { super.close(); + logger.debug("Engine '{}' closed.", this.engineIdentifier); } catch (Exception e) { - logger.warn("Ignoreable exception during close: {}", stringifyThrowable(e)); + logger.warn("Ignoreable exception during close of engine '{}': {}", this.engineIdentifier, + stringifyThrowable(e)); } - - logger.debug("Engine closed."); - - closed = true; - } else { - logger.debug("Engine already disposed and closed."); } lock.unlock(); @@ -428,14 +515,14 @@ public Condition newCondition() { * Therefore, the logger needs to be initialized on the first use after script engine creation. */ private void setScriptLogger() { - ScriptContext ctx = getScriptContext(); - Object fileName = ctx.getAttribute("javax.script.filename"); + ScriptContext ctx = getContext(); + Object fileName = ctx.getAttribute(CONTEXT_KEY_SCRIPT_FILENAME); Object ruleUID = ctx.getAttribute("ruleUID"); - Object ohEngineIdentifier = ctx.getAttribute("oh.engine-identifier"); + Object ohEngineIdentifier = ctx.getAttribute(CONTEXT_KEY_ENGINE_IDENTIFIER); String identifier = "stack"; if (fileName != null) { - identifier = fileName.toString().replaceAll("^.*[/\\\\]", ""); + identifier = fileName.toString().replaceAll("^.*[/\\\\]", "").replaceAll(".py", ""); } else if (ruleUID != null) { identifier = ruleUID.toString(); } else if (ohEngineIdentifier != null) { @@ -446,16 +533,8 @@ private void setScriptLogger() { Logger scriptLogger = LoggerFactory.getLogger("org.openhab.automation.pythonscripting." + identifier); - scriptOutputStream.setLogger(scriptLogger); - scriptErrorStream.setLogger(scriptLogger); - } - - private ScriptContext getScriptContext() { - ScriptContext ctx = delegate.getContext(); - if (ctx == null) { - throw new IllegalStateException("Failed to retrieve script context"); - } - return ctx; + scriptOutputStream.setOutputStream(new ContextOutputLogger(scriptLogger, Level.INFO)); + scriptErrorStream.setOutputStream(new ContextOutputLogger(scriptLogger, Level.ERROR)); } private String stringifyThrowable(Throwable throwable) { @@ -468,11 +547,57 @@ private String stringifyThrowable(Throwable throwable) { } private static Set transformArrayToSet(Value value) { - Set set = new HashSet<>(); - for (int i = 0; i < value.getArraySize(); ++i) { - Value element = value.getArrayElement(i); - set.add(element.asString()); + try { + Set set = new HashSet<>(); + for (int i = 0; i < value.getArraySize(); ++i) { + Value element = value.getArrayElement(i); + set.add(element.isString() ? element.asString() : element.toString()); + } + return set; + } catch (Exception e) { + String msg = "Can't convert python value '" + value.toString() + "' (" + value.getClass() + + ") to a java.util.Set\n" + e.getClass().getSimpleName() + ": " + e.getMessage(); + throw new IllegalArgumentException(msg, e); } - return set; + } + + private static State transformValueToState(Value value) { + try { + if (value.isBoolean()) { + // logger.info("VALUE: OnOffType {}", value.asBoolean()); + return OnOffType.from(value.asBoolean()); + } else if (value.isNumber()) { + // logger.info("VALUE: DecimalType {}", value.toString()); + return DecimalType.valueOf(value.toString()); + } else if (value.hasMember("ctime") && value.hasMember("isoformat")) { + // logger.info("VALUE: DateTimeType"); + return new DateTimeType(PythonScriptEngine.parseDatetime(value)); + } else if (value.isString()) { + // logger.info("VALUE: StringType {}", value.asString()); + return StringType.valueOf(value.asString()); + } else if (value.isNull()) { + // logger.info("VALUE: UnDefType.NULL {}", value.toString()); + return UnDefType.NULL; + } else { + // logger.info("VALUE: FALLBACK {}", value.toString()); + return StringType.valueOf(value.toString()); + } + } catch (Exception e) { + String msg = "Can't convert python value '" + value.toString() + "' (" + value.getClass() + + ") to an org.openhab.core.types.State object\n" + e.getClass().getSimpleName() + ": " + + e.getMessage(); + throw new IllegalArgumentException(msg, e); + } + } + + private static ZonedDateTime parseDatetime(Value value) { + return ZonedDateTime.parse(value.invokeMember("isoformat").asString() + + (!value.hasMember("tzinfo") || value.getMember("tzinfo").isNull() + ? OffsetDateTime.now().getOffset().getId() + : "")); + } + + public static @Nullable Language getLanguage() { + return engine.getLanguages().get(GraalPythonScriptEngine.LANGUAGE_ID); } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java index 5fd03957a31dc..6b6b45fbab163 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java @@ -12,13 +12,48 @@ */ package org.openhab.automation.pythonscripting.internal; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleDescriptor.Version; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.config.core.ConfigParser; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.OpenHAB; +import org.openhab.core.automation.module.script.ScriptEngineFactory; +import org.openhab.core.config.core.Configuration; +import org.osgi.framework.FrameworkUtil; +import org.osgi.service.component.annotations.Activate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + /** * Processes Python Configuration Parameters. * @@ -29,62 +64,448 @@ public class PythonScriptEngineConfiguration { private final Logger logger = LoggerFactory.getLogger(PythonScriptEngineConfiguration.class); - private static final String CFG_INJECTION_ENABLED = "injectionEnabled"; - private static final String CFG_HELPER_ENABLED = "helperEnabled"; - private static final String CFG_SCOPE_ENABLED = "scopeEnabled"; - private static final String CFG_DEPENDENCY_TRACKING_ENABLED = "dependencyTrackingEnabled"; - private static final String CFG_CACHING_ENABLED = "cachingEnabled"; - private static final String CFG_JYTHON_EMULATION = "jythonEmulation"; + private static final String SYSTEM_PROPERTY_POLYGLOT_ENGINE_USERRESOURCECACHE = "polyglot.engine.userResourceCache"; + + private static final String SYSTEM_PROPERTY_JAVA_IO_TMPDIR = "java.io.tmpdir"; + + private static final String PATH_SEPARATOR = FileSystems.getDefault().getSeparator(); + private static final String RESOURCE_SEPARATOR = "/"; + + public static final Path PYTHON_DEFAULT_PATH = Paths.get(OpenHAB.getConfigFolder(), "automation", "python"); + public static final Path PYTHON_LIB_PATH = PYTHON_DEFAULT_PATH.resolve("lib"); + public static final Path PYTHON_TYPINGS_PATH = PYTHON_DEFAULT_PATH.resolve("typings"); + public static final Path PYTHON_OPENHAB_LIB_PATH = PYTHON_LIB_PATH.resolve("openhab"); + + public static final Path PYTHON_WRAPPER_FILE_PATH = PYTHON_OPENHAB_LIB_PATH.resolve("__wrapper__.py"); + private static final Path PYTHON_INIT_FILE_PATH = PYTHON_OPENHAB_LIB_PATH.resolve("__init__.py"); + + private static final Pattern VERSION_PATTERN = Pattern.compile("__version__\\s*=\\s*\"([^\"]*)\"", + Pattern.CASE_INSENSITIVE); public static final int INJECTION_DISABLED = 0; public static final int INJECTION_ENABLED_FOR_ALL_SCRIPTS = 1; public static final int INJECTION_ENABLED_FOR_NON_FILE_BASED_SCRIPTS = 2; - private int injectionEnabled = 0; - private boolean helperEnabled = false; - private boolean scopeEnabled = false; - private boolean dependencyTrackingEnabled = false; - private boolean cachingEnabled = false; - private boolean jythonEmulation = false; + + // The variable names must match the configuration keys in config.xml + public static class PythonScriptingConfiguration { + public boolean scopeEnabled = true; + public boolean helperEnabled = true; + public int injectionEnabled = INJECTION_ENABLED_FOR_NON_FILE_BASED_SCRIPTS; + public boolean dependencyTrackingEnabled = true; + public boolean cachingEnabled = true; + public boolean jythonEmulation = false; + public boolean nativeModules = false; + public String pipModules = ""; + } + + private PythonScriptingConfiguration configuration = new PythonScriptingConfiguration(); + private Path bytecodeDirectory; + private Path tempDirectory; + private Path venvDirectory; + private @Nullable Path venvExecutable = null; + + private Version bundleVersion = Version + .parse(FrameworkUtil.getBundle(PythonScriptEngineConfiguration.class).getVersion().toString()); + + private Version graalVersion = Version.parse("0.0.0"); + private Version providedHelperLibVersion = Version.parse("0.0.0"); + private @Nullable Version installedHelperLibVersion = null; + + public static Version parseHelperLibVersion(@Nullable String version) throws IllegalArgumentException { + // substring(1) => remove leading 'v' + return Version.parse(version != null && version.startsWith("v") ? version.substring(1) : version); + } + + @Activate + public PythonScriptEngineConfiguration(Map config, PythonScriptEngineFactory factory) { + Path userdataDir = Paths.get(OpenHAB.getUserDataFolder()); + + String tmpDir = System.getProperty(SYSTEM_PROPERTY_JAVA_IO_TMPDIR); + if (tmpDir != null) { + tempDirectory = Paths.get(tmpDir); + } else { + tempDirectory = userdataDir.resolve("tmp"); + } + + try { + InputStream is = PythonScriptEngineConfiguration.class + .getResourceAsStream(RESOURCE_SEPARATOR + "build.properties"); + if (is != null) { + Properties p = new Properties(); + p.load(is); + String version = p.getProperty("helperlib.version"); + providedHelperLibVersion = parseHelperLibVersion(version); + version = p.getProperty("graalpy.version"); + graalVersion = Version.parse(version); + } + } catch (IOException e) { + throw new IllegalArgumentException("Unable to load build.properties"); + } + + String packageName = PythonScriptEngineConfiguration.class.getPackageName(); + packageName = packageName.substring(0, packageName.lastIndexOf(".")); + Path bindingDirectory = userdataDir.resolve("cache").resolve(packageName); + + Properties props = System.getProperties(); + props.setProperty(SYSTEM_PROPERTY_POLYGLOT_ENGINE_USERRESOURCECACHE, bindingDirectory.toString()); + bytecodeDirectory = initDirectory(bindingDirectory.resolve("resources")); + venvDirectory = initDirectory(bindingDirectory.resolve("venv")); + + Path venvPythonBin = venvDirectory.resolve("bin").resolve("graalpy"); + if (Files.exists(venvPythonBin)) { + venvExecutable = venvPythonBin; + } + + initHelperLib(); + + this.update(config, factory); + } /** * Update configuration * * @param config Configuration parameters to apply to ScriptEngine + * @param intitial */ - void update(Map config) { + public void modified(Map config, ScriptEngineFactory factory) { + boolean oldScopeEnabled = configuration.scopeEnabled; + boolean oldInjectionEnabled = !isInjection(PythonScriptEngineConfiguration.INJECTION_DISABLED); + boolean oldDependencyTrackingEnabled = isDependencyTrackingEnabled(); + + this.update(config, factory); + + if (oldScopeEnabled != isScopeEnabled()) { + logger.info("{} scope for Python Scripting. Please resave your scripts to apply this change.", + isScopeEnabled() ? "Enabled" : "Disabled"); + } + if (oldInjectionEnabled != !isInjection(PythonScriptEngineConfiguration.INJECTION_DISABLED)) { + logger.info("{} injection for Python Scripting. Please resave your UI-based scripts to apply this change.", + !isInjection(PythonScriptEngineConfiguration.INJECTION_DISABLED) ? "Enabled" : "Disabled"); + } + if (oldDependencyTrackingEnabled != isDependencyTrackingEnabled()) { + logger.info("{} dependency tracking for Python Scripting. Please resave your scripts to apply this change.", + isDependencyTrackingEnabled() ? "Enabled" : "Disabled"); + } + } + + private void update(Map config, ScriptEngineFactory factory) { logger.trace("Python Script Engine Configuration: {}", config); - this.scopeEnabled = ConfigParser.valueAsOrElse(config.get(CFG_SCOPE_ENABLED), Boolean.class, true); - this.helperEnabled = ConfigParser.valueAsOrElse(config.get(CFG_HELPER_ENABLED), Boolean.class, true); - this.injectionEnabled = ConfigParser.valueAsOrElse(config.get(CFG_INJECTION_ENABLED), Integer.class, - INJECTION_ENABLED_FOR_NON_FILE_BASED_SCRIPTS); - this.dependencyTrackingEnabled = ConfigParser.valueAsOrElse(config.get(CFG_DEPENDENCY_TRACKING_ENABLED), - Boolean.class, true); - this.cachingEnabled = ConfigParser.valueAsOrElse(config.get(CFG_CACHING_ENABLED), Boolean.class, true); - this.jythonEmulation = ConfigParser.valueAsOrElse(config.get(CFG_JYTHON_EMULATION), Boolean.class, false); + String oldPipModules = configuration.pipModules; + configuration = new Configuration(config).as(PythonScriptingConfiguration.class); + + if (!oldPipModules.equals(configuration.pipModules)) { + initPipModules(factory); + } } public boolean isScopeEnabled() { - return scopeEnabled; + return configuration.scopeEnabled; } public boolean isHelperEnabled() { - return helperEnabled; + return configuration.helperEnabled; } public boolean isInjection(int type) { - return injectionEnabled == type; + return configuration.injectionEnabled == type; } public boolean isDependencyTrackingEnabled() { - return dependencyTrackingEnabled; + return configuration.dependencyTrackingEnabled; } public boolean isCachingEnabled() { - return cachingEnabled; + return configuration.cachingEnabled; } public boolean isJythonEmulation() { - return jythonEmulation; + return configuration.jythonEmulation; + } + + public boolean isNativeModulesEnabled() { + return configuration.nativeModules; + } + + public String getPIPModules() { + return configuration.pipModules; + } + + public Path getBytecodeDirectory() { + return bytecodeDirectory; + } + + public Path getTempDirectory() { + return tempDirectory; + } + + public Path getVEnvDirectory() { + return venvDirectory; + } + + public @Nullable Path getVEnvExecutable() { + return venvExecutable; + } + + public boolean isVEnvEnabled() { + return venvExecutable != null; + } + + public Version getBundleVersion() { + return bundleVersion; + } + + public Version getGraalVersion() { + return graalVersion; + } + + public Version getProvidedHelperLibVersion() { + return providedHelperLibVersion; + } + + public @Nullable Version getInstalledHelperLibVersion() { + return installedHelperLibVersion; + } + + /** + * Returns the current configuration as a map. + * This is used to display the configuration in the console. + */ + public Map getConfigurations() { + ObjectMapper objectMapper = new ObjectMapper(); + Map objectMap = objectMapper.convertValue(configuration, + new TypeReference>() { + }); + return objectMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> { + if (entry.getValue() instanceof List listValue) { + return listValue.stream().map(Object::toString).collect(Collectors.joining("\n")); + } + return entry.getValue().toString(); + })); + } + + private void initPipModules(ScriptEngineFactory factory) { + String pipModulesConfig = configuration.pipModules.strip(); + if (pipModulesConfig.isEmpty()) { + return; + } + + if (!isVEnvEnabled()) { + logger.error("Can't install pip modules. VEnv not enabled."); + return; + } + + List pipModules = Arrays.stream(pipModulesConfig.split(",")).map(String::trim) + .filter(module -> !module.isEmpty()).collect(Collectors.toList()); + + if (pipModules.isEmpty()) { + return; + } + + final String pipCode = """ + import subprocess + import sys + + command_list = [sys.executable, "-m", "pip", "install"] + pipModules + proc = subprocess.run(command_list, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, check=False) + if proc.returncode != 0: + print(proc.stdout) + exit(1) + """; + + ScriptEngine engine = factory.createScriptEngine(PythonScriptEngineFactory.SCRIPT_TYPE); + if (engine != null) { + engine.getContext().setAttribute("pipModules", pipModules, ScriptContext.ENGINE_SCOPE); + try { + logger.info("Checking for pip module{} '{}'", pipModules.size() > 1 ? "s" : "", + configuration.pipModules); + engine.eval(pipCode); + } catch (ScriptException e) { + logger.warn("Error installing pip module{}", pipModules.size() > 1 ? "s" : ""); + logger.trace("TRACE:", unwrap(e)); + } + } else { + logger.warn("Can't install pip modules. No script engine available."); + } + } + + private void initHelperLib() { + if (!isHelperEnabled()) { + return; + } + + logger.info("Checking for helper libs version '{}'", providedHelperLibVersion); + + String resourceLibPath = PYTHON_OPENHAB_LIB_PATH.toString().substring(PYTHON_DEFAULT_PATH.toString().length()) + + PATH_SEPARATOR; + if (!RESOURCE_SEPARATOR.equals(PATH_SEPARATOR)) { + resourceLibPath = resourceLibPath.replace(PATH_SEPARATOR, RESOURCE_SEPARATOR); + } + + if (Files.exists(PYTHON_INIT_FILE_PATH)) { + try { + String content = Files.readString(PYTHON_INIT_FILE_PATH, StandardCharsets.UTF_8); + Matcher currentMatcher = VERSION_PATTERN.matcher(content); + if (currentMatcher.find()) { + installedHelperLibVersion = Version.parse(currentMatcher.group(1)); + @SuppressWarnings("null") + int compareResult = installedHelperLibVersion.compareTo(providedHelperLibVersion); + if (compareResult >= 0) { + if (compareResult > 0) { + logger.info("Newer helper libs version '{}' already installed.", installedHelperLibVersion); + } + return; + } + } else { + logger.warn("Unable to parse current version. Proceed as if it was not installed."); + } + } catch (IOException | IllegalArgumentException e) { + logger.warn("Unable to detect current version. Proceed as if it was not installed."); + } + } + + if (installedHelperLibVersion != null) { + logger.info("Update helper libs version '{}' to version {}.", installedHelperLibVersion, + providedHelperLibVersion); + } else { + logger.info("Install helper libs version {}.", providedHelperLibVersion); + } + + try { + Path bakLibPath = preProcessHelperLibUpdate(); + + try { + Enumeration resourceFiles = FrameworkUtil.getBundle(PythonScriptEngineConfiguration.class) + .findEntries(resourceLibPath, "*.py", true); + + while (resourceFiles.hasMoreElements()) { + URL resourceFile = resourceFiles.nextElement(); + String resourcePath = resourceFile.getPath(); + + ClassLoader clsLoader = PythonScriptEngineConfiguration.class.getClassLoader(); + if (clsLoader != null) { + try (InputStream is = clsLoader.getResourceAsStream(resourcePath)) { + Path target = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH + .resolve(resourcePath.substring(resourcePath.lastIndexOf(RESOURCE_SEPARATOR) + 1)); + + Files.copy(is, target); + initFile(target); + } + } else { + throw new IllegalArgumentException("Class loader is null"); + } + } + + postProcessHelperLibUpdateOnSuccess(providedHelperLibVersion, bakLibPath); + } catch (Exception e) { + postProcessHelperLibUpdateOnFailure(bakLibPath); + throw e; + } + } catch (Exception e) { + logger.error("Exception during helper lib initialisation", e); + } + } + + public void initHelperLib(String remoteUrl, Version remoteVersion) throws URISyntaxException, IOException { + Path bakLibPath = null; + try { + bakLibPath = preProcessHelperLibUpdate(); + URL zipfileUrl = new URI(remoteUrl).toURL(); + InputStream in = new BufferedInputStream(zipfileUrl.openStream(), 1024); + ZipInputStream stream = new ZipInputStream(in); + byte[] buffer = new byte[1024]; + ZipEntry entry; + while ((entry = stream.getNextEntry()) != null) { + if (!entry.getName().contains("/src/") || entry.isDirectory()) { + continue; + } + + int read; + StringBuilder sb = new StringBuilder(); + while ((read = stream.read(buffer, 0, 1024)) >= 0) { + sb.append(new String(buffer, 0, read)); + } + + Path target = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH + .resolve(new File(entry.getName()).getName()); + Files.write(target, sb.toString().getBytes()); + initFile(target); + } + + postProcessHelperLibUpdateOnSuccess(remoteVersion, bakLibPath); + } catch (IOException | URISyntaxException e) { + postProcessHelperLibUpdateOnFailure(bakLibPath); + throw e; + } + } + + private @Nullable Path preProcessHelperLibUpdate() throws IOException { + Path bakLibPath = null; + // backup old lib folder before update + if (Files.exists(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH)) { + bakLibPath = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH.getParent() + .resolve(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH.getFileName() + ".bak"); + Files.move(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH, bakLibPath); + } + initDirectory(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH); + return bakLibPath; + } + + private void postProcessHelperLibUpdateOnSuccess(Version version, @Nullable Path bakLibPath) throws IOException { + String content = Files.readString(PYTHON_INIT_FILE_PATH, StandardCharsets.UTF_8).trim(); + Matcher currentMatcher = VERSION_PATTERN.matcher(content); + content = currentMatcher.replaceAll("__version__ = \"" + version.toString() + "\""); + Files.writeString(PYTHON_INIT_FILE_PATH, content, StandardCharsets.UTF_8); + installedHelperLibVersion = version; + + if (bakLibPath != null) { + // cleanup old files + try (var dirStream = Files.walk(bakLibPath)) { + dirStream.map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete); + } + } + } + + private void postProcessHelperLibUpdateOnFailure(@Nullable Path bakLibPath) throws IOException { + // cleanup new files + try (var dirStream = Files.walk(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH)) { + dirStream.map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete); + } + + if (bakLibPath != null) { + // restore old files + Files.move(bakLibPath, PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH); + } + } + + private void initFile(Path path) { + File file = path.toFile(); + file.setReadable(true, false); + file.setWritable(true, true); + } + + private Path initDirectory(Path path) { + File directory = path.toFile(); + if (!directory.exists()) { + directory.mkdirs(); + directory.setExecutable(true, false); + directory.setReadable(true, false); + directory.setWritable(true, true); + } + return path; + } + + /** + * Unwraps the cause of an exception, if it has one. + * + * Since a user cares about the _Ruby_ stack trace of the throwable, not + * the details of where openHAB called it. + */ + private static Throwable unwrap(Throwable e) { + Throwable cause = e.getCause(); + if (cause != null) { + return cause; + } + return e; } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineFactory.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineFactory.java index f5af3dbe09a61..139b9e5ce9506 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineFactory.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineFactory.java @@ -12,39 +12,24 @@ */ package org.openhab.automation.pythonscripting.internal; -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.module.ModuleDescriptor.Version; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; +import java.time.ZoneId; import java.util.Arrays; -import java.util.Comparator; -import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.script.ScriptEngine; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.automation.pythonscripting.internal.fs.watch.PythonDependencyTracker; -import org.openhab.core.OpenHAB; +import org.graalvm.polyglot.Language; +import org.openhab.automation.pythonscripting.internal.fs.PythonDependencyTracker; +import org.openhab.automation.pythonscripting.internal.scriptengine.graal.GraalPythonScriptEngine.ScriptEngineProvider; import org.openhab.core.automation.module.script.ScriptDependencyTracker; import org.openhab.core.automation.module.script.ScriptEngineFactory; import org.openhab.core.config.core.ConfigurableService; +import org.openhab.core.i18n.TimeZoneProvider; import org.osgi.framework.Constants; -import org.osgi.framework.FrameworkUtil; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; @@ -59,41 +44,44 @@ * @author Holger Hees - Initial contribution * @author Jeff James - Initial contribution */ -@Component(service = ScriptEngineFactory.class, configurationPid = "org.openhab.automation.pythonscripting", property = Constants.SERVICE_PID - + "=org.openhab.automation.pythonscripting") -@ConfigurableService(category = "automation", label = "Python Scripting", description_uri = "automation:pythonscripting") +@Component(service = { ScriptEngineFactory.class, PythonScriptEngineFactory.class }, // + configurationPid = "org.openhab.automation.pythonscripting", // + property = Constants.SERVICE_PID + "=org.openhab.automation.pythonscripting") +@ConfigurableService(category = "automation", label = "Python Scripting", description_uri = PythonScriptEngineFactory.CONFIG_DESCRIPTION_URI) @NonNullByDefault -public class PythonScriptEngineFactory implements ScriptEngineFactory { +public class PythonScriptEngineFactory implements ScriptEngineFactory, ScriptEngineProvider { private final Logger logger = LoggerFactory.getLogger(PythonScriptEngineFactory.class); - private static final String RESOURCE_SEPARATOR = "/"; - - public static final Path PYTHON_DEFAULT_PATH = Paths.get(OpenHAB.getConfigFolder(), "automation", "python"); - public static final Path PYTHON_LIB_PATH = PYTHON_DEFAULT_PATH.resolve("lib"); - - private static final Path PYTHON_OPENHAB_LIB_PATH = PYTHON_LIB_PATH.resolve("openhab"); - - public static final Path PYTHON_WRAPPER_FILE_PATH = PYTHON_OPENHAB_LIB_PATH.resolve("__wrapper__.py"); - private static final Path PYTHON_INIT_FILE_PATH = PYTHON_OPENHAB_LIB_PATH.resolve("__init__.py"); - + public static final String CONFIG_DESCRIPTION_URI = "automation:pythonscripting"; public static final String SCRIPT_TYPE = "application/x-python3"; - private final List scriptTypes = Arrays.asList("py", SCRIPT_TYPE); + private final List scriptTypes = Arrays.asList("py", SCRIPT_TYPE); private final PythonDependencyTracker pythonDependencyTracker; - private final PythonScriptEngineConfiguration pythonScriptEngineConfiguration; + private final PythonScriptEngineConfiguration configuration; + + private final @Nullable Language language; @Activate public PythonScriptEngineFactory(final @Reference PythonDependencyTracker pythonDependencyTracker, - Map config) { + final @Reference TimeZoneProvider timeZoneProvider, Map config) { logger.debug("Loading PythonScriptEngineFactory"); this.pythonDependencyTracker = pythonDependencyTracker; - this.pythonScriptEngineConfiguration = new PythonScriptEngineConfiguration(); + this.configuration = new PythonScriptEngineConfiguration(config, this); - modified(config); + this.language = PythonScriptEngine.getLanguage(); + if (this.language == null) { + logger.error( + "Graal python language not initialized. Restart openhab to initialize available graal languages properly."); + } - if (this.pythonScriptEngineConfiguration.isHelperEnabled()) { - initHelperLib(); + String defaultTimezone = ZoneId.systemDefault().getId(); + String providerTimezone = timeZoneProvider.getTimeZone().getId(); + if (!defaultTimezone.equals(providerTimezone)) { + logger.warn( + "User timezone '{}' is different than openhab regional timezone '{}'. Python Scripting is running with timezone '{}'.", + defaultTimezone, providerTimezone, defaultTimezone); + // System.setProperty("user.timezone", "Australia/Tasmania"); } } @@ -103,8 +91,8 @@ public void cleanup() { } @Modified - protected void modified(Map config) { - this.pythonScriptEngineConfiguration.update(config); + protected void modified(Map config) { + this.configuration.modified(config, this); } @Override @@ -124,105 +112,23 @@ public void scopeValues(ScriptEngine scriptEngine, Map scopeValu if (!scriptTypes.contains(scriptType)) { return null; } - return new PythonScriptEngine(pythonDependencyTracker, pythonScriptEngineConfiguration); + return createScriptEngine(); } @Override - public @Nullable ScriptDependencyTracker getDependencyTracker() { - return pythonDependencyTracker; + public @Nullable ScriptEngine createScriptEngine() { + if (language == null) { + return null; + } + return new PythonScriptEngine(configuration, this); } - private void initHelperLib() { - try { - String pathSeparator = FileSystems.getDefault().getSeparator(); - String resourceLibPath = PYTHON_OPENHAB_LIB_PATH.toString() - .substring(PYTHON_DEFAULT_PATH.toString().length()) + pathSeparator; - if (!RESOURCE_SEPARATOR.equals(pathSeparator)) { - resourceLibPath = resourceLibPath.replace(pathSeparator, RESOURCE_SEPARATOR); - } - - if (Files.exists(PythonScriptEngineFactory.PYTHON_OPENHAB_LIB_PATH)) { - try (Stream files = Files.list(PYTHON_OPENHAB_LIB_PATH)) { - if (files.count() > 0) { - Pattern pattern = Pattern.compile("__version__\\s*=\\s*\"([0-9]+\\.[0-9]+\\.[0-9]+)\"", - Pattern.CASE_INSENSITIVE); - - Version includedVersion = null; - try (InputStream is = PythonScriptEngineFactory.class.getClassLoader().getResourceAsStream( - resourceLibPath + PYTHON_INIT_FILE_PATH.getFileName().toString())) { - try (InputStreamReader isr = new InputStreamReader(is); - BufferedReader reader = new BufferedReader(isr)) { - String fileContent = reader.lines().collect(Collectors.joining(System.lineSeparator())); - Matcher includedMatcher = pattern.matcher(fileContent); - if (includedMatcher.find()) { - includedVersion = Version.parse(includedMatcher.group(1)); - } - } - } - - Version currentVersion = null; - String fileContent = Files.readString(PYTHON_INIT_FILE_PATH, StandardCharsets.UTF_8); - Matcher currentMatcher = pattern.matcher(fileContent); - if (currentMatcher.find()) { - currentVersion = Version.parse(currentMatcher.group(1)); - } - - if (currentVersion == null) { - logger.warn("Unable to detect installed helper lib version. Skip installing helper libs."); - return; - } else if (includedVersion == null) { - logger.error("Unable to detect provided helper lib version. Skip installing helper libs."); - return; - } else if (currentVersion.compareTo(includedVersion) >= 0) { - logger.info("Newest helper lib version is deployed."); - return; - } - } - } - } - - logger.info("Deploy helper libs into {}.", PythonScriptEngineFactory.PYTHON_OPENHAB_LIB_PATH); - - if (Files.exists(PythonScriptEngineFactory.PYTHON_OPENHAB_LIB_PATH)) { - try (Stream paths = Files.walk(PythonScriptEngineFactory.PYTHON_OPENHAB_LIB_PATH)) { - paths.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); - } - } - - initDirectory(PythonScriptEngineFactory.PYTHON_DEFAULT_PATH); - initDirectory(PythonScriptEngineFactory.PYTHON_LIB_PATH); - initDirectory(PythonScriptEngineFactory.PYTHON_OPENHAB_LIB_PATH); - - Enumeration resourceFiles = FrameworkUtil.getBundle(PythonScriptEngineFactory.class) - .findEntries(resourceLibPath, "*.py", true); - - while (resourceFiles.hasMoreElements()) { - URL resourceFile = resourceFiles.nextElement(); - String resourcePath = resourceFile.getPath(); - - try (InputStream is = PythonScriptEngineFactory.class.getClassLoader() - .getResourceAsStream(resourcePath)) { - Path target = PythonScriptEngineFactory.PYTHON_OPENHAB_LIB_PATH - .resolve(resourcePath.substring(resourcePath.lastIndexOf(RESOURCE_SEPARATOR) + 1)); - - Files.copy(is, target); - File file = target.toFile(); - file.setReadable(true, false); - file.setWritable(true, true); - } - } - } catch (Exception e) { - logger.error("Exception during helper lib initialisation", e); - } + @Override + public @Nullable ScriptDependencyTracker getDependencyTracker() { + return pythonDependencyTracker; } - private void initDirectory(Path path) { - File directory = path.toFile(); - if (!directory.exists()) { - directory.mkdir(); - directory.setExecutable(true, false); - directory.setReadable(true, false); - directory.setWritable(true, true); - } + public PythonScriptEngineConfiguration getConfiguration() { + return this.configuration; } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/PythonConsoleCommandExtension.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/PythonConsoleCommandExtension.java new file mode 100644 index 0000000000000..84c949c1189c3 --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/PythonConsoleCommandExtension.java @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.console; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.SortedSet; +import java.util.UUID; + +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngine; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineConfiguration; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineFactory; +import org.openhab.automation.pythonscripting.internal.console.handler.InfoCmd; +import org.openhab.automation.pythonscripting.internal.console.handler.TypingCmd; +import org.openhab.automation.pythonscripting.internal.console.handler.UpdateCmd; +import org.openhab.core.automation.module.script.ScriptEngineContainer; +import org.openhab.core.automation.module.script.ScriptEngineFactory; +import org.openhab.core.automation.module.script.ScriptEngineManager; +import org.openhab.core.config.core.ConfigDescriptionRegistry; +import org.openhab.core.io.console.Console; +import org.openhab.core.io.console.ConsoleCommandCompleter; +import org.openhab.core.io.console.StringsCompleter; +import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension; +import org.openhab.core.io.console.extensions.ConsoleCommandExtension; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * The {@link PythonConsoleCommandExtension} class + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +@Component(service = ConsoleCommandExtension.class) +public class PythonConsoleCommandExtension extends AbstractConsoleCommandExtension implements ConsoleCommandCompleter { + private static final String INFO = "info"; + private static final String CONSOLE = "console"; + private static final String TYPING = "typing"; + private static final String PIP = "pip"; + private static final String PIP_INSTALL = "install"; + private static final String PIP_UNINSTALL = "uninstall"; + private static final String PIP_SHOW = "show"; + private static final String PIP_LIST = "list"; + private static final String UPDATE = "update"; + private static final String UPDATE_LIST = "list"; + private static final String UPDATE_CHECK = "check"; + private static final String UPDATE_INSTALL = "install"; + + private static final List COMMANDS = List.of(INFO, CONSOLE, UPDATE, TYPING); + private static final List UPDATE_COMMANDS = List.of(UPDATE_LIST, UPDATE_CHECK, UPDATE_INSTALL); + private static final List PIP_COMMANDS = List.of(PIP_INSTALL, PIP_UNINSTALL, PIP_SHOW, PIP_LIST); + + private final ScriptEngineManager scriptEngineManager; + private final PythonScriptEngineFactory pythonScriptEngineFactory; + private final ConfigDescriptionRegistry configDescriptionRegistry; + private final PythonScriptEngineConfiguration pythonScriptEngineConfiguration; + + private final String scriptType; + + @Activate + public PythonConsoleCommandExtension( // + @Reference ScriptEngineManager scriptEngineManager, // + @Reference PythonScriptEngineFactory pythonScriptEngineFactory, // + @Reference ConfigDescriptionRegistry configDescriptionRegistry) { + super("pythonscripting", "Python Scripting console utilities."); + this.scriptEngineManager = scriptEngineManager; + this.pythonScriptEngineFactory = pythonScriptEngineFactory; + this.pythonScriptEngineConfiguration = pythonScriptEngineFactory.getConfiguration(); + this.scriptType = PythonScriptEngineFactory.SCRIPT_TYPE; + this.configDescriptionRegistry = configDescriptionRegistry; + } + + @Override + public @Nullable ConsoleCommandCompleter getCompleter() { + return this; + } + + @Override + public List getUsages() { + ArrayList usages = new ArrayList(); + usages.add(buildCommandUsage(INFO, "displays information about Python Scripting add-on")); + usages.add(buildCommandUsage(CONSOLE, "starts an interactive python console")); + usages.add(getUpdateUsage()); + if (pythonScriptEngineConfiguration.isVEnvEnabled()) { + usages.add(getPipUsage()); + } + usages.add(buildCommandUsage(TYPING, "create type hint stub files")); + return usages; + } + + public String getUpdateUsage() { + return buildCommandUsage(UPDATE + " <" + String.join("|", UPDATE_COMMANDS) + ">", "update helper lib module"); + } + + public String getPipUsage() { + return buildCommandUsage(PIP + " <" + String.join("|", PIP_COMMANDS) + "> [optional pip specific arguments]", + "manages python modules"); + } + + @Override + public boolean complete(String[] args, int cursorArgumentIndex, int cursorPosition, List candidates) { + StringsCompleter completer = new StringsCompleter(); + SortedSet strings = completer.getStrings(); + if (cursorArgumentIndex == 0) { + strings.addAll(COMMANDS); + if (pythonScriptEngineConfiguration.isVEnvEnabled()) { + strings.add(PIP); + } + } else if (cursorArgumentIndex == 1) { + if (PIP.equals(args[0])) { + strings.addAll(PIP_COMMANDS); + } else if (UPDATE.equals(args[0])) { + strings.addAll(UPDATE_COMMANDS); + } + } + + return strings.isEmpty() ? false : completer.complete(args, cursorArgumentIndex, cursorPosition, candidates); + } + + @Override + public void execute(String[] args, Console console) { + if (args.length > 0) { + String command = args[0]; + switch (command) { + case "--help": + case "-h": + printUsage(console); + break; + case INFO: + info(console); + break; + case CONSOLE: + startConsole(console, Arrays.copyOfRange(args, 1, args.length)); + break; + case UPDATE: + executeUpdate(console, Arrays.copyOfRange(args, 1, args.length)); + break; + case TYPING: + executeTyping(console); + break; + case PIP: + if (pythonScriptEngineConfiguration.isVEnvEnabled()) { + executePip(console, Arrays.copyOfRange(args, 1, args.length)); + break; + } + default: + console.println("Unknown command '" + command + "'"); + printUsage(console); + break; + } + } else { + printUsage(console); + } + } + + private void info(Console console) { + new InfoCmd(pythonScriptEngineConfiguration, console).show(configDescriptionRegistry); + } + + private void startConsole(Console console, String[] args) { + final String startInteractiveSessionCode = """ + import readline # optional, will allow Up/Down/History in the console + import code + + vars = globals().copy() + vars.update(locals()) + shell = code.InteractiveConsole(vars) + try: + shell.interact() + except SystemExit: + pass + """; + + executePython(console, engine -> engine.eval(startInteractiveSessionCode), true); + } + + private void executeUpdate(Console console, String[] args) { + if (args.length == 0) { + console.println("Missing update action"); + console.printUsage(getUpdateUsage()); + } else if (UPDATE_COMMANDS.indexOf(args[0]) == -1) { + console.println("Unknown update action '" + args[0] + "'"); + console.printUsage(getUpdateUsage()); + } else { + UpdateCmd cmd = new UpdateCmd(pythonScriptEngineConfiguration, console); + switch (args[0]) { + case UPDATE_LIST: + cmd.updateList(); + break; + case UPDATE_CHECK: + cmd.updateCheck(); + break; + case UPDATE_INSTALL: + if (args.length <= 1) { + console.println("Missing release name"); + console.printUsage("pythonscripting update install <\"latest\"|version>"); + } else { + cmd.updateInstall(args[1]); + } + break; + } + } + } + + private void executeTyping(Console console) { + try { + if (!confirmAction(console, "You are about creating python type hint stub files in '" + + PythonScriptEngineConfiguration.PYTHON_TYPINGS_PATH + "'.")) { + return; + } + new TypingCmd(new TypingCmd.Logger(console)).build(); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + private void executePip(Console console, String[] args) { + if (args.length == 0) { + console.println("Missing pip action"); + console.printUsage(getPipUsage()); + } else if (PIP_COMMANDS.indexOf(args[0]) == -1) { + console.println("Unknown pip action '" + args[1] + "'"); + console.printUsage(getPipUsage()); + } else { + ArrayList params = new ArrayList(Arrays.asList(args)); + + if (PIP_UNINSTALL.equals(args[0]) && args.length >= 2) { + if (!confirmAction(console, "You are uninstalling python modules.")) { + return; + } + params.add(1, "-y"); + } + + final String pipCode = """ + import subprocess + import sys + + command_list = [sys.executable, "-m", "pip"] + PARAMS + with subprocess.Popen(command_list, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) as proc: + for line in proc.stdout: + print(line.rstrip()) + """; + + executePython(console, engine -> { + engine.getContext().setAttribute("PARAMS", params, ScriptContext.ENGINE_SCOPE); + return engine.eval(pipCode); + }, false); + } + } + + private void printLoadingMessage(Console console, boolean show) { + String loadingMessage = "Loading Python script engine..."; + if (show) { + console.print(loadingMessage); + } else { + // Clear the loading message + console.print("\r" + " ".repeat(loadingMessage.length()) + "\r"); + } + } + + /* + * Create Python engine. + * + * withFullContext = true => means a full openHAB-managed script engine with scoped variables + * including any injected required modules. + */ + private @Nullable Object executePython(Console console, EngineEvalFunction process, boolean withFullContext) { + String scriptIdentifier = "python-console-" + UUID.randomUUID().toString(); + ScriptEngine engine = null; + + try { + printLoadingMessage(console, true); + + if (withFullContext) { + ScriptEngineContainer container = scriptEngineManager.createScriptEngine(scriptType, scriptIdentifier); + if (container != null) { + engine = container.getScriptEngine(); + } + } else { + engine = pythonScriptEngineFactory.createScriptEngine(scriptType); + if (engine != null) { + engine.getContext().setAttribute(ScriptEngineFactory.CONTEXT_KEY_ENGINE_IDENTIFIER, + scriptIdentifier, ScriptContext.ENGINE_SCOPE); + } + } + + if (engine == null) { + console.println("Error: Unable to create python script engine."); + return null; + } + + printLoadingMessage(console, false); + + engine.getContext().setAttribute(PythonScriptEngine.CONTEXT_KEY_ENGINE_LOGGER_INPUT, + createInputStream(console), ScriptContext.ENGINE_SCOPE); + engine.getContext().setAttribute(PythonScriptEngine.CONTEXT_KEY_ENGINE_LOGGER_OUTPUT, System.out, + ScriptContext.ENGINE_SCOPE); + + return process.apply(engine); + } catch (ScriptException e) { + console.println("Error: " + e.getMessage()); + return null; + } finally { + if (withFullContext) { + scriptEngineManager.removeEngine(scriptIdentifier); + } else { + if (engine instanceof AutoCloseable closeable) { + try { + closeable.close(); + } catch (Exception e) { + console.println("Error while closing script engine. " + e.getMessage()); + } + } + } + } + } + + private boolean confirmAction(Console console, String msg) { + try { + console.readLine("\n" + msg + "\n\nPress Enter to confirm or Ctrl+C to cancel.", null); + console.println(""); + return true; + } catch (IOException e) { + console.println("Error: " + e.getMessage()); + return false; + } catch (RuntimeException e) { + console.println("Operation cancelled."); + return false; + } + } + + private InputStream createInputStream(Console console) { + return new InputStream() { + byte @Nullable [] buffer = null; + int pos = 0; + + @SuppressWarnings("null") + @Override + public int read() throws IOException { + if (pos < 0) { + pos = 0; + return -1; + } else if (buffer == null) { + assert pos == 0; + try { + String line = console.readLine("", null); + buffer = line.getBytes(StandardCharsets.UTF_8); + } catch (Exception e) { + return -1; + } + } + if (pos == buffer.length) { + buffer = null; + pos = -1; + return '\n'; + } else { + return buffer[pos++]; + } + } + }; + } + + @FunctionalInterface + public interface EngineEvalFunction { + @Nullable + Object apply(ScriptEngine e) throws ScriptException; + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/InfoCmd.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/InfoCmd.java new file mode 100644 index 0000000000000..d9c9f80e227e0 --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/InfoCmd.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.console.handler; + +import java.lang.module.ModuleDescriptor.Version; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.graalvm.polyglot.Language; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngine; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineConfiguration; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineFactory; +import org.openhab.core.config.core.ConfigDescription; +import org.openhab.core.config.core.ConfigDescriptionParameter; +import org.openhab.core.config.core.ConfigDescriptionRegistry; +import org.openhab.core.io.console.Console; + +/** + * Info command implementation + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +public class InfoCmd { + private final PythonScriptEngineConfiguration config; + private final Console console; + + public InfoCmd(PythonScriptEngineConfiguration config, Console console) { + this.config = config; + this.console = console; + } + + public void show(ConfigDescriptionRegistry registry) { + console.println("Python Scripting Environment:"); + console.println("======================================"); + console.println(" Runtime:"); + console.println(" Bundle version: " + config.getBundleVersion()); + console.println(" GraalVM version: " + config.getGraalVersion()); + Language language = PythonScriptEngine.getLanguage(); + console.println(" Python version: " + (language != null ? language.getVersion() : "unavailable")); + Version version = config.getInstalledHelperLibVersion(); + console.println(" Helper lib version: " + (version != null ? version.toString() : "disabled")); + console.println(" VEnv state: " + (config.isVEnvEnabled() ? "enabled" : "disabled")); + console.println(" Type hints: " + + (Files.isDirectory(PythonScriptEngineConfiguration.PYTHON_TYPINGS_PATH) ? "available" + : "not yet created")); + console.println(""); + console.println(" Directories:"); + console.println(" Scripts: " + PythonScriptEngineConfiguration.PYTHON_DEFAULT_PATH); + console.println(" Libraries: " + PythonScriptEngineConfiguration.PYTHON_LIB_PATH); + console.println(" Typing: " + PythonScriptEngineConfiguration.PYTHON_TYPINGS_PATH); + Path tempDirectory = config.getTempDirectory(); + console.println(" Temp: " + tempDirectory.toString()); + Path venvDirectory = config.getVEnvDirectory(); + console.println(" VEnv: " + venvDirectory.toString()); + + console.println(""); + console.println("Python Scripting Add-on Configuration:"); + console.println("======================================"); + ConfigDescription configDescription = registry + .getConfigDescription(URI.create(PythonScriptEngineFactory.CONFIG_DESCRIPTION_URI)); + + if (configDescription == null) { + console.println("No configuration found for Python Scripting add-on. This is probably a bug."); + return; + } + + List parameters = configDescription.getParameters(); + Map configMap = config.getConfigurations(); + configDescription.getParameters().forEach(parameter -> { + if (parameter.getGroupName() == null) { + console.println(" " + parameter.getName() + ": " + configMap.get(parameter.getName())); + } + }); + configDescription.getParameterGroups().forEach(group -> { + String groupLabel = group.getLabel(); + if (groupLabel == null) { + groupLabel = group.getName(); + } + console.println(" " + groupLabel); + parameters.forEach(parameter -> { + if (!group.getName().equals(parameter.getGroupName())) { + return; + } + console.print(" " + parameter.getName() + ": "); + String value = configMap.get(parameter.getName()); + if (value == null) { + console.println("not set"); + } else if (value.contains("\n")) { + console.println(" (multiline)"); + console.println(" " + value.replace("\n", "\n ")); + } else { + console.println(value); + } + }); + console.println(""); + }); + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/TypingCmd.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/TypingCmd.java new file mode 100644 index 0000000000000..45a055ce0fdfb --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/TypingCmd.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.console.handler; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineConfiguration; +import org.openhab.automation.pythonscripting.internal.console.handler.typing.ClassCollector; +import org.openhab.automation.pythonscripting.internal.console.handler.typing.ClassCollector.ClassContainer; +import org.openhab.automation.pythonscripting.internal.console.handler.typing.ClassConverter; +import org.openhab.core.io.console.Console; + +/** + * Update command implementations + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +public class TypingCmd { + private final Logger logger; + + private static final String PATH_SEPARATOR = FileSystems.getDefault().getSeparator(); + + public TypingCmd(Logger logger) { + this.logger = logger; + } + + public void build() throws Exception { + Path outputPath = PythonScriptEngineConfiguration.PYTHON_TYPINGS_PATH; + + // Cleanup Directory + if (Files.isDirectory(outputPath)) { + try (Stream paths = Files.walk(outputPath)) { + paths.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); + } + } + ClassCollector collector = new ClassCollector(logger); + + Map fileContainerMap = new HashMap(); + Set imports = new HashSet(); + // Collect Bundle Classes + Map bundleClassMap = collector.collectBundleClasses("org.openhab"); + for (ClassContainer container : bundleClassMap.values()) { + ClassConverter converter = new ClassConverter(container); + String classBody = converter.build(); + imports.addAll(converter.getImports()); + dumpClassContentToFile(classBody, container, outputPath, fileContainerMap); + } + + imports = imports.stream().filter(i -> !i.startsWith("org.openhab")).collect(Collectors.toSet()); + + Map reflectionClassMap = collector.collectReflectionClasses(imports); + for (ClassContainer container : reflectionClassMap.values()) { + ClassConverter converter = new ClassConverter(container); + String classBody = converter.build(); + dumpClassContentToFile(classBody, container, outputPath, fileContainerMap); + } + + // Generate __init__.py Files + dumpInit(outputPath.toString(), fileContainerMap); + + logger.info(bundleClassMap.size() + " bundle and " + reflectionClassMap.size() + " java classes processed"); + logger.info("Total of " + (bundleClassMap.size() + reflectionClassMap.size()) + " type hint files create in '" + + outputPath + "'"); + } + + public void dumpInit(String path, Map fileContainerMap) throws IOException { + File root = new File(path); + File[] list = root.listFiles(); + if (list == null) { + return; + } + + ArrayList files = new ArrayList(); + for (File f : list) { + if (f.isDirectory()) { + dumpInit(f.getAbsolutePath(), fileContainerMap); + } else { + files.add(f); + } + } + + if (!files.isEmpty()) { + StringBuilder initBody = new StringBuilder(); + // List modules = new ArrayList(); + for (File file : files) { + if (file.toString().endsWith("__init__.py")) { + continue; + } + ClassContainer container = fileContainerMap.get(file.toString()); + initBody.append("from .__" + container.getPythonClassName().toLowerCase() + "__ import " + + container.getPythonClassName() + "\n"); + } + + String packageUrl = path.replace(".", PATH_SEPARATOR) + "/__init__.py"; + dumpContentToFile(initBody.toString(), Paths.get(packageUrl)); + } + } + + private void dumpClassContentToFile(String classBody, ClassContainer container, Path outputPath, + Map fileContainerMap) throws IOException { + if (classBody.isEmpty()) { + return; + } + + String modulePath = container.getPythonModuleName().replace(".", PATH_SEPARATOR); + Path path = outputPath.resolve(modulePath) + .resolve("__" + container.getPythonClassName().toLowerCase() + "__.py"); + + fileContainerMap.put(path.toString(), container); + + dumpContentToFile(classBody, path); + } + + private void dumpContentToFile(String content, Path path) throws IOException { + Path parent = path.getParent(); + File directory = parent.toFile(); + if (!directory.exists()) { + directory.mkdirs(); + } + Files.write(path, content.getBytes()); + } + + public static class Logger { + private Object logger; + + public Logger(Console console) { + this.logger = console; + } + + public Logger(org.slf4j.Logger logger) { + this.logger = logger; + } + + public void info(String s) { + if (logger instanceof Console console) { + console.println("INFO: " + s); + } else { + ((org.slf4j.Logger) logger).info("{}", s); + } + } + + public void warn(String s) { + if (logger instanceof Console console) { + console.println("WARN: " + s); + } else { + ((org.slf4j.Logger) logger).warn("{}", s); + } + } + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/UpdateCmd.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/UpdateCmd.java new file mode 100644 index 0000000000000..4f9a54f696177 --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/UpdateCmd.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.console.handler; + +import java.io.IOException; +import java.lang.module.ModuleDescriptor.Version; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineConfiguration; +import org.openhab.core.io.console.Console; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +/** + * Update command implementations + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +public class UpdateCmd { + private static final String UPDATE_RELEASES_URL = "https://api.github.com/repos/openhab/openhab-python/releases"; + private static final String UPDATE_LATEST_URL = "https://api.github.com/repos/openhab/openhab-python/releases/latest"; + + private final PythonScriptEngineConfiguration config; + private final Console console; + + public UpdateCmd(PythonScriptEngineConfiguration config, Console console) { + this.config = config; + this.console = console; + } + + public void updateList() { + JsonElement rootElement = getReleaseData(UPDATE_RELEASES_URL); + if (rootElement != null) { + Version installedVersion = config.getInstalledHelperLibVersion(); + Version providedVersion = config.getProvidedHelperLibVersion(); + console.println("Version Released Active"); + console.println("----------------------------------------------"); + if (rootElement.isJsonArray()) { + JsonArray list = rootElement.getAsJsonArray(); + for (JsonElement element : list.asList()) { + String tagName = element.getAsJsonObject().get("tag_name").getAsString(); + String publishString = element.getAsJsonObject().get("published_at").getAsString(); + + boolean isInstalled = false; + try { + Version availableVersion = PythonScriptEngineConfiguration.parseHelperLibVersion(tagName); + if (availableVersion.equals(installedVersion)) { + isInstalled = true; + } else if (availableVersion.compareTo(providedVersion) < 0) { + continue; + } + + DateTimeFormatter df = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss", Locale.getDefault()); + OffsetDateTime publishDate = OffsetDateTime.parse(publishString); + console.println( + String.format("%-19s", tagName) + " " + String.format("%-19s", df.format(publishDate)) + + " " + String.format("%-6s", (isInstalled ? "*" : " "))); + } catch (IllegalArgumentException e) { + // ignore not parseable version + } + } + } else { + console.println("Fetching releases failed. Invalid data"); + } + } + } + + public void updateCheck() { + Version installedVersion = config.getInstalledHelperLibVersion(); + if (installedVersion == null) { + console.println("Helper libs disabled. Skipping update."); + } else { + JsonElement rootElement = getReleaseData(UPDATE_LATEST_URL); + if (rootElement != null) { + JsonElement tagName = rootElement.getAsJsonObject().get("tag_name"); + Version latestVersion = PythonScriptEngineConfiguration.parseHelperLibVersion(tagName.getAsString()); + if (latestVersion.compareTo(installedVersion) > 0) { + console.println("Update from version '" + installedVersion + "' to version '" + + latestVersion.toString() + "' available."); + } else { + console.println("Latest version '" + installedVersion + "' already installed."); + } + } + } + } + + public void updateInstall(String requestedVersionString) { + JsonObject releaseObj = null; + Version releaseVersion = null; + if ("latest".equals(requestedVersionString)) { + JsonElement rootElement = getReleaseData(UPDATE_LATEST_URL); + if (rootElement != null) { + releaseObj = rootElement.getAsJsonObject();// + JsonElement tagName = releaseObj.get("tag_name"); + releaseVersion = PythonScriptEngineConfiguration.parseHelperLibVersion(tagName.getAsString()); + } + } else { + try { + Version requestedVersion = PythonScriptEngineConfiguration + .parseHelperLibVersion(requestedVersionString); + JsonElement rootElement = getReleaseData(UPDATE_RELEASES_URL); + if (rootElement != null) { + if (rootElement.isJsonArray()) { + JsonArray list = rootElement.getAsJsonArray(); + for (JsonElement element : list.asList()) { + JsonElement tagName = element.getAsJsonObject().get("tag_name"); + try { + releaseVersion = PythonScriptEngineConfiguration + .parseHelperLibVersion(tagName.getAsString()); + } catch (IllegalArgumentException e) { + continue; + } + if (releaseVersion.compareTo(requestedVersion) == 0) { + releaseObj = element.getAsJsonObject(); + break; + } + } + } + } + } catch (IllegalArgumentException e) { + // continue, if no version was found + } + } + + if (releaseObj != null && releaseVersion != null) { + Version installedVersion = config.getInstalledHelperLibVersion(); + Version providedVersion = config.getProvidedHelperLibVersion(); + if (releaseVersion.compareTo(providedVersion) < 0) { + console.println("Outdated version '" + releaseVersion.toString() + "' not supported"); + releaseVersion = null; + } else if (installedVersion != null) { + if (releaseVersion.compareTo(installedVersion) < 0) { + // Don't install older version, if 'latest' was requested + if ("latest".equals(requestedVersionString)) { + console.println("Newer Version '" + installedVersion.toString() + "' already installed"); + releaseVersion = null; + } + } else if (releaseVersion.equals(installedVersion)) { + console.println("Version '" + releaseVersion.toString() + "' already installed"); + releaseVersion = null; + } + } + + if (releaseVersion != null) { + String zipballUrl = releaseObj.get("zipball_url").getAsString(); + + try { + config.initHelperLib(zipballUrl, releaseVersion); + console.println("Version '" + releaseVersion.toString() + "' installed successfully"); + } catch (URISyntaxException | IOException e) { + console.println("Fetching release zip '" + zipballUrl + "' file failed. "); + throw new IllegalArgumentException(e); + } + } + } else { + console.println("Version '" + requestedVersionString + "' not found. "); + } + } + + private @Nullable JsonElement getReleaseData(String url) { + try { + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)) + .header("Accept", "application/vnd.github+json").GET().build(); + + HttpResponse response = client.send(request, BodyHandlers.ofString()); + if (response.statusCode() == 200) { + JsonElement obj = JsonParser.parseString(response.body()); + return obj; + } else { + console.println("Fetching releases failed. Status code is " + response.statusCode()); + } + + } catch (IOException | InterruptedException e) { + console.println("Fetching releases failed. Request interrupted " + e.getLocalizedMessage()); + } + return null; + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/typing/ClassCollector.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/typing/ClassCollector.java new file mode 100644 index 0000000000000..271377dab95df --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/typing/ClassCollector.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.console.handler.typing; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.automation.pythonscripting.internal.console.handler.TypingCmd.Logger; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +/** + * Collects classes + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +public class ClassCollector { + private final Logger logger; + + public ClassCollector(Logger logger) { + this.logger = logger; + } + + public Map collectBundleClasses(String packageName) throws Exception { + List> clsList = new ArrayList>(); + Bundle bundle = FrameworkUtil.getBundle(ClassCollector.class); + Bundle[] bundles = bundle.getBundleContext().getBundles(); + for (Bundle b : bundles) { + List> bundleClsList = new ArrayList>(); + Enumeration entries = b.findEntries(packageName.replace(".", "/"), "*.class", true); + if (entries != null) { + while (entries.hasMoreElements()) { + String entry = entries.nextElement().toString(); + String clsName = entry.substring(entry.indexOf(packageName.replace(".", "/"))); + if (clsName.indexOf("/internal") != -1) { + continue; + } + clsName = clsName.replace(".class", "").replace("/", "."); + try { + Class cls = Class.forName(clsName); + if (!Modifier.isPublic(cls.getModifiers())) { + continue; + } + bundleClsList.add(cls); + } catch (ClassNotFoundException e) { + logger.warn("BUNDLE: " + b + " class " + clsName + " not found"); + } + } + } + if (!bundleClsList.isEmpty()) { + logger.info("BUNDLE: " + b + " with " + bundleClsList.size() + " classes processed"); + clsList.addAll(bundleClsList); + } + } + return processClasses(clsList); + } + + public Map collectReflectionClasses(Set imports) throws Exception { + List> clsList = new ArrayList>(); + for (String imp : imports) { + if (imp.startsWith("__")) { + continue; + } + + try { + clsList.add(Class.forName(imp)); + } catch (ClassNotFoundException e) { + logger.warn("Class " + imp + " not found"); + } + } + return processClasses(clsList); + } + + private Map processClasses(List> clsList) { + Map result = new HashMap(); + for (Class cls : clsList) { + result.put(cls.getName(), new ClassContainer(cls)); + } + return result; + } + + public static class ClassContainer { + private Class cls; + private List fields; + private Map methods = new HashMap(); + + private String pythonClassName; + private String pythonModuleName; + + public ClassContainer(Class cls) { + this.cls = cls; + + String packageName = cls.getName(); + this.pythonClassName = ClassContainer.parsePythonClassName(packageName); + this.pythonModuleName = ClassContainer.parsePythonModuleName(packageName); + + fields = Arrays.stream(cls.getDeclaredFields()).filter( + method -> Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers())) + .collect(Collectors.toList()); + + Constructor[] constructors = cls.getConstructors(); + for (Constructor constructor : constructors) { + String uid = constructor.getName(); + MethodContainer methodContainer; + if (!this.methods.containsKey(uid)) { + methodContainer = new MethodContainer(constructor); + this.methods.put(uid, methodContainer); + } + this.methods.get(uid).addParametersFrom(constructor); + } + + List methods = Arrays.stream(cls.getDeclaredMethods()).filter( + method -> Modifier.isPublic(method.getModifiers()) && !Modifier.isVolatile(method.getModifiers())) + .collect(Collectors.toList()); + for (Method method : methods) { + String uid = method.getName(); + MethodContainer methodContainer; + if (!this.methods.containsKey(uid)) { + methodContainer = new MethodContainer(method); + this.methods.put(uid, methodContainer); + } + this.methods.get(uid).addParametersFrom(method); + } + } + + public Class getRelatedClass() { + return cls; + } + + public List getFields() { + return fields; + } + + public List getMethods() { + return new ArrayList(methods.values()); + } + + public String getPythonClassName() { + return pythonClassName; + } + + public String getPythonModuleName() { + return pythonModuleName; + } + + public static String parsePythonClassName(String name) { + String className = name.substring(name.lastIndexOf(".") + 1); + if (className.contains("$")) { + className = className.replace("$", "_"); + } + return className; + } + + public static String parsePythonModuleName(String name) { + return name.substring(0, name.lastIndexOf(".")); + } + } + + public static class MethodContainer { + int modifier; + String methodName; + String rawStringRepresentation; + boolean isConstructor = false; + int mandatoryParameterCount = 999; + + List returnTypes = new ArrayList(); + List> returnClasses = new ArrayList>(); + List args = new ArrayList(); + + public MethodContainer(Constructor constructor) { + this.modifier = constructor.getModifiers(); + this.methodName = ClassContainer.parsePythonClassName(constructor.getName()); + this.rawStringRepresentation = constructor.toString(); + this.isConstructor = true; + } + + public MethodContainer(Method method) { + this.modifier = method.getModifiers(); + this.methodName = method.getName(); + this.rawStringRepresentation = method.toString(); + this.returnTypes.add(method.getGenericReturnType()); + this.returnClasses.add(method.getReturnType()); + } + + public void addParametersFrom(Constructor constructor) { + init(constructor.getParameters(), constructor.getGenericParameterTypes()); + } + + public void addParametersFrom(Method method) { + returnTypes.add(method.getGenericReturnType()); + returnClasses.add(method.getReturnType()); + + init(method.getParameters(), method.getGenericParameterTypes()); + } + + private void init(Parameter[] parameters, Type[] gpType) { + for (int i = 0; i < parameters.length; i++) { + if (args.size() <= i) { + args.add(new ParameterContainer(parameters[i], gpType[i])); + } else { + args.get(i).addParameter(gpType[i]); + } + } + + if (parameters.length < mandatoryParameterCount) { + mandatoryParameterCount = parameters.length; + } + for (int i = mandatoryParameterCount; i < args.size(); i++) { + args.get(i).markAsOptional(); + } + } + + public String getPythonMethodName() { + return methodName; + } + + public boolean isConstructor() { + return this.isConstructor; + } + + public int getModifiers() { + return modifier; + } + + public String getRawStringRepresentation() { + return rawStringRepresentation; + } + + public int getReturnTypeCount() { + return returnTypes.size(); + } + + public Type getGenericReturnType(int index) { + return returnTypes.get(index); + } + + public Class getReturnType(int index) { + return returnClasses.get(index); + } + + public List getParameters() { + return args; + } + + public int getParameterCount() { + return args.size(); + } + + public ParameterContainer getParameter(int index) { + return args.get(index); + } + } + + public static class ParameterContainer { + Parameter parameter; + boolean isOptional = false; + List types = new ArrayList(); + + public ParameterContainer(Parameter arg, Type type) { + this.parameter = arg; + this.types.add(type); + } + + public void addParameter(Type type) { + types.add(type); + } + + public String getName() { + return parameter.getName(); + } + + public int getTypeCount() { + return types.size(); + } + + public Type getGenericType(int index) { + return types.get(index); + } + + public void markAsOptional() { + isOptional = true; + } + + public boolean isOptional() { + return isOptional; + } + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/typing/ClassConverter.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/typing/ClassConverter.java new file mode 100644 index 0000000000000..9a1778f11d744 --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/typing/ClassConverter.java @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.console.handler.typing; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.automation.pythonscripting.internal.console.handler.typing.ClassCollector.ClassContainer; +import org.openhab.automation.pythonscripting.internal.console.handler.typing.ClassCollector.MethodContainer; +import org.openhab.automation.pythonscripting.internal.console.handler.typing.ClassCollector.ParameterContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Converts a Java class to a Python class stub + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +public class ClassConverter { + private final Logger logger = LoggerFactory.getLogger(ClassConverter.class); + + private static Pattern classMatcher = Pattern + .compile("(?:(?:super|extends) )?([a-z0-9\\.\\$_]+|\\?)(?:<.*?>|\\[\\])?$", Pattern.CASE_INSENSITIVE); + + private static Pattern instanceMatcher = Pattern.compile("([a-z0-9\\.\\$_]+)[;]{0,1}@[a-z0-9]+", + Pattern.CASE_INSENSITIVE); + + private static String baseUrl; + static { + // Version version = FrameworkUtil.getBundle(OpenHAB.class).getVersion(); + String v = "latest"; // version.getQualifier() == null || version.getQualifier().isEmpty() ? version.toString() + // : "latest"; + baseUrl = "https://www.openhab.org/javadoc/" + v + "/"; + } + + private final Map classGenerics; + private final Map imports; + private final ClassContainer container; + + public ClassConverter(ClassContainer container) { + this.container = container; + this.classGenerics = new HashMap(); + this.imports = new HashMap(); + } + + public List getImports() { + return new ArrayList(this.imports.keySet()); + } + + public String build() throws IOException, ClassNotFoundException { + // Class head + StringBuilder classBody = new StringBuilder(); + classBody.append(buildClassHead()); + + // Class documentation + String doc = buildClassDocumentationBlock(); + if (doc != null) { + classBody.append(doc); + classBody.append("\n"); + } + + // Class fields + classBody.append(buildClassFields()); + + // Class methods + List methods = container.getMethods(); + Collections.sort(methods, new Comparator() { + @Override + public int compare(MethodContainer o1, MethodContainer o2) { + return o1.getPythonMethodName().compareTo(o2.getPythonMethodName()); + } + }); + for (MethodContainer method : methods) { + + classBody.append(buildClassMethod(method)); + } + + // Class imports + if (!imports.isEmpty()) { + classBody.insert(0, "\n\n"); + classBody.insert(0, buildClassImports()); + } + + return classBody.toString(); + } + + private String buildClassHead() { + Type type = container.getRelatedClass().getGenericSuperclass(); + if (type != null) { + classGenerics.putAll(collectGenerics(type)); + } + + StringBuilder builder = new StringBuilder(); + builder.append("class " + container.getPythonClassName()); + List parentTypes = new ArrayList(); + Class parentClass = container.getRelatedClass().getSuperclass(); + if (parentClass != null) { + String pythonType = convertBaseJavaToPythonType(new JavaType(parentClass.getName()), classGenerics); + if (!"object".equals(pythonType)) { + parentTypes.add(pythonType); + } + } + Class[] parentInterfaces = container.getRelatedClass().getInterfaces(); + for (Class parentInterface : parentInterfaces) { + String pythonType = convertBaseJavaToPythonType(new JavaType(parentInterface.getName()), classGenerics); + parentTypes.add(pythonType); + } + if (parentTypes.isEmpty()) { + if (container.getRelatedClass().isInterface()) { + parentTypes.add("Protocol"); + imports.put("__typing.Protocol", "from typing import Protocol"); + } + } + if (!parentTypes.isEmpty()) { + builder.append("(" + String.join(", ", parentTypes) + ")"); + } + builder.append(":\n"); + return builder.toString(); + } + + private String buildClassFields() { + StringBuilder builder = new StringBuilder(); + for (Field field : container.getFields()) { + try { + JavaType javaType = collectJavaTypes(field.getGenericType(), classGenerics); + String type = convertJavatToPythonType(javaType, classGenerics); + String value = ""; + Class t = field.getType(); + + if (Collection.class.isAssignableFrom(field.getType())) { + List values = new ArrayList(); + if (field.get(null) instanceof Collection col) { + for (Object val : col) { + values.add(convertFieldValue(val)); + } + } + value = "[" + String.join(",", values) + "]"; + } else if (t == short.class) { + value = convertFieldValue(field.getShort(null)); + } else if (t == int.class) { + value = convertFieldValue(field.getInt(null)); + } else if (t == long.class) { + value = convertFieldValue(field.getLong(null)); + } else if (t == float.class) { + value = convertFieldValue(field.getFloat(null)); + } else if (t == double.class) { + value = convertFieldValue(field.getDouble(null)); + } else if (t == boolean.class) { + value = convertFieldValue(field.getBoolean(null)); + } else if (t == char.class) { + value = convertFieldValue(field.getChar(null)); + } else { + value = convertFieldValue(field.get(null)); + } + + builder.append(" " + field.getName() + ": " + type + " = " + value + "\n"); + } catch (IllegalArgumentException | IllegalAccessException e) { + logger.warn("Cant convert static field {} of class {}", container.getRelatedClass().getName(), + field.getName(), e); + } + } + if (!builder.isEmpty()) { + builder.append("\n"); + } + + return builder.toString(); + } + + private String buildClassMethod(MethodContainer method) { + HashMap localGenerics = new HashMap(this.classGenerics); + // Collect generics + for (int i = 0; i < method.getReturnTypeCount(); i++) { + localGenerics.putAll(collectGenerics(method.getGenericReturnType(i))); + } + for (ParameterContainer p : method.getParameters()) { + for (int i = 0; i < p.getTypeCount(); i++) { + localGenerics.putAll(collectGenerics(p.getGenericType(i))); + } + } + + // Collect arguments + List arguments = new ArrayList(); + if (!Modifier.isStatic(method.getModifiers())) { + arguments.add("self"); + } + for (ParameterContainer p : method.getParameters()) { + Set parameterTypes = new HashSet(); + for (int i = 0; i < p.getTypeCount(); i++) { + JavaType javaType = collectJavaTypes(p.getGenericType(i), localGenerics); + String t = convertJavatToPythonType(javaType, localGenerics); + parameterTypes.add(t); + } + List sorted = parameterTypes.stream().sorted().collect(Collectors.toList()); + arguments.add(p.getName() + ": " + String.join(" | ", sorted) + (p.isOptional ? " = None" : "")); + } + + // Build method + StringBuilder builder = new StringBuilder(); + if (Modifier.isStatic(method.getModifiers())) { + builder.append(" @staticmethod\n"); + } + String methodName = method.isConstructor() ? "__init__" : method.getPythonMethodName(); + builder.append(" def " + methodName + "(" + String.join(", ", arguments) + ")"); + + // Build return value + if (method.getReturnTypeCount() > 0) { + // Collect Return types + Set returnTypes = new HashSet(); + for (int i = 0; i < method.getReturnTypeCount(); i++) { + JavaType javaType = collectJavaTypes(method.getGenericReturnType(i), localGenerics); + String t = convertJavatToPythonType(javaType, localGenerics); + returnTypes.add(t); + } + List sortedReturnTypes = returnTypes.stream().sorted().collect(Collectors.toList()); + + builder.append(" -> " + String.join(" | ", sortedReturnTypes)); + } + + // Finalize method + builder.append(":\n"); + String doc = buildMethodDocumentationBlock(method); + if (doc != null) { + builder.append(doc); + } else { + builder.append(" pass\n"); + } + builder.append("\n"); + + return builder.toString(); + } + + private Object buildClassImports() { + StringBuilder builder = new StringBuilder(); + HashSet hashSet = new HashSet<>(imports.values()); + ArrayList sortedImports = new ArrayList<>(hashSet); + Collections.sort(sortedImports, new Comparator() { + @Override + public int compare(String o1, String o2) { + if (o1.length() > o2.length()) { + return 1; + } + if (o1.length() < o2.length()) { + return -1; + } + return o1.compareTo(o2); + } + }); + for (String importLine : sortedImports) { + builder.append(importLine + "\n"); + } + return builder.toString(); + } + + private JavaType collectJavaTypes(Type genericType, Map generics) { + JavaType javaType = null; + if (genericType instanceof TypeVariable) { + TypeVariable typeVar = (TypeVariable) genericType; + String type = generics.get(typeVar.getTypeName()); + if (type != null) { + javaType = new JavaType(type); + } else { + javaType = new JavaType("?"); + } + } else if (genericType instanceof ParameterizedType) { + ParameterizedType paramType = (ParameterizedType) genericType; + // System.out.println("ParameterizedType | " + _type + " | " + _type.getRawType().getTypeName() + " | " + // + _type.getActualTypeArguments()[0]); + javaType = collectJavaTypes(paramType.getRawType(), generics); + for (Type type : paramType.getActualTypeArguments()) { + javaType.addSubType(collectJavaTypes(type, generics)); + } + } else if (genericType instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) genericType; + // System.out.println("WildcardType | " + _type); + if (wildcardType.getUpperBounds().length > 0) { + javaType = collectJavaTypes(wildcardType.getUpperBounds()[0], generics); + } else if (wildcardType.getLowerBounds().length > 0) { + javaType = collectJavaTypes(wildcardType.getLowerBounds()[0], generics); + } else { + javaType = new JavaType("java.lang.Object"); + } + } else if (genericType instanceof GenericArrayType) { + GenericArrayType genericArrayType = (GenericArrayType) genericType; + // System.out.println("GenericArrayType | " + _type); + javaType = new JavaType("java.util.List"); + javaType.addSubType(collectJavaTypes(genericArrayType.getGenericComponentType(), generics)); + } else { + // System.out.println("OtherType | " + genericType.getTypeName()); + String type = genericType.getTypeName(); + JavaType activeJavaType = null; + while (type.endsWith("[]")) { + JavaType currentJavaType = new JavaType("java.util.List"); + if (activeJavaType == null) { + javaType = activeJavaType = currentJavaType; + } else { + activeJavaType.addSubType(currentJavaType); + } + activeJavaType = currentJavaType; + type = type.substring(0, type.length() - 2); + } + JavaType currentJavaType = new JavaType(type); + if (javaType == null) { + javaType = currentJavaType; + } else { + activeJavaType.addSubType(currentJavaType); + } + } + + return javaType; + } + + private String convertJavatToPythonType(JavaType javaType, Map generics) { + switch (javaType.getType()) { + case "char": + return "str"; + case "long": + case "int": + case "short": + return "int"; + case "double": + case "float": + return "float"; + case "byte": + return "bytes"; + case "boolean": + return "bool"; + case "void": + return "None"; + case "?": + if (javaType.hasSubTypes(1)) { + return convertJavatToPythonType(javaType.getSubType(0), generics); + } + return "object"; + } + + try { + Class cls = Class.forName(javaType.getType()); + if (!cls.equals(java.lang.Object.class)) { + if (Byte.class.equals(cls)) { + return "bytes"; + } else if (Double.class.equals(cls) || Float.class.equals(cls)) { + return "float"; + } else if (BigDecimal.class.equals(cls) || BigInteger.class.equals(cls) || Long.class.equals(cls) + || Integer.class.equals(cls) || Short.class.equals(cls)) { + return "int"; + } else if (Number.class.equals(cls)) { + return "float | int"; + } else if (Dictionary.class.equals(cls) || Hashtable.class.equals(cls) || Map.class.equals(cls) + || HashMap.class.equals(cls)) { + if (javaType.hasSubTypes(2)) { + return "dict[" + convertJavatToPythonType(javaType.getSubType(0), generics) + "," + + convertJavatToPythonType(javaType.getSubType(1), generics) + "]"; + } + return "dict"; + } else if (Collection.class.equals(cls) || List.class.equals(cls) || Set.class.equals(cls)) { + if (javaType.hasSubTypes(1)) { + return "list[" + convertJavatToPythonType(javaType.getSubType(0), generics) + "]"; + } + return "list"; + } else if (Iterable.class.equals(cls)) { + if (javaType.hasSubTypes(1)) { + return "iter[" + convertJavatToPythonType(javaType.getSubType(0), generics) + "]"; + } + return "iter"; + } else if (cls.equals(Class.class)) { + if (javaType.hasSubTypes(1)) { + return "type[" + convertJavatToPythonType(javaType.getSubType(0), generics) + "]"; + } + return "type"; + } + } + } catch (ClassNotFoundException e) { + } + + return convertBaseJavaToPythonType(javaType, generics); + } + + private String convertBaseJavaToPythonType(JavaType javaType, Map generics) { + switch (javaType.getType()) { + case "java.lang.String": + return "str"; + case "java.lang.Object": + return "object"; + case "java.time.ZonedDateTime": + imports.put("__java.time.ZonedDateTime", "from datetime import datetime"); + return "datetime"; + case "java.time.Instant": + imports.put("__java.time.Instant", "from datetime import datetime"); + return "datetime"; + default: + String typeName = cleanClassName(javaType.getType()); + if (typeName.contains(".")) { + String className = ClassContainer.parsePythonClassName(typeName); + // Handle import + if (!className.equals(container.getPythonClassName())) { + String moduleName = ClassContainer.parsePythonModuleName(typeName); + imports.put(typeName, "from " + moduleName + " import " + className); + return className; + } + return "\"" + className + "\""; + } else if (typeName.length() == 1) { + String newTypeName = generics.get(typeName); + if (newTypeName != null) { + return newTypeName; + } + } + return typeName; + } + } + + private String convertFieldValue(@Nullable Object value) { + if (value == null) { + return "None"; + } + if (value instanceof Number) { + return value.toString(); + } + if (value instanceof Boolean) { + return ((Boolean) value) ? "True" : "False"; + } + if (value instanceof String) { + return "\"" + value.toString() + "\""; + } + String valueAsString = value.toString(); + Matcher matcher = instanceMatcher.matcher(valueAsString); + if (matcher.find()) { + valueAsString = "<" + matcher.group(1) + ">"; + } + return "\"" + valueAsString + "\""; + } + + private Map collectGenerics(Type genericType) { + return collectGenerics(genericType, new HashMap()); + } + + private Map collectGenerics(Type genericType, Map generics) { + if (genericType instanceof TypeVariable) { + TypeVariable typeVar = (TypeVariable) genericType; + if (!generics.containsKey(typeVar.getTypeName())) { + generics.put(typeVar.getTypeName(), cleanClassName(typeVar.getBounds()[0].getTypeName())); + } + } else if (genericType instanceof ParameterizedType) { + ParameterizedType paramType = (ParameterizedType) genericType; + generics.putAll(collectGenerics(paramType.getRawType(), generics)); + for (Type typeArg : paramType.getActualTypeArguments()) { + generics.putAll(collectGenerics(typeArg, generics)); + } + } else if (genericType instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) genericType; + if (wildcardType.getUpperBounds().length > 0) { + for (Type upperType : wildcardType.getUpperBounds()) { + generics.putAll(collectGenerics(upperType, generics)); + } + } else if (wildcardType.getLowerBounds().length > 0) { + for (Type lowerType : wildcardType.getLowerBounds()) { + generics.putAll(collectGenerics(lowerType, generics)); + } + } + } + return generics; + } + + private String cleanClassName(String className) { + Matcher matcher = classMatcher.matcher(className); + if (matcher.find() && !className.equals(matcher.group(1))) { + // System.out.println("parseSubType: " + container.getRelatedClass().getName() + " | " + // + _type.getTypeName() + " | " + javaSubType + " | " + matcher.group(1)); + return matcher.group(1); + } + return className; + } + + private @Nullable String buildClassDocumentationBlock() { + if (!container.getPythonModuleName().startsWith("org.openhab.core")) { + return null; + } + + String classUrl = baseUrl + + container.getRelatedClass().getName().toLowerCase().replace(".", "/").replace("$", "."); + + StringBuilder builder = new StringBuilder(); + builder.append(" \"\"\"\n"); + builder.append(" Java class: ").append(container.getRelatedClass().getName()).append("\n\n"); + builder.append(" Java doc: ").append(classUrl); + builder.append("\n"); + builder.append(" \"\"\"\n"); + return builder.toString(); + } + + private @Nullable String buildMethodDocumentationBlock(MethodContainer method) { + if (!container.getPythonModuleName().startsWith("org.openhab.core")) { + return null; + } + + String classUrl = baseUrl + + container.getRelatedClass().getName().toLowerCase().replace(".", "/").replace("$", "."); + + StringBuilder builder = new StringBuilder(); + builder.append(" \"\"\"\n"); + builder.append(" Java doc url:\n"); + + String functionRepresentation = method.getRawStringRepresentation(); + Pattern pattern = Pattern.compile("([^\\.]+\\([^\\)]*\\))", Pattern.CASE_INSENSITIVE); + Matcher matcher1 = pattern.matcher(functionRepresentation); + if (matcher1.find()) { + functionRepresentation = matcher1.group(1); + } + functionRepresentation = functionRepresentation.replaceAll("<>\\?", "").replace("$", "."); + // System.out.println(classUrl + "#" + functionRepresentation); + builder.append(" ").append(classUrl).append("#").append(functionRepresentation); + + builder.append("\n"); + builder.append(" \"\"\"\n"); + return builder.toString(); + } + + public static class JavaType { + private final String type; + private final List subTypes = new ArrayList(); + + public JavaType(String type) { + this.type = type; + } + + public void addSubType(JavaType subType) { + this.subTypes.add(subType); + } + + public String getType() { + return this.type; + } + + public boolean hasSubTypes(int neededSize) { + return this.subTypes.size() >= neededSize; + } + + public JavaType getSubType(int index) { + return this.subTypes.get(index); + } + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java new file mode 100644 index 0000000000000..bc3ea70d50f82 --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.context; + +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * ContextOutput implementation + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +public class ContextInput extends InputStream { + private @Nullable InputStream stream; + + public ContextInput(@Nullable InputStream stream) { + this.stream = stream; + } + + public void setInputStream(@Nullable InputStream stream) { + this.stream = stream; + } + + @Override + public void close() throws IOException { + if (stream != null) { + stream.close(); + } + } + + @Override + public int read() throws IOException { + if (stream != null) { + return stream.read(); + } + return -1; + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutput.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutput.java new file mode 100644 index 0000000000000..16e770a255c27 --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutput.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.context; + +import java.io.IOException; +import java.io.OutputStream; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * ContextOutput implementation + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +public class ContextOutput extends OutputStream { + private OutputStream stream; + + public ContextOutput(OutputStream stream) { + this.stream = stream; + } + + public void setOutputStream(OutputStream stream) { + this.stream = stream; + } + + @Override + public void close() throws IOException { + stream.close(); + } + + @Override + public void flush() throws IOException { + stream.flush(); + } + + @Override + public void write(int b) throws IOException { + stream.write(b); + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/helper/LogOutputStream.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutputLogger.java similarity index 88% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/helper/LogOutputStream.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutputLogger.java index bff0ab70864a0..5baa9f32cafb4 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/helper/LogOutputStream.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutputLogger.java @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.scriptengine.helper; +package org.openhab.automation.pythonscripting.internal.context; import java.io.OutputStream; @@ -19,24 +19,24 @@ import org.slf4j.event.Level; /** - * LogOutputStream implementation + * ContextLogOutputStream implementation * * @author Holger Hees - Initial contribution */ @NonNullByDefault -public class LogOutputStream extends OutputStream { +public class ContextOutputLogger extends OutputStream { private static final int DEFAULT_BUFFER_LENGTH = 2048; private static final String LINE_SEPARATOR = System.lineSeparator(); private static final int LINE_SEPARATOR_SIZE = LINE_SEPARATOR.length(); - private Logger logger; - private Level level; - private int bufLength; private byte[] buf; private int count; - public LogOutputStream(Logger logger, Level level) { + private Logger logger; + private Level level; + + public ContextOutputLogger(Logger logger, Level level) { this.logger = logger; this.level = level; @@ -45,14 +45,6 @@ public LogOutputStream(Logger logger, Level level) { count = 0; } - public void setLogger(Logger logger) { - this.logger = logger; - } - - public Logger getLogger() { - return logger; - } - @Override public void write(int b) { // don't log nulls diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/DelegatingFileSystem.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/DelegatingFileSystem.java index 104a02bc40c1d..4bf8a3ddb83e1 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/DelegatingFileSystem.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/DelegatingFileSystem.java @@ -16,7 +16,9 @@ import java.net.URI; import java.nio.channels.SeekableByteChannel; import java.nio.file.AccessMode; +import java.nio.file.CopyOption; import java.nio.file.DirectoryStream; +import java.nio.file.FileSystems; import java.nio.file.LinkOption; import java.nio.file.OpenOption; import java.nio.file.Path; @@ -25,19 +27,31 @@ import java.nio.file.spi.FileSystemProvider; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; +import org.eclipse.jdt.annotation.NonNull; import org.graalvm.polyglot.io.FileSystem; /** * Delegate wrapping a {@link FileSystem} * - * @author Holger Hees - Initial contribution (Reused from jsscripting) + * @author Holger Hees - Initial contribution */ public class DelegatingFileSystem implements FileSystem { - private FileSystemProvider delegate; + // Inspiration from + // https://github.com/oracle/graal/blob/master/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/FileSystems.java + private final FileSystemProvider delegate = FileSystems.getDefault().provider(); + private final Path tmpDir; - public DelegatingFileSystem(FileSystemProvider delegate) { - this.delegate = delegate; + private volatile Path userDir; + private volatile Consumer consumer; + + public DelegatingFileSystem(Path tmpDir) { + this.tmpDir = tmpDir; + } + + public void setAccessConsumer(Consumer<@NonNull Path> consumer) { + this.consumer = consumer; } @Override @@ -66,29 +80,116 @@ public void delete(Path path) throws IOException { } @Override - public SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs) - throws IOException { - return delegate.newByteChannel(path, options, attrs); + public void copy(Path source, Path target, CopyOption... options) throws IOException { + delegate.copy(resolveRelative(source), resolveRelative(target), options); } @Override - public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) - throws IOException { - return delegate.newDirectoryStream(dir, filter); + public void move(Path source, Path target, CopyOption... options) throws IOException { + delegate.move(resolveRelative(source), resolveRelative(target), options); } @Override - public Path toAbsolutePath(Path path) { - return path.toAbsolutePath(); + public void createLink(Path link, Path existing) throws IOException { + delegate.createLink(resolveRelative(link), resolveRelative(existing)); } @Override - public Path toRealPath(Path path, LinkOption... linkOptions) throws IOException { - return path.toRealPath(linkOptions); + public void createSymbolicLink(Path link, Path target, FileAttribute... attrs) throws IOException { + delegate.createSymbolicLink(resolveRelative(link), target, attrs); + } + + @Override + public Path readSymbolicLink(Path link) throws IOException { + return delegate.readSymbolicLink(resolveRelative(link)); } @Override public Map readAttributes(Path path, String attributes, LinkOption... options) throws IOException { return delegate.readAttributes(path, attributes, options); } + + @Override + public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException { + delegate.setAttribute(path, attribute, value, options); + } + + @Override + public Path toAbsolutePath(Path path) { + if (path.isAbsolute()) { + return path; + } + Path cwd = userDir; + if (cwd == null) { + return path.toAbsolutePath(); + } else { + return cwd.resolve(path); + } + } + + @Override + public void setCurrentWorkingDirectory(Path currentWorkingDirectory) { + userDir = currentWorkingDirectory; + } + + @Override + public Path toRealPath(Path path, LinkOption... linkOptions) throws IOException { + return resolveRelative(path).toRealPath(linkOptions); + } + + @Override + public Path getTempDirectory() { + return tmpDir; + } + + @Override + public boolean isSameFile(Path path1, Path path2, LinkOption... options) throws IOException { + if (isFollowLinks(options)) { + Path absolutePath1 = resolveRelative(path1); + Path absolutePath2 = resolveRelative(path2); + return delegate.isSameFile(absolutePath1, absolutePath2); + } else { + return delegate.isSameFile(path1, path2); + } + } + + @Override + public SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs) + throws IOException { + final Path resolved = resolveRelative(path); + if (consumer != null) { + consumer.accept(resolved); + } + try { + return delegate.newFileChannel(resolved, options, attrs); + } catch (UnsupportedOperationException uoe) { + return delegate.newByteChannel(resolved, options, attrs); + } + } + + @Override + public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) + throws IOException { + Path cwd = userDir; + Path resolvedPath; + if (!dir.isAbsolute() && cwd != null) { + resolvedPath = cwd.resolve(dir); + } else { + resolvedPath = dir; + } + return delegate.newDirectoryStream(resolvedPath, filter); + } + + private Path resolveRelative(Path path) { + return !path.isAbsolute() && userDir != null ? toAbsolutePath(path) : path; + } + + private boolean isFollowLinks(final LinkOption... linkOptions) { + for (LinkOption lo : linkOptions) { + if (lo == LinkOption.NOFOLLOW_LINKS) { + return false; + } + } + return true; + } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/watch/PythonDependencyTracker.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonDependencyTracker.java similarity index 92% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/watch/PythonDependencyTracker.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonDependencyTracker.java index 0be4ff9c4e2dc..ceb34b816c27f 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/watch/PythonDependencyTracker.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonDependencyTracker.java @@ -10,10 +10,10 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.fs.watch; +package org.openhab.automation.pythonscripting.internal.fs; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.automation.pythonscripting.internal.PythonScriptEngineFactory; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineConfiguration; import org.openhab.core.automation.module.script.ScriptDependencyTracker; import org.openhab.core.automation.module.script.rulesupport.loader.AbstractScriptDependencyTracker; import org.openhab.core.service.WatchService; @@ -35,7 +35,7 @@ public class PythonDependencyTracker extends AbstractScriptDependencyTracker { @Activate public PythonDependencyTracker(@Reference(target = WatchService.CONFIG_WATCHER_FILTER) WatchService watchService) { - super(watchService, PythonScriptEngineFactory.PYTHON_LIB_PATH.toString()); + super(watchService, PythonScriptEngineConfiguration.PYTHON_LIB_PATH.toString()); } @Deactivate diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/watch/PythonScriptFileWatcher.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonScriptFileWatcher.java similarity index 77% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/watch/PythonScriptFileWatcher.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonScriptFileWatcher.java index 754ae7d9d59a9..07ba17a119a60 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/watch/PythonScriptFileWatcher.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonScriptFileWatcher.java @@ -10,12 +10,13 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.fs.watch; +package org.openhab.automation.pythonscripting.internal.fs; import java.nio.file.Path; import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineConfiguration; import org.openhab.automation.pythonscripting.internal.PythonScriptEngineFactory; import org.openhab.core.automation.module.script.ScriptDependencyTracker; import org.openhab.core.automation.module.script.ScriptEngineManager; @@ -33,7 +34,8 @@ * * @author Holger Hees - Initial contribution (Reused from jsscripting) */ -@Component(immediate = true, service = { ScriptFileWatcher.class, ScriptDependencyTracker.Listener.class }) +@Component(immediate = true, service = { ScriptFileWatcher.class, ScriptDependencyTracker.Listener.class, + PythonScriptFileWatcher.class }) @NonNullByDefault public class PythonScriptFileWatcher extends AbstractScriptFileWatcher { @Activate @@ -42,12 +44,13 @@ public PythonScriptFileWatcher( final @Reference ScriptEngineManager manager, final @Reference ReadyService readyService, final @Reference StartLevelService startLevelService) { super(watchService, manager, readyService, startLevelService, - PythonScriptEngineFactory.PYTHON_DEFAULT_PATH.toString(), true); + PythonScriptEngineConfiguration.PYTHON_DEFAULT_PATH.toString(), true); } @Override protected Optional getScriptType(Path scriptFilePath) { - if (!scriptFilePath.startsWith(PythonScriptEngineFactory.PYTHON_LIB_PATH)) { + if (!scriptFilePath.startsWith(PythonScriptEngineConfiguration.PYTHON_LIB_PATH) + && !scriptFilePath.startsWith(PythonScriptEngineConfiguration.PYTHON_TYPINGS_PATH)) { Optional scriptFileSuffix = super.getScriptType(scriptFilePath); if (scriptFileSuffix.isPresent() && "py".equals(scriptFileSuffix.get())) { return Optional.of(PythonScriptEngineFactory.SCRIPT_TYPE); @@ -55,4 +58,10 @@ protected Optional getScriptType(Path scriptFilePath) { } return Optional.empty(); } + + // Overriding to make it public, so it can be used in {@link JRubyConsoleCommandExtension} + @Override + public Path getWatchPath() { + return super.getWatchPath(); + } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scope/AbstractScriptExtensionProvider.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/AbstractScriptExtensionProvider.java similarity index 96% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scope/AbstractScriptExtensionProvider.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/AbstractScriptExtensionProvider.java index b7f13feaa3904..d38c1ceba2387 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scope/AbstractScriptExtensionProvider.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/AbstractScriptExtensionProvider.java @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.scope; +package org.openhab.automation.pythonscripting.internal.provider; import java.util.Collection; import java.util.HashMap; @@ -66,6 +66,7 @@ public Collection getTypes() { return types.keySet(); } + @SuppressWarnings("null") @Override public @Nullable Object get(String scriptIdentifier, String type) throws IllegalArgumentException { Map forScript = idToTypes.computeIfAbsent(scriptIdentifier, k -> new HashMap<>()); diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/helper/LifecycleTracker.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/LifecycleTracker.java similarity index 92% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/helper/LifecycleTracker.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/LifecycleTracker.java index 688d9bc3a5bd5..ce7d11c1d47ce 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/helper/LifecycleTracker.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/LifecycleTracker.java @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.scriptengine.helper; +package org.openhab.automation.pythonscripting.internal.provider; import java.util.ArrayList; import java.util.List; diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scope/OSGiScriptExtensionProvider.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/OSGiScriptExtensionProvider.java similarity index 94% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scope/OSGiScriptExtensionProvider.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/OSGiScriptExtensionProvider.java index 847da61e15549..2085dddf6b1b4 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scope/OSGiScriptExtensionProvider.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/OSGiScriptExtensionProvider.java @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.scope; +package org.openhab.automation.pythonscripting.internal.provider; import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.automation.module.script.ScriptExtensionProvider; diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/wrapper/ScriptExtensionModuleProvider.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/ScriptExtensionModuleProvider.java similarity index 95% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/wrapper/ScriptExtensionModuleProvider.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/ScriptExtensionModuleProvider.java index 1a70c5c5ced7a..dd1c7fc4b19d7 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/wrapper/ScriptExtensionModuleProvider.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/provider/ScriptExtensionModuleProvider.java @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.wrapper; +package org.openhab.automation.pythonscripting.internal.provider; import java.util.ArrayList; import java.util.HashMap; @@ -95,4 +95,8 @@ public ModuleLocator locatorFor(Context ctx, String engineIdentifier, public void put(String key, Object value) { this.globals.put(key, value); } + + public static interface ModuleLocator { + Map locateModule(String name, List fromlist); + } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable.java deleted file mode 100644 index ebc8daea361f1..0000000000000 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2010-2025 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.automation.pythonscripting.internal.scriptengine; - -import java.io.Reader; - -import javax.script.Bindings; -import javax.script.Compilable; -import javax.script.CompiledScript; -import javax.script.Invocable; -import javax.script.ScriptContext; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineFactory; -import javax.script.ScriptException; - -/** - * {@link ScriptEngine} implementation that delegates to a supplied ScriptEngine instance. Allows overriding specific - * methods. - * - * @author Holger Hees - Initial contribution (Reused from jsscripting) - */ -public abstract class DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable - implements ScriptEngine, Invocable, Compilable, AutoCloseable { - protected T delegate; - - @Override - public Object eval(String s, ScriptContext scriptContext) throws ScriptException { - return delegate.eval(s, scriptContext); - } - - @Override - public Object eval(Reader reader, ScriptContext scriptContext) throws ScriptException { - return delegate.eval(reader, scriptContext); - } - - @Override - public Object eval(String s) throws ScriptException { - return delegate.eval(s); - } - - @Override - public Object eval(Reader reader) throws ScriptException { - return delegate.eval(reader); - } - - @Override - public Object eval(String s, Bindings bindings) throws ScriptException { - return delegate.eval(s, bindings); - } - - @Override - public Object eval(Reader reader, Bindings bindings) throws ScriptException { - return delegate.eval(reader, bindings); - } - - @Override - public void put(String s, Object o) { - delegate.put(s, o); - } - - @Override - public Object get(String s) { - return delegate.get(s); - } - - @Override - public Bindings getBindings(int i) { - return delegate.getBindings(i); - } - - @Override - public void setBindings(Bindings bindings, int i) { - delegate.setBindings(bindings, i); - } - - @Override - public Bindings createBindings() { - return delegate.createBindings(); - } - - @Override - public ScriptContext getContext() { - return delegate.getContext(); - } - - @Override - public void setContext(ScriptContext scriptContext) { - delegate.setContext(scriptContext); - } - - @Override - public ScriptEngineFactory getFactory() { - return delegate.getFactory(); - } - - @Override - public Object invokeMethod(Object o, String s, Object... objects) - throws ScriptException, NoSuchMethodException, IllegalArgumentException { - return delegate.invokeMethod(o, s, objects); - } - - @Override - public Object invokeFunction(String s, Object... objects) throws ScriptException, NoSuchMethodException { - return delegate.invokeFunction(s, objects); - } - - @Override - public T getInterface(Class aClass) { - return delegate.getInterface(aClass); - } - - @Override - public T getInterface(Object o, Class aClass) { - return delegate.getInterface(o, aClass); - } - - @Override - public CompiledScript compile(String s) throws ScriptException { - return delegate.compile(s); - } - - @Override - public CompiledScript compile(Reader reader) throws ScriptException { - return delegate.compile(reader); - } - - @Override - public void close() throws Exception { - delegate.close(); - } -} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/InvocationInterceptingPythonScriptEngine.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/InvocationInterceptingPythonScriptEngine.java new file mode 100644 index 0000000000000..aa37b28dea91d --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/InvocationInterceptingPythonScriptEngine.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal.scriptengine; + +import java.lang.reflect.UndeclaredThrowableException; + +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptException; + +import org.eclipse.jdt.annotation.NonNull; +import org.graalvm.polyglot.PolyglotException; +import org.openhab.automation.pythonscripting.internal.scriptengine.graal.GraalPythonScriptEngine; + +/** + * Interception of calls, either before Invocation, or upon a {@link ScriptException} being + * thrown. + * + * @author Holger Hees - Initial contribution + */ +public abstract class InvocationInterceptingPythonScriptEngine extends GraalPythonScriptEngine { + protected abstract void beforeInvocation() throws PolyglotException; + + protected abstract String beforeInvocation(String source); + + protected abstract Object afterInvocation(Object obj); + + protected abstract E afterThrowsInvocation(@NonNull E e); + + @Override + public Object eval(String s, ScriptContext scriptContext) throws ScriptException { + try { + beforeInvocation(); + return afterInvocation(super.eval(beforeInvocation(s), scriptContext)); + } catch (ScriptException e) { + throw afterThrowsInvocation(e); + } catch (PolyglotException e) { + throw afterThrowsInvocation(toScriptException(e)); + } catch (Exception e) { + throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions + } + } + + @Override + public Object invokeMethod(Object o, String s, Object... objects) throws ScriptException, NoSuchMethodException { + try { + beforeInvocation(); + return afterInvocation(super.invokeMethod(o, s, objects)); + } catch (ScriptException e) { + throw afterThrowsInvocation(e); + } catch (PolyglotException e) { + throw afterThrowsInvocation(toScriptException(e)); + } catch (NoSuchMethodException e) { + throw afterThrowsInvocation(e); + } catch (Exception e) { + throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions + } + } + + @Override + public Object invokeFunction(String s, Object... objects) throws ScriptException, NoSuchMethodException { + try { + beforeInvocation(); + return afterInvocation(super.invokeFunction(s, objects)); + } catch (ScriptException e) { + throw afterThrowsInvocation(e); + } catch (PolyglotException e) { + throw afterThrowsInvocation(toScriptException(e)); + } catch (NoSuchMethodException e) { + throw afterThrowsInvocation(e); + } catch (Exception e) { + throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions + } + } + + @Override + public CompiledScript compile(String s) throws ScriptException { + try { + beforeInvocation(); + return (CompiledScript) afterInvocation(super.compile(beforeInvocation(s))); + } catch (ScriptException e) { + throw afterThrowsInvocation(e); + } catch (PolyglotException e) { + throw afterThrowsInvocation(toScriptException(e)); + } catch (Exception e) { + throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions + } + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable.java deleted file mode 100644 index 23219a458c128..0000000000000 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2010-2025 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.automation.pythonscripting.internal.scriptengine; - -import java.io.Reader; -import java.lang.reflect.UndeclaredThrowableException; - -import javax.script.Bindings; -import javax.script.Compilable; -import javax.script.CompiledScript; -import javax.script.Invocable; -import javax.script.ScriptContext; -import javax.script.ScriptEngine; -import javax.script.ScriptException; - -/** - * Delegate allowing AOP-style interception of calls, either before Invocation, or upon a {@link ScriptException} being - * thrown. - * - * @param The delegate class - * @author Holger Hees - Initial contribution (Reused from jsscripting) - */ -public abstract class InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable - extends DelegatingScriptEngineWithInvocableAndCompilableAndAutocloseable { - - protected String beforeInvocation(String source) { - beforeInvocation(); - return source; - } - - protected Reader beforeInvocation(Reader reader) { - beforeInvocation(); - return reader; - } - - protected void beforeInvocation() { - } - - protected Object afterInvocation(Object obj) { - return obj; - } - - protected Exception afterThrowsInvocation(Exception e) { - return e; - } - - @Override - public Object eval(String s, ScriptContext scriptContext) throws ScriptException { - try { - return afterInvocation(super.eval(beforeInvocation(s), scriptContext)); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public Object eval(Reader reader, ScriptContext scriptContext) throws ScriptException { - try { - return afterInvocation(super.eval(beforeInvocation(reader), scriptContext)); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public Object eval(String s) throws ScriptException { - try { - return afterInvocation(super.eval(beforeInvocation(s))); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public Object eval(Reader reader) throws ScriptException { - try { - return afterInvocation(super.eval(beforeInvocation(reader))); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public Object eval(String s, Bindings bindings) throws ScriptException { - try { - return afterInvocation(super.eval(beforeInvocation(s), bindings)); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public Object eval(Reader reader, Bindings bindings) throws ScriptException { - try { - return afterInvocation(super.eval(beforeInvocation(reader), bindings)); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public Object invokeMethod(Object o, String s, Object... objects) - throws ScriptException, NoSuchMethodException, NullPointerException, IllegalArgumentException { - try { - beforeInvocation(); - return afterInvocation(super.invokeMethod(o, s, objects)); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (NoSuchMethodException e) { // Make sure to unlock on exceptions from Invocable.invokeMethod to avoid - // deadlocks - throw (NoSuchMethodException) afterThrowsInvocation(e); - } catch (NullPointerException e) { - throw (NullPointerException) afterThrowsInvocation(e); - } catch (IllegalArgumentException e) { - throw (IllegalArgumentException) afterThrowsInvocation(e); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public Object invokeFunction(String s, Object... objects) - throws ScriptException, NoSuchMethodException, NullPointerException { - try { - beforeInvocation(); - return afterInvocation(super.invokeFunction(s, objects)); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (NoSuchMethodException e) { // Make sure to unlock on exceptions from Invocable.invokeFunction to avoid - // deadlocks - throw (NoSuchMethodException) afterThrowsInvocation(e); - } catch (NullPointerException e) { - throw (NullPointerException) afterThrowsInvocation(e); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public CompiledScript compile(String s) throws ScriptException { - try { - return wrapCompiledScript((CompiledScript) afterInvocation(super.compile(beforeInvocation(s)))); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - @Override - public CompiledScript compile(Reader reader) throws ScriptException { - try { - return wrapCompiledScript((CompiledScript) afterInvocation(super.compile(beforeInvocation(reader)))); - } catch (ScriptException se) { - throw (ScriptException) afterThrowsInvocation(se); - } catch (Exception e) { - throw new UndeclaredThrowableException(afterThrowsInvocation(e)); // Wrap and rethrow other exceptions - } - } - - private CompiledScript wrapCompiledScript(CompiledScript script) { - return new CompiledScript() { - @Override - public ScriptEngine getEngine() { - return InvocationInterceptingScriptEngineWithInvocableAndCompilableAndAutoCloseable.this; - } - - @Override - public Object eval(ScriptContext context) throws ScriptException { - return script.eval(context); - } - }; - } -} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonBindings.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonBindings.java similarity index 72% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonBindings.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonBindings.java index f42554afb5d0f..a88db47a74f26 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonBindings.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonBindings.java @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.graal; +package org.openhab.automation.pythonscripting.internal.scriptengine.graal; import java.util.AbstractMap; import java.util.HashMap; @@ -21,6 +21,7 @@ import javax.script.ScriptEngine; import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Value; /*** @@ -38,57 +39,26 @@ final class GraalPythonBindings extends AbstractMap implements j private ScriptContext scriptContext; private ScriptEngine scriptEngine; + private boolean isClosed = false; + GraalPythonBindings(Context.Builder contextBuilder, ScriptContext scriptContext, ScriptEngine scriptEngine) { this.contextBuilder = contextBuilder; this.scriptContext = scriptContext; this.scriptEngine = scriptEngine; } - GraalPythonBindings(Context context, ScriptContext scriptContext, ScriptEngine scriptEngine) { - this.context = context; - this.scriptContext = scriptContext; - this.scriptEngine = scriptEngine; - - initGlobal(); - } - - private void requireContext() { - if (context == null) { - context = GraalPythonScriptEngine.createDefaultContext(contextBuilder, scriptContext); - - initGlobal(); - } - } - - private void initGlobal() { - this.global = new HashMap<>(); - + public Context getContext() { requireContext(); - - context.getBindings(GraalPythonScriptEngine.LANGUAGE_ID).putMember("__engine__", scriptEngine); - if (scriptContext != null) { - context.getBindings(GraalPythonScriptEngine.LANGUAGE_ID).putMember("__context__", scriptContext); - } + return context; } @Override public Object put(String key, Object v) { requireContext(); - context.getBindings(GraalPythonScriptEngine.LANGUAGE_ID).putMember(key, v); return global.put(key, v); } - @Override - public void clear() { - if (context != null) { - Value binding = context.getBindings(GraalPythonScriptEngine.LANGUAGE_ID); - for (var entry : global.entrySet()) { - binding.removeMember(entry.getKey()); - } - } - } - @Override public Object get(Object key) { requireContext(); @@ -104,9 +74,14 @@ public Object remove(Object key) { return prev; } - public Context getContext() { - requireContext(); - return context; + @Override + public void clear() { + if (context != null) { + Value binding = context.getBindings(GraalPythonScriptEngine.LANGUAGE_ID); + for (var entry : global.entrySet()) { + binding.removeMember(entry.getKey()); + } + } } @Override @@ -115,14 +90,38 @@ public Set> entrySet() { return global.entrySet(); } + /** + * Closes the current context and makes it unusable. + * + * Error happens in guest language will throw an {@link PolyglotException}. + * Operations performed after closing will throw an {@link IllegalStateException}. + */ @Override - public void close() { + public void close() throws PolyglotException, IllegalStateException { if (context != null) { - context.close(); + context.close(true); + // context = null; + // global = null; } + isClosed = true; } - void updateEngineScriptContext(ScriptContext scriptContext) { - this.scriptContext = scriptContext; + public boolean isClosed() { + return isClosed; + } + + private void requireContext() { + if (context == null) { + if (isClosed) { + throw new IllegalStateException("Context already closed"); + } + context = contextBuilder.build(); + global = new HashMap<>(); + + context.getBindings(GraalPythonScriptEngine.LANGUAGE_ID).putMember("__engine__", scriptEngine); + if (scriptContext != null) { + context.getBindings(GraalPythonScriptEngine.LANGUAGE_ID).putMember("__context__", scriptContext); + } + } } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonScriptEngine.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java similarity index 50% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonScriptEngine.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java index 21a6da9a72a25..df16a912ef5f0 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonScriptEngine.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java @@ -10,12 +10,10 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.graal; +package org.openhab.automation.pythonscripting.internal.scriptengine.graal; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.Reader; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -30,250 +28,115 @@ import javax.script.ScriptException; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Context.Builder; import org.graalvm.polyglot.Engine; -import org.graalvm.polyglot.HostAccess; import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.SourceSection; import org.graalvm.polyglot.Value; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * A Graal.Python implementation of the script engine. It provides access to the polyglot context using - * {@link #getPolyglotContext()}. + * A Graal.Python implementation of the script engine. * * @author Holger Hees - Initial contribution * @author Jeff James - Initial contribution */ -public final class GraalPythonScriptEngine extends AbstractScriptEngine +public abstract class GraalPythonScriptEngine extends AbstractScriptEngine implements Compilable, Invocable, AutoCloseable { - public static final String LANGUAGE_ID = "python"; - private static final String POLYGLOT_CONTEXT = "polyglot.context"; - - private static final String PYTHON_OPTION_POSIXMODULEBACKEND = "python.PosixModuleBackend"; - private static final String PYTHON_OPTION_DONTWRITEBYTECODEFLAG = "python.DontWriteBytecodeFlag"; - private static final String PYTHON_OPTION_FORCEIMPORTSITE = "python.ForceImportSite"; - private static final String PYTHON_OPTION_CHECKHASHPYCSMODE = "python.CheckHashPycsMode"; - private final Logger logger = LoggerFactory.getLogger(GraalPythonScriptEngine.class); + private GraalPythonScriptEngineFactory factory; + private GraalPythonBindings bindings; - private final GraalPythonScriptEngineFactory factory; - private final Context.Builder contextConfig; - - GraalPythonScriptEngine(GraalPythonScriptEngineFactory factory) { - this(factory, factory.getPolyglotEngine(), null); + /** + * Creates a new GraalPython script engine from a polyglot Engine instance with a base configuration + * + * @param engine + * + * @param engine the engine to be used for context configurations + * @param contextConfig a base configuration to create new context instances + */ + protected void init(Engine engine, Context.Builder contextConfig, ScriptEngineProvider scriptEngineProvider) { + this.bindings = new GraalPythonBindings(contextConfig.engine(engine), this.context, this); + this.factory = new GraalPythonScriptEngineFactory(engine, scriptEngineProvider); + this.context.setBindings(bindings, ScriptContext.ENGINE_SCOPE); } - GraalPythonScriptEngine(GraalPythonScriptEngineFactory factory, Engine engine, Context.Builder contextConfig) { - Engine engineToUse = (engine != null) ? engine : factory.getPolyglotEngine(); - - Context.Builder contextConfigToUse = contextConfig; - if (contextConfigToUse == null) { - contextConfigToUse = Context.newBuilder(LANGUAGE_ID) // - .allowExperimentalOptions(true) // - .allowAllAccess(true) // - .allowHostAccess(HostAccess.ALL) // - // allow creating python threads - .allowCreateThread(true) // - // allow running Python native extensions - .allowNativeAccess(true) // - // allow exporting Python values to polyglot bindings and accessing Java - // choose the backend for the POSIX module - .option(PYTHON_OPTION_POSIXMODULEBACKEND, "java") // - // equivalent to the Python -B flag - .option(PYTHON_OPTION_DONTWRITEBYTECODEFLAG, "true") // - // Force to automatically import site.py module, to make Python packages available - .option(PYTHON_OPTION_FORCEIMPORTSITE, "true") // - // causes the interpreter to always assume hash-based pycs are valid - .option(PYTHON_OPTION_CHECKHASHPYCSMODE, "never"); - } - this.factory = (factory == null) ? new GraalPythonScriptEngineFactory(engineToUse) : factory; - this.contextConfig = contextConfigToUse.engine(engineToUse); - this.context.setBindings(new GraalPythonBindings(this.contextConfig, this.context, this), - ScriptContext.ENGINE_SCOPE); + /* + * First call will initialize lazy polyglot context + */ + protected Context getPolyglotContext() { + return bindings.getContext(); } - static Context createDefaultContext(Context.Builder builder, ScriptContext ctxt) { - return builder.build(); + protected boolean isClosed() { + return bindings.isClosed(); } /** - * Closes the current context and makes it unusable. Operations performed after closing will - * throw an {@link IllegalStateException}. + * Closes the current context and makes it unusable. + * + * Error happens in guest language will throw an {@link PolyglotException}. + * Operations performed after closing will throw an {@link IllegalStateException}. */ @Override - public void close() { - logger.debug("GraalPythonScriptEngine closed"); - - // "true" to get an exception if something is still running in context - getPolyglotContext().close(true); - } - - /** - * Returns the polyglot engine associated with this script engine. - */ - public Engine getPolyglotEngine() { - return factory.getPolyglotEngine(); - } - - public Context getPolyglotContext() { - return getOrCreateGraalPythonBindings(context).getContext(); + public void close() throws ScriptException, IllegalStateException { + try { + bindings.close(); + } catch (PolyglotException e) { + throw toScriptException(e); + } } - static Value evalInternal(Context context, String script) { - return context.eval(Source.newBuilder(LANGUAGE_ID, script, "internal-script").internal(true).buildLiteral()); + @Override + public GraalPythonScriptEngineFactory getFactory() { + return factory; } @Override public Bindings createBindings() { - return new GraalPythonBindings(contextConfig, null, this); + // Creating a new binding to replace the current one is not needed i context of pythonscripting + throw new IllegalArgumentException("Creating binding not supported"); } @Override public void setBindings(Bindings bindings, int scope) { - if (scope == ScriptContext.ENGINE_SCOPE) { - Bindings oldBindings = getBindings(scope); - if (oldBindings instanceof GraalPythonBindings gpBindings) { - gpBindings.updateEngineScriptContext(null); - } - } - super.setBindings(bindings, scope); - if (scope == ScriptContext.ENGINE_SCOPE && bindings instanceof GraalPythonBindings gpBindings) { - gpBindings.updateEngineScriptContext(getContext()); - } + // Setting a new binding to replace the current one is not needed i context of pythonscripting + throw new IllegalArgumentException("Setting binding not supported"); } @Override public Object eval(Reader reader, ScriptContext ctxt) throws ScriptException { - return eval(createSource(read(reader), ctxt), ctxt); - } - - static String read(Reader reader) throws ScriptException { - final StringBuilder builder = new StringBuilder(); - final char[] buffer = new char[1024]; - try { - try (reader) { - while (true) { - final int count = reader.read(buffer); - if (count == -1) { - break; - } - builder.append(buffer, 0, count); - } - } - return builder.toString(); - } catch (IOException ioex) { - throw new ScriptException(ioex); - } + return eval(read(reader), ctxt); } @Override public Object eval(String script, ScriptContext ctxt) throws ScriptException { - return eval(createSource(script, ctxt), ctxt); - } - - private static Source createSource(String script, ScriptContext ctxt) throws ScriptException { - final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); - if (val == null) { - return Source.newBuilder(LANGUAGE_ID, script, "").buildLiteral(); - } else { - try { - return Source.newBuilder(LANGUAGE_ID, new File(val.toString())).content(script).build(); - } catch (IOException ioex) { - throw new ScriptException(ioex); - } - } + return eval(createSource(script, ctxt)); } - private Object eval(Source source, ScriptContext scriptContext) throws ScriptException { - GraalPythonBindings engineBindings = getOrCreateGraalPythonBindings(scriptContext); - Context polyglotContext = engineBindings.getContext(); + private Object eval(Source source) throws ScriptException { try { - return polyglotContext.eval(source).as(Object.class); + return getPolyglotContext().eval(source).as(Object.class); } catch (PolyglotException e) { throw toScriptException(e); } } - private static ScriptException toScriptException(PolyglotException ex) { - ScriptException sex; - if (ex.isHostException()) { - Throwable hostException = ex.asHostException(); - // ScriptException (unlike almost any other exception) does not - // accept Throwable cause (requires the cause to be Exception) - Exception cause; - if (hostException instanceof Exception) { - cause = (Exception) hostException; - } else { - cause = new Exception(hostException); - } - // Make the host exception accessible through the cause chain - sex = new ScriptException(cause); - // Re-use the stack-trace of PolyglotException (with guest-language stack-frames) - sex.setStackTrace(ex.getStackTrace()); - } else { - SourceSection sourceSection = ex.getSourceLocation(); - if (sourceSection != null && sourceSection.isAvailable()) { - Source source = sourceSection.getSource(); - String fileName = source.getPath(); - if (fileName == null) { - fileName = source.getName(); - } - int lineNo = sourceSection.getStartLine(); - int columnNo = sourceSection.getStartColumn(); - sex = new ScriptException(ex.getMessage(), fileName, lineNo, columnNo); - sex.initCause(ex); - } else { - sex = new ScriptException(ex); - } - } - return sex; - } - - private GraalPythonBindings getOrCreateGraalPythonBindings(ScriptContext scriptContext) { - Bindings engineB = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE); - if (engineB instanceof GraalPythonBindings) { - return ((GraalPythonBindings) engineB); - } else { - GraalPythonBindings bindings = new GraalPythonBindings(createContext(engineB), scriptContext, this); - bindings.putAll(engineB); - return bindings; - } - } - - private Context createContext(Bindings engineB) { - Object ctx = engineB.get(POLYGLOT_CONTEXT); - if (!(ctx instanceof Context)) { - ctx = createDefaultContext(contextConfig, context); - engineB.put(POLYGLOT_CONTEXT, ctx); - } - return (Context) ctx; - } - - @Override - public GraalPythonScriptEngineFactory getFactory() { - return factory; - } - @Override public Object invokeMethod(Object thiz, String name, Object... args) throws ScriptException, NoSuchMethodException { if (thiz == null) { throw new IllegalArgumentException("thiz is not a valid object."); } - GraalPythonBindings engineBindings = getOrCreateGraalPythonBindings(context); - Value thisValue = engineBindings.getContext().asValue(thiz); - if (!thisValue.canInvokeMember(name)) { - if (!thisValue.hasMember(name)) { - throw noSuchMethod(name); - } else { - throw notCallable(name); - } - } try { + Value thisValue = getPolyglotContext().asValue(thiz); + if (!thisValue.canInvokeMember(name)) { + if (!thisValue.hasMember(name)) { + throw new NoSuchMethodException(name); + } else { + throw new NoSuchMethodException(name + " is not a function"); + } + } return thisValue.invokeMember(name, args).as(Object.class); } catch (PolyglotException e) { throw toScriptException(e); @@ -282,29 +145,19 @@ public Object invokeMethod(Object thiz, String name, Object... args) throws Scri @Override public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException { - GraalPythonBindings engineBindings = getOrCreateGraalPythonBindings(context); - Value function = engineBindings.getContext().getBindings(LANGUAGE_ID).getMember(name); - - if (function == null) { - throw noSuchMethod(name); - } else if (!function.canExecute()) { - throw notCallable(name); - } try { + Value function = getPolyglotContext().getBindings(LANGUAGE_ID).getMember(name); + if (function == null) { + throw new NoSuchMethodException(name); + } else if (!function.canExecute()) { + throw new NoSuchMethodException(name + " is not a function"); + } return function.execute(args).as(Object.class); } catch (PolyglotException e) { throw toScriptException(e); } } - private static NoSuchMethodException noSuchMethod(String name) throws NoSuchMethodException { - throw new NoSuchMethodException(name); - } - - private static NoSuchMethodException notCallable(String name) throws NoSuchMethodException { - throw new NoSuchMethodException(name + " is not a function"); - } - @Override public T getInterface(Class clasz) { checkInterface(clasz); @@ -322,23 +175,9 @@ public T getInterface(Object thiz, Class clasz) { return getInterfaceInner(thisValue, clasz); } - private static void checkInterface(Class clasz) { - if (clasz == null || !clasz.isInterface()) { - throw new IllegalArgumentException("interface Class expected in getInterface"); - } - } - - private static void checkThis(Value thiz) { - if (thiz.isHostObject() || !thiz.hasMembers()) { - throw new IllegalArgumentException("getInterface cannot be called on non-script object"); - } - } - - private static T getInterfaceInner(Value thiz, Class iface) { - if (!isInterfaceImplemented(iface, thiz)) { - return null; - } - return thiz.as(iface); + @Override + public CompiledScript compile(Reader reader) throws ScriptException { + return compile(read(reader)); } @Override @@ -347,14 +186,14 @@ public CompiledScript compile(String script) throws ScriptException { return compile(source); } - @Override - public CompiledScript compile(Reader reader) throws ScriptException { - Source source = createSource(read(reader), getContext()); - return compile(source); - } - private CompiledScript compile(Source source) throws ScriptException { - checkSyntax(source); + try { + // Syntax check + getPolyglotContext().parse(source); + } catch (PolyglotException pex) { + throw toScriptException(pex); + } + return new CompiledScript() { @Override public ScriptEngine getEngine() { @@ -363,35 +202,60 @@ public ScriptEngine getEngine() { @Override public Object eval(ScriptContext ctx) throws ScriptException { - return GraalPythonScriptEngine.this.eval(source, ctx); + return GraalPythonScriptEngine.this.eval(source); } }; } - private void checkSyntax(Source source) throws ScriptException { + private static void checkInterface(Class clasz) { + if (clasz == null || !clasz.isInterface()) { + throw new IllegalArgumentException("interface Class expected in getInterface"); + } + } + + private static void checkThis(Value thiz) { + if (thiz.isHostObject() || !thiz.hasMembers()) { + throw new IllegalArgumentException("getInterface cannot be called on non-script object"); + } + } + + private static T getInterfaceInner(Value thiz, Class iface) { + if (!isInterfaceImplemented(iface, thiz)) { + return null; + } + return thiz.as(iface); + } + + private static String read(Reader reader) throws ScriptException { + final StringBuilder builder = new StringBuilder(); + final char[] buffer = new char[1024]; try { - getPolyglotContext().parse(source); - } catch (PolyglotException pex) { - throw toScriptException(pex); + try (reader) { + while (true) { + final int count = reader.read(buffer); + if (count == -1) { + break; + } + builder.append(buffer, 0, count); + } + } + return builder.toString(); + } catch (IOException ioex) { + throw new ScriptException(ioex); } } - /** - * Creates a new GraalPython script engine from a polyglot Engine instance with a base configuration - * for new polyglot {@link Context} instances. Polyglot context instances can be accessed from - * {@link ScriptContext} instances using {@link #getPolyglotContext()}. The - * {@link Builder#out(OutputStream) out},{@link Builder#err(OutputStream) err} and - * {@link Builder#in(InputStream) in} stream configuration are not inherited from the provided - * polyglot context config. Instead {@link ScriptContext} output and input streams are used. - * - * @param engine the engine to be used for context configurations or null if a - * default engine should be used. - * @param newContextConfig a base configuration to create new context instances or - * null if the default configuration should be used to construct new - * context instances. - */ - public static GraalPythonScriptEngine create(Engine engine, Context.Builder newContextConfig) { - return new GraalPythonScriptEngine(null, engine, newContextConfig); + private static Source createSource(String script, ScriptContext ctxt) throws ScriptException { + final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); + if (val == null) { + return Source.newBuilder(LANGUAGE_ID, script, "").buildLiteral(); + } else { + try { + return Source.newBuilder(LANGUAGE_ID, new File(val.toString())).content(script).build(); + } catch (IOException ioex) { + throw new ScriptException(ioex); + } + } } private static boolean isInterfaceImplemented(final Class iface, final Value obj) { @@ -412,4 +276,47 @@ private static boolean isInterfaceImplemented(final Class iface, final Value } return true; } + + protected static ScriptException toScriptException(PolyglotException ex) { + ScriptException sex; + if (ex.isHostException()) { + Throwable hostException = ex.asHostException(); + // ScriptException (unlike almost any other exception) does not + // accept Throwable cause (requires the cause to be Exception) + Exception cause; + if (hostException instanceof Exception) { + cause = (Exception) hostException; + } else { + cause = new Exception(hostException); + } + // Make the host exception accessible through the cause chain + sex = new ScriptException(cause); + // Re-use the stack-trace of PolyglotException (with guest-language stack-frames) + sex.setStackTrace(ex.getStackTrace()); + } else { + SourceSection sourceSection = ex.getSourceLocation(); + if (sourceSection != null && sourceSection.isAvailable()) { + Source source = sourceSection.getSource(); + String fileName = source.getPath(); + if (fileName == null) { + fileName = source.getName(); + } + int lineNo = sourceSection.getStartLine(); + int columnNo = sourceSection.getStartColumn(); + sex = new ScriptException(ex.getMessage(), fileName, lineNo, columnNo); + sex.initCause(ex); + } else { + sex = new ScriptException(ex); + } + } + return sex; + } + + private static Value evalInternal(Context context, String script) { + return context.eval(Source.newBuilder(LANGUAGE_ID, script, "internal-script").internal(true).buildLiteral()); + } + + public static interface ScriptEngineProvider { + ScriptEngine createScriptEngine(); + } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonScriptEngineFactory.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngineFactory.java similarity index 66% rename from bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonScriptEngineFactory.java rename to bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngineFactory.java index ff8d5cd8d5c76..58ab83e983780 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/graal/GraalPythonScriptEngineFactory.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngineFactory.java @@ -10,9 +10,8 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.automation.pythonscripting.internal.graal; +package org.openhab.automation.pythonscripting.internal.scriptengine.graal; -import java.lang.ref.WeakReference; import java.util.List; import java.util.Objects; @@ -21,6 +20,7 @@ import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.Language; +import org.openhab.automation.pythonscripting.internal.scriptengine.graal.GraalPythonScriptEngine.ScriptEngineProvider; /** * A Graal.Python implementation of the script engine factory to exposes metadata describing of the engine class. @@ -29,46 +29,23 @@ * @author Jeff James - Initial contribution */ public final class GraalPythonScriptEngineFactory implements ScriptEngineFactory { - private WeakReference defaultEngine; - private final Engine userDefinedEngine; - private static final String ENGINE_NAME = "Graal.py"; private static final String NAME = "python3"; private static final String[] EXTENSIONS = { "py" }; - public GraalPythonScriptEngineFactory() { - this.userDefinedEngine = null; - - defaultEngine = new WeakReference<>(createDefaultEngine()); - } - - public GraalPythonScriptEngineFactory(Engine engine) { - this.defaultEngine = null; - this.userDefinedEngine = engine; - } + private final Engine engine; + private final Language language; + private ScriptEngineProvider scriptEngineProvider; - private static Engine createDefaultEngine() { - return Engine.newBuilder() // - .allowExperimentalOptions(true) // - .option("engine.WarnInterpreterOnly", "false") // - .build(); + public GraalPythonScriptEngineFactory(Engine engine, ScriptEngineProvider scriptEngineProvider) { + this.engine = engine; + this.scriptEngineProvider = scriptEngineProvider; + this.language = this.engine.getLanguages().get(GraalPythonScriptEngine.LANGUAGE_ID); } - /** - * Returns the underlying polyglot engine. - */ public Engine getPolyglotEngine() { - if (userDefinedEngine != null) { - return userDefinedEngine; - } else { - Engine engine = defaultEngine == null ? null : defaultEngine.get(); - if (engine == null) { - engine = createDefaultEngine(); - defaultEngine = new WeakReference<>(engine); - } - return engine; - } + return engine; } @Override @@ -78,7 +55,7 @@ public String getEngineName() { @Override public String getEngineVersion() { - return getPolyglotEngine().getVersion(); + return engine.getVersion(); } @Override @@ -88,25 +65,21 @@ public List getExtensions() { @Override public List getMimeTypes() { - Language language = getPolyglotEngine().getLanguages().get(GraalPythonScriptEngine.LANGUAGE_ID); return List.copyOf(language.getMimeTypes()); } @Override public List getNames() { - Language language = getPolyglotEngine().getLanguages().get(GraalPythonScriptEngine.LANGUAGE_ID); return List.of(language.getName(), GraalPythonScriptEngine.LANGUAGE_ID, language.getImplementationName()); } @Override public String getLanguageName() { - Language language = getPolyglotEngine().getLanguages().get(GraalPythonScriptEngine.LANGUAGE_ID); return language.getName(); } @Override public String getLanguageVersion() { - Language language = getPolyglotEngine().getLanguages().get(GraalPythonScriptEngine.LANGUAGE_ID); return language.getVersion(); } @@ -123,8 +96,8 @@ public Object getParameter(String key) { } @Override - public GraalPythonScriptEngine getScriptEngine() { - return new GraalPythonScriptEngine(this); + public ScriptEngine getScriptEngine() { + return scriptEngineProvider.createScriptEngine(); } @Override diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/wrapper/ModuleLocator.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/wrapper/ModuleLocator.java deleted file mode 100644 index ccf80a73fd95e..0000000000000 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/wrapper/ModuleLocator.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2010-2025 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.automation.pythonscripting.internal.wrapper; - -import java.util.List; -import java.util.Map; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * Locates modules from a module name - * - * @author Holger Hees - Initial contribution - */ -@NonNullByDefault -public interface ModuleLocator { - Map locateModule(String name, List fromlist); -} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml index 507d62bdd50a6..f9bd42c9adbba 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml @@ -27,10 +27,10 @@ true - + - If disabled, the openHAB Python helper module can be installed manually by copying it to /conf/automation/python/lib/openhab" + Install openHAB Python helper module to support helper classes like rule, logger, Registry, Timer etc...
    + If disabled, the openHAB python helper module can be installed manually by copying it to /conf/automation/python/lib/openhab" ]]>
    true
    @@ -46,8 +46,26 @@ 2 + + + + == followed by standard + python pip version constraint, such as "tzdata==2025.2".]]> + + + true + + + + + + + false + true + - + Dependency tracking allows your scripts to automatically reload when one of its dependencies is updated. You may want to disable dependency tracking if you plan on editing or updating a shared library, but don't want all your scripts to reload until you can test it. @@ -55,7 +73,7 @@ true - + Disable this option will result in a slower startup performance, because scripts have to be recompiled on every startup. @@ -64,7 +82,7 @@ true - + Jython Migration Guide
    . diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties index d2b727ac3ea77..95641b082264f 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties +++ b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties @@ -13,7 +13,7 @@ automation.config.pythonscripting.group.environment.label = Python Environment automation.config.pythonscripting.group.environment.description = This group defines Python's environment. automation.config.pythonscripting.group.system.label = System Behavior automation.config.pythonscripting.group.system.description = This group defines Python's system behavior. -automation.config.pythonscripting.helperEnabled.label = Install openHAB Python helper modules and keep it updated (requires scope module) +automation.config.pythonscripting.helperEnabled.label = Install openHAB Python helper modules (requires scope module) automation.config.pythonscripting.helperEnabled.description = Deploy and update openHAB Python helper modules like rule, logger, Registry, Timer etc...
    If disabled, the openHAB Python helper module can be installed manually by copying it to /conf/automation/python/lib/openhab" automation.config.pythonscripting.injectionEnabled.label = Inject scope and helper objects into UI based rules (requires helper modules) automation.config.pythonscripting.injectionEnabled.description = This injects the scope module and core helper Registry and logger into UI based rules. @@ -22,5 +22,9 @@ automation.config.pythonscripting.injectionEnabled.option.1 = Auto injection ena automation.config.pythonscripting.injectionEnabled.option.0 = Disable auto injection and use 'import' statements instead automation.config.pythonscripting.jythonEmulation.label = Enable Jython emulation automation.config.pythonscripting.jythonEmulation.description = This enables Jython emulation in GraalPy. It is strongly recommended to update code to GraalPy and Python 3 as the emulation can have performance degradation. For tips and instructions, please refer to Jython Migration Guide. +automation.config.pythonscripting.nativeModules.label = Enables support of native modules (requires a manually configured venv) +automation.config.pythonscripting.nativeModules.description = Native modules are sometimes necessary for pip modules which depends on native libraries. +automation.config.pythonscripting.pipModules.label = Python pip modules (requires a manually configured venv) +automation.config.pythonscripting.pipModules.description = A comma separated list of Python modules to install. Versions may be constrained by separating with an == followed by standard python pip version constraint, such as "tzdata==2025.2". automation.config.pythonscripting.scopeEnabled.label = Use scope and import wrapper automation.config.pythonscripting.scopeEnabled.description = This enables a scope module and and import wrapper.
    An scope module is an encapsulated module containing all openHAB jsr223 objects and can be imported with import scope
    Additionally you can run an import like from org.openhab.core import OpenHAB diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting_de.properties b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting_de.properties deleted file mode 100644 index 12763f8a40f6e..0000000000000 --- a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting_de.properties +++ /dev/null @@ -1,26 +0,0 @@ -# add-on - -addon.pythonscripting.name = Python Scripting -addon.pythonscripting.description = Fügt eine Python 3.x Skript-Engine hinzu. - -# add-on config - -automation.config.pythonscripting.cachingEnabled.label = Zwischenspeichern von kompilierten openHAB Python-Helfermodulen (.pyc Dateien) -automation.config.pythonscripting.cachingEnabled.description = Zwischenspeichern der openHAB Python-Module für eine verbesserte Startup-Performance.
    Deaktivieren dieser Option führt zu einer langsameren Start-Performance, da Skripte bei jedem Start neu kompiliert werden müssen. -automation.config.pythonscripting.dependencyTrackingEnabled.label = Abhängigkeitsüberwachung aktivieren -automation.config.pythonscripting.dependencyTrackingEnabled.description = Die Abhängigkeitsüberwachung ermöglicht es Ihren Skripten, automatisch neu zu laden, wenn eine ihrer Abhängigkeiten aktualisiert wird. Sie können die Überwachung von Abhängigkeiten deaktivieren, wenn Sie eine gemeinsam genutzte Bibliothek bearbeiten oder aktualisieren möchten, aber nicht wollen, dass alle Skripte neu geladen werden, bis Sie sie testen können. -automation.config.pythonscripting.group.environment.label = Python-Umgebung -automation.config.pythonscripting.group.environment.description = Diese Gruppe definiert die Python-Umgebung. -automation.config.pythonscripting.group.system.label = Systemverhalten -automation.config.pythonscripting.group.system.description = Diese Gruppe definiert das Systemverhalten von Python. -automation.config.pythonscripting.helperEnabled.label = Installieren und automatisches Aktualisieren der openHAB Python-Helfermodule (erfordert Scope-Modul) -automation.config.pythonscripting.helperEnabled.description = OpenHAB Python-Helfermodule wie 'rule', 'logger', 'Registry', 'Timer', usw. bereitstellen und aktualisieren.
    Wenn deaktiviert, kann das openHAB Python-Helfermodul manuell installiert werden, indem es nach "/conf/automation/python/lib/openhab" kopiert wird. -automation.config.pythonscripting.injectionEnabled.label = Bereitstellung von Scope- und Helfer-Objekten für UI-basierte Regeln (erfordert Helfer-Module) -automation.config.pythonscripting.injectionEnabled.description = Dies bettet das Scope-Modul und die Kern-Helfermodule 'Registry' und 'logger' in UI-basierte Regeln ein. -automation.config.pythonscripting.injectionEnabled.option.2 = Automatische Einbettung nur für UI und Transformationsskripte aktivieren (bevorzugt) -automation.config.pythonscripting.injectionEnabled.option.1 = Automatische Einbettung für alle Skripte aktivieren -automation.config.pythonscripting.injectionEnabled.option.0 = Automatische Einbettung deaktivieren und stattdessen 'import'-Anweisungen verwenden -automation.config.pythonscripting.jythonEmulation.label = Jython-Emulation aktivieren -automation.config.pythonscripting.jythonEmulation.description = Ermöglicht Jython-Emulation in GraalPy. Es wird dringend empfohlen, Code auf GraalPy und Python 3 zu aktualisieren, da die Emulation zu Performanceeinbußen führen kann. Für Tipps und Anweisungen wird auf Jython Migration Guide verwiesen. -automation.config.pythonscripting.scopeEnabled.label = Scope und Import Wrapper verwenden -automation.config.pythonscripting.scopeEnabled.description = Aktiviert ein Scope-Modul und Import-Wrapper.
    Ein Scope-Modul ist ein eingekapseltes Modul mit allen openHAB JSR223 Objekten und kann mit import scope
    importiert werden. Zusätzlich können Sie einen Import, wie from org.openhab.core import OpenHAB verwenden. From b95f817b8a87c7af8e11444e15f6002502cb20a2 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Mon, 18 Aug 2025 17:24:56 +0200 Subject: [PATCH 02/11] implement review feedback Signed-off-by: Holger Hees --- .../internal/console/handler/TypingCmd.java | 44 +++++++++---------- .../internal/context/ContextInput.java | 2 +- .../graal/GraalPythonScriptEngine.java | 4 +- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/TypingCmd.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/TypingCmd.java index 45a055ce0fdfb..1b81d023d23c5 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/TypingCmd.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/TypingCmd.java @@ -91,33 +91,31 @@ public void build() throws Exception { public void dumpInit(String path, Map fileContainerMap) throws IOException { File root = new File(path); File[] list = root.listFiles(); - if (list == null) { - return; - } - - ArrayList files = new ArrayList(); - for (File f : list) { - if (f.isDirectory()) { - dumpInit(f.getAbsolutePath(), fileContainerMap); - } else { - files.add(f); + if (list != null) { + ArrayList files = new ArrayList(); + for (File f : list) { + if (f.isDirectory()) { + dumpInit(f.getAbsolutePath(), fileContainerMap); + } else { + files.add(f); + } } - } - if (!files.isEmpty()) { - StringBuilder initBody = new StringBuilder(); - // List modules = new ArrayList(); - for (File file : files) { - if (file.toString().endsWith("__init__.py")) { - continue; + if (!files.isEmpty()) { + StringBuilder initBody = new StringBuilder(); + // List modules = new ArrayList(); + for (File file : files) { + if (file.toString().endsWith("__init__.py")) { + continue; + } + ClassContainer container = fileContainerMap.get(file.toString()); + initBody.append("from .__" + container.getPythonClassName().toLowerCase() + "__ import " + + container.getPythonClassName() + "\n"); } - ClassContainer container = fileContainerMap.get(file.toString()); - initBody.append("from .__" + container.getPythonClassName().toLowerCase() + "__ import " - + container.getPythonClassName() + "\n"); - } - String packageUrl = path.replace(".", PATH_SEPARATOR) + "/__init__.py"; - dumpContentToFile(initBody.toString(), Paths.get(packageUrl)); + String packageUrl = path.replace(".", PATH_SEPARATOR) + "/__init__.py"; + dumpContentToFile(initBody.toString(), Paths.get(packageUrl)); + } } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java index bc3ea70d50f82..6ba563d4f976d 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java @@ -19,7 +19,7 @@ import org.eclipse.jdt.annotation.Nullable; /** - * ContextOutput implementation + * ContextInput implementation * * @author Holger Hees - Initial contribution */ diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java index df16a912ef5f0..e50410c479d2f 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java @@ -95,13 +95,13 @@ public GraalPythonScriptEngineFactory getFactory() { @Override public Bindings createBindings() { // Creating a new binding to replace the current one is not needed i context of pythonscripting - throw new IllegalArgumentException("Creating binding not supported"); + throw new IllegalArgumentException("Creating new bindings is not supported in the context of pythonscripting"); } @Override public void setBindings(Bindings bindings, int scope) { // Setting a new binding to replace the current one is not needed i context of pythonscripting - throw new IllegalArgumentException("Setting binding not supported"); + throw new IllegalArgumentException("Setting bindings is not supported in the context of pythonscripting"); } @Override From dbdbf47ff318bf111304d93a1aed4d2f32931019 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Tue, 19 Aug 2025 11:10:34 +0200 Subject: [PATCH 03/11] improved README Signed-off-by: Holger Hees --- .../README.md | 63 ++++++++++++++++++- .../main/resources/OH-INF/config/config.xml | 4 +- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.automation.pythonscripting/README.md b/bundles/org.openhab.automation.pythonscripting/README.md index 76bd59ccbbf48..5f680b7d9efc7 100644 --- a/bundles/org.openhab.automation.pythonscripting/README.md +++ b/bundles/org.openhab.automation.pythonscripting/README.md @@ -60,10 +60,71 @@ including all examples above, much more detailed. ### Configuration -Check via Web UI => Settings / Add-on Settings / Python Scripting +Web based config dialog can be found via Web UI => Settings / Add-on Settings / Python Scripting ![Pythonscripting configuration](doc/pythonscripting_configuration.png) +Additionally, you can configure the Add-on via a config file `/openhab/services/pythonscripting.cfg` like below. + +``` +# Use scope and import wrapper +# +# This enables a scope module and and import wrapper. +# An scope module is an encapsulated module containing all openHAB jsr223 objects and can be imported with import scope +# Additionally you can run an import like from org.openhab.core import OpenHAB +# +#org.openhab.automation.pythonscripting:scopeEnabled = true + +# Install openHAB Python helper module (requires scope module) +# +# Install openHAB Python helper module to support helper classes like rule, logger, Registry, Timer etc... +# If disabled, the openHAB python helper module can be installed manually by copying it to /conf/automation/python/lib/openhab" +# +#org.openhab.automation.pythonscripting:helperEnabled = true + +# Inject scope and helper objects into rules (requires helper modules) +# +# This injects the scope and helper Registry and logger into rules. +# +# 2 => Auto injection enabled only for UI and Transformation scripts (preferred) +# 1 => Auto injection enabled for all scripts +# 0 => Disable auto injection and use 'import' statements instead +# +#org.openhab.automation.pythonscripting:injectionEnabled = 2 + +# Enables native modules (requires a manually configured venv) +# +# Native modules are sometimes necessary for pip modules which depends on native libraries. +# +#org.openhab.automation.pythonscripting:nativeModules = false + +# Enable dependency tracking +# +# Dependency tracking allows your scripts to automatically reload when one of its dependencies is updated. +# You may want to disable dependency tracking if you plan on editing or updating a shared library, but don't want all +# your scripts to reload until you can test it. +# +#org.openhab.automation.pythonscripting:dependencyTrackingEnabled = true + +# Cache compiled openHAB Python modules (.pyc files) +# +# Cache the openHAB python modules for improved startup performance.
    +# Disable this option will result in a slower startup performance, because scripts have to be recompiled on every startup. +# +#org.openhab.automation.pythonscripting:cachingEnabled = true + +# Enable jython emulation +# +# This enables Jython emulation in GraalPy. It is strongly recommended to update code to GraalPy and Python 3 as the emulation can have performance degradation. +# For tips and instructions, please refer to Jython Migration Guide. +# +#org.openhab.automation.pythonscripting:jythonEmulation = false +``` + +::: tip Configuration note +If you use the marketplace version of this Add-on, it is neccessary to use the config file. OpenHAB has a bug which prevents the web based config dialog to work correctly for `kar` file based Add-ons. +::: + ### Console The [openHAB Console](https://www.openhab.org/docs/administration/console.html) provides access to additional features of these Add-on. diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml index f9bd42c9adbba..0ab3e6d03caf7 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml @@ -35,9 +35,9 @@ true - + From 0ffb022f4ffbbe3b6d500f6d4a41728e1452b1d1 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Fri, 22 Aug 2025 13:28:47 +0200 Subject: [PATCH 04/11] implement copilot feedback Signed-off-by: Holger Hees --- .../internal/PythonScriptEngineConfiguration.java | 4 ++-- .../internal/fs/PythonScriptFileWatcher.java | 6 ------ .../scriptengine/graal/GraalPythonScriptEngine.java | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java index 6b6b45fbab163..c85c40c9d6569 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java @@ -165,7 +165,7 @@ public PythonScriptEngineConfiguration(Map config, PythonScriptE * Update configuration * * @param config Configuration parameters to apply to ScriptEngine - * @param intitial + * @param initial */ public void modified(Map config, ScriptEngineFactory factory) { boolean oldScopeEnabled = configuration.scopeEnabled; @@ -498,7 +498,7 @@ private Path initDirectory(Path path) { /** * Unwraps the cause of an exception, if it has one. * - * Since a user cares about the _Ruby_ stack trace of the throwable, not + * Since a user cares about the _Python_ stack trace of the throwable, not * the details of where openHAB called it. */ private static Throwable unwrap(Throwable e) { diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonScriptFileWatcher.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonScriptFileWatcher.java index 07ba17a119a60..8a36c338321c1 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonScriptFileWatcher.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/fs/PythonScriptFileWatcher.java @@ -58,10 +58,4 @@ protected Optional getScriptType(Path scriptFilePath) { } return Optional.empty(); } - - // Overriding to make it public, so it can be used in {@link JRubyConsoleCommandExtension} - @Override - public Path getWatchPath() { - return super.getWatchPath(); - } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java index e50410c479d2f..3fcac74f893a4 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java @@ -100,7 +100,7 @@ public Bindings createBindings() { @Override public void setBindings(Bindings bindings, int scope) { - // Setting a new binding to replace the current one is not needed i context of pythonscripting + // Setting a new binding to replace the current one is not needed in context of pythonscripting throw new IllegalArgumentException("Setting bindings is not supported in the context of pythonscripting"); } From 9da9fcdc0b2f9aa837ed34187e6485600272198d Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Thu, 4 Sep 2025 09:50:05 +0200 Subject: [PATCH 05/11] generate i18n translations Signed-off-by: Holger Hees --- .../OH-INF/i18n/pythonscripting.properties | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties index 95641b082264f..d8313da5203db 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties +++ b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties @@ -5,24 +5,24 @@ addon.pythonscripting.description = This adds a Python 3.x script engine. # add-on config -automation.config.pythonscripting.cachingEnabled.label = Cache compiled openHAB Python helper modules (.pyc files) +automation.config.pythonscripting.cachingEnabled.label = Cache compiled openHAB Python modules (.pyc files) automation.config.pythonscripting.cachingEnabled.description = Cache the openHAB python modules for improved startup performance.
    Disable this option will result in a slower startup performance, because scripts have to be recompiled on every startup. -automation.config.pythonscripting.dependencyTrackingEnabled.label = Enable Dependency Tracking +automation.config.pythonscripting.dependencyTrackingEnabled.label = Enable dependency tracking automation.config.pythonscripting.dependencyTrackingEnabled.description = Dependency tracking allows your scripts to automatically reload when one of its dependencies is updated. You may want to disable dependency tracking if you plan on editing or updating a shared library, but don't want all your scripts to reload until you can test it. automation.config.pythonscripting.group.environment.label = Python Environment automation.config.pythonscripting.group.environment.description = This group defines Python's environment. automation.config.pythonscripting.group.system.label = System Behavior automation.config.pythonscripting.group.system.description = This group defines Python's system behavior. -automation.config.pythonscripting.helperEnabled.label = Install openHAB Python helper modules (requires scope module) -automation.config.pythonscripting.helperEnabled.description = Deploy and update openHAB Python helper modules like rule, logger, Registry, Timer etc...
    If disabled, the openHAB Python helper module can be installed manually by copying it to /conf/automation/python/lib/openhab" -automation.config.pythonscripting.injectionEnabled.label = Inject scope and helper objects into UI based rules (requires helper modules) -automation.config.pythonscripting.injectionEnabled.description = This injects the scope module and core helper Registry and logger into UI based rules. +automation.config.pythonscripting.helperEnabled.label = Install openHAB Python helper module (requires scope module) +automation.config.pythonscripting.helperEnabled.description = Install openHAB Python helper module to support helper classes like rule, logger, Registry, Timer etc...
    If disabled, the openHAB python helper module can be installed manually by copying it to /conf/automation/python/lib/openhab" +automation.config.pythonscripting.injectionEnabled.label = Inject scope and helper objects into rules (requires helper modules) +automation.config.pythonscripting.injectionEnabled.description = This injects the scope and helper Registry and logger into rules. automation.config.pythonscripting.injectionEnabled.option.2 = Auto injection enabled only for UI and Transformation scripts (preferred) automation.config.pythonscripting.injectionEnabled.option.1 = Auto injection enabled for all scripts automation.config.pythonscripting.injectionEnabled.option.0 = Disable auto injection and use 'import' statements instead -automation.config.pythonscripting.jythonEmulation.label = Enable Jython emulation +automation.config.pythonscripting.jythonEmulation.label = Enable jython emulation automation.config.pythonscripting.jythonEmulation.description = This enables Jython emulation in GraalPy. It is strongly recommended to update code to GraalPy and Python 3 as the emulation can have performance degradation. For tips and instructions, please refer to Jython Migration Guide. -automation.config.pythonscripting.nativeModules.label = Enables support of native modules (requires a manually configured venv) +automation.config.pythonscripting.nativeModules.label = Enables native modules (requires a manually configured venv) automation.config.pythonscripting.nativeModules.description = Native modules are sometimes necessary for pip modules which depends on native libraries. automation.config.pythonscripting.pipModules.label = Python pip modules (requires a manually configured venv) automation.config.pythonscripting.pipModules.description = A comma separated list of Python modules to install. Versions may be constrained by separating with an == followed by standard python pip version constraint, such as "tzdata==2025.2". From b53c5b77bb7f9c1cf43b942606092b1a1be8976e Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Tue, 16 Sep 2025 08:22:51 +0200 Subject: [PATCH 06/11] revert pythonscripting.properties Signed-off-by: Holger Hees --- .../OH-INF/i18n/pythonscripting.properties | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties index d8313da5203db..d2b727ac3ea77 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties +++ b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting.properties @@ -5,26 +5,22 @@ addon.pythonscripting.description = This adds a Python 3.x script engine. # add-on config -automation.config.pythonscripting.cachingEnabled.label = Cache compiled openHAB Python modules (.pyc files) +automation.config.pythonscripting.cachingEnabled.label = Cache compiled openHAB Python helper modules (.pyc files) automation.config.pythonscripting.cachingEnabled.description = Cache the openHAB python modules for improved startup performance.
    Disable this option will result in a slower startup performance, because scripts have to be recompiled on every startup. -automation.config.pythonscripting.dependencyTrackingEnabled.label = Enable dependency tracking +automation.config.pythonscripting.dependencyTrackingEnabled.label = Enable Dependency Tracking automation.config.pythonscripting.dependencyTrackingEnabled.description = Dependency tracking allows your scripts to automatically reload when one of its dependencies is updated. You may want to disable dependency tracking if you plan on editing or updating a shared library, but don't want all your scripts to reload until you can test it. automation.config.pythonscripting.group.environment.label = Python Environment automation.config.pythonscripting.group.environment.description = This group defines Python's environment. automation.config.pythonscripting.group.system.label = System Behavior automation.config.pythonscripting.group.system.description = This group defines Python's system behavior. -automation.config.pythonscripting.helperEnabled.label = Install openHAB Python helper module (requires scope module) -automation.config.pythonscripting.helperEnabled.description = Install openHAB Python helper module to support helper classes like rule, logger, Registry, Timer etc...
    If disabled, the openHAB python helper module can be installed manually by copying it to /conf/automation/python/lib/openhab" -automation.config.pythonscripting.injectionEnabled.label = Inject scope and helper objects into rules (requires helper modules) -automation.config.pythonscripting.injectionEnabled.description = This injects the scope and helper Registry and logger into rules. +automation.config.pythonscripting.helperEnabled.label = Install openHAB Python helper modules and keep it updated (requires scope module) +automation.config.pythonscripting.helperEnabled.description = Deploy and update openHAB Python helper modules like rule, logger, Registry, Timer etc...
    If disabled, the openHAB Python helper module can be installed manually by copying it to /conf/automation/python/lib/openhab" +automation.config.pythonscripting.injectionEnabled.label = Inject scope and helper objects into UI based rules (requires helper modules) +automation.config.pythonscripting.injectionEnabled.description = This injects the scope module and core helper Registry and logger into UI based rules. automation.config.pythonscripting.injectionEnabled.option.2 = Auto injection enabled only for UI and Transformation scripts (preferred) automation.config.pythonscripting.injectionEnabled.option.1 = Auto injection enabled for all scripts automation.config.pythonscripting.injectionEnabled.option.0 = Disable auto injection and use 'import' statements instead -automation.config.pythonscripting.jythonEmulation.label = Enable jython emulation +automation.config.pythonscripting.jythonEmulation.label = Enable Jython emulation automation.config.pythonscripting.jythonEmulation.description = This enables Jython emulation in GraalPy. It is strongly recommended to update code to GraalPy and Python 3 as the emulation can have performance degradation. For tips and instructions, please refer to Jython Migration Guide. -automation.config.pythonscripting.nativeModules.label = Enables native modules (requires a manually configured venv) -automation.config.pythonscripting.nativeModules.description = Native modules are sometimes necessary for pip modules which depends on native libraries. -automation.config.pythonscripting.pipModules.label = Python pip modules (requires a manually configured venv) -automation.config.pythonscripting.pipModules.description = A comma separated list of Python modules to install. Versions may be constrained by separating with an == followed by standard python pip version constraint, such as "tzdata==2025.2". automation.config.pythonscripting.scopeEnabled.label = Use scope and import wrapper automation.config.pythonscripting.scopeEnabled.description = This enables a scope module and and import wrapper.
    An scope module is an encapsulated module containing all openHAB jsr223 objects and can be imported with import scope
    Additionally you can run an import like from org.openhab.core import OpenHAB From 4aad05d86360d0167f38ddc7b494ba4398ebeaa1 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Sat, 20 Sep 2025 14:28:50 +0200 Subject: [PATCH 07/11] revert pythonscripting_de.properties Signed-off-by: Holger Hees --- .../OH-INF/i18n/pythonscripting_de.properties | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting_de.properties diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting_de.properties b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting_de.properties new file mode 100644 index 0000000000000..12763f8a40f6e --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/i18n/pythonscripting_de.properties @@ -0,0 +1,26 @@ +# add-on + +addon.pythonscripting.name = Python Scripting +addon.pythonscripting.description = Fügt eine Python 3.x Skript-Engine hinzu. + +# add-on config + +automation.config.pythonscripting.cachingEnabled.label = Zwischenspeichern von kompilierten openHAB Python-Helfermodulen (.pyc Dateien) +automation.config.pythonscripting.cachingEnabled.description = Zwischenspeichern der openHAB Python-Module für eine verbesserte Startup-Performance.
    Deaktivieren dieser Option führt zu einer langsameren Start-Performance, da Skripte bei jedem Start neu kompiliert werden müssen. +automation.config.pythonscripting.dependencyTrackingEnabled.label = Abhängigkeitsüberwachung aktivieren +automation.config.pythonscripting.dependencyTrackingEnabled.description = Die Abhängigkeitsüberwachung ermöglicht es Ihren Skripten, automatisch neu zu laden, wenn eine ihrer Abhängigkeiten aktualisiert wird. Sie können die Überwachung von Abhängigkeiten deaktivieren, wenn Sie eine gemeinsam genutzte Bibliothek bearbeiten oder aktualisieren möchten, aber nicht wollen, dass alle Skripte neu geladen werden, bis Sie sie testen können. +automation.config.pythonscripting.group.environment.label = Python-Umgebung +automation.config.pythonscripting.group.environment.description = Diese Gruppe definiert die Python-Umgebung. +automation.config.pythonscripting.group.system.label = Systemverhalten +automation.config.pythonscripting.group.system.description = Diese Gruppe definiert das Systemverhalten von Python. +automation.config.pythonscripting.helperEnabled.label = Installieren und automatisches Aktualisieren der openHAB Python-Helfermodule (erfordert Scope-Modul) +automation.config.pythonscripting.helperEnabled.description = OpenHAB Python-Helfermodule wie 'rule', 'logger', 'Registry', 'Timer', usw. bereitstellen und aktualisieren.
    Wenn deaktiviert, kann das openHAB Python-Helfermodul manuell installiert werden, indem es nach "/conf/automation/python/lib/openhab" kopiert wird. +automation.config.pythonscripting.injectionEnabled.label = Bereitstellung von Scope- und Helfer-Objekten für UI-basierte Regeln (erfordert Helfer-Module) +automation.config.pythonscripting.injectionEnabled.description = Dies bettet das Scope-Modul und die Kern-Helfermodule 'Registry' und 'logger' in UI-basierte Regeln ein. +automation.config.pythonscripting.injectionEnabled.option.2 = Automatische Einbettung nur für UI und Transformationsskripte aktivieren (bevorzugt) +automation.config.pythonscripting.injectionEnabled.option.1 = Automatische Einbettung für alle Skripte aktivieren +automation.config.pythonscripting.injectionEnabled.option.0 = Automatische Einbettung deaktivieren und stattdessen 'import'-Anweisungen verwenden +automation.config.pythonscripting.jythonEmulation.label = Jython-Emulation aktivieren +automation.config.pythonscripting.jythonEmulation.description = Ermöglicht Jython-Emulation in GraalPy. Es wird dringend empfohlen, Code auf GraalPy und Python 3 zu aktualisieren, da die Emulation zu Performanceeinbußen führen kann. Für Tipps und Anweisungen wird auf Jython Migration Guide verwiesen. +automation.config.pythonscripting.scopeEnabled.label = Scope und Import Wrapper verwenden +automation.config.pythonscripting.scopeEnabled.description = Aktiviert ein Scope-Modul und Import-Wrapper.
    Ein Scope-Modul ist ein eingekapseltes Modul mit allen openHAB JSR223 Objekten und kann mit import scope
    importiert werden. Zusätzlich können Sie einen Import, wie from org.openhab.core import OpenHAB verwenden. From 3977538accc4de10abbc29d3aab0e06aff41754e Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Fri, 26 Sep 2025 12:33:00 +0200 Subject: [PATCH 08/11] adapt latest README feedback Signed-off-by: Holger Hees --- bundles/org.openhab.automation.pythonscripting/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.automation.pythonscripting/README.md b/bundles/org.openhab.automation.pythonscripting/README.md index 5f680b7d9efc7..259411eb23bf6 100644 --- a/bundles/org.openhab.automation.pythonscripting/README.md +++ b/bundles/org.openhab.automation.pythonscripting/README.md @@ -66,7 +66,7 @@ Web based config dialog can be found via Web UI => Settings / Add-on Settings / Additionally, you can configure the Add-on via a config file `/openhab/services/pythonscripting.cfg` like below. -``` +```text # Use scope and import wrapper # # This enables a scope module and and import wrapper. @@ -189,7 +189,7 @@ As first, you must enable [VEnv](#enabling-venv). After this is enabled, you can /openhab/userdata/cache/org.openhab.automation.pythonscripting/venv/bin/pip install requests ``` -### Enable Pyhton Autocompletion +### Enable Python Autocompletion Before you can enable autocompletion, you must generate the required type hint stub files. Login into [openHAB console](https://www.openhab.org/docs/administration/console.html) and run @@ -215,7 +215,7 @@ As a final step, the folders `/openhab/conf/automation/python/libs/` and `/openh 2025-07-25 12:10:06.001 [ERROR] [g.internal.PythonScriptEngineFactory] - Graal python language not initialized. Restart openhab to initialize available graal languages properly. ``` -This can happen after a new Add-on installation, if JSScripting is active at the same time. +This can happen after a new Add-on installation, if JavaScript Scripting is active at the same time. Just restart openhab to initialize available graal languages properly. @@ -270,7 +270,7 @@ You should also check your logs for a message related to the helper lib deployme SystemError, Option python.NativeModules is set to 'true' and a second GraalPy context attempted to load a native module '' from path '.so'. At least one context in this process runs with 'IsolateNativeModules' set to false. Depending on the order of context creation, this means some contexts in the process cannot use native module, all other contexts must fall back and set python.NativeModules to 'false' to run native extensions in LLVM mode. This is recommended only for extensions included in the Python standard library. Running a 3rd party extension in LLVM mode requires a custom build of the extension and is generally discouraged due to compatibility reasons. ``` -These errors can occur if you use a native library in your external module but forgot to enable "native modules". Check the [Add-on configuration](#configuration) and enable +These errors can occur if you use a native library in your external module but forgot to enable "native modules". Check the [Add-on configuration](#configuration) and enable "native modules". ## Limitations From 08b3158e37371f4a882f874fbc91255af15e41d9 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Wed, 1 Oct 2025 09:46:57 +0200 Subject: [PATCH 09/11] fix readme Signed-off-by: Holger Hees --- bundles/org.openhab.automation.pythonscripting/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.automation.pythonscripting/README.md b/bundles/org.openhab.automation.pythonscripting/README.md index 259411eb23bf6..fa0273d5b1bb4 100644 --- a/bundles/org.openhab.automation.pythonscripting/README.md +++ b/bundles/org.openhab.automation.pythonscripting/README.md @@ -19,7 +19,7 @@ If you create an empty file called `test.py`, you will see a log line with infor ... [INFO ] [ort.loader.AbstractScriptFileWatcher] - (Re-)Loading script '/openhab/conf/automation/python/test.py' ``` -To enable debug logging, use the [console logging](https://openhab.org/docs/administration/logging.html) commands to +Use the [console logging](https://openhab.org/docs/administration/logging.html) commands to enable debug logging for the automation functionality: ```text @@ -28,7 +28,7 @@ log:set DEBUG org.openhab.automation.pythonscripting ### Rules -Lets start with a simple rule +Let’s start with a simple script ```python from openhab import rule From 91107a37e0e9faf640dcc1003bc8a21f7c4140d1 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Mon, 6 Oct 2025 10:42:42 +0200 Subject: [PATCH 10/11] implement latest Feedback Signed-off-by: Holger Hees --- .../PythonScriptEngineConfiguration.java | 266 +--------------- .../internal/PythonScriptEngineFactory.java | 3 +- .../internal/PythonScriptEngineHelper.java | 300 ++++++++++++++++++ .../internal/console/handler/UpdateCmd.java | 3 +- .../internal/context/ContextInput.java | 2 +- .../internal/context/ContextOutput.java | 2 +- .../internal/context/ContextOutputLogger.java | 2 +- .../graal/GraalPythonBindings.java | 4 +- .../main/resources/OH-INF/config/config.xml | 10 +- 9 files changed, 324 insertions(+), 268 deletions(-) create mode 100644 bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineHelper.java diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java index c85c40c9d6569..0cbc2f4eb830d 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineConfiguration.java @@ -12,37 +12,21 @@ */ package org.openhab.automation.pythonscripting.internal; -import java.io.BufferedInputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.module.ModuleDescriptor.Version; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javax.script.ScriptContext; -import javax.script.ScriptEngine; -import javax.script.ScriptException; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.graalvm.polyglot.Context; import org.openhab.core.OpenHAB; import org.openhab.core.automation.module.script.ScriptEngineFactory; import org.openhab.core.config.core.Configuration; @@ -68,8 +52,8 @@ public class PythonScriptEngineConfiguration { private static final String SYSTEM_PROPERTY_JAVA_IO_TMPDIR = "java.io.tmpdir"; - private static final String PATH_SEPARATOR = FileSystems.getDefault().getSeparator(); - private static final String RESOURCE_SEPARATOR = "/"; + public static final String PATH_SEPARATOR = FileSystems.getDefault().getSeparator(); + public static final String RESOURCE_SEPARATOR = "/"; public static final Path PYTHON_DEFAULT_PATH = Paths.get(OpenHAB.getConfigFolder(), "automation", "python"); public static final Path PYTHON_LIB_PATH = PYTHON_DEFAULT_PATH.resolve("lib"); @@ -77,10 +61,7 @@ public class PythonScriptEngineConfiguration { public static final Path PYTHON_OPENHAB_LIB_PATH = PYTHON_LIB_PATH.resolve("openhab"); public static final Path PYTHON_WRAPPER_FILE_PATH = PYTHON_OPENHAB_LIB_PATH.resolve("__wrapper__.py"); - private static final Path PYTHON_INIT_FILE_PATH = PYTHON_OPENHAB_LIB_PATH.resolve("__init__.py"); - - private static final Pattern VERSION_PATTERN = Pattern.compile("__version__\\s*=\\s*\"([^\"]*)\"", - Pattern.CASE_INSENSITIVE); + public static final Path PYTHON_INIT_FILE_PATH = PYTHON_OPENHAB_LIB_PATH.resolve("__init__.py"); public static final int INJECTION_DISABLED = 0; public static final int INJECTION_ENABLED_FOR_ALL_SCRIPTS = 1; @@ -135,7 +116,7 @@ public PythonScriptEngineConfiguration(Map config, PythonScriptE p.load(is); String version = p.getProperty("helperlib.version"); providedHelperLibVersion = parseHelperLibVersion(version); - version = p.getProperty("graalpy.version"); + version = FrameworkUtil.getBundle(Context.class).getVersion().toString(); graalVersion = Version.parse(version); } } catch (IOException e) { @@ -148,15 +129,15 @@ public PythonScriptEngineConfiguration(Map config, PythonScriptE Properties props = System.getProperties(); props.setProperty(SYSTEM_PROPERTY_POLYGLOT_ENGINE_USERRESOURCECACHE, bindingDirectory.toString()); - bytecodeDirectory = initDirectory(bindingDirectory.resolve("resources")); - venvDirectory = initDirectory(bindingDirectory.resolve("venv")); + bytecodeDirectory = PythonScriptEngineHelper.initDirectory(bindingDirectory.resolve("resources")); + venvDirectory = PythonScriptEngineHelper.initDirectory(bindingDirectory.resolve("venv")); Path venvPythonBin = venvDirectory.resolve("bin").resolve("graalpy"); if (Files.exists(venvPythonBin)) { venvExecutable = venvPythonBin; } - initHelperLib(); + installedHelperLibVersion = PythonScriptEngineHelper.initHelperLib(this, providedHelperLibVersion); this.update(config, factory); } @@ -195,10 +176,14 @@ private void update(Map config, ScriptEngineFactory factory) { configuration = new Configuration(config).as(PythonScriptingConfiguration.class); if (!oldPipModules.equals(configuration.pipModules)) { - initPipModules(factory); + PythonScriptEngineHelper.initPipModules(this, factory); } } + public void setHelperLibVersion(Version version) { + installedHelperLibVersion = version; + } + public boolean isScopeEnabled() { return configuration.scopeEnabled; } @@ -283,229 +268,4 @@ public Map getConfigurations() { return entry.getValue().toString(); })); } - - private void initPipModules(ScriptEngineFactory factory) { - String pipModulesConfig = configuration.pipModules.strip(); - if (pipModulesConfig.isEmpty()) { - return; - } - - if (!isVEnvEnabled()) { - logger.error("Can't install pip modules. VEnv not enabled."); - return; - } - - List pipModules = Arrays.stream(pipModulesConfig.split(",")).map(String::trim) - .filter(module -> !module.isEmpty()).collect(Collectors.toList()); - - if (pipModules.isEmpty()) { - return; - } - - final String pipCode = """ - import subprocess - import sys - - command_list = [sys.executable, "-m", "pip", "install"] + pipModules - proc = subprocess.run(command_list, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, check=False) - if proc.returncode != 0: - print(proc.stdout) - exit(1) - """; - - ScriptEngine engine = factory.createScriptEngine(PythonScriptEngineFactory.SCRIPT_TYPE); - if (engine != null) { - engine.getContext().setAttribute("pipModules", pipModules, ScriptContext.ENGINE_SCOPE); - try { - logger.info("Checking for pip module{} '{}'", pipModules.size() > 1 ? "s" : "", - configuration.pipModules); - engine.eval(pipCode); - } catch (ScriptException e) { - logger.warn("Error installing pip module{}", pipModules.size() > 1 ? "s" : ""); - logger.trace("TRACE:", unwrap(e)); - } - } else { - logger.warn("Can't install pip modules. No script engine available."); - } - } - - private void initHelperLib() { - if (!isHelperEnabled()) { - return; - } - - logger.info("Checking for helper libs version '{}'", providedHelperLibVersion); - - String resourceLibPath = PYTHON_OPENHAB_LIB_PATH.toString().substring(PYTHON_DEFAULT_PATH.toString().length()) - + PATH_SEPARATOR; - if (!RESOURCE_SEPARATOR.equals(PATH_SEPARATOR)) { - resourceLibPath = resourceLibPath.replace(PATH_SEPARATOR, RESOURCE_SEPARATOR); - } - - if (Files.exists(PYTHON_INIT_FILE_PATH)) { - try { - String content = Files.readString(PYTHON_INIT_FILE_PATH, StandardCharsets.UTF_8); - Matcher currentMatcher = VERSION_PATTERN.matcher(content); - if (currentMatcher.find()) { - installedHelperLibVersion = Version.parse(currentMatcher.group(1)); - @SuppressWarnings("null") - int compareResult = installedHelperLibVersion.compareTo(providedHelperLibVersion); - if (compareResult >= 0) { - if (compareResult > 0) { - logger.info("Newer helper libs version '{}' already installed.", installedHelperLibVersion); - } - return; - } - } else { - logger.warn("Unable to parse current version. Proceed as if it was not installed."); - } - } catch (IOException | IllegalArgumentException e) { - logger.warn("Unable to detect current version. Proceed as if it was not installed."); - } - } - - if (installedHelperLibVersion != null) { - logger.info("Update helper libs version '{}' to version {}.", installedHelperLibVersion, - providedHelperLibVersion); - } else { - logger.info("Install helper libs version {}.", providedHelperLibVersion); - } - - try { - Path bakLibPath = preProcessHelperLibUpdate(); - - try { - Enumeration resourceFiles = FrameworkUtil.getBundle(PythonScriptEngineConfiguration.class) - .findEntries(resourceLibPath, "*.py", true); - - while (resourceFiles.hasMoreElements()) { - URL resourceFile = resourceFiles.nextElement(); - String resourcePath = resourceFile.getPath(); - - ClassLoader clsLoader = PythonScriptEngineConfiguration.class.getClassLoader(); - if (clsLoader != null) { - try (InputStream is = clsLoader.getResourceAsStream(resourcePath)) { - Path target = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH - .resolve(resourcePath.substring(resourcePath.lastIndexOf(RESOURCE_SEPARATOR) + 1)); - - Files.copy(is, target); - initFile(target); - } - } else { - throw new IllegalArgumentException("Class loader is null"); - } - } - - postProcessHelperLibUpdateOnSuccess(providedHelperLibVersion, bakLibPath); - } catch (Exception e) { - postProcessHelperLibUpdateOnFailure(bakLibPath); - throw e; - } - } catch (Exception e) { - logger.error("Exception during helper lib initialisation", e); - } - } - - public void initHelperLib(String remoteUrl, Version remoteVersion) throws URISyntaxException, IOException { - Path bakLibPath = null; - try { - bakLibPath = preProcessHelperLibUpdate(); - URL zipfileUrl = new URI(remoteUrl).toURL(); - InputStream in = new BufferedInputStream(zipfileUrl.openStream(), 1024); - ZipInputStream stream = new ZipInputStream(in); - byte[] buffer = new byte[1024]; - ZipEntry entry; - while ((entry = stream.getNextEntry()) != null) { - if (!entry.getName().contains("/src/") || entry.isDirectory()) { - continue; - } - - int read; - StringBuilder sb = new StringBuilder(); - while ((read = stream.read(buffer, 0, 1024)) >= 0) { - sb.append(new String(buffer, 0, read)); - } - - Path target = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH - .resolve(new File(entry.getName()).getName()); - Files.write(target, sb.toString().getBytes()); - initFile(target); - } - - postProcessHelperLibUpdateOnSuccess(remoteVersion, bakLibPath); - } catch (IOException | URISyntaxException e) { - postProcessHelperLibUpdateOnFailure(bakLibPath); - throw e; - } - } - - private @Nullable Path preProcessHelperLibUpdate() throws IOException { - Path bakLibPath = null; - // backup old lib folder before update - if (Files.exists(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH)) { - bakLibPath = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH.getParent() - .resolve(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH.getFileName() + ".bak"); - Files.move(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH, bakLibPath); - } - initDirectory(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH); - return bakLibPath; - } - - private void postProcessHelperLibUpdateOnSuccess(Version version, @Nullable Path bakLibPath) throws IOException { - String content = Files.readString(PYTHON_INIT_FILE_PATH, StandardCharsets.UTF_8).trim(); - Matcher currentMatcher = VERSION_PATTERN.matcher(content); - content = currentMatcher.replaceAll("__version__ = \"" + version.toString() + "\""); - Files.writeString(PYTHON_INIT_FILE_PATH, content, StandardCharsets.UTF_8); - installedHelperLibVersion = version; - - if (bakLibPath != null) { - // cleanup old files - try (var dirStream = Files.walk(bakLibPath)) { - dirStream.map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete); - } - } - } - - private void postProcessHelperLibUpdateOnFailure(@Nullable Path bakLibPath) throws IOException { - // cleanup new files - try (var dirStream = Files.walk(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH)) { - dirStream.map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete); - } - - if (bakLibPath != null) { - // restore old files - Files.move(bakLibPath, PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH); - } - } - - private void initFile(Path path) { - File file = path.toFile(); - file.setReadable(true, false); - file.setWritable(true, true); - } - - private Path initDirectory(Path path) { - File directory = path.toFile(); - if (!directory.exists()) { - directory.mkdirs(); - directory.setExecutable(true, false); - directory.setReadable(true, false); - directory.setWritable(true, true); - } - return path; - } - - /** - * Unwraps the cause of an exception, if it has one. - * - * Since a user cares about the _Python_ stack trace of the throwable, not - * the details of where openHAB called it. - */ - private static Throwable unwrap(Throwable e) { - Throwable cause = e.getCause(); - if (cause != null) { - return cause; - } - return e; - } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineFactory.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineFactory.java index 139b9e5ce9506..7b4f426f8aef3 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineFactory.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineFactory.java @@ -72,7 +72,7 @@ public PythonScriptEngineFactory(final @Reference PythonDependencyTracker python this.language = PythonScriptEngine.getLanguage(); if (this.language == null) { logger.error( - "Graal python language not initialized. Restart openhab to initialize available graal languages properly."); + "Graal Python language not initialized. Restart openHAB to initialize available Graal languages properly."); } String defaultTimezone = ZoneId.systemDefault().getId(); @@ -81,7 +81,6 @@ public PythonScriptEngineFactory(final @Reference PythonDependencyTracker python logger.warn( "User timezone '{}' is different than openhab regional timezone '{}'. Python Scripting is running with timezone '{}'.", defaultTimezone, providerTimezone, defaultTimezone); - // System.setProperty("user.timezone", "Australia/Tasmania"); } } diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineHelper.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineHelper.java new file mode 100644 index 0000000000000..afaaf67f1b409 --- /dev/null +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngineHelper.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2010-2025 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.pythonscripting.internal; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleDescriptor.Version; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.automation.module.script.ScriptEngineFactory; +import org.osgi.framework.FrameworkUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Processes Python Configuration Parameters. + * + * @author Holger Hees - Initial contribution + */ +@NonNullByDefault +public class PythonScriptEngineHelper { + + private final static Logger logger = LoggerFactory.getLogger(PythonScriptEngineHelper.class); + + private static final Pattern VERSION_PATTERN = Pattern.compile("__version__\\s*=\\s*\"([^\"]*)\"", + Pattern.CASE_INSENSITIVE); + + public static void initPipModules(PythonScriptEngineConfiguration configuration, ScriptEngineFactory factory) { + String pipModulesConfig = configuration.getPIPModules().strip(); + if (pipModulesConfig.isEmpty()) { + return; + } + + if (!configuration.isVEnvEnabled()) { + logger.error("Can't install pip modules. VEnv not enabled."); + return; + } + + List pipModules = Arrays.stream(pipModulesConfig.split(",")).map(String::trim) + .filter(module -> !module.isEmpty()).collect(Collectors.toList()); + + if (pipModules.isEmpty()) { + return; + } + + final String pipCode = """ + import subprocess + import sys + + command_list = [sys.executable, "-m", "pip", "install"] + pipModules + proc = subprocess.run(command_list, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, check=False) + if proc.returncode != 0: + print(proc.stdout) + exit(1) + """; + + ScriptEngine engine = factory.createScriptEngine(PythonScriptEngineFactory.SCRIPT_TYPE); + if (engine != null) { + engine.getContext().setAttribute("pipModules", pipModules, ScriptContext.ENGINE_SCOPE); + try { + logger.info("Checking for pip module{} '{}'", pipModules.size() > 1 ? "s" : "", + configuration.getPIPModules()); + engine.eval(pipCode); + } catch (ScriptException e) { + logger.warn("Error installing pip module{}", pipModules.size() > 1 ? "s" : ""); + logger.trace("TRACE:", unwrap(e)); + } + } else { + logger.warn("Can't install pip modules. No script engine available."); + } + } + + public static @Nullable Version initHelperLib(PythonScriptEngineConfiguration configuration, + Version providedHelperLibVersion) { + Version installedHelperLibVersion = null; + + if (!configuration.isHelperEnabled()) { + return installedHelperLibVersion; + } + + logger.info("Checking for helper libs version '{}'", configuration.getProvidedHelperLibVersion()); + + String resourceLibPath = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH.toString() + .substring(PythonScriptEngineConfiguration.PYTHON_DEFAULT_PATH.toString().length()) + + PythonScriptEngineConfiguration.PATH_SEPARATOR; + if (!PythonScriptEngineConfiguration.RESOURCE_SEPARATOR + .equals(PythonScriptEngineConfiguration.PATH_SEPARATOR)) { + resourceLibPath = resourceLibPath.replace(PythonScriptEngineConfiguration.PATH_SEPARATOR, + PythonScriptEngineConfiguration.RESOURCE_SEPARATOR); + } + + if (Files.exists(PythonScriptEngineConfiguration.PYTHON_INIT_FILE_PATH)) { + try { + String content = Files.readString(PythonScriptEngineConfiguration.PYTHON_INIT_FILE_PATH, + StandardCharsets.UTF_8); + Matcher currentMatcher = VERSION_PATTERN.matcher(content); + if (currentMatcher.find()) { + installedHelperLibVersion = Version.parse(currentMatcher.group(1)); + @SuppressWarnings("null") + int compareResult = installedHelperLibVersion.compareTo(providedHelperLibVersion); + if (compareResult >= 0) { + if (compareResult > 0) { + logger.info("Newer helper libs version '{}' already installed.", installedHelperLibVersion); + } + return installedHelperLibVersion; + } + } else { + logger.warn("Unable to parse current version. Proceed as if it was not installed."); + } + } catch (IOException | IllegalArgumentException e) { + logger.warn("Unable to detect current version. Proceed as if it was not installed."); + } + } + + if (installedHelperLibVersion != null) { + logger.info("Update helper libs version '{}' to version {}.", installedHelperLibVersion, + providedHelperLibVersion); + } else { + logger.info("Install helper libs version {}.", providedHelperLibVersion); + } + + try { + Path bakLibPath = preProcessHelperLibUpdate(); + + try { + Enumeration resourceFiles = FrameworkUtil.getBundle(PythonScriptEngineHelper.class) + .findEntries(resourceLibPath, "*.py", true); + + while (resourceFiles.hasMoreElements()) { + URL resourceFile = resourceFiles.nextElement(); + String resourcePath = resourceFile.getPath(); + + ClassLoader clsLoader = PythonScriptEngineHelper.class.getClassLoader(); + if (clsLoader != null) { + try (InputStream is = clsLoader.getResourceAsStream(resourcePath)) { + Path target = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH + .resolve(resourcePath.substring( + resourcePath.lastIndexOf(PythonScriptEngineConfiguration.RESOURCE_SEPARATOR) + + 1)); + + Files.copy(is, target); + initFile(target); + } + } else { + throw new IllegalArgumentException("Class loader is null"); + } + } + + installedHelperLibVersion = postProcessHelperLibUpdateOnSuccess(providedHelperLibVersion, bakLibPath); + } catch (Exception e) { + postProcessHelperLibUpdateOnFailure(bakLibPath); + throw e; + } + } catch (Exception e) { + logger.error("Exception during helper lib initialisation", e); + } + + return installedHelperLibVersion; + } + + public static void installHelperLib(String remoteUrl, Version remoteVersion, + PythonScriptEngineConfiguration configuration) throws URISyntaxException, IOException { + Path bakLibPath = null; + try { + bakLibPath = preProcessHelperLibUpdate(); + URL zipfileUrl = new URI(remoteUrl).toURL(); + InputStream in = new BufferedInputStream(zipfileUrl.openStream(), 1024); + ZipInputStream stream = new ZipInputStream(in); + byte[] buffer = new byte[1024]; + ZipEntry entry; + while ((entry = stream.getNextEntry()) != null) { + if (!entry.getName().contains("/src/") || entry.isDirectory()) { + continue; + } + + int read; + StringBuilder sb = new StringBuilder(); + while ((read = stream.read(buffer, 0, 1024)) >= 0) { + sb.append(new String(buffer, 0, read)); + } + + Path target = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH + .resolve(new File(entry.getName()).getName()); + Files.write(target, sb.toString().getBytes()); + initFile(target); + } + + Version version = postProcessHelperLibUpdateOnSuccess(remoteVersion, bakLibPath); + configuration.setHelperLibVersion(version); + } catch (IOException | URISyntaxException e) { + postProcessHelperLibUpdateOnFailure(bakLibPath); + throw e; + } + } + + private static @Nullable Path preProcessHelperLibUpdate() throws IOException { + Path bakLibPath = null; + // backup old lib folder before update + if (Files.exists(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH)) { + bakLibPath = PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH.getParent() + .resolve(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH.getFileName() + ".bak"); + Files.move(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH, bakLibPath); + } + initDirectory(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH); + return bakLibPath; + } + + private static Version postProcessHelperLibUpdateOnSuccess(Version version, @Nullable Path bakLibPath) + throws IOException { + String content = Files.readString(PythonScriptEngineConfiguration.PYTHON_INIT_FILE_PATH, StandardCharsets.UTF_8) + .trim(); + Matcher currentMatcher = VERSION_PATTERN.matcher(content); + content = currentMatcher.replaceAll("__version__ = \"" + version.toString() + "\""); + Files.writeString(PythonScriptEngineConfiguration.PYTHON_INIT_FILE_PATH, content, StandardCharsets.UTF_8); + + if (bakLibPath != null) { + // cleanup old files + try (var dirStream = Files.walk(bakLibPath)) { + dirStream.map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete); + } + } + + return version; + } + + private static void postProcessHelperLibUpdateOnFailure(@Nullable Path bakLibPath) throws IOException { + // cleanup new files + try (var dirStream = Files.walk(PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH)) { + dirStream.map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete); + } + + if (bakLibPath != null) { + // restore old files + Files.move(bakLibPath, PythonScriptEngineConfiguration.PYTHON_OPENHAB_LIB_PATH); + } + } + + /** + * Unwraps the cause of an exception, if it has one. + * + * Since a user cares about the _Python_ stack trace of the throwable, not + * the details of where openHAB called it. + */ + private static Throwable unwrap(Throwable e) { + Throwable cause = e.getCause(); + if (cause != null) { + return cause; + } + return e; + } + + private static void initFile(Path path) { + File file = path.toFile(); + file.setReadable(true, false); + file.setWritable(true, true); + } + + public static Path initDirectory(Path path) { + File directory = path.toFile(); + if (!directory.exists()) { + directory.mkdirs(); + directory.setExecutable(true, false); + directory.setReadable(true, false); + directory.setWritable(true, true); + } + return path; + } +} diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/UpdateCmd.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/UpdateCmd.java index 4f9a54f696177..cd917018f298d 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/UpdateCmd.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/console/handler/UpdateCmd.java @@ -27,6 +27,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.automation.pythonscripting.internal.PythonScriptEngineConfiguration; +import org.openhab.automation.pythonscripting.internal.PythonScriptEngineHelper; import org.openhab.core.io.console.Console; import com.google.gson.JsonArray; @@ -169,7 +170,7 @@ public void updateInstall(String requestedVersionString) { String zipballUrl = releaseObj.get("zipball_url").getAsString(); try { - config.initHelperLib(zipballUrl, releaseVersion); + PythonScriptEngineHelper.installHelperLib(zipballUrl, releaseVersion, config); console.println("Version '" + releaseVersion.toString() + "' installed successfully"); } catch (URISyntaxException | IOException e) { console.println("Fetching release zip '" + zipballUrl + "' file failed. "); diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java index 6ba563d4f976d..7917ac48860b4 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextInput.java @@ -19,7 +19,7 @@ import org.eclipse.jdt.annotation.Nullable; /** - * ContextInput implementation + * ContextInput wraps an @nullable InputStream, used as Standard Input for pythonscripting * * @author Holger Hees - Initial contribution */ diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutput.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutput.java index 16e770a255c27..8af33cbdce289 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutput.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutput.java @@ -18,7 +18,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; /** - * ContextOutput implementation + * ContextOutput wraps an @nullable OutputStream, used as Standard Output for pythonscripting * * @author Holger Hees - Initial contribution */ diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutputLogger.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutputLogger.java index 5baa9f32cafb4..a57120fbb123a 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutputLogger.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/context/ContextOutputLogger.java @@ -19,7 +19,7 @@ import org.slf4j.event.Level; /** - * ContextLogOutputStream implementation + * ContextOutputLogger is the default way of handling the Standard Output for pythonscripting. * * @author Holger Hees - Initial contribution */ diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonBindings.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonBindings.java index a88db47a74f26..36ba0e355be16 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonBindings.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonBindings.java @@ -93,8 +93,8 @@ public Set> entrySet() { /** * Closes the current context and makes it unusable. * - * Error happens in guest language will throw an {@link PolyglotException}. - * Operations performed after closing will throw an {@link IllegalStateException}. + * @throws PolyglotException when an error happens in guest language + * @throws IllegalStateException when an operation is performed after closing */ @Override public void close() throws PolyglotException, IllegalStateException { diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml index 0ab3e6d03caf7..6c19f290fee47 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.automation.pythonscripting/src/main/resources/OH-INF/config/config.xml @@ -36,9 +36,7 @@
    - + This injects the scope and helper Registry and logger into rules. @@ -58,9 +56,7 @@ - - - + Native modules are sometimes necessary for pip modules which depends on native libraries. false true @@ -82,7 +78,7 @@ true - + Jython Migration Guide. From 510673859f4bc4bef84514520fb65a0ffb785565 Mon Sep 17 00:00:00 2001 From: Holger Hees Date: Tue, 7 Oct 2025 10:24:07 +0200 Subject: [PATCH 11/11] implement latest Feedback Signed-off-by: Holger Hees --- bundles/org.openhab.automation.pythonscripting/README.md | 6 +++--- .../pythonscripting/internal/PythonScriptEngine.java | 2 +- .../scriptengine/graal/GraalPythonScriptEngine.java | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.automation.pythonscripting/README.md b/bundles/org.openhab.automation.pythonscripting/README.md index fa0273d5b1bb4..ac74309a444bb 100644 --- a/bundles/org.openhab.automation.pythonscripting/README.md +++ b/bundles/org.openhab.automation.pythonscripting/README.md @@ -122,7 +122,7 @@ Additionally, you can configure the Add-on via a config file `/openhab/services/ ``` ::: tip Configuration note -If you use the marketplace version of this Add-on, it is neccessary to use the config file. OpenHAB has a bug which prevents the web based config dialog to work correctly for `kar` file based Add-ons. +If you use the marketplace version of this Add-on, it is necessary to use the config file. OpenHAB has a bug which prevents the web based config dialog to work correctly for `kar` file based Add-ons. ::: ### Console @@ -133,9 +133,9 @@ The [openHAB Console](https://www.openhab.org/docs/administration/console.html) 2. `pythonscripting console` provides an interactive python console where you can try live python features

    ![Pythonscripting console](doc/console_pythonscripting_console.png) -3. `pythonscripting update` allowes you to check, list, update or downgrade your helper lib

    ![Pythonscripting update](doc/console_pythonscripting_update.png) +3. `pythonscripting update` allows you to check, list, update or downgrade your helper lib

    ![Pythonscripting update](doc/console_pythonscripting_update.png) -4. `pythonscripting pip` allowes you check, install or remove external python modules.

    Check [pip usage](#using-pip-to-install-external-modules) for details +4. `pythonscripting pip` allows you check, install or remove external python modules.

    Check [pip usage](#using-pip-to-install-external-modules) for details 5. `pythonscripting typing` generates python type hint stub files.

    Check [python autocompletion](#enable-pyhton-autocompletion) for details diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngine.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngine.java index 7e531bc945f83..54c486982a133 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngine.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/PythonScriptEngine.java @@ -256,7 +256,7 @@ protected void beforeInvocation() throws PolyglotException { if (engineIdentifier != null) { this.engineIdentifier = engineIdentifier; } else { - logger.warn("Failed to retrieve script indentifier"); + logger.warn("Failed to retrieve script identifier"); } logger.debug("Initializing GraalPython script engine '{}' ...", this.engineIdentifier); diff --git a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java index 3fcac74f893a4..2678675fde32b 100644 --- a/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java +++ b/bundles/org.openhab.automation.pythonscripting/src/main/java/org/openhab/automation/pythonscripting/internal/scriptengine/graal/GraalPythonScriptEngine.java @@ -94,14 +94,14 @@ public GraalPythonScriptEngineFactory getFactory() { @Override public Bindings createBindings() { - // Creating a new binding to replace the current one is not needed i context of pythonscripting - throw new IllegalArgumentException("Creating new bindings is not supported in the context of pythonscripting"); + // Creating a new binding to replace the current one is not needed for scripting addons + throw new IllegalArgumentException("Creating new bindings is not supported"); } @Override public void setBindings(Bindings bindings, int scope) { - // Setting a new binding to replace the current one is not needed in context of pythonscripting - throw new IllegalArgumentException("Setting bindings is not supported in the context of pythonscripting"); + // Setting a new binding to replace the current one is not needed for scripting addons + throw new IllegalArgumentException("Setting bindings is not supported"); } @Override

    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 literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_typing.png b/bundles/org.openhab.automation.pythonscripting/doc/console_pythonscripting_typing.png new file mode 100644 index 0000000000000000000000000000000000000000..4551d809fb4847a100590ed8ed405c548e2cb9c6 GIT binary patch literal 72494 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