From 3b36004396fd9c986daad5fd3ad8ea5a7d664046 Mon Sep 17 00:00:00 2001
From: Lorenzo Ruozzi
Plugin allowing to import data from Akeneo PIM to your Sylius store.
- - -> **Please note!!**+ Plugin allowing to import data from Akeneo PIM to your Sylius store. +
++ + -{% endif %} -``` - -### Importing configurable products, product options and their values - -If you have product models on Akeneo this plugin will create relative configurable products along with their variants on -Sylius. To make this possible **you must create on Sylius the product options with the same code of the related Akeneo's -family variant axes attributes**. You can leave the product options empty (without values) because they will be created -during actual product import. To do so you must configure the **product options value handler** in -the `config/packages/webgriffe_sylius_akeneo_plugin.yaml`: - -```yaml -# config/packages/webgriffe_sylius_akeneo_plugin.yaml - -webgriffe_sylius_akeneo: - # ... - value_handlers: - product: - # ... - product_option: - type: 'product_option' -``` - -The `product_option` value handler doesn't need any configuration; it must be configured only once, and it will handle -all the product options created on Sylius. - -### Importing product prices - -If you manage product prices on Akeneo you can import them on Sylius. To do so you have to configure the channel pricing -value handler in the `config/packages/webgriffe_sylius_akeneo_plugin.yaml` file: - -```yaml -# config/packages/webgriffe_sylius_akeneo_plugin.yaml - -webgriffe_sylius_akeneo: - # ... - value_handlers: - product: - # ... - price: - type: 'channel_pricing' - options: - $akeneoAttribute: 'price' -``` - -In the `$akeneoAttribute` option you have to set the code of the **Akeneo price attribute** where you store your -products prices. Then they will be imported into Sylius for channels whose base currency is the same as the price -currency on Akeneo. - -If you also manage the original price on Akeneo, you can import it using the same channel price value handler. Add -the `$syliusPropertyPath` option to the configuration and specify which price you are importing: price (default) or -original_price. -As above use the `$akeneoAttribute` option to specify the code of the **Akeneo original price attribute** where you -store your products original prices. - -```yaml -# config/packages/webgriffe_sylius_akeneo_plugin.yaml - -webgriffe_sylius_akeneo: - # ... - value_handlers: - product: - # ... - price: - type: 'channel_pricing' - options: - $akeneoAttribute: 'price' - $syliusPropertyPath: 'price' # Not required, it is the default - original_price: - type: 'channel_pricing' - options: - $akeneoAttribute: 'original_price' - $syliusPropertyPath: 'original_price' -``` - -### Importing product metrical properties - -**NB. This feature is only available from Akeneo PIM version 5** - -If you manage product metrical attributes on Akeneo you can import them on Sylius as product properties (like weight, -length, height and depth). To do this, you have to configure the metrical properties value handler in -the `config/packages/webgriffe_sylius_akeneo_plugin.yaml` file: - -```yaml -# config/packages/webgriffe_sylius_akeneo_plugin.yaml - -webgriffe_sylius_akeneo: - # ... - value_handlers: - product: - # ... - weight: - type: 'metric_property' - options: - $akeneoAttributeCode: 'weight' - $propertyPath: 'weight' - height: - type: 'metric_property' - options: - $akeneoAttributeCode: 'height' - $propertyPath: 'height' - $akeneoUnitMeasurementCode: 'CENTIMETER' -``` - -For each `metric_property` value handler you have to configure, in `$propertyPath`, the Sylius product property path of -the property where to store the value of the Akeneo attribute whose code is configured with `$akeneoAttributeCode`. Be -sure this is a metrical attribute on Akeneo. -In the same way you can import other product metrical properties like height and other custom properties you possibly -added to your store. -In addition, you can decide in which unit of measure to import the value. To do this, enter the desired Akeneo unit of -measurement code in the attribute `$akeneoUnitMeasurementCode`. If this field is not specified, the plugin will import -the value using Akeneo's standard unit of measure. -For more information about Akeneo's units of measurement, consult -the [documentation](https://help.akeneo.com/pim/serenity/articles/manage-your-measurements.html). - -### Importing product-taxons associations - -This plugin **will not import Akeneo categories into Sylius taxons**, but **it will associate Sylius products to -existing taxons** based on Akeneo product-categories associations. This plugin will associate products only to those -Sylius taxons which already exist on Sylius and have the same code of their related Akeneo categories. In this way, -products taxons association import does not need any configuration and you can have all the categories you want on -Akeneo, even those you don't want on your Sylius store. Indeed, if there are products associated to Akeneo categories -which doesn't exist on Sylius, the import will succeed with no error. - -So, all you have to do is to **create on Sylius those taxons that you want products associated with** when importing -from Akeneo, paying attention to **assign the same code** of the corresponding category on Akeneo. - -### Importing product associations - -This plugin will also import product associations. It's a zero configuration import. All you have to do is to **create -on Sylius the same association types that you have on Akeneo** paying attention to assign the same association type -code. If you have some association type on Akeneo that you don't need on your store, simply do not create it on Sylius -and product associations importer will ignore it. - -### Import data - -To actually import data from Akeneo PIM you have two options: import from UI in the admin section or from the CLI with -the **webgriffe:akeneo:import** command. -Import procedure assumes that [Symfony Messenger](https://symfony.com/doc/current/messenger.html) is installed and -working as required since Sylius v1.11. - -#### Import from admin Akeneo PIM button - -This button allows you to import a product directly from the admin index page. - -![Schedule Akeneo PIM import button](schedule-akeneo-import-button.png) - -#### Import from CLI - -To import multiple items at the same time you can use the `webgriffe:akeneo:import` console command: - -```bash -bin/console webgriffe:akeneo:import --since="2020-01-30" -``` - -This will import all Akeneo entities updated after the provided date. - -You can also use a "since file" where to read the since date: - -```bash -echo "2022-01-30" > var/storage/akeneo-sincefile.txt -bin/console webgriffe:akeneo:import --since-file="var/storage/akeneo-sincefile.txt" -``` - -When run with the since file, the import command will write the current date/time to the since file after the importing -process is terminated. This is useful when you put the import command in cron: - -```bash -* * * * * /usr/bin/php /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --since-file=/path/to/sylius/var/storage/akeneo-import-sincefile.txt -``` - -This way the import command is run repeatedly importing only products modified since the last command execution. - -You can also import items only for specific importers: - -```bash -bin/console webgriffe:akeneno:import --importer="Product" --importer="MyImporter" --since="2020-01-30" -``` - -You can also import items regardless of their last update date: - -```bash -bin/console webgriffe:akeneno:import --all -``` - -### Products reconciliation - -Product reconciliation can be useful when one or more products are deleted on Akeneo. By default, reconciliation does -not delete products on Sylius but places them in a deactivated state. -This is because the Sylius structure does not allow you to delete products if they are associated with any order. -To reconcile the products you can use the webgriffe:akeneo:reconcile console command: - -```bash -bin/console webgriffe:akeneo:reconcile -``` - -It could be useful to add also this command to your scheduler to run automatically every day or whatever you want. - -### Suggested crontab - -To make all importers and other plugin features work automatically the following is the suggested crontab: - -``` -0 * * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --all --importer="AttributeOptions" -* * * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --since-file=/path/to/sylius/var/storage/akeneo-import-sincefile.txt --importer="Product" --importer="ProductAssociations" -0 */6 * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:reconcile -``` - -This will: - -* Import the update of all attribute options every hour -* Import, every minute, all products that have been modified since the last execution, along with their associations -* Reconcile Akeneo deleted products every 6 hours - -Import and Reconcile commands uses a [lock mechanism](https://symfony.com/doc/current/console/lockable_trait.html) which -prevents running them if another instance of the same command is already running. - -## Architecture & customization - -> This plugin makes use of [Symfony Messenger](https://symfony.com/doc/current/messenger.html) component. It is highly -> recommended to have a minimum knowledge of these component to understand how this integration works. - -This plugin has basically two entry points: - -* The UI admin import button, this will import only products -* The Import CLI command, this will import both product, product associations and attribute options - -Both this entry points deals to identify entities to import from Akeneo. When they have collected them they dispatch -an `Webgriffe\SyliusAkeneoPlugin\Message\ItemImport` message on the messenger default bus. -By default, in the configuration this message is handled by the main bus, the same bus used as default by Sylius for -catalog promotions. This means that, if you have configured the main bus to run synchronously the import will be -executed at the same time, otherwise it will be handled by the Messenger queue asynchronously. -We suggest to run it asynchronously especially if you plan to run the import command manually infrequently or with -option --all. - -To be able to import entities (or even only different parts of each entity), -the `Webgriffe\SyliusAkeneoPlugin\MessageHandler\ItemImportHandler` (the Messenger message handler) use an ** -importer registry** which holds all the registered **importers**. - -An importer is a service implementing the `Webgriffe\SyliusAkeneoPlugin\ImporterInterface` and that mainly holds the -logic about how to import its Akeneo entities. If you want to import from Akeneo other entities not implemented in this -plugin you have can implement your own importer. You can also replace an importer provided with this plugin by -decorating or replacing its service definition. - -To implement a new custom importer create a class which implements the `Webgriffe\SyliusAkeneoPlugin\ImporterInterface`: - -```php -// src/Importer/CustomImporter.php - -namespace App\Importer; - -use Webgriffe\SyliusAkeneoPlugin\ImporterInterface; - -final class CustomImporter implements ImporterInterface -{ - // ... -} -``` - -Then define the importer with the `webgriffe_sylius_akeneo.importer` tag: - -```yaml -# config/services.yaml - -app.custom.importer: - class: App\Importer\CustomImporter - tags: - - { name: 'webgriffe_sylius_akeneo.importer' } -``` - -Anyway, this plugin already implement the following importers. - -### Product Importer - -Akeneo is a PIM (Product Information Management) system so its job is to manage product data. For this reason, this -Sylius -Akeneo plugin is focused on importing products and provides a **product -importer** (`\Webgriffe\SyliusAkeneoPlugin\Product\Importer`). - -This product importer processes Akeneo product data through the following components: - -#### Taxons resolver - -A **taxons resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\TaxonsResolverInterface`) which is responsible to return -the list of Sylius taxons for a given Akeneo product. The provided implementation of the taxons resolver is -the `Webgriffe\SyliusAkeneoPlugin\Product\AlreadyExistingTaxonsResolver` class which returns the already existent Sylius -taxons which have the same code as the related Akeneo categories. - -#### Product options resolver - -A **product options resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolverInterface`) which is -responsible to return the related Sylius's **product option(s)** when the product being imported is part of a parent -product model. The provided implementation of the product options resolver is -the `Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolver` class, which returns already existing product options -but also creates new ones if needed. - -#### Channels resolver - -A **channels resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\ChannelsResolverInterface`) which is responsible to -return the list of Sylius channels where the products should be enabled. The provided implementation of the channels' -resolver is the `Webgriffe\SyliusAkeneoPlugin\Product\AllChannelsResolver` class which simply enables the product in all -available Sylius channels. - -#### Status resolver - -A **status resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\StatusResolverInterface`) which is responsible to return -the Sylius product status (enabled or disabled, true or false). The provided implementation of the status resolver is -the `Webgriffe\SyliusAkeneoPlugin\Product\StatusResolver` which returns the same product status of the related Akeneo -product, but only if this doesn't belong to a parent product model, otherwise it will always return true (enabled). This -is because in Sylius the product status is at product level and not (also) at product variant level; instead, in Akeneo -the status is only at product level and not at product model level. So, in Akeneo, you could have only one disabled -product variant for a parent product which have several other variants enabled. This situation can't be mapped on Sylius -at present. - -#### Value handlers resolver - -A **value handlers resolver** (`Webgriffe\SyliusAkeneoPlugin\ValueHandlersResolverInterface`) which is responsible to -return a list of **value handlers** (`Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface`) for each Akeneo product -attribute value. - -The provided implementation of the value handlers resolver is -the `Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver` which returns, for each attribute value, the list of -all the value handlers supporting that attribute value sorted by a priority. Each value handler returned by the resolver -for a given attribute is then called to handle that value. - -For more detail on how the Product importer works look at the code of -the `Webgriffe\SyliusAkeneoPlugin\Product\Importer::import()` method. - -#### Value handlers - -By default, the provided `Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver` is configured with value handlers -specified in the `webgriffe_sylius_akeneo.value_handlers.product` array as explained in the configuration paragraph. -This plugin already provides some value handler implementations that are: - -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\AttributeValueHandler` (type `generic_attribute`) it will automatically - handle Sylius attributes whose attribute code matches Akeneo attribute code. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ChannelPricingValueHandler` (type `channel_pricing`): it sets the value - found on a given Akeneo price attribute (`options.$akeneoAttribute`) as the Sylius product's channels price or - original price for - channels whose base currency is the price currency of the Akeneo price. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler` (type `file_attribute`): it saves the file - downloaded from the Akeneo file attribute (`options.$akeneoAttributeCode`) to the given destination - path (`options.$downloadPath`). -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\GenericPropertyValueHandler` (type `generic_property`): using - the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets - the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property - path (`options.$propertyPath`) of both product and product variant. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler` (type `image`): it downloads the image found on a given - Akeneo image attribute (`options.$akeneoAttributeCode`) and sets it as a Sylius product image with a provided type - string (`options.$syliusImageType`). -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImmutableSlugValueHandler` (type `immutable_slug`): it slugifies the value - found on a given Akeneo attribute (`options.$akeneoAttributeToSlugify`) and sets it on the Sylius slug product - translation property. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\MetricPropertyValueHandler` (type `metric_property`) using - the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets - the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property - path (`options.$propertyPath`) of both product and product variant. It automatically converts it to the default unit - of measurement or the one specified (`options.$akeneoUnitMeasurementCode`). -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler` (type `product_option`): it sets the value found - on a given Akeneo attribute as a Sylius product option value on the product variant. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\TranslatablePropertyValueHandler` (type `translatable_property`): using - the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets - the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property - path (`options.$translationPropertyPath`) of both product and product variant translations. - -To add a custom value handler to the resolver you can implement your own by implementing -the `Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface` and then tag it with -the `webgriffe_sylius_akeneo.product.value_handler` tag: - -```yaml -# config/services.yaml - -app.my_custom_value_handler: - class: App\MyCustomValueHandler - tags: - - { name: 'webgriffe_sylius_akeneo.product.value_handler', priority: 42 } -``` +
-### Product associations importer +## What does this plugin do? -Another provided importer is the **product associations -importer** (`Webgriffe\SyliusAkeneoPlugin\ProductAssociations\Importer`). This importer imports the Akeneo products -associations to the corresponding Sylius products associations. The association types must already exist on Sylius with -the same code they have on Akeneo. +The _SyliusAkeneoPlugin_ takes care of importing and updating products, product associations and attributes from _Akeneo_ to _Sylius_. -### Attribute options importer +## How can I install the plugin on my Sylius store? -Another provided importer is the **attribute options -importer** (`\Webgriffe\SyliusAkeneoPlugin\AttributeOptions\Importer`). This importer imports the Akeneo simple select -and multi select attributes options into Sylius select attributes. The select attributes must already exist on Sylius -with the same code they have on Akeneo. +Please, check the documentation at the [Installation](docs/installation.html) step. -## Contributing +## Where do I start? -See `docs/Contributing.md` file. +First, we recommend that you read the entire documentation. Then you could start to +install the plugin and use the basic features it gives such as the abandoned cart. You could also think to suggest some +new features that this plugin could add. So, let's start! 🚀 ## License diff --git a/UPGRADE-2.0.md b/UPGRADE-2.0.md deleted file mode 100644 index eda05484..00000000 --- a/UPGRADE-2.0.md +++ /dev/null @@ -1,181 +0,0 @@ -# UPGRADE FROM `v1.16.2` TO `v2.0.0` - -In the 2.0 version, we have introduced the Symfony Messenger component and removed all deprecations. Symfony Messenger -has allowed us to remove all the Queue manager infrastructure so that we can now focus only on the Akeneo - Sylius -exchange. Obviously, the removal of the queue has provoked also the removal of the admin queue page, which is useful for -some store managers to check for product imports, but we are already working on other solutions to provide a similar -tool to the administrators! - -Here you can find all the passages to upgrade your plugin to v2.0 starting from v1.16.2. Naturally, we have written all -the passages for a simple project without customizations. In this case, you can find more in the below section [Codebase](#Codebase) which -contains all the detailed edits applied to this version and, obviously all the BC contained in this major version. - -## Simple upgrade - -Remove occurrences of `Resources` in `config/packages/webgriffe_sylius_akeneo_plugin.yaml`: - -```diff -- - { resource: "@WebgriffeSyliusAkeneoPlugin/Resources/config/config.yaml" } -+ - { resource: "@WebgriffeSyliusAkeneoPlugin/config/config.yaml" } -``` - -Remove occurrences of `Resources` in `config/routes/webgriffe_sylius_akeneo_plugin.yaml` or where you import the plugin routes: - -```diff -webgriffe_sylius_akeneo_plugin_admin: -- resource: "@WebgriffeSyliusAkeneoPlugin/Resources/config/admin_routing.yaml" -+ resource: "@WebgriffeSyliusAkeneoPlugin/config/admin_routing.yaml" -``` - -Be sure that your configuration in `config/packages/webgriffe_sylius_akeneo_plugin.yaml` is already using the new name arguments -as specified [here](https://github.com/webgriffe/SyliusAkeneoPlugin/releases/tag/1.13.0). - -If you do not have already installed the official Ajeneo PHP SDK client we suggest to follow the installation instructions -showed [here](https://github.com/akeneo/api-php-client#installation). - -After having installed the Akeneo PIM client you can now require the new version of plugin: - -```bash -composer require webgriffe/sylius-akeneo-plugin ^2.0 -``` - -Run migration diff command and then execute it: - -```bash -bin/console doctrine:migrations:diff -bin/console doctrine:migrations:migrate -``` - -Now you have to update your crontab configuration by following this example: - -``` -0 * * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --all --importer="AttributeOptions" -* * * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --since-file=/path/to/sylius/var/storage/akeneo-import-sincefile.txt --importer="Product" --importer="ProductAssociations" -0 */6 * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:reconcile -``` - -If everything works well you have just completed your upgrade! Obviously, we suggest that you check the import of some products, -product associations and attribute options before considering the upgrade complete 😉. - -## Codebase - -### Use PHP 8 syntax ([#128](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/128)) - -#### TL;DR -Refactored the codebase to use PHP 8 syntax. - -#### BC Breaks - -##### Changed - - [BC] The return type of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface#convert() changed from no type to array|bool|int|string - - [BC] The parameter $value of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface#convert() changed from no type to a non-contravariant array|bool|int|string - - [BC] The parameter $value of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface#convert() changed from no type to array|bool|int|string - - [BC] The parameter $value of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverter#convert() changed from no type to a non-contravariant array|bool|int|string - -### API client replacement ([#125](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/125)) - -#### TL;DR -Removed our API Client interface in favor of the Akeneo PHP SDK client. - -#### BC Breaks - -##### Changed - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\AttributeOptions\Importer#__construct() changed from Webgriffe\SyliusAkeneoPlugin\AttributeOptions\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\Converter\UnitMeasurementValueConverter#__construct() changed from Webgriffe\SyliusAkeneoPlugin\MeasurementFamiliesApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\Product\Importer#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolver#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\ProductAssociations\Importer#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - -##### Removed - - [BC] Class Webgriffe\SyliusAkeneoPlugin\AttributeOptions\ApiClientInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\ApiClientInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\MeasurementFamiliesApiClientInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\ApiClient has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\FamilyAwareApiClientInterface has been deleted - -### Remove deprecations ([#130](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/130)) - -#### TL;DR -Removed all deprecations of the v1.x releases. - -#### BC Breaks - -##### Changed - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverter#__construct() increased from 0 to 1 - - [BC] The parameter $translator of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverter#__construct() changed from Symfony\Contracts\Translation\TranslatorInterface|null to a non-contravariant Symfony\Contracts\Translation\TranslatorInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\Product\Importer#__construct() increased from 12 to 13 - - [BC] The parameter $variantStatusResolver of Webgriffe\SyliusAkeneoPlugin\Product\Importer#__construct() changed from Webgriffe\SyliusAkeneoPlugin\Product\StatusResolverInterface|null to a non-contravariant Webgriffe\SyliusAkeneoPlugin\Product\StatusResolverInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\AttributeValueHandler#__construct() increased from 3 to 4 - - [BC] The parameter $valueConverter of Webgriffe\SyliusAkeneoPlugin\ValueHandler\AttributeValueHandler#__construct() changed from Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface|null to a non-contravariant Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\ChannelPricingValueHandler#__construct() increased from 4 to 5 - - [BC] The parameter $propertyAccessor of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ChannelPricingValueHandler#__construct() changed from Symfony\Component\PropertyAccess\PropertyAccessorInterface|null to a non-contravariant Symfony\Component\PropertyAccess\PropertyAccessorInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler#__construct() increased from 5 to 7 - - [BC] The parameter $translationLocaleProvider of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler#__construct() changed from Sylius\Component\Resource\Translation\Provider\TranslationLocaleProviderInterface|null to a non-contravariant Sylius\Component\Resource\Translation\Provider\TranslationLocaleProviderInterface - - [BC] The parameter $translator of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler#__construct() changed from Symfony\Contracts\Translation\TranslatorInterface|null to a non-contravariant Symfony\Contracts\Translation\TranslatorInterface - -##### Removed - - [BC] Property Webgriffe\SyliusAkeneoPlugin\DependencyInjection\WebgriffeSyliusAkeneoExtension::$valueHandlersTypesDefinitions was removed - -### Others ([#134](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/134), [#147](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/147), [#150](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/150)) - -#### TL;DR - - The route `webgriffe_sylius_akeneo_product_enqueue` has been renamed in `webgriffe_sylius_akeneo_product_import`. - - The grid resource route `webgriffe_sylius_akeneo_admin_queue_item` has been removed. - - The grid template action `enqueueProduct` has been renamed in `importProduct`. - - The grid `webgriffe_sylius_akeneo_admin_queue_item` has been removed. - - The `sylius_admin_product` grid action `enqueue` has been renamed in `import`. - - A new `Webgriffe\SyliusAkeneoPlugin\Message\ItemImport` Symfony Messenger message has been added. - - The config `bind_arguments_by_name` under the `webgriffe_sylius_akeneo_plugin` has been removed. - - The config `resources` under the `webgriffe_sylius_akeneo_plugin` has been removed. - - Messages are changed, please view the new `translations/messages.en.yaml` file. - - The commands `webgriffe:akeneo:consume` and `webgriffe:akeneo:queue-cleanup` has been removed. - - The command `webgriffe:akeneo:enqueue` has been renamed to `webgriffe:akeneo:import`. - -#### BC Breaks - -##### Changed - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler#__construct() increased from 4 to 5 - - [BC] The parameter $akeneoAttributeCode of Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler#__construct() changed from string to a non-contravariant Webgriffe\SyliusAkeneoPlugin\TemporaryFilesManagerInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler#__construct() increased from 5 to 6 - - [BC] The parameter $akeneoAttributeCode of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler#__construct() changed from string to a non-contravariant Webgriffe\SyliusAkeneoPlugin\TemporaryFilesManagerInterface - -##### Removed - - [BC] Method Sylius\Bundle\ResourceBundle\DependencyInjection\Extension\AbstractResourceExtension#registerResources() was removed - - [BC] These ancestors of Webgriffe\SyliusAkeneoPlugin\DependencyInjection\WebgriffeSyliusAkeneoExtension have been removed: ["Sylius\\Bundle\\ResourceBundle\\DependencyInjection\\Extension\\AbstractResourceExtension"] - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Menu\AdminMenuListener has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\EventSubscriber\CommandEventSubscriber has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Controller\ProductEnqueueController has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Doctrine\ORM\QueueItemRepository has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Command\ConsumeCommand has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Command\EnqueueCommand has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Command\QueueCleanupCommand has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Repository\CleanableQueueItemRepositoryInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Repository\QueueItemRepositoryInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Entity\QueueItemInterface has been deleted - -### Test changes - -#### TL;DR -Edits made on test classes during the previous changes. - -#### BC Breaks - -##### Removed - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Page\Admin\QueueItem\IndexPage has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Page\Admin\QueueItem\IndexPageInterface has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Setup\QueueContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Db\QueueContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Cli\QueueCleanupCommandContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Cli\ConsumeCommandContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Cli\EnqueueCommandContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\System\DateTimeContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Transform\QueueItemContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Ui\Admin\ManagingQueueItems has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\DependencyInjection\CompilerPassTest has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\DependencyInjection\ExtensionTest has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\TestDouble\DateTimeBuilder has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\TestDouble\ApiClientMock has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\TemporaryFilesManagerTest has been deleted diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..abf75b2e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,18 @@ +# just-the-docs-template + +## Building and previewing your site locally + +Assuming [Jekyll] and [Bundler] are installed on your computer: + +1. Change your working directory to the root directory of your site. + +2. Run `bundle install`. + +3. Run `bundle exec jekyll serve` to build your site and preview it at `localhost:4000`. + + The built site is stored in the directory `_site`. + +---- + +[Jekyll]: https://jekyllrb.com +[Bundler]: https://bundler.io diff --git a/docs/architecture_and_customization.md b/docs/architecture_and_customization.md new file mode 100644 index 00000000..b2d937ee --- /dev/null +++ b/docs/architecture_and_customization.md @@ -0,0 +1,180 @@ +--- +title: Architecture & customization +layout: page +nav_order: 5 +--- + +# Architecture & customization + +> This plugin makes use of [Symfony Messenger](https://symfony.com/doc/current/messenger.html) component. It is highly +> recommended to have a minimum knowledge of these component to understand how this integration works. + +This plugin has basically two entry points: + +* The UI admin import button, this will import only products +* The Import CLI command, this will import both product, product associations and attribute options + +Both this entry points deals to identify entities to import from Akeneo. When they have collected them they dispatch +an `Webgriffe\SyliusAkeneoPlugin\Message\ItemImport` message on the messenger default bus. +By default, in the configuration this message is handled by the main bus, the same bus used as default by Sylius for +catalog promotions. This means that, if you have configured the main bus to run synchronously the import will be +executed at the same time, otherwise it will be handled by the Messenger queue asynchronously. +We suggest to run it asynchronously especially if you plan to run the import command manually infrequently or with +option --all. + +To be able to import entities (or even only different parts of each entity), +the `Webgriffe\SyliusAkeneoPlugin\MessageHandler\ItemImportHandler` (the Messenger message handler) use an ** +importer registry** which holds all the registered **importers**. + +An importer is a service implementing the `Webgriffe\SyliusAkeneoPlugin\ImporterInterface` and that mainly holds the +logic about how to import its Akeneo entities. If you want to import from Akeneo other entities not implemented in this +plugin you have can implement your own importer. You can also replace an importer provided with this plugin by +decorating or replacing its service definition. + +To implement a new custom importer create a class which implements the `Webgriffe\SyliusAkeneoPlugin\ImporterInterface`: + +```php +// src/Importer/CustomImporter.php + +namespace App\Importer; + +use Webgriffe\SyliusAkeneoPlugin\ImporterInterface; + +final class CustomImporter implements ImporterInterface +{ + // ... +} +``` + +Then define the importer with the `webgriffe_sylius_akeneo.importer` tag: + +```yaml +# config/services.yaml + +app.custom.importer: + class: App\Importer\CustomImporter + tags: + - { name: 'webgriffe_sylius_akeneo.importer' } +``` + +Anyway, this plugin already implement the following importers. + +### Product Importer + +Akeneo is a PIM (Product Information Management) system so its job is to manage product data. For this reason, this +Sylius +Akeneo plugin is focused on importing products and provides a **product +importer** (`\Webgriffe\SyliusAkeneoPlugin\Product\Importer`). + +This product importer processes Akeneo product data through the following components: + +#### Taxons resolver + +A **taxons resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\TaxonsResolverInterface`) which is responsible to return +the list of Sylius taxons for a given Akeneo product. The provided implementation of the taxons resolver is +the `Webgriffe\SyliusAkeneoPlugin\Product\AlreadyExistingTaxonsResolver` class which returns the already existent Sylius +taxons which have the same code as the related Akeneo categories. + +#### Product options resolver + +A **product options resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolverInterface`) which is +responsible to return the related Sylius's **product option(s)** when the product being imported is part of a parent +product model. The provided implementation of the product options resolver is +the `Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolver` class, which returns already existing product options +but also creates new ones if needed. + +#### Channels resolver + +A **channels resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\ChannelsResolverInterface`) which is responsible to +return the list of Sylius channels where the products should be enabled. The provided implementation of the channels' +resolver is the `Webgriffe\SyliusAkeneoPlugin\Product\AllChannelsResolver` class which simply enables the product in all +available Sylius channels. + +#### Status resolver + +A **status resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\StatusResolverInterface`) which is responsible to return +the Sylius product status (enabled or disabled, true or false). The provided implementation of the status resolver is +the `Webgriffe\SyliusAkeneoPlugin\Product\StatusResolver` which returns the same product status of the related Akeneo +product, but only if this doesn't belong to a parent product model, otherwise it will always return true (enabled). This +is because in Sylius the product status is at product level and not (also) at product variant level; instead, in Akeneo +the status is only at product level and not at product model level. So, in Akeneo, you could have only one disabled +product variant for a parent product which have several other variants enabled. This situation can't be mapped on Sylius +at present. + +#### Value handlers resolver + +A **value handlers resolver** (`Webgriffe\SyliusAkeneoPlugin\ValueHandlersResolverInterface`) which is responsible to +return a list of **value handlers** (`Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface`) for each Akeneo product +attribute value. + +The provided implementation of the value handlers resolver is +the `Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver` which returns, for each attribute value, the list of +all the value handlers supporting that attribute value sorted by a priority. Each value handler returned by the resolver +for a given attribute is then called to handle that value. + +For more detail on how the Product importer works look at the code of +the `Webgriffe\SyliusAkeneoPlugin\Product\Importer::import()` method. + +#### Value handlers + +By default, the provided `Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver` is configured with value handlers +specified in the `webgriffe_sylius_akeneo.value_handlers.product` array as explained in the configuration paragraph. +This plugin already provides some value handler implementations that are: + +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\AttributeValueHandler` (type `generic_attribute`) it will automatically + handle Sylius attributes whose attribute code matches Akeneo attribute code. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ChannelPricingValueHandler` (type `channel_pricing`): it sets the value + found on a given Akeneo price attribute (`options.$akeneoAttribute`) as the Sylius product's channels price or + original price for + channels whose base currency is the price currency of the Akeneo price. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler` (type `file_attribute`): it saves the file + downloaded from the Akeneo file attribute (`options.$akeneoAttributeCode`) to the given destination + path (`options.$downloadPath`). +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\GenericPropertyValueHandler` (type `generic_property`): using + the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets + the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property + path (`options.$propertyPath`) of both product and product variant. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler` (type `image`): it downloads the image found on a given + Akeneo image attribute (`options.$akeneoAttributeCode`) and sets it as a Sylius product image with a provided type + string (`options.$syliusImageType`). +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImmutableSlugValueHandler` (type `immutable_slug`): it slugifies the value + found on a given Akeneo attribute (`options.$akeneoAttributeToSlugify`) and sets it on the Sylius slug product + translation property. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\MetricPropertyValueHandler` (type `metric_property`) using + the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets + the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property + path (`options.$propertyPath`) of both product and product variant. It automatically converts it to the default unit + of measurement or the one specified (`options.$akeneoUnitMeasurementCode`). +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler` (type `product_option`): it sets the value found + on a given Akeneo attribute as a Sylius product option value on the product variant. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\TranslatablePropertyValueHandler` (type `translatable_property`): using + the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets + the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property + path (`options.$translationPropertyPath`) of both product and product variant translations. + +To add a custom value handler to the resolver you can implement your own by implementing +the `Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface` and then tag it with +the `webgriffe_sylius_akeneo.product.value_handler` tag: + +```yaml +# config/services.yaml + +app.my_custom_value_handler: + class: App\MyCustomValueHandler + tags: + - { name: 'webgriffe_sylius_akeneo.product.value_handler', priority: 42 } +``` + +### Product associations importer + +Another provided importer is the **product associations +importer** (`Webgriffe\SyliusAkeneoPlugin\ProductAssociations\Importer`). This importer imports the Akeneo products +associations to the corresponding Sylius products associations. The association types must already exist on Sylius with +the same code they have on Akeneo. + +### Attribute options importer + +Another provided importer is the **attribute options +importer** (`\Webgriffe\SyliusAkeneoPlugin\AttributeOptions\Importer`). This importer imports the Akeneo simple select +and multi select attributes options into Sylius select attributes. The select attributes must already exist on Sylius +with the same code they have on Akeneo. diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..3ed4c191 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,27 @@ +--- +title: Configuration +layout: page +nav_order: 3 +--- + +# Configuration + +First you must configure your Akeneo API connection parameters. Edit +the `config/packages/webgriffe_sylius_akeneo_plugin.yaml` file by adding the following content: + +```yaml +# ... + +webgriffe_sylius_akeneo: + api_client: + # These values are from the official Akeneo PIM demo, replace with yours. + base_url: 'https://demo.akeneo.com/' + username: 'admin' + password: 'admin' + client_id: '1_demo_client_id' + secret: 'demo_secret' +``` + +Pay attention that among these parameters there are some sensitive configuration that you probably don't want to commit +in your VCS. There are different solutions to this problem, like env configurations and secrets. Refer +to [Symfony best practices doc](https://symfony.com/doc/current/best_practices.html#configuration) for more info. diff --git a/docs/Contributing.md b/docs/contributing.md similarity index 98% rename from docs/Contributing.md rename to docs/contributing.md index 49b50a0c..a3b15104 100644 --- a/docs/Contributing.md +++ b/docs/contributing.md @@ -1,3 +1,9 @@ +--- +title: Contributing +layout: page +nav_order: 6 +--- + # Contributing To contribute to this plugin clone this repository, create a branch for your feature or bugfix, do your changes and then @@ -162,7 +168,7 @@ bin/console app:taxa-import ``` Then create a new connection in Connect > Connection settings with type data destination and save the credentials in you .env.local. - + ```dotenv WEBGRIFFE_SYLIUS_AKENEO_PLUGIN_BASE_URL=http://localhost:8080/ WEBGRIFFE_SYLIUS_AKENEO_PLUGIN_CLIENT_ID=SAMPLE diff --git a/schedule-akeneo-import-button.png b/docs/images/schedule-akeneo-import-button.png similarity index 100% rename from schedule-akeneo-import-button.png rename to docs/images/schedule-akeneo-import-button.png diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..164a2867 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,35 @@ +--- +title: Home +layout: home +nav_order: 0 +--- + +# Webgriffe Sylius Akeneo plugin + +> **Please note!!**W$3GLi=*n&t{BY67$?~Wcl5yuYl3Pr3~+~XJQ zFN5Pni!%rdD2x29G5}lVTTh)HH)6m=5gGaxNFLbUegr>|fgM5R^nxU2Z6EjuBZJL5 zz1)OT@W?uV%kS$+g)!>d%$NF)STrBC1_tAQ{zhQag=#PQR0f|gB8N6Hgjg$xn2tn- zW$be`on9Y~gkQ6mu!-GM@}NljwhO}!cFd=^X2NFA@`zQw%tTqXI~m&=dawulIMif< zA_0TpJ(cA@HHBRs)ne%QEri+hq;)QKoSTR&+40$=kPH!#Mas3CE|adlx1Y0%s2{I? zu1jr;5!Ji9ynh6_un?q34`b^9wNrPccNp{{Rz(Q WuWkt
$tf9NEQgtuqqG)V6YCv29_tzFs>(DOO)e^*yP-U#yjx&i z7*&|AYQYrA^o9id%OTDxjx=tUsZ8x_5oytfN&ceCB9bC$)v_XpGF_2Y5n5rzWPG7o zF_lVFHcyU%imQ5*I$2>t5w&7#!JRHjnNcA@R{P}ZiRoN>_3WsikpYW$T(~wQHoW_k zr3OU#mbpL22FBiu3g*m|@)zW0uII%S)F>8f?*_(;QH<73m|1RGBv|rV!k~9qCIy`n z%iATRmLm<|Qzh3>+s~{Y>on_>5b+0OLXG+%`n8K5E$S`OS5LilZWFJt&+2y5$9=ga z9YcqShhkS4 8lpbFbT8_giF-%4R<@ zNvcS%7;(!!W?Ut6VgbaYiI?TLj-ksx`OqQ1#=y<6z|fheo`;!-mKTv1H6Ua5r0PRe zgc+4tz(&u;_+Y}1sbp9kjrQ9&sHDj(jc IZsa8A>X0uHT>^bwG1K{Nq$yDgRFYuz)6UE-^x}BC+Se zNkJ##yW;4b^PQx@skpsC(m`c-t(_d7>@}TB+A)ShatTtu$M)6t74^MRs#O{*INv@x z3)!Z~6G<^*7Z=RtCYPwn;*}5ytq4t|KJEW7Kky@Qk~6&r(98ODKQz00FhT$y@k015 z !oyCbvtrt~1gF7D` zKQg~>5}LC*@0cOm+#3Fw=x7Yy(LJB1+nzqlIYZetm>J#EK39CqYy#||c@ 7o=z3(YGDN+RQ zVp#zUP<-<+fz4-wI(%i)#;+KoUvGF0!?=7E$r%@z13p!m+B76tI66t%vfRI0Ox{e; zNJUt_Tk)sEo+Jw;)7SdcWHFd!ewlgcNoqpsNb35AU8~YT_E33aEXj1FGTfA^e=wem z_0WKz*7*MY*sr~~R#HBaSh8k=xay*ok#ajpBN(2M$OKs-v255u$+=d`s`Nlq2X)g_ zJ$R;a!;`)4LiwwTtmMxrWrgkB^c3Hs8_Q2N8?y%-QI-3 wq*!|)>hpX!PaI_ z=NS$Q#WqD4F9gQrI^K;{7fO{Zo4lS(5~mbrqcc!fGIvt*UeUQ2P~K=?+z#c|5wTsh zZGs3HdUoP=Qqc=Q_J|Lfb%@l*m4RA171(vmpsDeNuT4$oZ_g+8Ct*63h&kb7;qJTX z+f?T?XJ_;$xUrL+@RKXQ088{TDlFj%=+cPdc)^0E!&Az5YM*1rtKqt2+GIfF+ej|T z8otJwM5yjOa?Km7XVxUuOtZ?f9+8riyA}vb&|UX&f_JZcq(=G(K*=TAsq$#8ukc1i zJfA+_Aayx?d-uoO@sjn)OmZrxK+~{fT9cjd+06{A*;FAmge=nF4C1y&xT?Hs8r9FD zF<-`YzjFt4tdn-_R~s(2nQ8{tAU^E!yD!{dB~rBW4#7SxG kb!Xo3iWs zTdr^Phgx_Mrw4c lQy>Yg{XX}z z1{bkc)hmg|RgIgh!%=vFxVoO~yOQ^EKl_(8Bz+6+E8sQo-E7~-H}0ly-OKMI&IbGD z##}uP&s$tQVeG`5XBPomokzVZA3f5~ea*ZMuA _}w=T;ddAVM0cMQ#Iwe;t4PZra!w-b*_ysS`6pM|b!XX$g#cv|#h;Q@!P 9;WP faxkUgX60giODl{;Lqj9z@W~9IEFtwT@`wL~ zXf2$a>;P eFz^{_y;-z{wHtZ&)=8vB7% z@OLdh(bCP-T2sQ(=7BvAa|pBZv-1f4gWx}!{ypVCN!1)p9mGL450p;A|7P&Ni2r-z z|DW(5b87v2PTsfw&y@eI TO-&pZaKL4ZkfziTPf^2^YO&Ci*RZIa1Nfb#| z;+?A7qrFsgL)EFcJCU02TstiRNRP63AMqF_MaYHk*S~a0>H5k$^HRYjMt&| ?LmK3n2J`RSpbgPMw-nUhRsZX=B=`8GDDodZ zL@`Kcu& 7_EBVm5~ zlc!CBUbNjcOV}}m_YVoUKYsQ< _n1GC8xp4ODeCJB{ZqC_$bTe;M}$8LP#I#E=AaYo zO8kz0%Bh!c_kL4dL)j23eRKK2RLBA^|3vD)<@i;`Pz)0iv&pcExIf`Y^RXV6_%z7> zhs*ocR!;as(I1phMHHqn)PsG0jhp6kwr_;iKJ*up|Br%U7Qqiqe~< Gu&?hes`x(?ox`Wh7|d zW}?DE9i6vgtA`4=zkZG~K5u7ko%83tGe<}m4>d&pnaCe_g8#siGSFwd6opqE* `D3&1@PI~&@$D2B=AiF;v2yBc@M|%OeY|^s;gQ(Q4Cnezwsa4P;ZdRCr213~Q z1U^bl*!YIAM0C+F3> +@QQ*YglYIRP<`Py?F<6HX`RJrQ3xJiKiO~2 zxj5(Oh<|mCs7z@3KNS8i)3mfhyCg!Gko_#a%5|e-bVI^H>J8MJ3n !IW4mlX#dn!1+ZW;uI@4XbZ41^g*z!B)t0D@QoxmoM0^1<9?F?Uq#;@6NV# zUJG8{EkIt?t~HJE7dK5kD8ssv#@xsz5fLfL*e3h)KeSdfe#KwfLNFjzW$BNln^1yb z0!D$e&^#CGt4{sqn{k_hMoj?=7c$3w`Upp|l$C?YtCrO0p@vNG&wBS7PFEa*nwwwu zMx*ENqT2rf1ODR8|5A7`7*7e>U1ytBon(8~e?@Ck&N)g^Hh>$O*2%1nR(xB6$$To& zNXVLreDIp1QG!!o+p)oXo~5R8j==O1ULPa1^j^3BW&HoQ2~3Jir`+k f8`5-$YP-_3NC$_o5%HP{+((8QwGJk3eUQ+<>0@ z11VEuw&(Ek)l6xTk-39nD}#jDeEP<(3kl%zR+EIJjLzlH>1AwQ>!X~_{H>e(EjGoX zhq2P1TX*Tr;B!?rpsA6nK|7mWN{`6=YwfvNf|tD1XM%aF=YsjIyIV8RBv&0zbYz=H zP= t7byB)rlrr$bcB8LxVwk1^>lTK;7JNlj*6@?Ky)(ioUA{`NLIeBmR7s?oX 1^r#c#dMy@2ZezG>vGWz1(B^^4;IHOH750xCWkz~)IC5k(ELv2{U^myz zcM^fYG(i2l8f+aGYB5=Nl7j~4h{R0+0o=A1maQPYs`&*e4SjD{vJSC*8Ts(eyFE%l zyWWTmH+el2m%U*rah0kWb^Td0NvI%Q(C*OqC7IolCae0J#IUo8m!CFMx{v3*#urb6 zu{II&m9v6u)S9kBw4LIaw1?;3(n?BtyQC5MIrK&|{xcig-sd-xoaq9#+F!pd(YU$} zH#a^5f^|Xyr!5e|;6Fl0q6WW3*>Zq#YG-kZnY~%`xi||nwCori+JLEIp8r)vBi~8( zD306t;Hqtk1*;ZXlikwLS 50)V52Iu_yX%GvM5>Bwl Q%lddLHHKu}W7t>r(y7C7G1^Arz ;8hQUZmS!v)vg{drUmt^R5y^MaZ0asI%L{3j=N9DQ(s>% zVRd2#+blfB94maO*g7`7$3P!OyUSGFRPThrHtc57Z(C!y8b8?|j#RR8HiXg}p6pf{ zazwu4?_=KU(*RZ5a6WJsp86w{+eU$`v2h09c*8bZ;%oQJfA5`CpR&@hM=WvdYG0&^ zRQ0~o`&k2bC%{^!vxl=DqDEj;ab|_kS8Z2?sGK#N`6BvaGjqTawtJ`(RM7R7&CCVP zRe^S4ay feuD3{!lW!CW{*4t%_dq{lSXRe&a@Csmfi3O z#N6~l&p=^}-Pu}VTCnGW@SBb*d1bQVkfN+&fPs16B~y>~a4Rc!$^IfhIk*ICG&QNG zDM4{mGqrQ)$q;kBg?7P`4K~K-&? *RadLm;{5&Q0BOvl}CM}GH&R`g)sSw7MG-Q(WA~sg`zMfiGTC-=Bsp#e? z*r)DPW)^j0v@#u?ds*NtL3t8FES)Kykwiubdlc8W%d@E6s7h6gvMQ;J( DF4rYDD4 m}a1rSW;Y7X2mmYZRH4%cCE5FH{m4lo^cx%b`1qxLi#6asxUs9MD;3( zGNUv3jPB7O6w`dW0zq{58ZxCh^(Y?m;GZXR2rUy=34;?qpGP52o=8i5!XoW8r)4%G z^}lVRxa+YEN|1i8)b2VepBNI3Bd({GO<)$WR2-UdnM)%gfpq?TKPeQT+E2#;pu8)8 z(MKAhKoY`M_?2ni(kZc{_4&P`sjI3ks=9BN8qp+Iqm+;JH>WNog5@KkgaY#dq@rH^ z*=m&hlOc+BjRthI$17g;jAPNOLdmOH^(NW0Vom#}^RHhsaXVWFNQ6%r{9t _(j+M=rT|VAal@ z)yHM+S;>dAs3uORvGR0WqI2&~qts3MI*PAvF~OE<4(I*$n8((0tpsW_ErYp`og}LU zm28E1V+Fd#!Xq mHZTRViwOV>UEXIr*CtYC dJnJkMF}!^NGV% j321xJfWXy-Q; ;_hE&qkq(th@qoIQ`>!z9!Oi zQp|I077?7}1ALGFLmAp?Bs1Qt&ii{vw;F>CBvffwtq%Op*~gS#!wNV1T;WUytSNDR zPexyzc{1GkED(A+<2Hh?&wkX7)_O#y6??z!No!kurQgk4caJO}u{WtPBthWmNtf?9 z1snm60>^+9Z0uRM1}%MXJl4*kgvgbygJ!uQeZ7!A<`=U`k5(7sZ}p5XZ7gjFdd-UK z0d)9;l*ST^tneF`h9PX+Cmc4`JQPsD`sp+0!5c*jLeeS-SZ8;LHHNtBIx>yJcs*wg zwM3I+iqEXnqk5-$)~-`I@XNHG_xq_Ce)B3%6^Uw2#bW4kiR}N=)Nj-4= z8aVTQ5RWqnGuJU+=nRMLZnxX)>fQpitw U#5o6m~J__BtQFd)VMy(~zu!xJRrGC-GjYQ``y( zdtQC=vg^dr$Qc)LIC-MK(2Pzd$2<@rr9@yf#zTdGLBPr4m!&q>YoG<(V!5jD$S1tK zPZl5tfYZ7ufacUlAn5MM*M4qxz5X;W4r+@y`F?m4eB<5MW#D~*a^NjLSn76FGZ !{3(g0A_Sob9-H zwiL7$zY_DUK_xcK;k>n?=oY-k=T1S^;wDjV7@!SF&THosWxTvW`?0(Hu9?#% zyRh>IU}CqBHKVS=`Zw^^aGp?610)Gdu-~)&et1-tFuav{LiO|dD}ca9haSgCcjTza zdossaLAVKc{(;-sJ+x_YKyB`otULQ8R_NL_6?d4tQcS!wj{@k*C^?fzQR6TQPms|v znc}5hJu@0FI)yXp7s1Rgh-8(D4{v5*67nr%}n!&ufy6AGLT-kuvWI4gd7jbSG~D zt0iqN9<>AqUN7|e>34!1no~{#)vI5S*&u+uJ=7Q)ZFvFZOy}~BJjWaC7Jj(P7=7-d z*)vYu$CSbZLs0CjO|scuW67@;TKO2Tu0e(#L5+f7@~$0P^aYzgeBhleC>5ojpwQ z6N7EtA5o+`V>kG^9mxOm`EIk*@+OfJW!dNj1I|dryjKI~L=Z^$gk~&SH Q4g7qP7-kgcf9ZdpwS>^SV{cD|O24edU&TH-` zu?qh680yAB00|qUX5p>+v0C?xZbN_u+QDLvrL|T2DX7^Tb?yNYm(v2l+tOd)vsaH@ z(;LTTXKfEq6%r_F&!oyrX$i?>v Q|bUNMAjQLOy}3$EG19h-d2v!C%!RtQik>8oM0)D>)yaASpk3ZFn2(D846 z-x0`fM2gz?oX-(|UdY~~()vz$6G0s>6h5$Z#-0o GUybvfoihqvrypkRiIHe0 z>lHew?bQStkfBZ0Dq*iDNLJN*t7U{oM6&O5Etj^Y181jT+@OIr`8B^udBDWh$Gu62 zXK|{)1iSRkjUU*wU{!gKis@b2$KPSjTcVLxe%{cG!sAEwQ?}7bTOV5+pXo?sTrUNw znYEfzkVwJnYgLXlIE@R4)VuWuw~oF99~`)3N1FY(7`?y4Y`t2QbK3)^AGmZ*?3iMI zqoo!rQG9m_^Sw16Z^g=u7qzCMwkSj_-|qZO2%nx)v2Ho6t;u_S@?l$pT0OQeI6go* zyQfhdcu&OEY@^ ryMW)fQ=ZR3ffho0b`A zOVY+I5E8mVUd6$%Tu26M7bXC!b=8V}Q6cf<4v;o5E{n`JE`#nIJB1bh0OJXL>^8CbxE+sgHaz%M_ zd|B7suKT{d?v x#$vs`Kh_Gbu`CuuCY^nw_nDH!s0f_(>5;e+{P!9ZSYEb?T)-g7D9h9 zWN=u-B5=cL8ueFvjVP|oSvgWP`@;?dL4utl;U{&Pt9{_>ek&9syEcwzy~l8FMd9qf zSn2WXSFu%ifF=S?l6h|Eb&&0v*f|V=)RdWdA87E}Ynj&AqacWNyw_`IW|U!zbLD{x zMLPflqqfz%g SDorwC;P zy=BBKUFlLc(#_US>1x7#9_*mgWc=Nn?7+FDNkfI_RhMKk@vj4vN@Y5+Iw@ 6T zmhXy((~}%e(ke_0YGZ9Ix(9*r?>KwT$N;U_%B`9UKLNZr&X?eLWg;Py^1@t?v|*dS z@vEN7J{;)o^{Fjsr;`xp@XVk*dv)_eyU-SBO7+KmonFIm!AJ6|CCFPfq#lDF`z9pW z8%O*5$WvbR_g78s!C~dw$3lFbIT&&D4?w&y+QW z7yR07eD~(BWv^O>t$&pi=mB|dPY4>00THmM?7|5 z*WE-G2@{>&>uL;=hp!Hs swz|Jn+_w=gzS|-jjha3z{lu1Qy XOa}!SVxGtoaqw7 zqm4E#(t5+{k8H!xU8NsGkHpKxBfik`OSKG`F>-#j%*M?K)_9yWt7QNpSIL2ZtVPO_ z{d!jH|4ywLk&}Kk*nVS>Yhlz;p%%y`RvsQOK^f$1&3fdc#3K=;3wh+3;doY`=Kzk~ z`*doi0MBb^itzDqbpjBOJl|O49eH0An>My*<-y6PB7i3WJnH3+JIy=w937>X%q| +kD*>!`SlI0iL`FA=bU_xXAL9dztrdsJF>)zsQ- z%TNGTa@O^^IEQ0kSGXphRsUp+j=n4*@N7Lh@;<;LBv2+(&u*-R=y(oCBwaD9pnE<) zYycMqmEz&5pBtu{50{Uz>Rhw*TB*sm6lwtXeOvn_9rMJgb4k?PbmpsfE^ZHd(>oE6 zyQvlzt*Mca828Ogct9|r$G(Tn)gz^a2K8!LfH{s3n7Uk*_-?6`x4ujb4d$9tTM31! zy-))pcF;dK-_^=l;*lJ1JL&1wF}()WzvvIym82cp(cEE$-adr(`y5N1JrP!E=CVJV z`%>~ZU4Qy|1bjZvwgd~AATo)}P8%g11znq_%w<~Ae}_2POW+}Jz?44B6JUjq)qU}w z_w9a442o0BdP(bzJq)pNv6*_pov!cQ2k8@4lne}_#2OkJ8^G$q!0Q)pn6NM%#+#+o zY*1*|9`B{mM`qD=j3B?df}}!RkxU&NTg>EkXABNY{Z{jbmmi{p7B)7)>8 ei zP+Fcxq>k9sDikP&n@-Zta;m T_<2&LcW@*2j1Yj@abgN}gL?iOhkTK#bA_3I^)g$DU+m&X5|_&C(#O z^)$v Xt?;HB|Mfn$Tf#esi`T!87$|s}G2PoqEJpuW5d7 z)M@^zTv?*bpkX?sRr`LbXnn3KuQG1qa&Zp&0|<@ensl<)%C*NqIPp#OqZ{rvOicCd zZEy3rW_Hy_v&n~H|J}YLL#+ne29O=-w OsjUp zi!EbwD*_h0-V~{^xbQ{5R+rt7H)(mluTU_DzPIzEEra !t3KvpyypQGy9+*dP zY3cmkjeDbgH)4PaX?mh7um3HIv=P@7K9RyvO`onSLKpb22(}+P&B%Bn-(!`fZ!h0k zATzDpKDg(ruUg&7A5dJ_#g)0R@zuox?z ?~0#bnC zt$yj@)o#8%PyV8Jzg3m$BNbq03ZKg7lOpmMso9 B#)^gJqa~tCm$vs&qmu)lPl2Gf?lxQ9C<>B)xNKY zoV;@h>%wZoW|!9P`_j_e;sRUjBi_PjaY q2jxQVC4Rt;>R*OdTRM+auBvIP^VY&b_Je3A88I B! zjUk@X&DZ$2l>KpsDrVZj9(p^PfV@bXxTBq#7p}OWZGM$1
bSA*AL9twF zjR+lPyum9Z9tEwhuN)TNGA2yroTb&sN3}+`b^>fh #UwFr)l$ zQ7}0HMXsYZe(;_;nk&4^U_r8HUm$vC`HMax?V1~{Hm!JQj-+FNvs(D!A`36*JcDL+ zuQqZUy+yh3FeL?l*X2gLS5-oo<`yV#)W2O!YgaXYTvGPxKjVK$nBlLGS%&<^`49W~ zgE=FS0wpAq3k@Jtv(EG$jxMUoS;UgaxEiXoE5`g|D!Pe3ubR{!)a$;IX3jvTv=eAL zzEhU^ykEco^%l~mvIiHGmJ`@UJVC*Pctl1Pny4JXU-DJM#n<`8Nj;q(!*q@@jQ#2C znwhA(BS 4mJAXUFsXy;@ zsUT8HU9$c8pxKf>FF)S}SOgvc`QDja>~of_4kB{$N&*2kQ>+Fd*N2+0(tT?JeCq4j z{NwA*#Xx`px8C=lJX0vY_DcEn%cv&pQg0?o-%Sv8$Kj{u%|*B2Jt&?PFIX2@-e_LO zI(oKYwoX5o_xNf p}TuIbw4-{RlF_mTUtBmFa3gKhsbAiZ{ b@I*r?+$(`?=iu?VVASqk-rBzlZ%I*S(d{nuzge5*CjkgZXKtl-Asgh+ z$-)LNyWK?J8_xt>e^e3}nNBm|>W|n=GM-5u`C!J$W-7B=+7en97k!|mBH hNpdB>X$jOdE>*@y~~KER@9~mJzKB~2$;0C{k^cjqVS!y-OGbP%}r7- z*z4(tsNqJEuvN~8AG?;?%0_%6!)9G;Je%t&o5OM~dLP+mghuc+f&zXT=7|O$8d_Aa z{3EK}_8MPt#%!qxU)qS4(ij>4B0i)5MG|DAdUJD5ChXH)Se(G}Sy)xV+Gcm_R6HCS zc$~)?zKNvrik{+y#zLL8Ms2HrCXsRWam28&g@T5(rDn)Nvn+gXSlf3k+f}Q0A)awX z^%figx$3EXXN5TDO#?VjQh5&Na!o7%c1$`6U9S18Q5SJ|KP4W|2~hS_%vF_!wqA|Q z{!CJq{W5tccDObfY`*1qxrEN^c0g`-Yl4{flB6hpenf)Kx<7&!M!i^%OXa|_zoH7o z3x4u HCXuPO|O_`&20eb0W6y4(5cbb$U%^nfM1 z!+sk3#A=$idzJnibm7JBAivO@CR-{WfjwNxQ?3L~> UuVHAfl3YR_t$SWO8^Yqi#_=QSyPcJecYchDin_X&DT`@naSLUi#k zn}6<3DL>Kt@JzhjkIkFkZmCYKdz}fNl0PCLKyNgG-$rI+nfa~&hka^FAwRuaGdFR$ z(#pKPU3c^zx=ca5TTS3DX^|o$!Mr5N=!Bl0yPj{((PTocLR(DUrJ4L^{-K+k=)ta( zvmRXv?euv#Iiuyo(o~aNT~Wysvh%$zS{UGi6^pc}PS~~6t(U>HQ?87*zTU2FHZ!2M zE|a(0Q>C@8B^w1tS&Uhjrw9h#cW|uDvwHs8=>wG~ZSQi7d3dI%JX-wGuDg)9(7{Xs z?`~S87HAd$&C6`Tbl#6pls=@ky_5E`8lqBsQD;8?Bi?l9(zdZ2k8Q2R99M*fF|E{% zW0R%Iqj!R$L@xy633rEGX-J2=&=~i}2pK;pYVGq`7d~UYA5YAlKiIdwIM@^T`6=;6SsF@ga$lkQX81$zzE m*-@727-wHKyK|DQe28f3zyEbR&1agsxr|x0*n02Xq5JsN`+o#B?BMt#PE=_c zCM}l}sgMo4OU3!fG$F^-zrjiW43UC)kdxvY*r;mt^jc}pYx$bI9|br5dT*V=Nz!jF z-wj>eRGgj0l9qWX7{)g9Qd~ntj>12{!xe*Bnrd!t#M%J2w~ZCneA<1KU~P@^g@p#` zA(f%R;{41fIf)(pHS;70eRXN65-o9MPsqe @>ajm99;3lVa|SE^ zx#VWrrJ~^xMoVk&ha3*Q9dYrfZE;BhtXBQyPjr7{N`5C#_yI#iKZk&A7T~&w$&U&l z?G@wn1%;)ZYnCdRrlnjfDk|l}<6Pu~%cPz*St~BT5cWy5fVQ&WquGUqM-PlDmt|St zDa@TS(B9ljsp8Yn^e?%*ox+8(YnTppQXKAg-(}~QJGGYx=VzMiOcU`}n;ptCS6wv+ zW H&Z;KlAomv z`-gsHP$S2GW9F8!DzaNUGFnR${*siW9T*fy%TNF8r|i#=k1`Uvx|FoEv=X;!FQ(zF zWAubgjjsESEya_Fl!PQ*@}@G^RA|!@Boe{t{G9ebed>SK_}PoKG1Si2GWR2rX1b-N zm!O3TDa>T<1*MC84&LkioX#7K&xQL~-h8q7^#n1AO5RRp0kVlZ+}=C51;-u0a<``! zgY;55lKlC*o= v0|kd~%XI{>7xn~-vtn;Gv+SYkwl5Sva-HCH$S zQdge1^rib!c){iKqQtM_c?0x(Xz#A%IH?=NM=|5vng&`zcSsM2H_IVJP~O6;a#TYt z)4vJy{WHzI4fRC^+?@h&b!W@WFHHUrhh$ZSW|fpso{!*P+Oi_Wm8Oo6x8hzxhK4(r zb+lC2jI9x~jY2>a1b5H@9(GOkL#o0t`$>yFb%oWoS98@Vjs9FE#bgbR;-h+SCIQot zl_qzf`3HM`5j8=`yP<8i9g5`UBFuRMYC&jf+lrekI}7eCgEWGCctHo=3NPe$P10^g z$hRs SF3D012{oFWtHi? zC_;&+@dRE0w M`B?s@3-I78>{;v#$KUO0@}NBs`?z@`$igp62Ie zlou&c) #;pm<5F~D|)7mKgAjSFmB9g%-Qu3eY4w~PPg6s>&14`l3#E+}G z?OJq4wKa0&&+HeA3ikH)xNP-=ln}oZE-tS_FLtBa+C))*X4itr>FFi=hJ-^!b-wLk za~OlNaz3XCn xx>B=&fmimvNz;7e7lckp^NG%Xr1#`_GVtwV~v=p^*vz1|24VcZW@hZI-0m5q4 z%QSZysNGkaH1_UyYSZ;AhG&ms#6M~kcS2N2e|_Q#@ISN|+tB=tRP0Cyo^C~C@+K4+ zgB%@+AXk%YbiBOM#Co#D^MxJ7IXa{|;Jn>(wCOe04y23zWF- L3ZiJMEo6mnO!hrr{n8a{6ZGnN?$;k 2 z)mo@0>o5A2^mK0Xr2r+a?(5QyP=1xSEc1^qv2a aV-U^-|ti?&`(UKkPE #$MW2dgZfvijR9x2cI4_A#ceFBk`Bqrk49ycNJHT>Ht;Z_EdJrE>zj zj_i9znFU2}BrNSQ{r8PDTRfMQ|(psdL>`Vz`I*JVs7dKbf=@gz{JI{a&9?3gi45}g4iK(@v26Kg#!dJ-4 zK !hoL&5ON)4b4vy;y mPHmT7`EmoF|2qD(0MTogNv`vzhDvUBuzR!0W1^ zT4xPPg{;;Nb*>k~EW5t~>*|{uhshziaol`VPs4n@u2GFqya`@E4&%AREzKw)$1ByJ zenm$m*Gp-QijGFBzM-nB?RPdIQT8zk1N*qKbW*W*q{8V#&k@lN;`k7pm;@8Y ;@%a4}Beb;P87IfMgzNsdCal{Er)_6GhYO6nkNsWw z!tl2{6ii>N$jpY*Xcd;NoA0i4@;1uyENy`{QZX2 +?QxAp4N-%*Dfif}+2Xd-I#`;*hXvL*e;H*$` z P$b-kj)hU*>NHKdA;+qA_RSz^=Dod zHZ&Peauoj5K@;$22e}0CIqA@MJ0RI=yJE8vZ)8I%kUt6@zd}Vr&&p}WU~9e* n)VL%EB$axJ)#>jp4-G!^JhHhZ7r3Jb-$sR +KqB86ieiG1 zMt}~wpAw)p Q+)`ziV}fT~*(F@pBJ z7*cei=uOu`HI)i>`L5;bn1Kdk<0K cYqn5Si zoSzPe3!7VcNJ95eI+!+}`Oh!#s|_5@JPMzPcij2D8I=6+%si3P{ hD?d( *AnpMG%GfsJRta0{Yx*m{SO6u$zj#iSpES4 zA&Imo+WcM)5~aTwzI2L ?a|E-}SB 0H+R_P8Z*?3<(|*-i^Tir=SR zmVc4CzxloThz5wJG3;;W%SRiplR5u#jVaCY{hrh9HtJvF1i{V9Wi$dsZ?84wsgpF+ zy8{S58O~`^%oMXNGZ3QW6}&ArO{tLsH7`fwr#bx^-*bV@f83n X*xQ| z o-XJ2{CjMlS=~}XB0^br&Nh~xqP4@A|ka>XY zXQ?ww8Ky;xCrSa$TI&Q(wax=tKBVgdU^#vrbYL>K$l@itzJLSM<-ffE=r^rIv3)%} z7S=Y<>dI#BF3p9(2j&;1n5;O_`(A{iT(FDvlgkGG>&@x|j@W7#@vs6c=6ws|+|*sLrUaB|vtS6$3hG`A2#fv}P$ zQZMrto?OND5u7enYFC+7KsVs#;`;VoIU q0yD4u&8K!Y&Lkl5O1@tPIBQr2YFo8uu;qu40nbART5IorZ3UcZSs&QkF>Fk zl@ev7r8}|EV}*qdOw96oeO?90D=X`NXNCsg?Ue0zwveKPO4kdgww|5f$a7Fqz7`Y| z>>;7U(VY+sk{Dhq(WqO0DM_6g8%wj(|MDMdH!MeeeE~-^6&Rwc0T~Yn6hvxu(-vtv zX>_|6ijT*NoXrQsD$T6I+J+*5L8Lri;7QsA^$!3xZ`){K@Yy-IARGHKTqeK7`pb@? zY_f=owT_Lr>+_!)(<7 o0a55eHKSC0bJI`u8m+8y?Zd>}(u`)fgP@Uy4Yy zLt KHO EK2y+3R^Id@F!x};biDU89e;H*)C9K8IKV=Q+xb{_m6;7J6;J-5M^F}z=h6R0 z%44~&&E|(luCA>+WhI6YiK_p~>3b~q-UXJ9+dpI+#=AdL1(j*W)IwtWao&c?ywma^ z+up$pJ`r#=E+FxmR;spSAuS!eEE2Mc0W{NF!uGkZLV4q)rc1~1o^4Qg!GvDdvTVm$ z$}Q@Wy`*>k5;``e80j>(vkMRdFGb)(R)P-~YVmi W=8d+)l{mkW%LcuVI9fH~(Xv{a;D}EJ6w3?vzyW^F`DLEO>&D z>Y0A7Z8N3q{DRqexTG!DCnh81uxHbKiL_< 7Nj_4+VD{pkwP^Y-8$~GK#lzCN> zX?0G4Uau6vIw(9TWX_H42Q^D7cNy33l1g0-K0)J{pBF`o7Z>NAnEZ}Lgl=Z`qNo#6 zHwjr3oFOsI?9Ab_QB 6OR0va(6t-f`T zElSZn`^V2OL=jx6sA+u5T8Z5oMGmmpZ4#y)-bHc#7)c9fLyveA@t=WKO|SwRe`#fw z5lg|aZ33U_`y i_)P=XOMwM(t)W z7BK;r4H}L#$mVW{dUG=k<4sBA)Syg93a9-~PJ>(yI|JCq)d+SedfC1#`dI8+SQeQM zXlu!RUET_6BYp9vpNyj~kPTQ~fVenw^qD%9TLdtoUJdAtBy2CKTc+Flb(mjJ+SSqw zJ~_&jAw}Z;nUWYLW_!lQ%KqVJy(s)fM%%|5>2N*lUpb5A!A)nvLZZvElA@L&&5ct* zpw95{a3fDY<26F2+JBTg|4a1r0l=izV6@18O{ZQ+wP6SVd1npsW(Jh54^J_BMR$ke z?wU}#dMGkPudt=fHd$_sDN?K6QBza*4W)$q`Y?$`i1{vg>c-OILR8nA!<}Nu-rM3{ zn#Ra+xsVF_39bY-=swaW3okjWgYCUQacCdRi`GqH=yKZ7s=L;4+sEey4|YBlu~&HW zJ$h1P*HR=g+s`UiJZ1{Bw6GwC&qEi}XO7}Xip!MjuCYstaI{gIcDM?ur6ih9y_0KZ zqq5 (PT(cl9}z*wiMnEbjfa#WKQ!^^sfuq@2$18 z!fgi&Uw}RCWi1wJ3D?%vg2ThRr>OV(5}C1WZEZ>WUIV`7y~JB31`uPLzOrCwR}wMY zn*qS;GQ3>cmk)8+*e;iGD&65wksm+kEZPZ8Fa>9qG4vOkNlNHRZvr!GvR?VDpD0zR z2qP?}k(N?isP|TvfLieU^z>v`QUA9TK?zF{L5SqwKa*iT=HUWzg4L~16 L187ztd7!UXR ?VdK=9^p}k6KyXQ+3e~0;Tyjjqy zKyn!756zAwHuZ%oN14XfynHD2&6T6J*H;&d8$fJIq1bT1>q)(V2UQXB0OVQMysEdX z0q^oTG=f0xwl4R#AFb5k_4C9&(ojq-e*OII)1~1s71#Hd{K>@3$`pgpL8WuojB}dN z>8uBbaMRqKIiU-&*T -mO ?>61MK)@B z-4%>l3);&RH5|$Dx)vogqgq!5o*7}K=Zn?wBv^(Y27g5nb#UXDc;Dsr=pLJ1AiCAS zRXyYU(ajE5f9qkEdaaqcHm$X#R45&i|K*pkI_|@($2&8&{6`O7FTS(8xA8j^-?f2j zh)(Bj1d6?6i}k-V5xBj8aD*i&bdP;s$w$KQrh 9rAcoTgAYF{~JAWRoL-sMp2QFgORZ%$hB%T%OPNVQ|#!!JRo_B@4#$a$vsY z=O`I{sj)v_zO^GR?@(Pi%I2oKe<}G*Z{YpnwMNcFirE1g`qwO7uMbwY_Y_7R8N>+p zQntGdJd<>8-*GXFMNu6<_cuo?=_1lvU?4C98>sk^@2ZtOQ`*d+^|bl%+iwlwXUoN_ zlANPS!tV?71Yn0n4_z$fdGhH-kWYgK$c>PmoDyKp$4*>8`f&B0utfIYsZ(;ZNn>_F zk1UM=_!;w@E!P=b(0P6fy%dQ|ZAWJ#9}Q^-1sUV(&1{TiC^x%4U2OXyILmbUa_3&q zD59FR>6tZM;)u)JRnA{r&9@$P=RHxeBlMN2SqrC=L2Dp;HqEb_Ih{X`{+v!9Ch`u$ zk1iRut#fas>sbo05&GNGvH=oUS<#OuGPPsQlF3kL!L^E?kA)4+lNoJdVUaLMrO5qU z%i_h3fDMJ)V56O!o(rFLhemfasKM(rd_+eY7##SS48#jfpks ;N{={c{8hMc zYWH0vQc&6Cn?p;&Z60hxC5vx_s=YHUa6e={J=wlU=v=kw+6#1RS{AVar`wC5@onZM z8oigM Up4i<&w9a7Jii*+WF=asmgwMx<$^voS`F2_B zHR{B*(mA?Aav$f;b5d0U2x&R!y0TzTg33&nx@~dgKHcv{Ka-z6n#lV6SDWk)KK{?2 z3t?|xYkr%adlDI2x8oHrRMzltm($)AK}A)QI%)`;l$4_DSJ^P< &I5~cV)?1dHz^fXmSpbEaSc_|}zob(ye^GO(Rj)cvTB@0st#&2; z{d*&zO^=G2UQE?5+ax?(7+h^_8htUEKvd)CNJ^EkzBmUL)51y0j6{uy7%Uwu>>|S9 zo6T2NhSVf>i2YkgvxR2giDO>mq$I(u{U;ZFU7L9b*h3Jqardp4*+3s{_IYPgOr*-F z$Tu@LE Ahttqyl&37r<*QaU{I%&ZfV=t!S*w&`F12}GHTv-mE z(r{$9JSG!x9KlU9fliA3=0cO6=}Ss @jsJV~pz`W#SiVK3rI^87zOCn$3ymETh zr59MY%}PlB;x*AfFlkK JHG^31tM-_WQJF `xuh#JhMkKPOECJ#p+2+j7FlKGAP8ny*o1i^DE~8CW4gFM z+HOuKOwW;Yf{VPySVa<1=#}s{ErrOYMR)XoZarG+3 OE_+?5X`abyqr0sjdWxq30XKb&9Fz?9~SZi%y&khy&ffBtDQ=XcWYZH zjVxcpd+|(W!?oIsDFtaJ J?ggBr#KxE031 z>Sb!BhIGPZ_5+ph92C4ys?)vGI}#t5{zk?7%gCve+@?WyEv~oTI0e(i>0CCur&oWv zW9}v<7) $f=RomZ*c-xx|)Gc!rakn&`uIx_=8KU+V!e@*8jgb6~yAtBw>rXRjzy1abPI0R!Q z=RaekL9)a;DSR=E9tS<~mJ9L HS! i35(Xu!)xMxr8zJj)T)xJ9Tv#z)pzC5yUDp0XKrQDCSv{0yO+R+@ep z_-Ao`dF#zGvWd J8aH2-gy;k6!1j{-KW->|S41=UQ*uSCZNMOu2RQROJ26U@d>}GgZq)8_Y$7 z6Gi8?Y-Qc%NR4h}=(A8aW4Z_7LS#x5Ufh$*g|i&E?4i7VC#mb_% M1{H&^Kf z+Ups}xa{?Y?U37d_`d42L~i+$73Zh4*w~TQyX~DdTA>iJqWV?O+XM4ix83?FaP?YN zT}fx4;oIQ~e(U*&$4_z_pNOpVWe`(SRlJYA)-dg~uWv (KoWUnVB;&18oE;`; zF>!*zYUySdK=+F r9`=_dFx{tR znYW)cJ^fh8O;aYIY1{t%wCDOd**-KvIdk)eV|wO#aWbXkoo>QHwc>=(vDe*~c)rh_ zyhkpo4L11%-Jc4F6{}}#OorNO^pefzqaOD;O&YfloMl-LK$Wz=J*GkSZu^cQiM7mg zhbB(doH9}eLTl6C7bqi!(8z;b3Rta6ycFKQ1^&p8L|t57^w}a#Hau+6H*L_p6adC_ zdNfUDy|>pe2qH&~ayV=`L-m9=nDb-#3C BYslp5H(J9{tE&na1zsZ|WL*}di2hk{#*)%F!tGEPho<^$6C z(gr5MQKdRZk?5stZ-_Zkgv}D#gvJ|T!{0m5;}oQZ z_TOK7j$$ovZKEf+Ol2L)Si4JhAS!9sx6ZOm9ZfSN{PcT!$vIDzEosUgZVVQ}^?SeT zpqqSu$3J~eg>}Ee>omJdj~%`fmHX-Z*%AmnHe0-&00M^%Ej4Sf yJv^f0V2{7^Ih<(u1_lvmkxr$xCp>LHB!VM4K)1gp_%Oufc9I|WZO-G= z6Y%)Gwv`rbJDDvs8?d}wo!_*arMI>dKkXe4B_ebia@g#Dt+R!BFuAWPrp-a@`PQ6N zJZh{T*HLFF;VN^p(pV|pwE}M~-LLLj+tP_1xftSAeq91*v?3#yYTpNmj4ivLP$8^X z#Wo1S8Hi`(xlHbSCC9F8G*$|Wdl-n8n)AsY`+VzR$Kt+`m)X*ct`-v$^?o;Kw*OR> zi{+gb`jg9f8<>jLHY0}|w^z nr{~0-l$?x)_dbWKTJhQu zQPfTA&JfJ5$LZc|v?h~h!BPwll2dHBSFmMv0$mr_PQLH{h1W`RWn!Y!jHu;Cr)QLn zzE~Ym*0Z*A9(EJo_;JP}GKe@S@Me=Tfhv`mv4^|8t`>W)Y%_VUXt(Gxye78 FFv5*LETo24~a{1TKHC;P6cBy7VU@N3fhYun|CA| zkGF_ZsSV*Zj~#gzcFkw*t}PB#wvz@lCY#Eh7I`H1Qq2hM7=s3cM7P-~qy;Vm{+!j% zjJP3VOcgy#!7YAX7jk|L$Gd&|AeI}LA)8j#$(S-NOj*s>FjJSiYL344cSm_j`QQvF zZ?rwA#E(H!*!R^OW~_1c`d?!|+$>+xo_MXtKHdi%iT*GFJnfGpha0d{FuYE0zE{59 zB=T~_EKN?{Th5c!euoWAzpE>2*V$J!%U@k!;j QA*^tWL9QOGI#8! zfC>H_AII{jX!Ju(3fDKMcZKrG((BLg#^&eYS{b|)xFISNl;ZbqvIG~w{iYvGpcdU{ zhU_0j%!0TdgwWUw@uWaVXuRymrZMcRsz==Qs%m~IDJ*@XMK20{*UZoTB89usu9OM5 zo!|~-ZEr#}R09Pv>YZRs8naa0)Vwk(0lRzHd>Rim(}$Rei63St{Z3 ml3Jd3v`7Qtpz2dSYtq`*N@!V_K)Nm-bOy%k*NQUn?OKg^WS`vE3eN*r2SaDpV|v z{pvqI7MJAnt$6RWHgu*UX_PU^?jsjfRei~uKTu&W&Heb?#!puz3$0x|P2LbAhomOe zYNoa;A)IkHw#QYhj@i4Ghf)<^7B`2;7C`TZRB9bD?>07Fk>rqXpa1xv6HHGBM7kYU z{^*xEvOBi3p6&6*Ph19ilV4n60)7j_y@aDg^nWk)Lg8JHx8)-6xOri}IYCSExxt#X zD2}e*uKlv5oSVgZ8F;?EFkW0`Jkm_Sj>=37 AHF^u{TaePpXB z-Q`0};B`>_FVW(eO!(NgJ;4k?m7?GlrRcK0kFK`}FmCL#)a;8Wzn5cZC~8Q}v)8nR zhXkS>=PBmodFA`nW!qJuRkW&2c^6W~f7JYley~vYmVL#ZGjNgXgSmoA#^*fbUvHYq zE#|n$t@F<7hH&&qjsV^`cGBlRlhQ!NLk^(NM1XgQf>fz3*jM_PXEm Y^<2XDxFIQg;+r2jLoFqnAY}iY+Z*rmwJ! z2J5Wzq@F$?Y2MZS{-lUjz5S82Fv$23Ql^vd{7$@N`q(8tTF!aOqd8@#YIOzw!~XTh zr682NB0z9L6UQvIo%CbmC|725us7wAYJbqeY-OyhRFQ 056omK6KR=I7rfZ|PeiR|X3MQV0iw0|e zHbZK=v^mp5(}@+yTB{coT0AT&)_4*i^N!Y$cH7;2+V9U+{e%0zyJ=6%_y^RrSZ}sx z<`7$T=cZr%g1Vo}-IJjHnqr8bT}Vdd>pHjYNkv5nMzai805@CF{*QqEE4q!}yu@}N zZ5ur;(!ohqYrSeUjY=>_KUGYr7r)Pn5LZgmhEzmUGsqecm-RfGXaIT8-LrYbAT~ct zWO`+*@&RO5Pd9f8H%`mnzb3bam2GV=(j`=6)wRGr&SoBS)f&=`oJzM&!(uUE{FdvO zCrV4Cw@eP*Vrb=1Sx@|DGvLVy)k3QhUha8M(&e+_xuxXXiSF{Ltls!6r!!ekc 4Xm8EVZ>x8v{UFsCOB%H3 z441gV&d5l-xAzNckN`zs@V5q}d2)VdV9v~#(_QO&?`}_6K&S|GVt{SCOK6E$h|!g; zBk$CY4wmj)IhDKWRY9fy(h&|&3|(0X`(5YEtG|+E`4OcvPzp|X`YL6r_BW+?4P!K? zNH5PASgddJ3DS$-4#6|oJ#OUe)-H${8^?Hp*cF3RxA#?R?xt%NYdHG-sp37>f5bgB z)Pw@;5?a{^NSoApqu5B3LNFDyNuwiLTCe2;&PzQAAeOiH2^;DWvx~6?nC?3*4a @rV~wicGGHOL3das0t^2G@XQQQHp3Y_ zd0v?iG=nxuab4l=6n(AqWCXGw3^Q5GG_H{_yL8q >8LR%IN9~O>9*QS&X;$CCSyIedrpWH5;f4wI>$6z`U z3t9#5E)D0(F8A=vf&*u19Z6|W^>=M-UnXGB{cK_#+??jse$O1?_-=4Tyxc z( JswG5vhe){8nSn^)%#uA%Uspe`eml0yU2v7N~N^qdVnuIfgr{kT|Gq zrzqL!{a`O-_PNt{%jL 5t4SACwzMP}B=xso7LABhhPz4IG~Nju@lB!4EgFQd(+FL-BQbw0nI;W_@3beks0k z@p71Qg&yv7$vYH!?O>wuHQePAZl}%d&R)hBmIlC&iEA0WytMMc$Xz#YNE=1v9L(2W zd9?!Idr^8KQj^PVt}y7d8UZ2w)X3MGh` 9e3lTVe?%r0$ zV%ri!U4KSO9@ZBaM=pa0uV!mLSBQ-$Bl_JBXN86-C l9RrAAuDQ75h4bUkq&KQ}YNA2{5GScYz7Oo4iqaB^2GpD( z0b+e$@GqOT iu*Ih1f~B;nVUZ z_f?X6y(uRr?o!#OBvEnQt@u>cW=kBYL5p3;9La2Bgu=>QFaNNpyQY0`)%B7oi%ivE zqK=Bx4##%qk6+A=Tri~YhL-Kvo8xCzXOWj`32(Z*2Qb46g5vVjSwNX>wy@1K+hok& zvi*?W3Vr=!b6XFk+p>QRdbky`IYhU8W~s@?$@0NN0ZwWa3lmMyH%&Y6H=TazA`%`w z?`_?|w(^KNYV6qb_DGOO6K+!VR5J!eKn_&~ZqtSU28KPzRy*0KZ|JJGBby-B$S6w- zpKECr5}9cQzG}Mu{KdgljcD wNDs(5PO@OiMon+hX S$z)qYfWROUu}TY{n!I 7md&YW?!X{!Y_=!p(31U2{H;4n%5S}HA3SuNu(8=J=MNgaWzAUER^J?k zPdZ91$s>>YsYpMEkSR)OttENfu$#u6Rhs>tDlBULy7V*r!zkxdGuge^^3p4&)DClY zZVT=d{hcTcaAHDOh37m`OwqL2&AD`uO(!s`WY|Dk%1YnXNnMl=Vn9twc?a)CmQGq9 z9H{)^^!~^}Ok6!VTpg6mn@*CdRR*!sr~x<2`<2TF4_;D7Y>>qf1Xk68HV+@^Lpc(G zGNmgu`!qDt9OgytZV&?Vnq@=T=#AsWfquGo-R+Mf*ev^p28ZPxU;l)pNxW@0FI`z6 zhyxUAf16=g@`fbo%sQt6HSf!pmLu3s{w?yP`-42y(sB5V`?ft(7qYZMXFFl%EmwnR z#ZcR)=0Z=r*fj%b#ol!nmT=o1#*`(x*OT2l^wMMYtg3MtTD#pjekI}@+Z)4P>!?xn z4V;p{|7>{Rt?lxlL!A83zDDBXa@nFW9s*Y$E04%4leQFTG!)Pzc5wva*XBdfQ4UCt zXLB6h*#cU%>pb6M9|14 ^O7gX}<*wL&hL@O(K|RF~9Z{oCQe^b(?)Wlkpr7Xs?P z@pG*>{fRooH@sR$gv%=R7i}M9GIGK)i}4XOi39yg1vtHKu22C%2?^|=v&z+;l{;RV z!3uk*diJMJozh)~+n=-B6G$?u);6GiO&$6oV)vgDY%X~W8yy2|;@uh;)vv|OmoVJv znN;UZIhz3z+9R0<4lD)5!nZ?EJV!-L2kbG@1%lM_Pb78 %{f-)a+Z|bn;@VK6=E9Cs=iJvNmKFq5M>D3X>ALOG_=w*$1)uVQ zf?F)rkY+b(} zU#$6(TNcND
#Pzqy}bry4Di=QxhUJCI?K>~SWJa%gd~@J(Q@}_8a|8YkI*!$l!v%?_`;n| z5L MuA$-@r}P~Ch#aK!AcSzOB~ z$-W=jR)%9dqV;2+xIPwJiza4bX2UuXTysfpa9>fYeiesY)WFJ#NEQ^{_T2p7e6ZL` z%*gM;uhkrPa*<;nwIS8zo4Kgz;sX2~CQYnk{q=e4P4P+%rjzY@e1c%+5KxL^2QDx$ z_l1@fW1hf)4UxJ~DZ=!8yrGAF=|L5|PEk6896ua-iJz@as_@Cu+2Bje{i!?m$S)eU zc2c{FMFb@=3L?q2Ub1aC*CXPb!ooO4@w!K`mjLr+m%MVv1ADz+wJdosh~#UM#}tlv zv%f*6R}Jw1FYIN+jWzeu-dH`krk~ryf7>nQ=)p#>jbSt9Jih_qyPoO1fl%M|-xl9k z0K>^7Z}eKfS=*;d0-y%;%G&yS$2+7?Gwf-3){e6d4Lx!R`dg~;t?e58%^Bm9cGx8p z&lmOl*VYaz8-^qh!=5xv`zC2^0t-^OFL$f+-~NW`!U`eB4q^&M`}I-+k?EJ4EYpQu z!O`D=>x(sA+R*A|9^Q{-2J|)E+7Mg1-;kOS$L7-8K2P*8VK^v?y=yj;RxiX6MxSNb zVHO=02pgP07Z;|-PnIoMQiH$lmAk$>gUUq>mx~#F6Ts~AaxHH?9SSWU4~R`L(S!SJ zya?zRy04ZN%J(5^0=7)=A9!#A>XwA+Y$&w6`3QdcmJSDk^tYqwt^=2pL4@~p>(F2P zBurI+h5(=Za=Ws#SqciaS)M`aYzbK%IWBj66rfp%UrmA?f7NOIC8w`ko!q)+DvT)& zhpm3vVT=$(_W)~-70PqWxK|B+XjJjfnt4oSD@->hLloxT{>^uD+Z~tdc6^4lUFFDw zwKadFsUx=#=Xad0x$kg=QvVyXQ5)A;s2pD8jtfBt9WF9YB42kfgm%M$2 m (F?uH#+gd z9?&onarH7La69+@-$>>^v9wQBy1+0;i}CaA{s)@B=wO>9*~imWLZ-DrTI#`xC8*$< zlI8<;81pw(#lFRs+kCn~-|*YdgH-uBmg?bWQ(D1<+#li^DC+rszeQM-vRI4>7UsSt z3tCIIPYh+xqlz4VJ0P#F2wHz|=lWFj>lH`jf~doNy#DAiuf#x~C|}LnegieVs$>JH z7H#}aK^&Zfw#mtupE-M6M&yd<_9Y1cy-1GM(;BimbMYQDH|p84$A+q*0uK0)dCq=A zVr$VmtDw*kHML%;iS4g>-{`>i+S4yzuC+K;^Vlg3YRilne8)EyR>8@sIwR0#(mzfw z>R$FY=gPdl*&i+D`$D>XsGjn}zd3L|`>@aU=zZ^XMSSJ~#*mv~comSm*UTbV&p7Y3 zGWnO2u@y(hS~OdgQejACf47$VbTS#5m-gGdS?K&x;*2ZfB4643I0M|~PmsS_trUj6 zvI?`ir
8C1@&*@c4wGWjm>bz&sI%
fN$!I)E#Qmj0tzM9Q6e{?XTCJ^(rP{qZ7&T&u+@6vUGmJL0 z98A?G_)7(s=PmOZq~)!h*8`l4b>rJ5M%1px!+SIiuU9Ap5~4n-YYBr$Yo9V<_c31O zeIn)H0Wb}jGPnY1&noq icsGcbylNO`yo3 ziecO2H?wAhWYBhFxEL;Bc$9c3r*54%mLzzn%QC_}Qq3G`Mw$2vB68m!8ibCU+i_ns zXFlqY*c(1qM%L Pz)`0s3y)!&7Pl3nuGCk zZxW9irxYc%*Jn%DO2M#qa+Pm>^e2NYN7_3@Y-~$PlWV~vPpwLZkkIvV! @dZ3d66y zDr=v>QZH)YO@NEAzmY4IXh**@?(*Vgl#vz@&ulX}!eLPNjO#ms89~~AcyjH1+n65q z9rf!~eXX>zrr*0p=2~iPn5O +(7PC;~hi*)|06@tS# zhj8-tLZ45EefGgue)AADGQCA`{PXsUQB{z+TNfEADZ%sgG^4{7-0e^^*tM6f+G-h@ z`d0xU5+r0RNJ8@#$t4VfoQTKY5L$QE3uJT|WTNI!`A%M%A63Rflmc~X(LBFa_bs85 z0bc!dgc^?9FDVC=iEdr!xZSzv9%Ol(OunT}B}sxXYo5D-zL8YC1X!bYnO9=WA!j8e zYpQPei+KNRu~Jq&!2{yAl0ZffBCooQy;9z4NOtOV;q&kRTKe8qd#shxY{yo>U3uE6 zFu2cK!S+f&g`~lG$T>KfbYj%ql~u&XJauepGi_Lowj<53U-qTKYYT~tVLnywoaZI= zjrwlaoT!x62FU G54Y-Qv0!7>m@PikkYo1MkJw!hh!+%Sh(pMi>i} zm40Gy)0sh$=9|?|qIWmOe2zdGt8~T^rcU@)FY6pgZDo>z*(|p>fq~&ZDR)0)e7*JR z?b!W ;`cOhU=>5DscY27PZcksQE$Dx63vCo#cL6n z?k9g4J9nZ2hxiH-Z-xZEgrl-t2XE++=rsqeOcO@8stq*Nv8|5XAy?yLm}~Z){W{i; z-bAKm5W36Wd7V^ym;3k3m&!+h@`lFkU(z=R4&d_-=66-3rEZ^{>;09DW;9}1vh81r zs#_o1ZSHKg^M8C%!sX!0-@PDA$VCQRV+0IIi8}9Bec*Ev0XDA1X)tttlAh6<=sFEH zohEoQ8H4_Q89u;};>(lK=OF8s0gF-xa>D`z_=L?)=+@Ni3X811W$5 ovXrD8|v#kicUE61fzhlg0DTNG=*Yf_fsGr9fOlDtyI6Sl?jUQnQXL(kh(QrY{G zOYxdnyb#dyDf8wvaHFFaGpx^*w1<1L7fn!_?-j((# H^Qf@CLT;ejg)1;|)3pg%se#)+F#Hra=%rU<(9UgZoW z(061u*?2y 3Qa|VjHRzrE*AmUZvS+MBIw9xfb?; zvG{XlDMtd%ld-~~m63)}PY|0yb#S3w6P*ZELf@;R+@mjKN9wWguG32E;x+k2>d=2m zAhF(0LLL#GCvNk9IHpgGWZOdTLU2m}g<&jkNjGnr{Zj%-YP0*=+D6cOLavMn7BnKm z?%)Gvv`{Cjp6xjNHR<1VKvgO`+@l83A5^6W<0$fn>RAikOtY|#{{tKx`p{E9GR%yi zsimNyTeV3K|NM6Tn_>q~v!J}95Y>S4?5fp4H nR}g<{L@jE@uaeR*ZZ13Vbq6hB5wl6XJ% zo5pt|a nKT1-LCJdp@~=h+S*NZ<&IC-lq!YMQ}1)UXMMLn zNiD&_@>3e}Tfz`Q_OsuJI;h3Zo{_e*Ko|BWJgXsNhuI%RG@F9&8u*+TC3^}Pod~v< zaf}E9S;Zqm7X(TvAQ+2N#41f}1VycjrX&4GIhHl(Zz?u_9kl^NpesWmx+Jn2%E)pp zyZp)2nLA0ND_o^vjOmf?vg;;gMFh|lQ!Rskmy`cQjW8j98_i}Ta+b9O`;*=gM&+%9 zUQ)@U_~aG&*Cp3rCD@s0U~kV>qP^1u_MgNdKnAdwZNc{dJ6ebgDnLYze44==9Xf1A z?~~arx@y=pVdH*6T>5X(M~MrQT~xjwT(*z>#2l+sO0j)$FYoVoeI@85OPc1k#jgq` zLqC;osn0PNcW<&{=W;NQBzeTJSyO^!s0}Lj(a~p1q=c4CwunfrYd=)4z1S{W365G7 zh-i0j^^x!KNls4od3X@IIdSpy (O9=aAZ-8s16-P;w6nc7 zvf-~gkZes#Mb$UA>@ZQ+2`HXxI >1v=3*siKR zTTW}wQ#hW29VXdujmKU<@6&90(qlb8ojIcFSYwZ5V4Ehr0in@|c5QSNWBB*HoE9kb5e1tQ z%K=p>&d%-7(Qv&V)(HZguYxpk_^n#5q+C2MS-(#t?yyi}GHSB*1lPSBy1if9@bZ=0 zK`|kkM7H8I4YsK>xSQBg671O?8j#A@F1a?9rWRH3QB z9uuqXIrW95`8GZL8d`6-i#^p%>t;TcgP+^9BkHyS#Fm`sbZ{LWB#iWbE0V$To=LF4 zunrjC?EijE1Y|GetQkRN%Ll_Jy$?FtzX^F4YQ)duEr0$>3zx$Grfg&^t0P{zf?}z^ z3WWyt61%@ZXlRg-lM`)G`M^+rfk&X(jGJY=la*hNYkKdjD>2D2G+%@A2z=KTy~MJn zCLbXL8Z^`t3z1GBNf?yjFb;B5=u)#iRWH@%q$sebpQ#1FPeiDBQ=c_ NUA_;ey z&rBj)aQbT9LmU5}=JG#e?HJLFQ^{)CnXn6ve=XW(20hBA!75r~x}*b;i_pzRZfr!t zMDc;b(2%NP?wh(gvgD=O$Rc=+#1n90AB5vLyGz-=JKoF z5&tEYw%=-~)8m^C_FQTUEA3q@2y)4)WL{Yir*gn OgdB9Rw;}U}p&54Y2s~-4p(eIgjWMo=PDMr6m3cdehKq~b zTK-wg{YoeV{0?^PuKjw_vz@SR$@k`TLmq7o{`b(d1|Eh_?G^J)F6G8_LL=!+6|R@- zdAbQ9E~xoUh>0W=$K>l`wF(TNvqk4nD!0w) z?Awz~vg^)xoiP693pPIqg~gJS+yh$Jg$T|G3z *aB)A`SLbv>F#P0b6nPW>tT5vzJo(D;w1U`|${MzR(5GR`=a>Zi zk&C|iWuGhkC1U$*kilZ9I3WQiNlZK|zaC&JI@FphAMvVy6Y%z(;8zzaeKO$+n OCI flKg5e?f*E)gAC|El3_G$6%Sds9 Gu6)a+JXBOoM~53m6dK-5n}U%v{jx04qZdIH{E zito%+m_RxLv7xX@%ffeni|gOt2z=LG-H|xBz;*B~gu{VKoE@Qlqu0a&d6~>zMp$}` zC~J(@{K3N1rZ>ky#QNK1=O0=*V^OqiPni#x*SPJjnfvUOc8z+!pWQGYuynG(?voT* zX5PlGjsLFG(bQ3ijHKVA%jF@nMj!%+_aH?B-{09TB2^8>tQGxJyY>HhpgBJLS?`C~ zOWZ#%`q-y ck?uoHpR0bSH3}5ec{D_bB>_F1o|+~$zAtCTG_H=phjbjcsFw9 zl=qt+W5<2^qpxsKCDW;|-mc>sLiyz7eRpIlX|)pa-Hns(HC(l%L|gR-{*O_ eSS=vm8aKS{@QnLMQ1l$LL3@GW#$sb1( LJxeW?$ _{ta(0BaqkQ|9@lKBuO%Sk0slS-~2TI zl(GQN!^_+L{B3VUq7T{QYj+%m1wxKW5SGT;+Tgc-@3Kh7MKv8Uy_)>7z=?w|NS$#2 z#H-$vOYWclA7Nh^7H79)8xj&ESR=t*g1c*i2MZEt+}#^@3$B6S8VK(0?yiAG8g1O& z<@R^ZnYs7QoNwk2577JRAN$>J?W$F)*3waqHfU?fk!`RIHJ?p?eIi%eYD^_qeO@KP zLfkQ)8FUn)44Q2OU`HCcGa|v-bcjui1BN8}JS1ssDRkS3X_KRI9l&sFtvgQ%NL^Br zgO+wj!s#!L1%=q=!a_uUfB(YG=cof7dqy5AY7%i7W%lb6A-{%|^w%OHc9B`Ea4IWa z5l?QJm;$M0c@qCySdQ S{o7G_1M(7t+Lq=oa3SBw7+HMCT_%Yf@YhuTN}Q zf>^AUYyvQk`ZQ`k1ef50?K=`Xk>0Uzw+36VadBRq4voPPhRzVuM_gQ8dvY3u z^g$?5*1VNE2zv}&8yYu_`aeHtKg>dkUjY@m$p1X!r)gNHmzS)}8c2?EQ3>TbQ+mYR z6=H+A7i!oVY%j{EWw|)>h-KJeZEdgYzWO#hS-|DrY8tZiU-xoaFK0#m$Qyki{18}J zXph`*ygOMS@(!Ie>R5*#TH))RutS~0e6dfU!nX4%t*X&hzFa4~(bVGnc=}9>nLKSI z^49_4vbL?b?jEDUO87AQHW70#>~>CpHvCDC8J$`h!Ie+zSF;(Zq946~AZ?8~gML&j zEGrx)_Oeda3DVVQfL}8rl=u9{_4NPWLH{ptExvO>a_!by>T0r*LvJJE {nhq0_c zVr+l9n%#J7laIlSNizr`>!n~QW4E-luG;a09P$Fe&NbUk7AnHm=r>U|yt@#dqM zLErt+ygL~&OgqRG;=B5Ed;7CU`s>)QPzHlE397sn@CcSL3jWdOhAJ^$uKTK92TAI_ z6?Pxo1Z-TTQ>JZ?FRJaj{JspyBT39F$RrHZ)C-8+6t70oA o ziR>74szlrPqHA$Uz6u0Gzm8dP~RO=555e7z? zJ(LM~Rt;+-_!sG8sevKCbQrdEt=AA7^q!Mfs2JfhAK~ LabGNd=`z+8QAJ<4H$J7f1x-kao;)9dR`ihew= zpIQ~QHG}`eJ257AAg+4fP{zg0nAhheYgrViA4Yes=|fu+CZ{oTQc{@&ciR&b$Em5Q zX+$an{iu$0)8rxT+?HMGuRa>EG)ygPSrc^}OCFl|Mq}aNy!G|<<;V<-N>quj%9}sr zE>*8eA23!k1mTk!#kQkm1N()pLD6TYi}L?lj8JfV-4V7X;J8kYvbPjPF0fn`X;^L* zs~zG=`_68;j`X~z`7zmtl@2xU(Lji&qq9}BA++o2=Kw*KdZ5w8ch6a}APH*TAMxS4 zGzN_hkM4-5$l`F00>kPsdxAk0T2UDf8un@j9rOq>Y&her5C437c~jttHVTNQzK?77 zOXicwumJ gJ=63jou-vboqq~;Cg_%) z1>#B=ps&8Vy}KoAAwv&QRvEnsX(-^yp-Alng9msW81` (9cFg9*2*Y}T*RQ?U z%#JI@tD^fd7|08ls?-zXq;A#wWBDxqhC}+FFR6dc&rYO?^|ZK56Zi$K3L>*^Ga0w- z?5Acz4~j-%fh|hP&EODtN+u4%-yxTM-3f%F&pWI4y^IonP)~3A-lH$WyfE&Fz VNuf5Ng ^s+YUK0f;uJfG>+oRE_G1i^G~oQ@__*K?EB#|n #-UxcXFd-TuPS%u#k{#P8Oli7=kIZ?8VBix3(qxktxY2mH!JY)HhnI ^8{uj*UwX_;ZO(NmQZT^xECM2|J{xSfRngI=YtvWmC0A zcf6~s2UWoJsF!EeD=N_EX|l`;$eCTDen0rU?^4PR9aR4Nbp2nUGF=v4p>gfuAdU+r za4S`_D;-HR`Q9<9T!P|)cKF)0=0n%W3>J& z3~aJ@JbCOHG-fnPlukTxiUZ)zAJ+|pwd?!$ZCb__F2n31hA0sXx+eqav)4AWHgRIw z0{`M THgZ@-Cet_tbCnGxaTiboJWBHE|V5n3b2?5z&UnC9LBHJXjhzp?4k;d#6kc3>C=h zhj>!QRqV{Ts^vQPV5ObDlZ@nKyt$dGQROb84jZWE8q35Zepe*Fl0uTbgC#*?xq3(w zhndmVxe1= Jvf_oTg)`Hlm6=7MT9RNJx#= zu=O0KD5Rx1Eh$h96l3GRE${y$a@*Sic(chfjvoEJ0n5#pw(foRWi*l1h^-WjG7DdB z%sNQUBo7m80G=`5B+-w*e;@6k9XG(&f?vKaOXHazi@EbgP$7G^SaIO5qmSGbwB7W3 z_mKWYK$g~P_54ue^btX2&+wxA2`tzBn@2bNm57Mob4AQqUulrp=-%VqYL@;ueMrwk zWJ;~VH&{CSn~Drg4WK~RsK%$kbfy+415V {Cz@APy)vOxjok zib_QwT6asPvGJk_NT+RJhPRE5XsMZs70Ke6;j3K3TCi=?mq|T?cq=O_=5wX^kB?NE zfwd*#;%>YoKDR#bZ0tdyZOWQ;p*>?@y^tFbFLdwwOGyh5oV7{bqe5Kk^>oZ#s0m5F z^Q=IO1x`p7K1^bc<}Gw96cLRbK!1L5aSBDB0rjBrtTi8$OS!l(@9bejmbEv3`}f47 z{~N9xBRY|s|GFWU1GPQ`j?D2n-1M{do^Q;i*^lK;^)EAsl# DqTmv3JwO9VyjbT!$NP#BKf9%JV&8@IsQN11FR29JK%U6Fv_3p;!G?J*CN>`rhdvw52>_lc=V)6vb8K z>Rn>RQuy(i4XfvwWn{KFVYhZO1^ms)!VqG0+yqcmPyimz%(cd$>lFU+Va8%R kc OTe=jN*$NwI{atP?J`*QY~_Z7@7R{ptnm1uJTowwDUC1Y zpgB%OG1RsF4!?vKfhAn%H e*( z_?Z*Rg@8o(#Jp2!GV!_AY9*d|C&CJGxuaY==46|xPq?{9pw`lKyhUt8ouiJLuzsUw zuOs!sc0_TtK@RWx@ex!}@ta&dN2T?J%k6X@Ppuhl<^%2RG+Q~WT=Iv0)JJOHfKAhX zB;KI65>F{prKkJTtW?PLAda#ntC`}uU`pB`6W+ jd_Tp^-hg}J4@ zTcW*Qw00?&XB5+vxaSuY7l7Y5Jw+6k-~t_P!`W=*;R*7>{gylz=nwQveC*CVJ-akO z0OUs{&5z2%YdbonREJJL7`kh9qUDq9sV91PL-A=AGrXt_`+vrWM0>Zm_Cy#~u+}Ub zZMR$F*@q_2!{koif*A29-uf8@-~SDt_5UJsJBV-t6{{cDjAu9;?aAnHjDj!A*izAh zYT$!GiIwBHY^BwKMu}c6uEJ- lwlEJMlHQ{_Q`cdvId_eHyoo9IZ_6JEU51)nPeNwyI#0dG774#qDNo{ILiu_bQ~ z7S@X5r@we_L47$4_j3*2kQtsxacrmZFMKpvYX9yQK>o{>M6NrK{0W8(nL_R%BBygn zA{)xvuWdgYK03myvo2qb(tFJ3SsXlf1P^ 8lE`E`bL&1>r-D}9-NTk*vfI49Cj-&AeD&-&|41$J@0=EN *vI=@V z8Ta-{8jSB><*$xpd41oD02096TJjh0952SimlD-{U4=zZUV_)m#dIxv@H)+UclOb| z8pIA}b)PKw9GSA`_~Wcq-a8MbsEVcPs^0iw6>BV>Qp2RbI;v~?s}fB~5$Y1vLU+#3 zWhiqr101iW+00TZu=%v@?O6@!D%Fx?oXnR9Twm4|+>-geO~z_P7p;zW$_ZP?#iv?8 zS~6QZ+=u=|)&K*|00qRh#`r*#uACRO#3e=T_z8?Li@{+z$&D`WQU=MG@(chGrg{4t z*%YgJ9dYaMz96R$H@nO4;o$t! IfQ z_KEiD83qInP7KO5hDsQYm4-wZ@+ftRUOcYhD3R6CRxjSEM%12DK50!rc8J8(4Dsm~ zuiS1{J%Rx5b(WJyQl#AUPnc&ZKv974(J1k7MCF{JmhAJM?k(Q %V*>Wi ze)|*96oGPQ+XgE@1Wf5khGZoS+gWGC^&&~hc&vyGVQBAhH;r`7r#ZlmK!m_<=E+lc zl?3}c@x@*G_(t%(I<(_#@`Sbet7{D%nq7*kvImV}n)q76*Y>`__T|&dlX9*HsjH*t zSuI!S!&`>QdX31UpBE>K^*F&-` c-`8 zVhf4=H7>bXTJ%2cjXFgcb-RowAgph8*mm6c>s*+a+8_0r@uw}Pg>Zp6Oh1#3(h NhN9_71hsrTW1nJbx2$J0}?*-hQc pq?y}HuRu7iDWKUVUmX#4*Ltk_dc$}>A!PwrkZ5UC=CV1`;ZfC@(cgL z 5p8d0fhNEW~Tdr;z&0r~K>veNJ(@(Rk<6t4x~YRJ_K{I7EQ z-<0k4^%%Sc0Vh+h&h*`6+?x^?m&zXqT8` foGWRdLP) ziVcUOYKsXUl`F_YmVoP*WD7bvlyzbPs`1*?Eotx4x!7zpwCZKH@|2=+7Dh=-b|rP? z@GF6vjm3|8RjFxr#ByVu)RgZi{Gwa_HQ6_COa8?A%c|9aCsE 0% 0j zL)RsZ6I;6-#> )oA#zvqK&ag z8B>QsVn`Z~hTrYPIg^okCKV9P(bUVr!`kwsY85yiqdO~P=YF}*NMEpSgb`ky#y;Pj zHON^_FXW2ydD%fNh24$tR&=d z${H@dvXqPOTxeyhW)*rY?V|lHy6E5h7iYHNxF~&oku~_j`yk~Z%G}*hO1SQKUmt8z zRIAa2qnv=Fc4a7j+CXg>5|6n(FBXXQfu*@8cd(sbwvJh4=eU_(!Z<-$sq80j+7L*> z>3PHk%zIFpFh6LItu$Du6aD8SA7zURZnJvvM_X~?`bL*S>B!xgGRdXNwO8W7@1O(V ztnLPsCjKb2O^b^p=zdktSwR}}fKHNbpzYBHtM@uG6fe=MJ*(rCmT{Zw-OOKLDZ%H? z`z7qJ_&vBBK2@R33fV~;`P8GsK32=BZgu-6bP9Tur>UsXP>M+zQt Ro-F=lmk`z$Y5JT#d%!e)uEc^aZVg-4ng@G=f2S)CX`>Nh+ z2=MwcP9!z1y6sb*@YqcucXt9S{jlGxw+ zF!E%fi)H7rj~4K3#5pc%|83FKF&s zT0miVq9c3QXcfDx?&>R&_0kSyT6=CHn$ismX?Oo1T@X5gp#0+}y79%T^-Z+I3y!Rx ztX(N+-o_DaqcfFL*O7~Iu=grL*tCnsQI912g6L>2gLG+cc4r_LjzGSUe(A)qUD( zRDtI|i?RPU$QdoZR*K`b6=DY}%(S7NTtx>e?>-sMi9QZ`)j;3flz_qoZoj*#E52If zw6aVuk1J@9O;gK{DwVasBD6{TxM4F}uVb3rnB3$0%L**`VRcj|{KqE|n0CvoCoj-H zr^ 8iA5_=tix*OK9_oar#2q0ue1F!q(-_> z4{25N)zE~UEI@?&CyfSC5v_+ZBaI~&0n+5`U3!CES(*2A&1VO3-oH}>9 ;VCuj)#T9=eSCPEoySVrtpe-#!fN*x3_j7PCHqP=$& zzQvPI6VK6$A;IG%gToq#fhm0AzJ(%F_x# z<;NdiGNLLa%V+`!=c}KYzlCmjXn$rB1|qjW*Rxjj-H4U{4y@e~^siAn6-pCX5Yc5L ziAc%1eaU~sjhJKm3TlWxHA>!4)pA|;6`APyYbq!hw6jjUJ>Y$w@fEbxTlH?BW%b1{ z5i10hms!xxn~(TLmkUV%jcQ|6@5NZV_4mV-p!FzH4%?Vc2NSZH0BUo2gD!9ND8BREfR>tUHN%7%kS$a_!--8Z zjx_ q>l(MnP5_m2J#fA(F5}J}U$9Fv$<|LE`CnM|YM MK9OK~QsgIjs zuL3=gXmc6Fs~je9Bq6j*q85(}u{dws>-0{JE7Rz)qAVx(=nlutrm_0o@f+{p{1P}Y zW&})kq}7F@Gu}ZzDHCv?K+Lokc(mC+$Ww?`*^Vec2@=gI-m6)&4mc8Xa0sBQn2q*5 z_hN^SXEz>p187ET`SfSCkT1qrw3`4}Qs~0_2!FU=s!5l2NDLdbTR`G8+B1O6RubiU zQ-dp@Kx~?J;A!ILU0)l)ZcTUsv#kodQn4L2roTq%;KgqZVWZB5W55=BdmVn!w72^6 z#LHx88!)yrxq_^n@7F`!IP3ls;VRS*kDhNFFyBwL3Up}M9lb_p3BfqxPvU-KG`Vwr z?e(b}6*IG8WM1vZ)5c-zVM4a_VmcDiMOu<(WN4#4N^2EX03LHASsUJn@XGLyZg<4! zYq6Ju4ZuP(zw>v729-Kn=qjY4gRwW*#`Bge6ye?_W*|ro)gVY^wSDJR{)9&OWhqgu zF=rw}f0mgt@bUD(u+%I(mR oUrm{{ z!;%XTcdjh!r1HLZOpG{Poo8bJJgNCAU_XrPRxIJ=y^>_}r=?lor_~1#lwa%K3wZHV zycI4Mk%_#(Q)MV=pNH#EBsD%B>&ZsNM+`gLxtfW}O6X`hDZlqZaAA?>F4MXWX9p{U ztdCit)R=7hVDH4IOteOVkK%3`$Wp*1A_GTUO-!2CF5;C#vUJ^}NkB?RUtvT3AfrJW zozXfSBi7~r07U-_)8?<5GZI#a<@6NSZ8*_j5a9XQJzpmSoPo9r{sS*pY$R?+I;G3) zgfXiQ)W JTA(iRW#Fj zny>Ey?`YopgKab2fw(BGnE8QwgM=A}#6`mpUe_1 uMD{p>A)H; zYqyBJ4s{VdNkJ~EuHm)Hn|AZ}0xmi{0# ebeK%iT^iBWJu*r;13>!)ORZJ2 *rmNiLG*Agen0)OUc+mH6$z9QX$V3 z=);VP4LF!%FF02h4y7_&PD6pykx9Dj+T`>a!)T9_RlR2VMaK9#E&j;~)pxjZ^88mo zXmyD4^x4Uax81dg;v^27hQs-=u)E(NfeL)fM?Fu{w 2Y*fSyAFGBpaS%$ zA8mCt0nIUXHVzd&pb0^&{f2`e(2vOuLSKm0V)>H`&tE*)QIpBB3_4NL-tZS2o(FNx z59 ZD^x!(%J=ZVR9J?{xDH~H-GF5*l;HP)cptoZt`RY1r>}E-{tD784y>j*m+e2 z@V}DIW3!3o46b{LLhs;4N07tg!pK+}Fd!gBygdwAFuf7hWnk&J;G^gfwO{Vr5hH=0 zuRFomu28pw--wVz`=!4`@bcipoojP+4uzNyS)pNi^g{Q;e&6bMOM3Nq`o&lHq{fia zQGuClxB6(zSnMzc+mg_06%XY*8UiPBj5pRYwDaT19@1QY@Lf>mRy<=`Amo!%yYtTp z-BY3Iy4xJBkJhs`l=En8Ul9DDX!71l#fsH~_a0&sdf*E0XH4^5iMd)mVFPQQ$S$Q> zef*xC-u77h8(msp?`J)Slv>r{?=opfy#KnZv)I5zY8nF4C|Y|MD}+;cRFJXK=$ZV& z$hc-NZ 7=D}pU$qd8>SB3V;R)_b< zQ83*IWpPAYn)B~od~Y#9cv@RANihSYZnk`fSlvWF5`P#Tf%E=?NJKx0tA^0-t#6Gv z2b*v&Qmu}L8)Y2~I`cU*(6y!xe5IWp_Q4m`Rr6DnMNF*Ba}cN8Qmd<*+rmpw-Kd6O z5nxJEe{;+e*r5ldY<1zztPn@wvh #eXT98SB0f7i+tx }DvGXL7x0s1+cj;}O7Vm_xy6Zz`()nCnQNq~2W#@TqX4HJSzK>wg=-jK zC0@-t2e3>&8frz+>XJ3t|EJ*)YA+f73U`qaL(J~PavzGBbM}1IF=^oW>L{33nJC@$ z>sRP)nZ6GgCV|r%y6PID7mDui6FEw8hZmDFL}gy!#8zq(4dfI)4>_R^DQvd_VNwlL z#$V025Sp1rWJdEj5iCz5_P!~P;dxj>w~|z rny!}b@IQ&)pfuMY++6@c(Stu-$yw+f{ZgEzuZlV|4#@ z(ssuVtxZ6H-#n2gL2LBrHm8J0Nd-guWm#B5c420K7mA59t)!%6SUk51$XyQ0O^I1M zEK)HFHW|z->rbAO&g14(xKW+&(b*`%M> Yy*5~8X6t5gBV`L`9iF^o!KL(G<<^Jb%!;X&C2S@cjDZC*uFls!DaLm!*sk=f zA10y#f`LBA7}pYmQO9`iK(4YHH_Nu-b?>>r2}Om_GTN3ukOCO98L&j1BN+kTJiYb# z4IKhFkK8>Cs#!8sIM+Ya`oWS|ljol#(*Mr1wO_ DDs)Z9Hn~ITkGEWi+`)Xdb*EBn& z(phLhNd`;H_%sVDC>D&^^qX5Wab;dOVTwaR(sdNO=O#EsAIwUyiy8to-OYP6U6;*B z<_ZaV=mM(!Ewp9}vJv=mGaN hnPr>kmzrnhn9hfq@r5ev8+Z-Ww{V?3+fo&Ik?Gx9v^IT6gF z`ub!$Q2EbIko4~iq%(Jno)LL&3=-PaWm>%O1(X?v(v?upu6~RbWo}l;@dj7gkJQW{ zs^CytQt&8W;03?FJgv&>WWmYtwpoU9qkI#7?MS_` wsUTp>p_CzW!gJKA% zVQtgf!{CtF!F2|3O{hbxO@N7O6h%&1AgDe(&<)LY|0`QVXR$;0z(#Yz#?gt}G?aE{OY3Pu;)RuTKctoYE=0RO1dAPS8`x`95-J9!$E;tVXYZh~DY@Z0 z!0!eQpMRwlRZBQc>^e1+-U|*#Y(v1e^_ x*d(4|}s4@E+CE1qH$U70MA#}DnE}Wv}0M6ojX$A|*fDr2W zAs;$hZGLc`uTUSrXR&HVtk?AV;{3dGrR^a$F3ukh*$tN0V`JlX_Z+{`)AL0k5Ptn8 z1XW5`fu!DUHEh-jXo%mpS~hyo;`{O$o831*