From 7bd6287ba6de475b525e5bebef0a3b97be45c24a Mon Sep 17 00:00:00 2001 From: mcop1 <89011527+mcop1@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:58:30 +0100 Subject: [PATCH] [Task] Update docs (#920) * Added new doc for alias operator * Added new doc for alias operator * Fix operators * Removed isOperator variable * Removed debug info * Added new operator section and documentation * Added new operator section and documentation * More operators * Added examples and screenshots * Reverted change to merge operator * Added mutation examples * Update security settings * Fix links * Fix links * Updated mutations page * Updated mutations page * Code format and lightboxes * Added info boxes * Updated documentation for advanced relations * Removed unused screenshots * Removed unused screenshots --- doc/02_Basic_Principle.md | 4 + .../01_Configuration/01_General_Settings.md | 12 +- .../01_Configuration/02_Schema_Settings.md | 9 ++ .../01_Configuration/03_Security_Settings.md | 28 +++- .../04_Query/05_DataObject_Queries.md | 15 +-- doc/10_GraphQL/04_Query/06_Operators.md | 103 --------------- doc/10_GraphQL/04_Query/08_Localization.md | 6 +- doc/10_GraphQL/04_Query/10_Filtering.md | 4 +- .../05_Sample_Element_Properties.md | 2 + .../11_Query_Samples/11_Sample_GetAsset.md | 9 ++ .../12_Sample_Asset_Metadata.md | 4 + .../13_Sample_GetAssetListing.md | 4 + .../20_Sample_Manufacturer_Listing.md | 2 + .../21_Sample_ManyToMany_Object_Relation.md | 2 + ...ple_Advanced_ManyToMany_Object_Relation.md | 65 ++++----- ...e_Advanced_ManyToMany_Relation_Metadata.md | 124 +++++++++++------- .../24_Sample_Fieldcollections.md | 6 + .../25_Sample_Parent_Children_Siblings.md | 7 + .../26_Sample_Get_Linked_Data.md | 11 +- .../27_Sample_Translate_Values.md | 4 + doc/10_GraphQL/04_Query/11_Using_Aliases.md | 2 +- .../04_Query/15_Add_Custom_Query_Datatype.md | 2 +- .../04_Query/16_Add_Custom_Query_Operator.md | 11 +- .../04_Query/20_Add_Custom_Query.md | 1 + .../07_Mutation/01_Document_Mutations.md | 6 +- .../07_Mutation/20_DataObject_Mutations.md | 112 ++++++---------- .../07_Mutation/21_Mutation_Operators.md | 17 --- ...formAPI_Create_Document_with_Areablocks.md | 1 + .../02_FreeformAPI_Update_Email_Document.md | 2 + ...03_FreeformAPI_Create_new_Link_Document.md | 3 + ...TreeAPI_Create_Document_with_Areablocks.md | 2 +- .../10_Sample_Add_Relations.md | 4 +- .../25_Add_Custom_Mutation_Datatype.md | 2 +- .../26_Add_Custom_Mutation_Operator.md | 6 +- .../07_Mutation/27_Add_Custom_Mutations.md | 1 + .../08_Operators/Mutation/IfEmpty.md | 50 +++++++ .../08_Operators/Mutation/LocalCollector.md | 56 ++++++++ .../08_Operators/Mutation/LocaleSwitcher.md | 51 +++++++ doc/10_GraphQL/08_Operators/Query/Alias.md | 46 +++++++ .../08_Operators/Query/AssetThumbnail.md | 42 ++++++ .../08_Operators/Query/AssetThumbnailHTML.md | 40 ++++++ .../08_Operators/Query/Concatenator.md | 40 ++++++ .../08_Operators/Query/DateFormatter.md | 42 ++++++ .../08_Operators/Query/ElementCounter.md | 41 ++++++ doc/10_GraphQL/08_Operators/Query/Merge.md | 3 + .../08_Operators/Query/StaticText.md | 39 ++++++ .../08_Operators/Query/Substring.md | 44 +++++++ .../08_Operators/Query/TranslateValue.md | 48 +++++++ doc/10_GraphQL/08_Operators/Query/Trimmer.md | 42 ++++++ doc/10_GraphQL/08_Operators/README.md | 21 +++ doc/10_GraphQL/README.md | 6 + doc/20_Deployment.md | 8 +- .../advanced_many_to_many_object_relation.png | Bin 50783 -> 41390 bytes ...advanced_many_to_many_object_relation2.png | Bin 32246 -> 15847 bytes doc/img/graphql/alias_config.png | Bin 0 -> 6304 bytes doc/img/graphql/alias_example.png | Bin 0 -> 7703 bytes doc/img/graphql/concat_config.png | Bin 0 -> 7432 bytes doc/img/graphql/concat_example.png | Bin 0 -> 9197 bytes doc/img/graphql/configuration2.png | Bin 29054 -> 0 bytes doc/img/graphql/dataobject_structure.png | Bin 16089 -> 0 bytes doc/img/graphql/date_formatter.png | Bin 4306 -> 0 bytes doc/img/graphql/date_formatter_config.png | Bin 0 -> 9741 bytes doc/img/graphql/date_formatter_example.png | Bin 0 -> 10780 bytes doc/img/graphql/element_counter_config.png | Bin 0 -> 7216 bytes doc/img/graphql/element_counter_example.png | Bin 0 -> 9782 bytes doc/img/graphql/ifempty_config.png | Bin 0 -> 5358 bytes doc/img/graphql/ifempty_example.png | Bin 0 -> 6924 bytes doc/img/graphql/locale_collector_config.png | Bin 0 -> 5620 bytes doc/img/graphql/locale_collector_example.png | Bin 0 -> 5593 bytes doc/img/graphql/locale_switcher_config.png | Bin 0 -> 7098 bytes doc/img/graphql/locale_switcher_example.png | Bin 0 -> 4101 bytes doc/img/graphql/logo_mini.png | Bin 1554 -> 0 bytes doc/img/graphql/many2many.png | Bin 15821 -> 34340 bytes doc/img/graphql/many2many_data.png | Bin 0 -> 27382 bytes doc/img/graphql/mutation_grid.png | Bin 58167 -> 51204 bytes doc/img/graphql/operator_concatenator.png | Bin 21065 -> 0 bytes doc/img/graphql/operator_elementcounter1.png | Bin 20305 -> 0 bytes doc/img/graphql/operator_thumbnail.png | Bin 33272 -> 0 bytes doc/img/graphql/security1.png | Bin 21606 -> 60438 bytes doc/img/graphql/static_text_config.png | Bin 0 -> 5934 bytes doc/img/graphql/static_text_example.png | Bin 0 -> 8473 bytes doc/img/graphql/substring_config.png | Bin 0 -> 10176 bytes doc/img/graphql/substring_example.png | Bin 0 -> 4960 bytes doc/img/graphql/thumbnail_config.png | Bin 0 -> 7968 bytes doc/img/graphql/thumbnail_example.png | Bin 0 -> 7423 bytes doc/img/graphql/thumbnail_html_config.png | Bin 0 -> 8206 bytes doc/img/graphql/thumbnail_html_example.png | Bin 0 -> 5553 bytes doc/img/graphql/translate_value_config.png | Bin 0 -> 8078 bytes doc/img/graphql/translate_value_example.png | Bin 0 -> 7472 bytes doc/img/graphql/trim_config.png | Bin 0 -> 10382 bytes doc/img/graphql/trim_example.png | Bin 0 -> 5767 bytes 91 files changed, 887 insertions(+), 325 deletions(-) delete mode 100644 doc/10_GraphQL/04_Query/06_Operators.md delete mode 100644 doc/10_GraphQL/07_Mutation/21_Mutation_Operators.md create mode 100644 doc/10_GraphQL/08_Operators/Mutation/IfEmpty.md create mode 100644 doc/10_GraphQL/08_Operators/Mutation/LocalCollector.md create mode 100644 doc/10_GraphQL/08_Operators/Mutation/LocaleSwitcher.md create mode 100644 doc/10_GraphQL/08_Operators/Query/Alias.md create mode 100644 doc/10_GraphQL/08_Operators/Query/AssetThumbnail.md create mode 100644 doc/10_GraphQL/08_Operators/Query/AssetThumbnailHTML.md create mode 100644 doc/10_GraphQL/08_Operators/Query/Concatenator.md create mode 100644 doc/10_GraphQL/08_Operators/Query/DateFormatter.md create mode 100644 doc/10_GraphQL/08_Operators/Query/ElementCounter.md create mode 100644 doc/10_GraphQL/08_Operators/Query/Merge.md create mode 100644 doc/10_GraphQL/08_Operators/Query/StaticText.md create mode 100644 doc/10_GraphQL/08_Operators/Query/Substring.md create mode 100644 doc/10_GraphQL/08_Operators/Query/TranslateValue.md create mode 100644 doc/10_GraphQL/08_Operators/Query/Trimmer.md create mode 100644 doc/10_GraphQL/08_Operators/README.md create mode 100644 doc/img/graphql/alias_config.png create mode 100644 doc/img/graphql/alias_example.png create mode 100644 doc/img/graphql/concat_config.png create mode 100644 doc/img/graphql/concat_example.png delete mode 100644 doc/img/graphql/configuration2.png delete mode 100644 doc/img/graphql/dataobject_structure.png delete mode 100644 doc/img/graphql/date_formatter.png create mode 100644 doc/img/graphql/date_formatter_config.png create mode 100644 doc/img/graphql/date_formatter_example.png create mode 100644 doc/img/graphql/element_counter_config.png create mode 100644 doc/img/graphql/element_counter_example.png create mode 100644 doc/img/graphql/ifempty_config.png create mode 100644 doc/img/graphql/ifempty_example.png create mode 100644 doc/img/graphql/locale_collector_config.png create mode 100644 doc/img/graphql/locale_collector_example.png create mode 100644 doc/img/graphql/locale_switcher_config.png create mode 100644 doc/img/graphql/locale_switcher_example.png delete mode 100644 doc/img/graphql/logo_mini.png create mode 100644 doc/img/graphql/many2many_data.png delete mode 100644 doc/img/graphql/operator_concatenator.png delete mode 100644 doc/img/graphql/operator_elementcounter1.png delete mode 100644 doc/img/graphql/operator_thumbnail.png create mode 100644 doc/img/graphql/static_text_config.png create mode 100644 doc/img/graphql/static_text_example.png create mode 100644 doc/img/graphql/substring_config.png create mode 100644 doc/img/graphql/substring_example.png create mode 100644 doc/img/graphql/thumbnail_config.png create mode 100644 doc/img/graphql/thumbnail_example.png create mode 100644 doc/img/graphql/thumbnail_html_config.png create mode 100644 doc/img/graphql/thumbnail_html_example.png create mode 100644 doc/img/graphql/translate_value_config.png create mode 100644 doc/img/graphql/translate_value_example.png create mode 100644 doc/img/graphql/trim_config.png create mode 100644 doc/img/graphql/trim_example.png diff --git a/doc/02_Basic_Principle.md b/doc/02_Basic_Principle.md index 5fda502f..5731a3c2 100644 --- a/doc/02_Basic_Principle.md +++ b/doc/02_Basic_Principle.md @@ -6,11 +6,15 @@ Pimcore Datahub allows defining multiple endpoints that allow data delivery and 1. Open the Datahub configuration panel: +
+ ![Configuration Overview](./img/graphql/configuration3.png) 2. Choose an endpoint technology: + + ![Add Configuration](./img/add_config.png) 3. Get the configuration done by defining the followings: diff --git a/doc/10_GraphQL/01_Configuration/01_General_Settings.md b/doc/10_GraphQL/01_Configuration/01_General_Settings.md index 7c713e9d..9f659a7d 100644 --- a/doc/10_GraphQL/01_Configuration/01_General_Settings.md +++ b/doc/10_GraphQL/01_Configuration/01_General_Settings.md @@ -1,5 +1,7 @@ # General Settings + + ![General Settings](../../img/graphql/general.png) #### Some Aspects: @@ -8,9 +10,15 @@ the [workspace settings](./03_Security_Settings.md). SQL Condition is currently deprecated but still enabled by default. If you want to disable it, you can do so in the symfony configuration tree: -``` + +```yaml pimcore_data_hub: graphql: allow_sqlObjectCondition: false ``` -Please note that this option will be also removed in the next major version. \ No newline at end of file + +:::caution + +Please note that this option will be also removed in the next major version. + +::: \ No newline at end of file diff --git a/doc/10_GraphQL/01_Configuration/02_Schema_Settings.md b/doc/10_GraphQL/01_Configuration/02_Schema_Settings.md index e261438d..1a0a247b 100644 --- a/doc/10_GraphQL/01_Configuration/02_Schema_Settings.md +++ b/doc/10_GraphQL/01_Configuration/02_Schema_Settings.md @@ -2,6 +2,8 @@ Schema settings define which data entities (Data Object classes, Assets, Documents) should be exposed via the endpoint. For Assets and Documents, default schemas are provided, for Data Object classes the schema can be defined in the field configuration. + + ![Add](../../img/graphql/schema_add.png) ## Query Schema @@ -14,9 +16,16 @@ When adding a new entity with the `Add` button, you can access the `Available Fi In addition, you can employ a set of operators. + + ![Schema Settings](../../img/graphql/schema.png) +:::info + Please note that not all data types are supported yet! + +::: + You will get a notice if you try to add an unsupported data type. ## Mutation Schema diff --git a/doc/10_GraphQL/01_Configuration/03_Security_Settings.md b/doc/10_GraphQL/01_Configuration/03_Security_Settings.md index 2d3965da..7fd824dd 100644 --- a/doc/10_GraphQL/01_Configuration/03_Security_Settings.md +++ b/doc/10_GraphQL/01_Configuration/03_Security_Settings.md @@ -1,5 +1,11 @@ # Security Settings +The security settings define how the endpoint is secured and which data is accessible. + + + +![security1.png](../../img/graphql/security1.png) + ## Authentication Here you can define how users are authenticated when accessing the endpoint. @@ -7,11 +13,19 @@ Here you can define how users are authenticated when accessing the endpoint. #### Supported Methods * API Key: needs to be sent with every request. -* ... more to come + +#### API Key + +To automatically create an API key use the button next to the input. +For each click on the button a new API key is generated and will be added to the input field in addition to the list of existing keys. ## Introspection Settings -Introspection provides an information about queries which are supported by GraphQl schema. This is currently enabled by default. It can be disabled via security settings or in the symfony configuration tree: +Introspection provides an information about queries which are supported by GraphQl schema. +If introspection is enabled, the endpoint will provide a schema definition which can be used by GraphiQL or other tools to provide auto-completion and documentation. +If introspection is disabled, the schema definition will not be provided and therefore no auto-completion or documentation will be available. + +This is currently enabled by default. It can be disabled via security settings tab directly in the backend or in the symfony configuration tree: ``` pimcore_data_hub: graphql: @@ -20,17 +34,21 @@ pimcore_data_hub: ## Workspace Settings -Defines workspaces for data that should be accessible via the endpoint. +Defines workspaces for data that should be accessible via the endpoint. The definition is similar to Pimcore user [workspace permissions](https://pimcore.com/docs/6.x/Development_Documentation/Administration_of_Pimcore/Users_and_Roles.html) +:::warning + +If no workspace is selected, no directories are accessible. + +::: + Available permissions: * Create * Read * Update * Delete -![Settings](../../img/graphql/security1.png) - ## Error Handling - Configuration Values diff --git a/doc/10_GraphQL/04_Query/05_DataObject_Queries.md b/doc/10_GraphQL/04_Query/05_DataObject_Queries.md index 10655b6b..0ea77dd8 100644 --- a/doc/10_GraphQL/04_Query/05_DataObject_Queries.md +++ b/doc/10_GraphQL/04_Query/05_DataObject_Queries.md @@ -1,6 +1,6 @@ # DataObject Queries -## Supported Data Types +## Suppored Data Types Also check out the Pimcore's [data type documentation](https://pimcore.com/docs/6.x/Development_Documentation/Objects/Object_Classes/Data_Types/index.html). @@ -53,18 +53,7 @@ Also check out the Pimcore's [data type documentation](https://pimcore.com/docs/ ## Available Query Operators -Check out the [Operators](./06_Operators.md) page for more information. - -* Alias -* Asset Thumbnail -* Asset Thumbnail HTML -* Concatenator -* Date Formatter -* Element Counter -* Merge -* Substring -* Static Text -* Trimmer +Check out the [operators section](../08_Operators/README.md) for more information. ## Get single Data Object diff --git a/doc/10_GraphQL/04_Query/06_Operators.md b/doc/10_GraphQL/04_Query/06_Operators.md deleted file mode 100644 index 9f940a5b..00000000 --- a/doc/10_GraphQL/04_Query/06_Operators.md +++ /dev/null @@ -1,103 +0,0 @@ -# Query Operators - -Operators allow to modify and transform the data before it is delivered to the endpoint. - -![Overview](../../img/graphql/queryoperators_overview.png) - -#### Alias - -Simply gives the child node a different name. -See also [Using Aliases](./11_Using_Aliases.md) for more information on how to use aliases. - -#### Date Formatter - -Utilizes the PHP date formatter. - -![Datahub Configs](../../img/graphql/date_formatter.png) - -#### Asset Thumbnail - -Returns the thumbnail URL of the assigned image. - -![Thumbnail Config](../../img/graphql/operator_thumbnail.png) - -#### Asset Thumbnail HTML - -Returns the thumbnail HTML tag of the assigned image. - -![Thumbnail Config](../../img/graphql/operator_thumbnail.png) - -#### Concatenator - -Concatenates the child values. - -![Concatenator Config](../../img/graphql/operator_concatenator.png) - -Request: -``` -{ - getPerson(id: 28) { - concatenatedname - } -} -``` - -``` -{ - "data": { - "getPerson": { - "concatenatedname": "John Doe" - } - } -} -``` - - -#### Element Counter - -Counts the child elements. - -![Datahub Configs](../../img/graphql/operator_elementcounter1.png) - -Request: -``` -{ - getUser(id: 50, defaultLanguage: "de") { - count_myobjects - } -} - -``` - -Response: -``` -{ - "data": { - "getUser": { - "count_myobjects": 2 - } - } -} -``` - - -#### Merge - -... - -#### Substring - -As the name says. - -#### Static Text - -Adds some static text. - -#### Translate Value - -Similar to Pimcore's [Translate Value](https://pimcore.com/docs/6.x/User_Documentation/DataObjects/Grid_Configuration_Operators/Operators/TranslateValue.html). -For an example see [Website Translations](./11_Query_Samples/27_Sample_Translate_Values.md) - -#### Trimmer - -As the name says. diff --git a/doc/10_GraphQL/04_Query/08_Localization.md b/doc/10_GraphQL/04_Query/08_Localization.md index b74db6ac..4b399979 100644 --- a/doc/10_GraphQL/04_Query/08_Localization.md +++ b/doc/10_GraphQL/04_Query/08_Localization.md @@ -6,7 +6,7 @@ You can change the default language for localized fields by passing the `default for single and listing queries. ##### Sample Request -``` +```graphql { getNewsListing(defaultLanguage: "de") { ... @@ -18,7 +18,7 @@ for single and listing queries. However, you can always provide an alternative language for a specific field. ##### Sample Request -``` +```graphql { getUser(id: 50, defaultLanguage: "en") { myAdvancedObjects { @@ -39,7 +39,7 @@ However, you can always provide an alternative language for a specific field. ``` ##### Response -``` +```graphql { "data": { "getUser": { diff --git a/doc/10_GraphQL/04_Query/10_Filtering.md b/doc/10_GraphQL/04_Query/10_Filtering.md index 7a4841ed..cc47520c 100644 --- a/doc/10_GraphQL/04_Query/10_Filtering.md +++ b/doc/10_GraphQL/04_Query/10_Filtering.md @@ -6,7 +6,9 @@ to filter listing. ## Sample -Get all `Manufacturer` objects which have 'ca' in their name field. +Get all `Manufacturer` objects which have 'ca' in their name field. + + ![Filtered Grid](../../img/graphql/filtering.png) diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/05_Sample_Element_Properties.md b/doc/10_GraphQL/04_Query/11_Query_Samples/05_Sample_Element_Properties.md index e9364df6..ba55c3df 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/05_Sample_Element_Properties.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/05_Sample_Element_Properties.md @@ -1,5 +1,7 @@ # Get Element Properties + + ![Sample Document Properties](../../../img/graphql/element_properties.png) ### Request diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/11_Sample_GetAsset.md b/doc/10_GraphQL/04_Query/11_Query_Samples/11_Sample_GetAsset.md index 4924dbab..a1f01fee 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/11_Sample_GetAsset.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/11_Sample_GetAsset.md @@ -1,15 +1,24 @@ # Get Asset By Id If you want to access an Asset directly. + +:::caution + Note that the data will be base64 encoded and quite time-consuming to deliver. +::: + Deeplink: [http://pimcore-demo-basic.pim.zone/admin/login/deeplink?asset_4_image](http://pimcore-demo-basic.pim.zone/admin/login/deeplink?asset_4_image) ### Request +:::info + Note that for the fullpath and the base64 encoded data you can specify a thumbnail config. You can use the `format` argument to retrieve the values for a specific format like `webp`. +::: + ``` { getAsset(id: 4) { diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/12_Sample_Asset_Metadata.md b/doc/10_GraphQL/04_Query/11_Query_Samples/12_Sample_Asset_Metadata.md index 9ad8c7af..73735a12 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/12_Sample_Asset_Metadata.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/12_Sample_Asset_Metadata.md @@ -1,5 +1,7 @@ # Get Asset Metadata + + ![Metadata](../../../img/graphql/asset_metadata.png) Deeplink: [http://pimcore-demo-basic.pim.zone/admin/login/deeplink?asset_4_image](http://pimcore-demo-basic.pim.zone/admin/login/deeplink?asset_4_image) @@ -82,6 +84,8 @@ Get the custom asset metadata for language `de` ## Get Asset Embedded Meta Info + + ![Metadata](../../../img/graphql/asset_embeddedMetaInfo.png) ### Request diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/13_Sample_GetAssetListing.md b/doc/10_GraphQL/04_Query/11_Query_Samples/13_Sample_GetAssetListing.md index b0ba3e69..9cea78c4 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/13_Sample_GetAssetListing.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/13_Sample_GetAssetListing.md @@ -2,8 +2,12 @@ ### Request +:::info + Note that for the fullpath and the base64 encoded data you can specify a thumbnail config. +::: + ``` { getAssetListing { diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/20_Sample_Manufacturer_Listing.md b/doc/10_GraphQL/04_Query/11_Query_Samples/20_Sample_Manufacturer_Listing.md index a467fcb6..59a735a8 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/20_Sample_Manufacturer_Listing.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/20_Sample_Manufacturer_Listing.md @@ -1,5 +1,7 @@ # Get Manufacturer Listing + + ![Grid](../../../img/graphql/manufacturer_listing.png) ### Request diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/21_Sample_ManyToMany_Object_Relation.md b/doc/10_GraphQL/04_Query/11_Query_Samples/21_Sample_ManyToMany_Object_Relation.md index 7e5dd33b..ad068f29 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/21_Sample_ManyToMany_Object_Relation.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/21_Sample_ManyToMany_Object_Relation.md @@ -1,5 +1,7 @@ # Many-to-Many Object Relation + + ![Data](../../../img/graphql/many_to_many_object_relation.png) ### Request diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/22_Sample_Advanced_ManyToMany_Object_Relation.md b/doc/10_GraphQL/04_Query/11_Query_Samples/22_Sample_Advanced_ManyToMany_Object_Relation.md index 32a74302..28251736 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/22_Sample_Advanced_ManyToMany_Object_Relation.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/22_Sample_Advanced_ManyToMany_Object_Relation.md @@ -1,32 +1,37 @@ # Advanced Many-to-Many Object Relation and Metadata ->TODO: Align this with the new demo as soon as reasonable content is available. +Data Model for class `AccessoryPart`: -Data Model: + ![Data](../../../img/graphql/advanced_many_to_many_object_relation.png) Data: + + ![Data](../../../img/graphql/advanced_many_to_many_object_relation2.png) ### Request +:::info + Note that the response differs from `Advanced Many-to-Many Relations` as there can be only class. +::: + ``` { - getUser(id: 50, defaultLanguage: "en") { - myAdvancedObjects { + getAccessoryPart(id:408) { + id, + classname + advAdditionalCategories { element { - id + id, classname - title, - deTitle: title(language: "de"), - shortText(language: "de") } metadata { - name + name, value } } @@ -36,48 +41,22 @@ Note that the response differs from `Advanced Many-to-Many Relations` as there c ### Response -Here you also see the use of aliases. - ``` { "data": { - "getUser": { - "myAdvancedObjects": [ + "getAccessoryPart": { + "id": "408", + "classname": "AccessoryPart", + "advAdditionalCategories": [ { "element": { - "id": "8", - "classname": "news", - "title": "In enim justo", - "deTitle": "Li Europan lingues es membres", - "shortText": "Lor separat existentie es un myth. Por scientie, musica, sport etc, litot Europa usa li sam vocabular." + "id": "392", + "classname": "Category" }, "metadata": [ { - "name": "altname", - "value": "Ratman" - }, - { - "name": "name", - "value": "Canine" - } - ] - }, - { - "element": { - "id": "3", - "classname": "news", - "title": "Lorem ipsum dolor sit amet", - "deTitle": "Er hörte leise Schritte hinter sich", - "shortText": "Das bedeutete nichts Gutes. Wer würde ihm schon folgen, spät in der Nacht und dazu noch in dieser engen Gasse mitten im übel beleumundeten Hafenviertel?" - }, - "metadata": [ - { - "name": "altname", - "value": "Spike" - }, - { - "name": "name", - "value": "Doctor" + "name": "altName", + "value": "AlternativeNameForCategory" } ] } diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/23_Sample_Advanced_ManyToMany_Relation_Metadata.md b/doc/10_GraphQL/04_Query/11_Query_Samples/23_Sample_Advanced_ManyToMany_Relation_Metadata.md index c7d03c67..ee8e71d6 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/23_Sample_Advanced_ManyToMany_Relation_Metadata.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/23_Sample_Advanced_ManyToMany_Relation_Metadata.md @@ -1,24 +1,46 @@ # Get Advanced Many-to-Many Relation Metadata + + ![Metadata](../../../img/graphql/many2many.png) ->TODO: Align this with the new demo as soon as reasonable content is available. +Data: + + + +![many2many_data.png](../../../img/graphql/many2many_data.png) ### Request -News listing with limit 3 and offset 1 -``` +:::info + +Make sure to use the correct inline fragments to access data from the related classes. +The exact class name is required to access the data. E.g. for manufacturer data use `... on object_Manufacturer`. + +::: + +```graphql { - getUser(id: 50) { - # advanced many-to-many relation - multimeta { + getAccessoryPart(id:408) { + id, + classname + additionalLinkedElements { element { - ... on asset { + ... on asset { + id, + fullpath + } + ... on object_Manufacturer { + id, + name + } + ... on document_page { + id, fullpath } } metadata { - name + name, value } } @@ -28,52 +50,52 @@ News listing with limit 3 and offset 1 ### Response -``` +```json { - "data": { - "getUser": { - "multimeta": [ - { - "element": { - "fullpath": "/screenshots/properties-2.png" - }, - "metadata": [ - { - "name": "aname", - "value": "B" - }, - { - "name": "multi", - "value": "1,2" - }, - { - "name": "name", - "value": "A" - } - ] - }, - { - "element": { - "fullpath": "/screenshots/pim1.png" - }, - "metadata": [ - { - "name": "aname", - "value": "D" - }, - { - "name": "multi", - "value": "3,2" - }, - { - "name": "name", - "value": "C" - } - ] + "data": { + "getAccessoryPart": { + "id": "408", + "classname": "AccessoryPart", + "additionalLinkedElements": [ + { + "element": { + "id": "97", + "fullpath": "/en/Find-and-Buy/On-Sale" + }, + "metadata": [ + { + "name": "altName", + "value": "OnSale" + } + ] + }, + { + "element": { + "id": "33", + "fullpath": "/Car%20Images/austin%20healey/austin-healey-1019023.jpg" + }, + "metadata": [ + { + "name": "altName", + "value": "CarImage" + } + ] + }, + { + "element": { + "id": "35", + "name": "Austin-Healey" + }, + "metadata": [ + { + "name": "altName", + "value": "Manufacturer" + } + ] + } + ] } - ] } - } } ``` diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/24_Sample_Fieldcollections.md b/doc/10_GraphQL/04_Query/11_Query_Samples/24_Sample_Fieldcollections.md index c906b868..03bf371b 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/24_Sample_Fieldcollections.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/24_Sample_Fieldcollections.md @@ -4,12 +4,16 @@ If you want to run this sample on the [Official Demo Site](https://demo.pimcore.fun), please create the following configuration + + ![Schema](../../../img/graphql/news_configuration.png) ### Sample Data Deeplink: https://demo.pimcore.fun/admin/login/deeplink?object_767_object + + ![Sample Data](../../../img/graphql/news_sample_data.png) ### Request @@ -42,6 +46,8 @@ Deeplink: https://demo.pimcore.fun/admin/login/deeplink?object_767_object and make sure that the `/News` folder is readable. + + ![Workspace](../../../img/graphql/news_workspace.png) ### Response diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/25_Sample_Parent_Children_Siblings.md b/doc/10_GraphQL/04_Query/11_Query_Samples/25_Sample_Parent_Children_Siblings.md index a5313d2b..fb59c799 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/25_Sample_Parent_Children_Siblings.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/25_Sample_Parent_Children_Siblings.md @@ -2,11 +2,18 @@ For example, to get `berlina` object's (id:261) parent, children and siblings + + ![](../../../img/graphql/sample_parentChildrenSiblings.png) ### Request +:::info + Note that for `children` and `_siblings` you can use the `objectTypes` argument to filter for specific types. + +::: + Any combination of `variant`, `object`, `folder` is possible as a value for the `objectTypes` argument (default: `["object", "folder"]`). ```graphql diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/26_Sample_Get_Linked_Data.md b/doc/10_GraphQL/04_Query/11_Query_Samples/26_Sample_Get_Linked_Data.md index 7ab1caec..6f8581bb 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/26_Sample_Get_Linked_Data.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/26_Sample_Get_Linked_Data.md @@ -6,8 +6,15 @@ Deeplink: [https://demo.pimcore.fun/admin/login/deeplink?object_277_object](https://demo.pimcore.fun/admin/login/deeplink?object_277_object) -Note that you have to adapt your schema definition as depicted below. The thumbnail -will generated using the [Thumbnail Operator](../06_Operators.md). +:::info + +Note that you have to adapt your schema definition as depicted below. + +::: + +The thumbnail will be generated using the [Thumbnail operator](../../08_Operators/Query/AssetThumbnail.md). + + ![Schema Definition](../../../img/graphql/manufacturer_thumbnail.png) diff --git a/doc/10_GraphQL/04_Query/11_Query_Samples/27_Sample_Translate_Values.md b/doc/10_GraphQL/04_Query/11_Query_Samples/27_Sample_Translate_Values.md index 45cf6cc7..7f2ea80a 100644 --- a/doc/10_GraphQL/04_Query/11_Query_Samples/27_Sample_Translate_Values.md +++ b/doc/10_GraphQL/04_Query/11_Query_Samples/27_Sample_Translate_Values.md @@ -6,10 +6,14 @@ Deeplink: [http://pimcore-demo-basic.pim.zone/admin/login/deeplink?object_373_ob Operator Config: + + ![Operator Config](../../../img/graphql/operator_translated1.png) Website Translation Grid: + + ![Data](../../../img/graphql/operator_translated2.png) The idea in the following example is to use the website translation feature to convert diff --git a/doc/10_GraphQL/04_Query/11_Using_Aliases.md b/doc/10_GraphQL/04_Query/11_Using_Aliases.md index a3939b97..efa89ff5 100644 --- a/doc/10_GraphQL/04_Query/11_Using_Aliases.md +++ b/doc/10_GraphQL/04_Query/11_Using_Aliases.md @@ -7,7 +7,7 @@ There are two ways to use aliases: ## Alias Operator -See [06_Operators.md](06_Operators.md) for more information. +See [Alias operator](../08_Operators/Query/Alias.md) for more information. ## Alias in the Query diff --git a/doc/10_GraphQL/04_Query/15_Add_Custom_Query_Datatype.md b/doc/10_GraphQL/04_Query/15_Add_Custom_Query_Datatype.md index ddfe5fac..59b97315 100644 --- a/doc/10_GraphQL/04_Query/15_Add_Custom_Query_Datatype.md +++ b/doc/10_GraphQL/04_Query/15_Add_Custom_Query_Datatype.md @@ -7,7 +7,7 @@ For adding a new query data type two steps are necessary: To add a type definition, add a section similar to this one to your `services.yml` file. -``` +```yaml pimcore.datahub.graphql.dataobjectquerytypegenerator_datatype_mycustomdatatype: class: Pimcore\Bundle\DataHubBundle\GraphQL\DataObjectQueryFieldConfigGenerator\MyCustomDatatype tags: diff --git a/doc/10_GraphQL/04_Query/16_Add_Custom_Query_Operator.md b/doc/10_GraphQL/04_Query/16_Add_Custom_Query_Operator.md index d041d299..3fd2eff4 100644 --- a/doc/10_GraphQL/04_Query/16_Add_Custom_Query_Operator.md +++ b/doc/10_GraphQL/04_Query/16_Add_Custom_Query_Operator.md @@ -8,7 +8,7 @@ For adding a new query operator two steps are necessary: Add a section similar to this one to your `services.yml` file. -``` +```yaml pimcore.datahub.graphql.querytypegenerator_operator_mycustomoperator: class: Pimcore\Bundle\DataHubBundle\GraphQL\QueryOperatorConfigGenerator\MyCustomOperator tags: @@ -24,7 +24,12 @@ You have to provide both JavaScript code dealing with the UI configuration aspec and the server-side PHP implementation doing the actual calculations. A JS sample can be found [here](https://github.com/pimcore/data-hub/blob/master/src/Resources/public/js/queryoperator/Trimmer.js). -Note that the namespace would be `pimcore.plugin.datahub.operator.mycustomoperator`. + +:::info + +Note that the namespace would be `pimcore.plugin.datahub.operator.mycustomoperator`. + +::: Make sure, that your extension gets loaded. See [Pimcore Bundles](https://pimcore.com/docs/6.x/Development_Documentation/Extending_Pimcore/Bundle_Developers_Guide/Pimcore_Bundles/index.html) docs page for further details. @@ -35,7 +40,7 @@ A sample can be found [here](https://github.com/pimcore/data-hub/blob/master/src Finally, we have to define how the operator instances get created. In most cases we use the `DefaultOperatorFactory` for that: -``` +```yaml pimcore.datahub.graphql.dataobjectqueryoperator.factory.mycustomoperator: class: Pimcore\Bundle\DataHubBundle\GraphQL\Query\Operator\Factory\DefaultOperatorFactory arguments: diff --git a/doc/10_GraphQL/04_Query/20_Add_Custom_Query.md b/doc/10_GraphQL/04_Query/20_Add_Custom_Query.md index 35d9e616..903e1f52 100644 --- a/doc/10_GraphQL/04_Query/20_Add_Custom_Query.md +++ b/doc/10_GraphQL/04_Query/20_Add_Custom_Query.md @@ -43,6 +43,7 @@ if you need more information on Pimcore's event mechanism. $event->setConfig($config); }); ``` + ![iExplorer](../../img/graphql/add_query.png) diff --git a/doc/10_GraphQL/07_Mutation/01_Document_Mutations.md b/doc/10_GraphQL/07_Mutation/01_Document_Mutations.md index 17502b11..ed7af5b3 100644 --- a/doc/10_GraphQL/07_Mutation/01_Document_Mutations.md +++ b/doc/10_GraphQL/07_Mutation/01_Document_Mutations.md @@ -28,7 +28,11 @@ creating and updating documents. ### Free-form API -> Important Note: To be able to fully exploit this feature you have to understand Pimcore's [editable naming strategy](https://pimcore.com/docs/6.x/Development_Documentation/Documents/Editable_Naming_Strategies.html) +:::info + +Important Note: To be able to fully exploit this feature you have to understand Pimcore's [editable naming strategy](https://pimcore.com/docs/6.x/Development_Documentation/Documents/Editable_Naming_Strategies.html) + +::: Update or add single or multiple editables by defining their exact name and their content. diff --git a/doc/10_GraphQL/07_Mutation/20_DataObject_Mutations.md b/doc/10_GraphQL/07_Mutation/20_DataObject_Mutations.md index 432de25e..20713476 100644 --- a/doc/10_GraphQL/07_Mutation/20_DataObject_Mutations.md +++ b/doc/10_GraphQL/07_Mutation/20_DataObject_Mutations.md @@ -1,77 +1,39 @@ # DataObject Mutations ->TODO: Align this with the new demo as soon as reasonable content is available. - -* Create Objects -* Update Objects -* Delete Objects +Data object mutations are used to create, update and delete data objects, documents, assets and translations. +Keep in mind that for all kinds of mutations you need the `Write` permission and the mutation itself needs to be enabled in the configuration. -In addition, you can turn on mutations to modify assets, create object folders and on on. - +:::info + +Please be aware, that not all operations are supported for all data types. + +::: + + ![Mutation grid](../../img/graphql/mutation_grid.png) - + +:::info + Note that for `Create` and `Update` operate you can query the updated data using the same request. -Keep in mind that for all kinds of mutations you need the `Write` permission. -## Supported Mutation Datatypes +::: -![Mutation grid](../../img/graphql/mutation_grid.png) +## Supported Mutation Datatypes -Also check out the Pimcore's [data type documentation](https://pimcore.com/docs/6.x/Development_Documentation/Objects/Object_Classes/Data_Types/index.html). - -* Boolean Select -* Checkbox -* Country -* Countries (Multiselect) -* Date -* DateTime -* Email -* External Image -* Field Collections -* Firstname -* Gender -* Geopoint -* Image -* ImageGallery -* Input -* Input Quantity Value -* Language -* Lastname -* Link -* Many-to-One Relation -* Many-to-Many Relation -* Many-to-Many Object Relation -* Advanced Many-to-Many Relation -* Advanced Many-to-Many Object Relation -* Multiselect -* Newsletter Active -* Newsletter Confirmed -* Numeric -* Quantity Value -* Select -* Slider -* Table -* Textarea -* Time -* Wysiwyg +Also check out the Pimcore's [data type documentation](https://pimcore.com/docs/6.x/Development_Documentation/Objects/Object_Classes/Data_Types/index.html). +For supported mutation datatypes please check the `DataObjectMutationFieldConfigGenerator` folder in `src/GraphQL/`. ## Supported Mutation Operators -* IfEmpty -* Locale Switcher -* ... - -See [the overview page](./21_Mutation_Operators.md) for more details. +See [operators section](../08_Operators/README.md) for more details. ## Create Object -TBD: do we need an extra workspace permission for that ? (in addition to write which would be only used for updates) - Request: -``` +```graphql mutation { - createNews(parentId: 66, key: "testcreate27", published: false) { + createNews(parentId: 429, key: "news_created_by_gql", published: false) { success message output(defaultLanguage: "de") { @@ -85,16 +47,16 @@ mutation { ``` Response: -``` +```json { "data": { "createNews": { "success": true, - "message": "object created: 98", + "message": "object created: 1196", "output": { - "id": "98", - "creationDate": 1559642310, - "fullpath": "/tests/testcreate2/testcreate27", + "id": "1196", + "creationDate": 1732785597, + "fullpath": "/Product Data/Accessories/lights/indicator lights/chevrolet-bel air-tail lights/news_created_by_gql", "title": null } } @@ -107,25 +69,31 @@ Response: Updates german title and short text and returns the modification date. Request: -``` +```graphql mutation { - updateNews(id: 773, defaultLanguage: "de", input: {title: "german TITLE", shortText: "new short text"}) { + updateNews(id: 1196, defaultLanguage: "de", input: { + title: "german TITLE", + shortText: "new short text" + } + ) { success output { - modificationDate + modificationDate, + title } } } ``` Response: -``` +```json { "data": { "updateNews": { "success": true, "output": { - "modificationDate": 1559746654 + "modificationDate": 1732785648, + "title": "german TITLE" } } } @@ -135,9 +103,9 @@ Response: ## Delete Object Request: -``` +```graphql mutation { - deleteBlogCategory(id: 37) { + deleteNews(id: 1196) { success message } @@ -145,10 +113,10 @@ mutation { ``` Response: -``` +```graphql { "data": { - "deleteBlogCategory": { + "deleteNews": { "success": true, "message": "" } @@ -157,8 +125,6 @@ Response: ``` - - ## Extend Data Object Mutations It is possible to add custom mutation data types and mutation operators. For details see detail documentation pages: diff --git a/doc/10_GraphQL/07_Mutation/21_Mutation_Operators.md b/doc/10_GraphQL/07_Mutation/21_Mutation_Operators.md deleted file mode 100644 index 12fcccbb..00000000 --- a/doc/10_GraphQL/07_Mutation/21_Mutation_Operators.md +++ /dev/null @@ -1,17 +0,0 @@ -# Mutation Operators - -Operators allow to modify and transform the data before it is stored in Pimcore. - -![Overview](../../img/graphql/mutation_operators.png) - -#### IfNotEmpty - -Only sets the value if current one is empty. - -#### Locale Switcher - -Switches to different language other than the default language. - -#### Locale Collector - -Allows editing all languages for a single field. diff --git a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/01_FreeformAPI_Create_Document_with_Areablocks.md b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/01_FreeformAPI_Create_Document_with_Areablocks.md index 8b7f5289..86f108a1 100644 --- a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/01_FreeformAPI_Create_Document_with_Areablocks.md +++ b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/01_FreeformAPI_Create_Document_with_Areablocks.md @@ -62,5 +62,6 @@ mutation { } } ``` + ![Grid](../../../img/graphql/document_create_mutation.png) \ No newline at end of file diff --git a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/02_FreeformAPI_Update_Email_Document.md b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/02_FreeformAPI_Update_Email_Document.md index 07b48e96..ea15ec88 100644 --- a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/02_FreeformAPI_Update_Email_Document.md +++ b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/02_FreeformAPI_Update_Email_Document.md @@ -27,4 +27,6 @@ mutation { } ``` + + ![Grid](../../../img/graphql/document_updateemail_mutation.png) \ No newline at end of file diff --git a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/03_FreeformAPI_Create_new_Link_Document.md b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/03_FreeformAPI_Create_new_Link_Document.md index 03030915..66abd3b1 100644 --- a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/03_FreeformAPI_Create_new_Link_Document.md +++ b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/03_FreeformAPI_Create_new_Link_Document.md @@ -12,4 +12,7 @@ mutation { } } ``` + + + ![Grid](../../../img/graphql/document_create_link.png) diff --git a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/04_TreeAPI_Create_Document_with_Areablocks.md b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/04_TreeAPI_Create_Document_with_Areablocks.md index ad3991c7..a8418cb1 100644 --- a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/04_TreeAPI_Create_Document_with_Areablocks.md +++ b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/04_TreeAPI_Create_Document_with_Areablocks.md @@ -99,4 +99,4 @@ mutation { } } } -``` \ No newline at end of file +``` \ No newline at end of file diff --git a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/10_Sample_Add_Relations.md b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/10_Sample_Add_Relations.md index 87fd20a2..6e3d0e11 100644 --- a/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/10_Sample_Add_Relations.md +++ b/doc/10_GraphQL/07_Mutation/24_Mutation_Samples/10_Sample_Add_Relations.md @@ -2,7 +2,9 @@ This will add relations to categories relation field of Car object. Type can be omitted for mutations only allowing one type, e.g. many-to-many-objects . -> Note: Read permissions are required for related objects to be assigned. +:::info +Note: Read permissions are required for related objects to be assigned. +::: Request: ``` diff --git a/doc/10_GraphQL/07_Mutation/25_Add_Custom_Mutation_Datatype.md b/doc/10_GraphQL/07_Mutation/25_Add_Custom_Mutation_Datatype.md index f1f0bbdf..bab92b1f 100644 --- a/doc/10_GraphQL/07_Mutation/25_Add_Custom_Mutation_Datatype.md +++ b/doc/10_GraphQL/07_Mutation/25_Add_Custom_Mutation_Datatype.md @@ -6,7 +6,7 @@ For adding a new mutation data type two steps are necessary: Add a section similar to this one to your `services.yml` file. -``` +```yaml pimcore.datahub.graphql.dataobjectmutationtypegenerator_datatype_mycustomdatatype: class: Pimcore\Bundle\DataHubBundle\GraphQL\DataObjectMutationFieldConfigGenerator\MyCustomDatatype tags: diff --git a/doc/10_GraphQL/07_Mutation/26_Add_Custom_Mutation_Operator.md b/doc/10_GraphQL/07_Mutation/26_Add_Custom_Mutation_Operator.md index f7b4b898..009b6d92 100644 --- a/doc/10_GraphQL/07_Mutation/26_Add_Custom_Mutation_Operator.md +++ b/doc/10_GraphQL/07_Mutation/26_Add_Custom_Mutation_Operator.md @@ -7,7 +7,7 @@ For adding a new mutation operator two steps are necessary: ### Type Definition Add a section similar to this one to your `services.yml` file. -``` +```yaml pimcore.datahub.graphql.dataobjectmutationtypegenerator_operator_mycustommutationoperator: class: Pimcore\Bundle\DataHubBundle\GraphQL\DataObjectMutationOperatorConfigGenerator\MyCustomMutationOperator tags: @@ -29,8 +29,12 @@ and the server-side PHP implementation processing the input (the input processor A JS sample can be found [here](https://github.com/pimcore/data-hub/blob/master/src/Resources/public/js/mutationoperator/IfEmpty.js). +:::info + Note that the namespace in your case would be `pimcore.plugin.datahub.mutationoperator.mycustommutationoperator`. +::: + Make sure that your extension gets loaded. See [Pimcore Bundles](https://pimcore.com/docs/6.x/Development_Documentation/Extending_Pimcore/Bundle_Developers_Guide/Pimcore_Bundles/index.html) docs page for further details. diff --git a/doc/10_GraphQL/07_Mutation/27_Add_Custom_Mutations.md b/doc/10_GraphQL/07_Mutation/27_Add_Custom_Mutations.md index c78dd1d8..e06cd5d7 100644 --- a/doc/10_GraphQL/07_Mutation/27_Add_Custom_Mutations.md +++ b/doc/10_GraphQL/07_Mutation/27_Add_Custom_Mutations.md @@ -38,6 +38,7 @@ if you need more information on Pimcore's event mechanism. $event->setConfig($config); }); ``` + ![iExplorer](../../img/graphql/add_mutation.png) diff --git a/doc/10_GraphQL/08_Operators/Mutation/IfEmpty.md b/doc/10_GraphQL/08_Operators/Mutation/IfEmpty.md new file mode 100644 index 00000000..a25d7e59 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Mutation/IfEmpty.md @@ -0,0 +1,50 @@ +# If Empty + +Only sets the value if current one is empty. Add the operator to the list and drag & drop the desired field into the operator. + +## Configuration + + + +![ifempty_config.png](../../../img/graphql/ifempty_config.png) + +- **Label**: Field name to be used in the query. + +## Example + + + +![ifempty_example.png](../../../img/graphql/ifempty_example.png) + +Request: +```graphql +mutation { + updateCar( + id:82 + input:{ + UpdateDescription:"Description if description is empty" + } + ) { + success, + output { + description + } + } +} +``` + +Response: +```json +{ + "data": { + "updateCar": { + "success": true, + "output": { + "description": "Description if description is empty" + } + } + } +} +``` +[] + diff --git a/doc/10_GraphQL/08_Operators/Mutation/LocalCollector.md b/doc/10_GraphQL/08_Operators/Mutation/LocalCollector.md new file mode 100644 index 00000000..f160da46 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Mutation/LocalCollector.md @@ -0,0 +1,56 @@ +# Locale Collector + +Allows editing all languages for a single field. + +## Configuration + + + +![locale_collector_config.png](../../../img/graphql/locale_collector_config.png) + +- **Label**: Name for the field to be used in the mutation. + +## Example + + + +![locale_collector_example.png](../../../img/graphql/locale_collector_example.png) + +Request: +```graphql +mutation { + updateCar( + id:82 + input:{ + LocaleEditorName: { + en:"Name_en", + de:"Name_de", + fr:"Name_fr" + } + } + ) { + success, + output { + name_en: name(language:"en"), + name_de: name(language:"de"), + name_fr: name(language:"fr") + } + } +} +``` + +Response: +```json +{ + "data": { + "updateCar": { + "success": true, + "output": { + "name_en": "Name_en", + "name_de": "Name_de", + "name_fr": "Name_fr" + } + } + } +} +``` \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/Mutation/LocaleSwitcher.md b/doc/10_GraphQL/08_Operators/Mutation/LocaleSwitcher.md new file mode 100644 index 00000000..f3edfeb5 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Mutation/LocaleSwitcher.md @@ -0,0 +1,51 @@ +# Locale Switcher + + + +![locale_switcher_config.png](../../../img/graphql/locale_switcher_config.png) + +Switches to different language other than the default language. Add the operator to the list and + +## Configuration + + + +![locale_switcher_example.png](../../../img/graphql/locale_switcher_example.png) + +- **Label**: Field name to be used in the query. +- **Locale**: The locale you want to switch to. + +## Example + +Request: +```graphql +mutation { + updateCar( + id:82 + input:{ + name_ger:"Wert für name Feld" + } + ) { + success, + output { + name_en:name(language:"en") + name_de:name(language:"de") + } + } +} +``` + +Response: +```json +{ + "data": { + "updateCar": { + "success": true, + "output": { + "name_en": "Name_en", + "name_de": "Wert für name Feld" + } + } + } +} +``` \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/Query/Alias.md b/doc/10_GraphQL/08_Operators/Query/Alias.md new file mode 100644 index 00000000..c737beb9 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/Alias.md @@ -0,0 +1,46 @@ +# Alias + +Simply gives the child node a different name. + +If you are looking for a way to directly use aliases in a GraphQL query, please see [11_Using_Aliases.md](../../04_Query/11_Using_Aliases.md) . + +## Configuration + + + +![alias_config.png](../../../img/graphql/alias_config.png) + +- **Attribute**: The new name for the field to be used in the query. + +## Example + + + +![alias_example.png](../../../img/graphql/alias_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + key, + AliasForKey + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "81", + "key": "Cobra 427", + "AliasForKey": "Cobra 427" + } + } +} +``` + + + diff --git a/doc/10_GraphQL/08_Operators/Query/AssetThumbnail.md b/doc/10_GraphQL/08_Operators/Query/AssetThumbnail.md new file mode 100644 index 00000000..82f3fd1c --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/AssetThumbnail.md @@ -0,0 +1,42 @@ +# Asset Thumbnail + +Returns the selected thumbnail URL. + +## Configuration + + + +![Thumbnail Config](../../../img/graphql/thumbnail_config.png) + +- **Attribute**: Name for the field to use in the query. +- **Thumbnail**: Select the desired thumbnail from the list. + +## Example + + + +![thumbnail_example.png](../../../img/graphql/thumbnail_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + contentThumbnail + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "82", + "contentThumbnail": "/Car%20Images/ac%20cars/68/image-thumb__68__content/automotive-car-classic-149813.44c4f656.jpg" + } + } +} +``` + +[] \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/Query/AssetThumbnailHTML.md b/doc/10_GraphQL/08_Operators/Query/AssetThumbnailHTML.md new file mode 100644 index 00000000..bac408cf --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/AssetThumbnailHTML.md @@ -0,0 +1,40 @@ +# Asset Thumbnail HTML + +Returns the selected thumbnail HTML tag. + +## Configuration + + + +![thumbnail_html_config.png](../../../img/graphql/thumbnail_html_config.png) + +- **Attribute**: Name for the field to use in the query. +- **Thumbnail**: Select the desired thumbnail from the list. + +## Example + + + +![thumbnail_html_example.png](../../../img/graphql/thumbnail_html_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + contentThumbnailHTML + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "82", + "contentThumbnailHTML": "\n" + } + } +} +``` \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/Query/Concatenator.md b/doc/10_GraphQL/08_Operators/Query/Concatenator.md new file mode 100644 index 00000000..0b066d66 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/Concatenator.md @@ -0,0 +1,40 @@ +# Concatenator + +Concatenates the values of the selected fields. + +## Configuration + + + +![concat_config.png](../../../img/graphql/concat_config.png) + +- **Label**: Name for the field to use in the query. +- **Glue**: The string that will be used to concatenate the values. + +## Example + + + +![concat_example.png](../../../img/graphql/concat_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + ConcatYearCountry + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "82", + "ConcatYearCountry": "1966-GB" + } + } +} +``` \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/Query/DateFormatter.md b/doc/10_GraphQL/08_Operators/Query/DateFormatter.md new file mode 100644 index 00000000..333aba40 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/DateFormatter.md @@ -0,0 +1,42 @@ +# Date Formatter + +Utilizes the PHP date formatter. + +## Configuration + + + +![date_formatter_config.png](../../../img/graphql/date_formatter_config.png) + +- **Label**: The name for the field to be used in the query . +- **Date Format**: The format you want to use. For formatting options see [PHP Date Format](https://www.php.net/manual/en/function.date.php). + +## Example + + + +![date_formatter_example.png](../../../img/graphql/date_formatter_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + modificationDate, + FormattedModificationDate + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "82", + "modificationDate": 1732709167, + "FormattedModificationDate": "Wednesday 27th of November 2024 12:06:07" + } + } +} +``` \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/Query/ElementCounter.md b/doc/10_GraphQL/08_Operators/Query/ElementCounter.md new file mode 100644 index 00000000..0f67e4fb --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/ElementCounter.md @@ -0,0 +1,41 @@ +# Element Counter + +Counts the elements assigned to the selected field. +Useful for counting the number of elements in a relation field. + +## Configuration + + + +![element_counter_config.png](../../../img/graphql/element_counter_config.png) + +- **Label**: Name for the field to use in the query. +- **Count Empty**: If checked, the operator will also count empty fields. + +## Example + + + +![element_counter_example.png](../../../img/graphql/element_counter_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + CategoriesCount + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "82", + "CategoriesCount": 2 + } + } +} +``` \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/Query/Merge.md b/doc/10_GraphQL/08_Operators/Query/Merge.md new file mode 100644 index 00000000..55674c2a --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/Merge.md @@ -0,0 +1,3 @@ +# Merge (deprecated) + +This operator is deprecated and will be removed in the next major release. diff --git a/doc/10_GraphQL/08_Operators/Query/StaticText.md b/doc/10_GraphQL/08_Operators/Query/StaticText.md new file mode 100644 index 00000000..c0002726 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/StaticText.md @@ -0,0 +1,39 @@ +# Static Text + +Adds the configured static text to the query. + +## Configuration + + + +![static_text_config.png](../../../img/graphql/static_text_config.png) + +- **Text**: The text to add to the query. + +## Example + + + +![static_text_example.png](../../../img/graphql/static_text_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + StaticTextForQuery + } +} +``` + +Result: +```json +{ + "data": { + "getCar": { + "id": "81", + "StaticTextForQuery": "StaticTextForQuery" + } + } +} +``` \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/Query/Substring.md b/doc/10_GraphQL/08_Operators/Query/Substring.md new file mode 100644 index 00000000..1b40a8b8 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/Substring.md @@ -0,0 +1,44 @@ +# Substring + +This operator extracts a substring from a string. + +## Configuration + + + +![substring_config.png](../../../img/graphql/substring_config.png) + +- **FieldName**: Name for the field to use in the query. +- **Start**: The position of the first character to extract. +- **Length**: The number of characters to extract. +- **Ellipses**: If the string is longer than the specified length, an ellipsis is added at the end. + +## Example + + + +![substring_example.png](../../../img/graphql/substring_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + description, + ShortDescription + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "82", + "description": "Description that clearly exceeds 10 characters in length
", + "ShortDescription": "Descript..." + } + } +} +``` diff --git a/doc/10_GraphQL/08_Operators/Query/TranslateValue.md b/doc/10_GraphQL/08_Operators/Query/TranslateValue.md new file mode 100644 index 00000000..d04d0e7e --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/TranslateValue.md @@ -0,0 +1,48 @@ +# Translate Value + +Translates the values of the selected fields. For translation the default locale is used. + +Similar to Pimcore's [Translate Value](https://pimcore.com/docs/6.x/User_Documentation/DataObjects/Grid_Configuration_Operators/Operators/TranslateValue.html). For a detailed example see [Website Translations](../../04_Query/11_Query_Samples/27_Sample_Translate_Values.md). + +## Configuration + +
+ +![translate_value_config.png](../../../img/graphql/translate_value_config.png) + +- **Label**: The label of the field. +- **Prefix**: The prefix for the translation key. + +## Example + + + +![translate_value_example.png](../../../img/graphql/translate_value_example.png) + +:::info + +Note: Make sure to add the translation key to the translations in the Pimcore backend, using the admin domain. + +::: + +Request: +```graphql +{ + getCar(id: 82) { + id, + TranslatedName + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "82", + "TranslatedName": "NameValuedAddedToTranslations" + } + } +} +``` diff --git a/doc/10_GraphQL/08_Operators/Query/Trimmer.md b/doc/10_GraphQL/08_Operators/Query/Trimmer.md new file mode 100644 index 00000000..458153f1 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/Query/Trimmer.md @@ -0,0 +1,42 @@ +# Trimmer + +Trims the value. + +## Configuration + + + +![trim_config.png](../../../img/graphql/trim_config.png) + +- **Label**: Name for the field to use in the query. +- **Trim**: Where to trim, either `both`, `left`, `right` or `disabled`. + +## Example + + + +![trim_example.png](../../../img/graphql/trim_example.png) + +Request: +```graphql +{ + getCar(id: 82) { + id, + name, + TrimmedName + } +} +``` + +Response: +```json +{ + "data": { + "getCar": { + "id": "82", + "name": " Cobra 427 ", + "TrimmedName": " Cobra 427" + } + } +} +``` \ No newline at end of file diff --git a/doc/10_GraphQL/08_Operators/README.md b/doc/10_GraphQL/08_Operators/README.md new file mode 100644 index 00000000..8314acf2 --- /dev/null +++ b/doc/10_GraphQL/08_Operators/README.md @@ -0,0 +1,21 @@ +# Operators + +Operators allow to modify and transform the data before it is delivered to the endpoint or stored in Pimcore, +depending on whether they are used in a query or a mutation. + + + +![Overview](../../img/graphql/queryoperators_overview.png) + +Operators can be selected in the GraphQL configuration using the `Schema Definition` tab. +In the `Query Schema` section use the `gear` icon to open the configuration dialog for a data object class you want to use in queries. +In the `Mutation Schema` section use the `gear` icon to open the configuration dialog for a data object class you want to use in mutations. + +This will open the `Schema Fields` configuration dialog where you can select the fields you want to use in queries or mutations. +In the tree on the left side you can select th operators you want to use by clicking on one of the 3 tabs: `Formatters`, `Others` or `Transformers`. + +Add an operator by double-clicking on it or by dragging it to the right side of the dialog. +Depending on the operator an options dialog will open where you can configure the operator. +After adding an operator you can drag & drop fields under the operator to apply the operator to them. + +Please see the contents of this chapter for more information on the available operators. \ No newline at end of file diff --git a/doc/10_GraphQL/README.md b/doc/10_GraphQL/README.md index 866aeeb4..e151be9e 100644 --- a/doc/10_GraphQL/README.md +++ b/doc/10_GraphQL/README.md @@ -12,6 +12,8 @@ and services via GraphQL and test them with the integrated [![Preview](../img/graphql/intro_preview.png)](../img/graphql/intro.mp4) + + ![Explorer](../img/graphql/iexplorer.png) @@ -61,6 +63,8 @@ See following pages for a general overview of possible mutations: [GraphiQL explorer](https://github.com/graphql/graphiql/tree/main/packages/graphiql#readme) can be opened for an endpoint in an iframe within Pimcore or as an additional browser tab. + + ![Open iExplorer](../img/graphql/open_explorer.png) @@ -94,4 +98,6 @@ see [Events Documentation](./10_Events.md). Open the settings and change `request.credentials` to `include`. Otherwise the `XDEBUG_SESSION` cookie header will get removed by default. + + ![Settings](../img/graphql/debugging.png) diff --git a/doc/20_Deployment.md b/doc/20_Deployment.md index cbd6208d..cb521efa 100644 --- a/doc/20_Deployment.md +++ b/doc/20_Deployment.md @@ -14,7 +14,7 @@ When deploying configurations following steps are necessary: Either call: ```bash datahub:configuration:rebuild-workspaces -``` +``` to do that for all definitions, or: @@ -23,7 +23,11 @@ datahub:configuration:rebuild-workspaces --configs=assets,events ``` for specific definitions. ->Note: The command ```datahub:graphql:rebuild-definitions ``` is marked as deprecated and will be removed in a future release. +:::warning + +Note: The command ```datahub:graphql:rebuild-definitions ``` is marked as deprecated and will be removed in a future release. + +::: ### Configuration Storage diff --git a/doc/img/graphql/advanced_many_to_many_object_relation.png b/doc/img/graphql/advanced_many_to_many_object_relation.png index 1471879ee42503377b533458cfb4488a489f3d5e..8f32b5ef0a61b702eff928eb1341acf7c0c2d1e7 100644 GIT binary patch literal 41390 zcmc$`XIzu{7Bxx}=~V&gRg?}QRY2)QKtOu$0xC^9Br2ha(v&73B1NSa=_L}7UIe5I zAxIHvp(a2`-UrVxGtP0&dw=(SxF3z-$-nNs_F8K{F}L(ID9M<~@bK^`wKP=?@$d*S zczF1cB*efc9Z^sG@bDhuX{p}09cZ)Gj0>wy}T4a9g{VZ;&HG|Ism$)RLQ zT&pBAWQq3`m77R5ZIut{flna2aRLYDK+0pZf6R<_77E$r2RjL8o?RtX zj&33O@BfBBN5bn2+829Gy@JKVb32V>{4uhb7T3aiO>I;v>ZJ4uOg=SFb3(qyCj9pt ztVwY{eh3V-gi=9+mhSWh9)vPTd(PgL-Xt;p+DQ2?KUjf`{g@rPbvx^;bga?a!MT#! zS;JT^$XEQ|PB}mbGf7_dMJue)tRYZKI5IF|^qhk_lkfN!qHTZGTIIZqcp6dIQECDf z0@EkqYR=ULX~3Y{hpT=PW%Prr3USi2fhxj!u|q4+GOh1PN^;M->hPh1XS3ngKi}kB z>GD#1<|JqP9IRVEx+wi78CiCbmW8#vG@JwLLnNgx?k98h_&jq;qFmBCr&4|LZ`XcP z6K!kVV8*}Gz(s!G7cQ_d6UlH8q>8!08@HtM*rJaofIEC~)Np&dMNGM|YD0MJg{3t} zWr`Gc>*P|Q&MX*KMaLbMeCzwJg{i+x)GzyW$%SH==(neajT9I2Ty!j^>Aujb?suQu za-M|L=6s59BYGxd=-e7m)kLGwg=}>tqJ2ri)u43NDqSsbgkqSS6cTle^nCfLlH`MB z(wW5Bipx$}K4llh*+^kbNjAQOIo9bNi`m9CRc0U|3P;Pr-GU+P;*Q6A!-F>Br$aOj zXRQ?0A}Cz=Rm7g+5jc*4{PlU{iZ5fRbgqyb==RBG+rHHJO2IA0T;5YXz%Lb_x#s0Y zHRP>COiW2s;!AeVviy@$cBZluYzi0c7ut41b>B^jJ>k{R@6Ibc5vdd+WK0`qor&o* z94ykZcsD )LHJc^Z5zydGMS|F-6^$c+*Ljr=2X zyuO%V`RIOxrZfka4Fo01bxit4)WO6-a1jqsDu;^(pqbae2^o?-vk-TaOLAd1PMXGN z#hxRMXZ;nyXFaq&uiaDqam^+b>jP$(Z7ujRd^t*-xjbrOT6|5zPJ{W92xnnW*g>E? zJ(ktwVqr5n;*%`zMcuT5^BKA!?#gxVk&Fon*CNdFUW|WbRklljfg67tgn&(j28)~W zZ#Q_0kI&>D-1gp-YT&CLy?#f30A$U-@C-6d_r1 E{)M=`z;R zDd3DHIrJ$flhzl|(ya|dwm%BV$UtMjg3tPr1Z=>}jY%Btdb~QeuX5vNewOSRHD3N> z5k&kb30U0OIyTX4ulsD#1zz<_m|F6GyHP#b0r87EiXjxz_rKnX9Z^1yx~~%JVV;+| zeJRDcKF|%n!ho ^j2(H1BcdixN+G-}kS6DueVPkVOc*Jo(^_HAG%0P$s!<#I%%X+l0DDQ<@diXX zU5v-OZ$r`&g(N>X=kg}U=U^=8sfO4pNp m#G@=F}lzFFZx? zdsf-8*B9Du`b<_Ag8q|B^S5CY=0a;^rpw5(B{8MT%gookeAs&h&HL^rq9Tu9JnY)w zb>ZeB!`)N jc64n&%ZnF_466mEVn3F(Ny`5AwUa z{R^V#vY3UwFTwtBR43)CJ@-3gkyzaX2JpmJ#lIlLcp8sJ+}yGfuAXgMiCekp^k pc@3 *R&D#%+|LL)**S6=rdJtIge~?xu{ojLyY#tpaun#<3*PNhLXW6 zX_Yqm3MtpyCGGE1aLLeqS~H(~XXWHWmKd|`f08Mj=dK~8s;@rmDm8EC8LP=CzSqf< zCi}AEYYoZGD^EY0(JYlp7UrK%RG?9r5D|Phx8#;rYD`DEMf4Y(@^~1H-TKyf8PmRV z8nor0VBfS!JI*Hga9H7 fx z7gpY8m$FoD?rxB8a2 BZ_6pm J1NbVeRuE-mP5sH{5CFw2(h^O!8AW#|giVew(GY}J!#Mn L{q! {wp(KyMrW& zR#!P16qpf0Z8F#%+ zyg9xvwHU{n=rL}`xntkivvWH{!LxX1Z}ZOr tV0^M~lBi5a> z^dx#I5TyXICv#qIXD}Z%X%e&E4?hlEcCn9>%|1)>WPme_?HL&QRprpMGHr&t)6wh= zyRuUN-Ic^2n-AW?M4u7YtB|JU5@USgRPZ4Iw;3sT+sXebXi|eVYjIC-*w1?}>!b~S zbi46mN|w;I1rHB|@p<*$Wd~^HK5^7AJKy@CK(g$EB{L~bn{2B>48~Hd{X=$qnW6Ux zMzTI&qLk3YW57ENR4Nh@{66`>J`aXGD+P0$?hxWwM-#04=i#wcPY&aU_`@~}h7xcc z=MtveU`Wc3O3cc4lwb7=W!DCo_~g2(rGAob2_RbvT)FVMqwd<^qpL%GrSWusGZBf)PrW;lptdu>&QK}2>rOZo1l zr{)3FSlPFX#j&gKHQDK~( i4RWGOh_uF~ISe zESC}l2f3_gJz<*^`J!*7!)AS-AsG{cc bj0YSA1)Z{-qekO3cz=r3SU{?-$>(4E6X_y%aRCxLYt7;!loqXO2n4D_EP| z7^};^Va<=x86h#Bw+_~RK)bSzpLVveO07Bq>`-8(o-T(l9cWBb{z_u+qBSgk9y|7b z`OP1b%qBtJ+X9Ah`UL}8BGaveq5Zc;|HsW9T#QP>3(J|<9e~;n^GoqFVhrlBa z9jm8EQL$-Uu(m{xYS@gDg3JBG9*znXbP(hxo?#;gXRO9A4Nh(_o+ip);DiynmjYA- z8fwY0Y`J55Fr>S|zGU)q&foPQE!GXYNb0lV`9hWB`xn04rxoR;Wr?wCk+Xv_Y^`kJ z6{xmXq`+)JyU8j;Nuj3H;IHKn+!MiL)vrl@smK7IV{6H Qh4@z+_%#;D@} zfM;QM_67Tq1ogV|Nr#v`;8%uAHGh#8-I>qY!y_9nKCTTSuC{F7IjhU`yj#2Np~`(v zl8&(#SxUA1M9}Jce1qC_2H ~P z0$>sT3?ctmgsWcUxDkCNYiTEVRw+~)90QAaKkS>Op^{b^5<7iOuzslOjXYiOv)yFY zrP`=flNC>32MVK8)zI(cC|c*ISo?B(265HA^Ymk~RA<+SDP%YMT1W`C`&PDOlFsNN zQr}W`?fICjz`tAM!`~#ly5V#!`g4ca%`1=F6<1k1iUtce77nGu2K@gm1^@|!Jv4xs z%SPk(*bGR2zPpz(dD*|MbpUoLL0x5kn(~0ZUGOvo{e!G2!!L=%(Eo*}{;@*i4^33C zq+4{q1@@OQ9yfEjaFD<=f8^fiuTUHccNFihsUn11gkoxyu=#&7UHndLr;#r4$du@D ztKF{YUorM?q>+pQrtqd16U8QR2tdI(-Ma;3QvEKuKan>(h&Wd%{7(q*cYLaVp-{)2 zIsG&E4h*{fp2dR>LKBuaenLFjQ!9lJWuGQ!C_e(~og3YoS~j=qK&%n}*6RdQR|gWO zmNi8>RJ?Q9B>RIs>RLTvv&y5gTfal?r~%%rn6hvIz~n_mMKVX*vY4gxT;XqvJLX@T zf{bRGcutB+60Sq;vY(XDFXIJu!bAzc+n Ue>*zB%Gq|tVKy?V7Z{Db_M|4QEF(|y`UUST@EaEcJ*>9EP;wq?(Q zvI3XBd!KO0?%ozp^>AUj%JBqC($sbz89UaDul8$ON5hoF9)6z9eEEe*4NdO)T(iEX zpW_LqSiRl)p42U#ZneCcGj);Dxfd4*8d@ zLs}N=g?RjUV|&QxiZ0xI79|$edN3zd@ly3JP=P`Jq_j*GYHBVmR}!Bd&WW}`yIosg z1!$DVh>f>_ahs-!jCD8N?^6B`e~=T!he^a!rY8pYD{TvQ-;9zEl#fIr-~u5!cro;) zyP*v4eQVWFtGo?fT+eP^$+`dO>T2fGOAOm%tD~$gQfOM)Vs9$J%k7;o63_C5qs*7@ zJ|`jtmwoP&-SDOI3FLdym4C&|M#p391_azS>h;0my2#bo@9*FZwGzQ}wgDo|xqrZ^ zf1D&9gp&96C%MG&XP>TIsFo2vIRU$uNWr1md=|N+PG42FMEf}<#Um!~sT-pQEe<*g z68sh|Pbn^L%$Yp@mtvuW$oR-&pPPM|)%*UJ2y7qZ@Pdcw66tz41!@L7hPN z`w~#vQLpp)s NK!C$rLCW*Rrm%U#7Z5bJ~Ey<7Lpk#G9bhfxj zec2%_Q(uou!rnTHRu;?2eI&_3-Sh9~!8JZ#fS@e)InL}y&{Zw+ll!Tlil%HglI^=M zNh5Dz{JxLp285%RYcv_zn*mTo#g*0y7(bYj+{2G;E88?Uf~4muNZIBUhEHl9U>-dc zh~Lu;3JA(Y=U^wrF7AYr14_8r`=kpC1S!3_ hBpN^hi|leg@fE$6$vasQKuZ`&X*w$%Y4^0Fe2(Ovc LednGpv%gC)Hr! z7KpOs+QqQaN+J#P;&nY Qb}tqrO$dQ$6em-*Xfws*FH_H4PYiEi}lsK`7+t#yhLdA0ozM5=-0EOHkg#f z_sb45kA7B?4+sxlNk!2x oicmn5om0(q((lR2%j#+2^M$C@J)}I8d*!m6j{ 2EU$`>a2 &5N^~h-j%%d6w%+==2`-s#%^2p+Gx8-ZG`yXQUAka(CR6!SnAMY<-UN*e> z$^L13!h=$%-(3lZM=*U&VKx*p770hi*P(L40$VVXu}Tu&0m#O{8jRxeYmfuS^x;)o zFbnEP%5FTyaOzt&Tf0&yZyf)XeAFP=lMsvG*l1$}Tih25^yW|u8$3oYjpXn0L&YCA zDjg8ACSp=Bo54u-uekNMtMRd|W*V*RK&@@ga=RN)SWHbCLWFF$Cmrj&zeQSPG8EPY zumsmdaOAUNxRjo5tvvYx+; Cwj!I#7BWbm(Ed zw9%^&Pf~luC}+!J9V2R|#HOY!6IFlD=Rup?O%k48({Fobwe=NTRKWP#5GIEACVzlM z1gUC-G9jbHn$1Kp`(L8Fhrg3Z*Ee%9SsLwYJ{s$s60uI)eE>^xSbZrUPj 4cZwM`W;DD%fy$ZFL>fHzLT_TwXUh0P=|8Wj3%JRil4;hDCE zfxfTS1>6~~UN;DJ#jvY_45#*ERd~=n2=}0L4c)Jc?pAhUV;-l74_L^Eok?;(Ww?k< zke`-tNA4w M$6HWKEU407lR7HvbSq-moB zFy+f5gQ~*b>;ekQGfeSzW0N)}HSxsj$#6oG`a}&En(TK{dUc rHOctGv?Ej z(yn_|K0;ca6Yb-wF({xRqGf%~Puec_+@fRKz=Netu8jVEwP?J%moUf-F=gc^-XsOA zX|wvUsc%~LhixkJWeM4M=e>qf5uW-hk6$ C+lRkmrQHVDy@v!$rC`Ks5MlObsQ$ z7?lq8z;JcK>!S1B935LL`gcDPN-Tie2 zcGZ9Z+oyOpxKrMH{Bzj;E}nekM(a$gXXEx2rd832Hb9H?2p2eDBR^3{^)hdcYlT&5 zW?QuPXGo7akZ=W@<`7L_lZ7ElJI_VuHjY{zY8Z`TY@5nnLU|D21JY3McXDzMTkUS2 z;_ee1`@cBs?VlXB$4r~(&cWtk`4tVNa956Ff{ieZR0Yh~{*En6YjgG?eq588-eBg( zM90xH1Q(v}F|D1@AJsRKF{KbVVsG4YZrD@w+n1Fq`;MqMHZavw&H9i&xLZQbu|Q zJOcDhVlGwN1-}#H!&pNU4l{3r9^lvTLWOL!HFGp@WYlc71+cGGM!{#{2G0h5Iw}EgKV+y$T=OVsh1OX}Ow2WD)0}2AW zK<>Y&(!Yt~|A4Z;Na<_9V-K(V|Mh2 3=7u33Gnk#}{X$A76({^n!w{FrZxq0x`S)IMpFZ{FK36WA|#OjCBcR6pS| z_|Gu<7AZZK%7HGE*=@nSaigbR>tG5@}Jxr`CXls)1;0=yc|3Yb5ti5t3{3uCYU zz~bJ)=qwu$wikTh3C8IBNuX`Q(yPkIz(we3RCwTV_vV+dQa;Qj?$iOh`gb6`u96$S zuc_e?JU{v&;Ki-MZ<|MoMnSmLvSX#d)lD$*Y;Z3fuA%{RFOeNPWS1YMbSeg1?9=5U z`fo9SY+(PB(2|2akp>|N1q;dDo18(_nI>I!{=))}+>p=F)P#hD$P0j2*xMa@C0dV3 z%&Bqfk_&@iep0RY>0125k0D|~inE0t+cfQUtOl;C @WspAi-Ty7dd6%*Tv06+P*41_HGSdYm$>DoF#lnt$OR;A&S8IGtS_tRD_F>_#mO z@6>rOgp>;F6x(#q9Wr9$UqO^U@SEx?$wz$jB5(9^u?~UqZ;c%*ESC=G-IEhKFzV z;4lUbZt~H3f|V#jl6B!^VM Nf;xpfiBAzYqX9$$`F&b6yFdfS4x;+QwF3Ge>Xw% zoBBivG6wE=T^m#|={ua9M)*DU6y}TU2nPbsfYbZ%4?@KH9Srw&@YpkXP>#|ZuUwcC z0{_AQT3JW&H1S)mya%{^L0J6xAcBV+k0^(kXl~5g)$G>4;8wusDOQ%AUY=iUG5Uyr z95P&YJXX|N3uoK1t0WM=?V%+KgTDN fYIcqiSA1cMjMy*r!FDi z7QT-V?Cmn$SD7t6Etmem?KFBpj?1@{O!J^4=*6?xB8$7e!L*>D0NzK)a*hs7yjETB zK8~B5GUjyH`C%bgI3bequo&5<#H#9KS~!e%OGZ9+Lj6LIXZ`^tQJ-6$Y36Z4t>C{M zOjg7o2m@Z%KFnr4@T}X7 3V4nSNqfN*`|3HS$ ze12I4Zj|BYA*8#ius{6GlPV((YI6LvSn1z( I0Y$!9<~j!8H_ z2F-9t^X{MIU!^~-lK$V=o?bPBO^u>2*!Ow6pXZ`H^)l%r{zhkQtsOU-z_Rsu(*1RZ zEOfc0fZC~TW!TYNa6!Db{?I9PS_|MV2^Bdopdh-Z936Er?XAT=p;?LYNvd)2@nM!K zf5xo8@m%whM*+_u;2>M3oSDfVXSp$v_-!PdiT;9nS?58H8CBo7w^uHtsf=w2k2#IF z@ )hx3AQ-+FA)_2gt(g1alE(vZsSw7XkL?NUU669D0Kjvg zRB4#2;#}M1mJH}e-fw@i%fMKZr)5?nAStJO?-DJ zD&Ljd(WH6w{aVU;{F5$o7+X0+!3dN+%l=Tj{-Lww9C_CoRa-!6DRNn?s`Ywc0P&e4 zCbBMD(RKMMo` &$bI@Q0;S-4Sxb@tet%$o<2 z&c{C!Z#Fzy()3c@fj9cS?`V8E5PRw#p<@h#L(Q~m^No$rYLB0pwY^&FfN@kn;K5 >Mfwr7?bho2 zO!yF~PVvTxg`x8OmJ`ouupo?M!a(3HK?K cZUt4rZ#&UmR{J<-v9FPpWjap3Vwc$Va;pWE4v9 z8R0psAO304+(L(Ck$zGadO)Tp>f*H
UGfLafyNDK{$=F`)Q1S5Q>|s z^x)jsA32|RCx99{#mV`fYIkH~_c4jDG5VWC`|*it!WzkgVJx8i;MDYu9h5 NZXMfe!1?BR81Hl%(evUF~^67{LH~ z4uguEMkhGqPd`ePXm*?DE7>Ut8^!ETCvd-?l*{=vin76>iwCRNXr4B}^aDYZrMH!l zC}|T2`=Yb%r8raJ?!1uz08amjtsuzKutWmYu!Kxq{;m-(Q$)NVtR*cbX2F0R6>|CM zH3~9c!CI^s-`6L>ephyGeiV$*aJvKb>uVh T7bYw5#P*s&WBWf#Mlr!Q4Ef3h)sAqIdlYSwJeq4doYyui z@^RX9Mj0NaE4B40A9}>+IH)El2`D1~N#|*6U9T j1(+meiQ Q3Fm?wZY z1{g_=+8;0)xTpa3Zl^!3@KGO-(1r&UdP{yP4BM+LCWg_LNi4H8h1PTLY1v4j`6G LXaDkdhyt_I zKMfY}5g2%WA=Zz(j3w6fg)2HZ4TgBvTyC`S(A@gg`=m4=cacQWmM_bx2LM*lH9D-+ zN^*UIj&F3_k+|3$P8nL|JJST)?tHarZ7?eOR>XGbmwr+qtM}}>?jCrF)>YBHxi6$5 zXkWZShu8nuvN^GrPQ|+>$rk0LRizob!aS>zZa932e|N?FL)s^+zNxpz-}%#RGp-x5 zyBhb|U8H;H`7!=s=6J{Z;leTDIA?`Z0pS-Y3rqsHR&iTx&d+ %-p zSJZKU&gjT|Fyf4=M(*gDL?Hz|&svC|4}P!zrXPO#%!cu+>3qRh4!&IfvY`AZs5&~f z>zbj3cf*%&wyJt2nd}(?Wir+R9@k&3ud%{M&C^t9`)oy_q6-PKrXpc{&)U=Y)-<$P z0B`dph2X-5??&vCpR9teekVv0*EtM$!Q#iPQ2PE;MX~E?*!TqwL+?e{)~ug1-en<$ zicAHi7SO&-Qy%~s(FN{YH^1FG=v^8#P$gVD;F~#}mrIDK&AwdnVi8mzsqK6wAT{p8 zi`ihN;t==@2^4UK1hV8esl&=X2aYc9Mg7)q2ApN`m5r#~-dv2F+WBL37+mW^Cmkk= zkO_G($08Kf^eXN0RlIXRe&}v|);Gi<03H)zV M7j6W$9!djxmS zz`!$8n Pz#Ru0cN z9wZI2w>@JSeHB!eRGT-NcGHA+>_%iIi=|OYL674eMaT_klW-Lf<;MmPo>`@u!E*SH zym7nQD +RXqiY9YI=4uCBbej(qgmyy&IhX_ x56vR^)Gf_fGa}uOPhKxt?Bsrly&GV4@^@M&AfR6;z4Zk{*CSUrNTc_ zMzh&~kBLQ&_ay*z*ip%Ub7E`xq#@#G7lfITStgBP?C-7zriBiqtm*kL#ns>B^?wwf zf2(7D2}!?d?tgD<_ V~`9o~1SdCG*LlLJw#Ff_(VXIB+tFJY&9U z^Pedy#RQsv4ivvVX6cFedLZP&0k@TY0nA$N7hdR}->2S=Qo_=n1%pVg#Ba34<95U` zM+M8PPT;|1&!IPAMVH&3iY=ACCv~36hjWodaU<0jZ{4Pk_WzqXUaLskz3OKNkZ=h| z=Q4)f!P)uD;I)uGhOn50D}(c%;G>L}>tn-u-#vz7HSdvs{0g mzX|g zAc|32U?`xSp?L`Yd^UUVtmD`A2ZeJ}h2jxaT6v{~*|Q>FJf`ITSmVUf4R|tz3-=AC zHhhQ!`MZOnMu}LY7wd{KDvJH}s5t#_)Q7@6De{x*@yqa!+7~eJ**m*w%~?z26VgX@ z!iP#qyX01l`)B>Crd2dxp50p!k`j8ezD6W3eY;F0EQhlO><*+JG>!uX#YqKwv<7#Y z*5a)MvLkoeUe}Q>6Y5gZGku< ^&E`e%S}xCHJ>rXubCMy2%XtO#KJs^r zweJ07a^L5loDm$=>z)?+c-+F &b%^N6LD+MY5bVRjO*ct4`?tLZt Ml7 zoApb=l+Vhv@ZV=$q=4gL0JZpLTAHk7kF8nejR$WYe0_960Tvn0FY=J4`3$f;Mp{l& zp)n+?%Q_04sLM@)4BGeyYM~Q~ zDG$4(wm_vu%aoy9u(oJ8_OWhn_PwV~R)p-i3ciVgU*z!@QvT#%MEPE@1M#SUw?coJ z7S)xM&`uA5R`O_yC^5e`59}fy5VRtglD78`3Eo6juO}OhDNDG-pza2xl^Bny6E3xE zOGb@eOPVh6D8Fj_<3?3kJV!?d;A^aBQ7jz)koJT}%zeEG6V}yrCiiP&>QDc*`!`*L zcFUB^{Ao}bo; dXiPsOo0U4>(s+Ob{QdU6ALFMoxQ}Fok zT3>7B=UN?&vw&`v%w*7G(eDu4BrtAh@_E$Pc-rn(d h670yT>OnrHm1L T0P`)7s8B -q4+$woQ)8RdQrcvOtQ-WOC6K{rklM8aMfuUdcoYmNgf+Y$g&^M!ltZZoi$u zSKO0B5x`h4EW-ICDS#zCSLrsk*ji4G2CMFDF1svsL?dfe2+}r3^xX2lUGt~7@9&wE zsndlt-X7mY_O7M?f?26nxVD#n08Pt{wpZG75OF6?|Mn?M`_@ y6iE zh-d6-t$`7G{o910d^WVs?zqEK0M}7F$;j34UlD$y`QSm;8hG&9BaY3CYR2`DAEwX_ zTil_kUsY*>%_Yb7m59f}>BA!%Kf9e8ED2Z)g8zwUi+soVX817UCC60eWg~ifBZXf2 zCM+cG0+oga92DksHUov9w_j@V1*(LzV;SNx&m&4HRwrP?G_)D-sa8jSAUydn`M$;V z7j-WQ_4Bw}!&Sqp8~=7@))(sQk+p75jTkV#cP?T+@uX rX#>A tlb2;8*BZkz^f0`hDS(s@=C~FhZxAEes&2+26zyLsj4`& zC1m_X_a&tCd8`Nb*2SeBL2bs=B^tNkHtO_jcjG5vxdwgtse;Lauu;}+!SzzD_uRHS zX4fuE38>t)er`l=n$kP2s(#t5v(8M*rvmU$5cf4tZf713vx0b19`v6q%NQuGqlC=A zsi6+xj^CTAt%4>`t=vDDIM+*georLF`mb*4RM%>*a$QF&!V3({ gUdyifWQ#qXeXBS2j0BBPasATI zTm`7rDX(W#c#GCF{Q1S{Nsal8ej;__O~RB=_5UDss%FpUHashUfTZ8kLO`N7;Ann+ zYSfuGK%M3TW4#28B)u+Uk>Fwg^@=Db0MxG!v>ghuW_*H`dbP=7__j4SW7}A-% sz*D{q0gd4{+4jF?wyb^HxM z-g}M|zKlH@N&1c#nF~vYp`%ydnl>vsyO)Iv-A{WcD^P^CJgO a|Rz-m8Bt z;Vq>Zyno=f--C$LRy<8 !0nh#UUUH9G2qLDs~PWK#)LhV`)?GjnvB+a z3`POV13R$3?VJsR^GgOlg})l~5Sh{#Q~0G0C~Oa)!!!am0J?$AHv&NWjPe-%|EDk1 zAaMtWwjb@pW&ykVf3D2WiNDbfpr27IO0yjk2~3 zG`4UJc&7kwfpm7E<%i9)*$URF@vV2x{m+qM6-kZvvu^E(Gd(-S3qKpgf3qApCrjRX z=luWWdC~A=tVPyb(dLDxCjWafD6a+Fu4|@DdPmD-=a0y3BlLx=Us^L_1h%q>aKP&t z@*q2n?|Kv?;JI7d2SOk@6p;)2Oq2#t+T2ty6Fq8F3MjnaSp6gbdNflPC~k@hD)XL? zc+SMeR&rz|eXREhi4@Zl6&VYg75(2Mf)Z{W>o=Pv?t9MQn%D-8G@!xEQJ}3n;X^v; z;U2A!?Xk7>g<3he^VnOLAZ+mC`!mb#ALxSvg7;y9Xk?U N-e5ck z0*2RDZQJNVlMxJ9rQ-uR#iPkVgd>a8+yTAl#4_f{1N^Zp{@T5_@24BSO>tnOLpGah zH+C%9{`WS^({S&_hhlg^9~LP Q z-wS|tnnIb|&MG4DpT@^KZq90W4=SK0V9>CmTI9N?l9iDO_ZC|_^q{}zsKl~%p8p8N zbC@rRm>XR7*lyX~mTg?NWF~aN#Va0uV@3czE5(pjMXI3VodcCX_z^rF#X^id$i_`7 zf&v;KtecE2$TOkeRX8fYWlYyva)U~eM2^sdxXg%y6@ABV9b$_674ZnC!%y0W)c&}$ ziaxmG{hDE4@a{x~_Df52cIc1G6qJ;R9*^Fu%ReBJcsD_dg8SbI>kE89Iy#K&gU)ck z7qKs^*(FC=*-x*J>6?8Us+8EJ(q(;kFTZJJg=1p;A``{bbk7}v3)Y-&!`HWC^zVL% z_uS>-s2Cia)GLjb)b6St`Fl&h0bk4WIk*BBx3)88)4Alh$x02RjhpKjCnh;CTN1NX;F2 z2Z5DMFw}t7`Er}sMpa0ibKP+`wW3)S{49GQ9&W3RW2$V?jWB700c)~S_*v&$cw>~U zE_D>ghefkEgMr1~=g-mO_of9_xIfuGRTo^A2$*{)jMY2z9n5}bMei0!)9vrMN`jNd z?%A%ZQ}LG=@MZ^%&Bn9FN-B3 +;PkUTe`o^R>?+~ep&S0VC6Zkx(Pxuqq54%T^;nw4 z2D}kEmg2VDY>8IufTEf=$M1~@IqimP);8Ve#Z*j;Bf~k?N}CwHp{u2hYpdJeI5ykH zTlV*~U-sc}UzfS}SC5sBFDo9W4}N)ZRXPAK`|!)#wQ(O^CtC@NU)r#N=nFhOOjo79 z_h SNcuwG7ql`?hNRTd}vz^2~e|B6G;`ZDelIV z1~eCOV o3@<9w}@F#j|lwNH|;{&Re#yzP(w${Hly3tZ`Ql zV%tMTL~zwP<~#Ho+vYopct$rRzrzRp`#yc!77G@UyRkyOdx=AUKdv#tmdHBzVCKjt z>dJZ8Wu4NYWhL7m6`s79Bz<+=t{{2D&G!kjA#SRPiD!Kj{l9(O81}+$g29X}*uAMl zVm(lh@G^fJZn63w+uNUK+yB#NAaD*u9l^676(EeT ZguN}=;Q-HWfD`@)o;kaa8ui(atOwl?8(O3QdWMa!-tYjHNQQg zKm`nJZDnKHv3*&las4xGo0-3mgup3&mS?M*d(v|xd@{|Wict48j1x0JUg=mKa?D7_ zI(B9kUD%%0?c+F%Xy(l1c~W^jb2k*2XY6!$f-k>y-jpzgj#^=t<|04T@PeMmR=y~> z-X&3n-^soqd!T>v&GAq?=mU3^#Gq~7)PLsLiwV`pWXbOh4VCprv4T)mM 9Mh0-yFe_xL79!YE>~T8QBi`If9cUc$lJ zhT4%uevz`MvfyHm`%$HKSndP2w1i}g+H1A>nPy}O#8#c8i#x0`3v(1}iya2d+_jYT zbUT;eaWR*~X(4>1N+kE3Q}CnWm!i)IB+6!IZgG(l^pN1!cWgt54sMpF7sEEM#au5S z>ROgCRA#1e;_xZ1%(_O|Dl2Lpa-%dRw6; n z2fw@{;oo4~*8Wr5;~(Su=fY!RNRMpIc?}p=jdrR}OO5{! {8oFFlt$EbkR|aIpQDp{8vnu-D-CB6qO|&rMB7?LpdQd$|q3Q?>|sinS=}Y zph*R&60guJ&)R%{(geI->F0;h0RT%~88>u32zX@#&Cky^0om1wEm!cw-h1+QBwVvO zn-K7{k@OhvX~)~oFV3@#-9~$Uy)?hQD0uRkilJ|pS>>^;dcv>%^TrCH!pX*y*PDa` z@4NWh!|Zh-Cu)nUts+oc`F?P23RR5FkoGLh2!Q;}?fakMHK`2#YcJj3hy1zfFD-qZ zuR5)k4UX=RMvi1-ZyyKt*L!~>elv85;1S*lb}Q_Ld{8w#aTK5ahW@|5!^vlRK`RvV zjiWPUc8C2d0PVzd>A}FiNALPQ5X1mr>eBpH-J!P;75la5K`?e_-=pklCVI3CWQ?*Y z?JSw=mxi~Gl~}G5$5V%WSDC2w%zl|47tp+Fy^lJWMYYt@F^X7~kK_$G0qGiB3P-h| z5Vk<*^;+sn@2PP=1Xw@sjj#3E4J-#D&bCRWH3xHNm7>?DYdvO^s9XnMeHtw?9gQES zus-R1{LgM}Q7Mq(igXxPoou9?xc=y-K>&gS%SOx5{XE0VmIe9J#}SM+pXpYo`7pSB zPaHs7BBOqE22i+lU0`M|JXq5QAJSJ&-tBkw_yqLMK0C`1`uUZ`Ht-gY3yRr;*xK{l zi1AWuBc&SJ9PoBG|N6M$5(aZ^qkfq^B#Z2-H8Tr47~_2u%2J|>z=|xsI+)o6xsv0; zP&03Zk1cENw#JIKyaP44{BjJxYoYZsLo4(a{2aG#stfD=Z2Mvpv2D4F>XV`m)k gvdLdi^=y>?2migKqtK`fRkS z^K^3vYHIt^Rz-Xm#qwZwE#CuR=>LbhH;;$1f7{0u%2Fg`H &ht3V@ZYr6Y;k^3mq{cXqBKFc!~5qqmY`Wi$fv+BIa2c+2z(fH?R3W8cZW4s zW?qH+$&v>NWx~S3>t(dL=2lxerIj)(*VK~dc{w>hRlhpLlC*``&XF{Wy%x|a?>hbf zgc==v1BEfgo5yahLddmHS26&tx#Co|ZU|awYTXao&IVQDJeT_g>*TGtAKuHnNO+cT z5bIl?9S^yc?3uJ3qz2jhevK%>_fy#)KO1ooP1$k+03gn0`)R44q2>xF5z%lE8iuP| zU%fQ4wU7*P3s|qy{I^~GPrbn(?Ylz0)!nG2%d<$~qkQ|s>0k9{Y*>TOOg2jj&`y&{ zIP(A}P2-&4_pja*#ETdcfSp{~9} U@cXg` z-sI xRbDwTW|S`V;oLDYC~D{29ZZ zH5BtyW5_$D@XCm0 6|PR#If zXVgih5xw5OPlxZ#zl?L5t#<=zb8=Nrzc~BaQBC?hu`YO2=OS#(8n*0XnQ=mJv!ywu9w-D)bcFfwZ3<+pgwu}7llKX@R~94 zDLshF1sYy0R9b4wKY@ObN9p*=KcefO0L#mpW8a2EpE)&~^orTIq+Bj^dl!vDKsv3| z(^|;E%t7ztg;1}9gigx#W6m<3ug#^a89*b*u)5sFyUca_R!TRR8)XAzZT nK{G$Yi!{GNdfCJumSnc;Yig@&`z= >lMOLpx4aEFx(S%uyXSPawZINxze zbzMyQi8?p<`um&?3vSB?&kwq~B2`ab)l!yKuZ|!)fDgFj+$QhH H!R)jqeoA$HJrweh;ak^++k=8&fU{ZMG)%LT1SEGr;2YRg5AKmY!ZkGGB6%8U zCSlK_;$0Ck-cri1Co{{@m)yt5bp98Lv|G)>5VqFN@m8Xj&T2Lp`#PKsXBuuD28rD? z$=GN6`0?W!ZfmOZTj&S`J_XC@UT_M9+uCMn{l||eE%L(MY5ZBPB8cnm7Z+-c1V5Y1CR@8! zUyVE!S)p`rj}ZXnj&CC*zWoqb Ma;JGPwXjz@|15!5(v=#Ob#!=!B7_I{-f4 z_UY~oa-a!av-oMbD`_H>QaoIGk 3? zCy2AF>_Gs1&S!x+(s{rk#U)Vre~;&Xo4+c>LaepI*ScRivAFolrasTFtM+~Puzf=( zNptGMBIH5cD-7e-J6|q0i7gS&ik#$XqipTcX32h$s2Uvugv&v%2J;xUnQw6ZG`Eh= z#aS?nP(yrh^p%sM@E4(t^_(C@1II@%XLp?Tqy^Q(ySgi1OHZ1d7_0|?IY+wxFRnTc z%SN8Xz?W^u7wTS?@%$*|m`&C?qNpwWP8cM6IzUm|f9qQL_QP+!q6epglZl;IUgsa% zI=*<;SsH-3{d8x^La%iWDnn! _onrk_Z!{VYUj+4UR#`Xtnh#_X@kKVGg* z_E_2GI`|w&5upx5aalHQaYwdgr4Y&PXzTi{nqlu*vNBiTTIDYPyfRABA){d=Rw(}c z*=v`NK6{pY=32<}^Vh$2tDDMd8}-e^haHn_U5K&2d8(BD#j`AtNWW{e+0W$@^72IR z=>ZPD>_bCSm+O|pp9R3|>RUDn#zu6^aVDO(ms#x|<0`4Hs(tIOq6Ql0Qc+ LpGUz|_&Arpe-hlpeBY+*nsrs$SOrQ&UwJFpaNmVT@aCs46b6l}akHZ9&&WdWR) 7R;*@s*7R%YYp%MyIyyo~=LHvakHIYF!|>tb(nP@}7XOn|ZWfxH+lt*D3t zR~|aNp=dCA!=Q1cREIAB5DqD4U!*q8j`wXym@-d{%bJn|@bM5qEd?E7Pu-zrw}# z)!doJ8mF(FTp4^yq9N_ov)a(JXSij?x-EQ+>oM6pYCp!ygkBgNEt%BzRldT1r=-F{ z50R&nMvXW< cnvfZ!k%U4_Vt}-I8BtMKF<^Caj<;ghN zQ$}ZPkurf)j8|ulf4V$&R&t_;E#YcoU((fXcz}zg9p+7!XF?O98rw5KQck!Ej-YOw z-zA $<`c4V z!eXND>G?g%t7fKOG7;QSKK%fG%inmSnpRTqQO3++xqsoJ7aGRs?c>9pO8qpLve_IM z&;@J3s8dN+&tJM`$F$Fsv| >})~}4QZN} zTIE7us#DHZbsn#4>vj+YN3I&k0jEMHY~$Ftlzi~7H5b_ukKHu|@r;z4ZQkwd*H3DC zik!pMKv#kgM-i)?r0X*oWYsIX?08p3N3xX_&&OjhSKVgifS}D&?7w=>rEcA8l_JrR z4kzF;aGZ|g895}sga#UT=Wj4T@tCiE^2S@S4c-<7qghO)3{5VF+r)F}l)yGU1a9!7 zVI7Ud(UGYS@(4}GNc?=b!leVtz1QqVfhRU$ _;Qnk-aPhD-RC%y4} ziB@QM *Ig~T{HQ3GcyCWuTxj-L5${-S;BA5j|T`q z5BjpT2SVvtmr~suGjk0xxKjhXc2>-sTwSk7gr8GCT!lEMf{8CLUFhZR)ocbT!AfGe z-Q)~g_QaG($S3QFsz7r@3oMC5y_mn(XBRN(mA+e=rcp)PX1ch1iP#0rAj`dViSiM_ z*`Z3jWQpowkO>i+tJH8tGd_juX5KM_TX|{x;71=IRidT-Zc z)*|RUBJ(LV85n3x6fM(Ip?T?W38c;^MqNW=xjlwQVs-Cw`1treZkdNCuE^Dblg36# zvn_yn4B#!g5u`9ij{df&mHalFyjO>TZ-KAU6rI~V873=iL_beYfc*TC8RoCNRKIaz zZ+#~s@3OEJeSf_g5U!*N5ZuPIz(8ug@tW(CrQ%X=`#l-*>#gaD<;SHl;E!0;LSM7u z?nu&mmAEkfw(V}K4^YZdec~|=M*M2lOg<}Vkz6{+gYHSFrzg1dyi>dv=(}oSY`oO^ zf>poUbYonGX>)bBc%THp{i$>F^P)mRS~O9$N(Xm)033vPF-GU%;bALx1pU;HOj0er z^I84UJQua+Vo&0 6tls%ZJRSt)w#UqcTjl}TC>l3=O zH>%z8u@Pw_+S=MCK0Z~P-ndqinMIbMX``8*kmJnnhQBZp0)k?XFcI(TQ%(pUW#Xvb zbi8CBEILCo`jO 5W}F{oP6lF%7zAAR1OjqJCDKIg-5%)yRkKmk{jb#S;F9;>3F?=d5yKP zu{swQ*Y>X;JRWJjvP;zD?d5^Aqwst8xLr|=RyUU&?CtI82tq Ww?ABg(We{!Vl9#MO2g>OnHYOY*0OKT^V)+-?7D*4Em8XeD1onNQV1JAhyoZL)XV zNf&Nt_)?CT?o1{TZPV(mBD0sv9gw> *^)&ocK~mBgk9f6d z`X=($3#z@c$T(bvf=8A@Cn#>)+|2C7!CMvoG6fAVi2rGmyY)X_&PY%>ZRMFcEI1fg zFs_$exx6qfeGKXw3`vrAJ#sAaw_QU)GJ)jAs1i%p$Mm>%ry7{X+F4BE;VznHdph=y zWs$}dPS^YE`N9#}$txw#$v)_tLw5`6EDdlQ)rJlZxt|rOIREhvlrYp+$-n=EjzD$h z_oX H~ek&R6ZPYw$ zzHRhS`N!0hjmy!Q>y&u>=aIiU0}|R$**J5KEcpfAn^T8&)a|=iJKk^aBIlBroIEhs z78Mhf$xM0m)cr@Ut~tQju5oE9G9~QqK`|WlxsAz)1IqpN9()RaOQ VV*LH*1*H0X235GX^ z(zCI!oFjeOKFWtrzI4~t@&xoHB~%}yb}woosd@S0$PdzjKz;@X9S|txRP{oDGnReK zpJ;Eu{(0=mnzl OJ&&ILO;IXxOGFq_*?5H)EHU 3%UjA?%X6O6U&lk2R#sL 941P?Hq|N3nxYS8l{ aH eRRpH*0i4gBJoD@A4}Do&xc?JQZDEbl;nT eb|b-QeY~>5bwbYLt%iKu;Ht-`Uo1Wi{r$#W-QBFoiWp?Ns)c1q zVPUo;f)H=r7$jN}$b%nR{L0PEeZ6U9-e`}JL*jWip&nn$kEAlp;2;-fuwd54WcIfQ z4BDI*n~=(^gDmiihnN2`>gN13u)5Gu1pN1@4x%T_*1m$eAB97q4V=XpvX1e$Rk9F{ z145tEfiV@W=9?_;#PTYtGoHD0DtRY3gPo1-QD!Q&k9%;2_SjA^ggiP@3gM7BwvG4b zNmsonfyLgdd7L>AK*Xki;f-$^-ouOQse>JkKAr(7`xFhh79RpDo)gpI1Jp6XA`7Pc zF_X^O@I482HpnmgdbhkS?Qhp-aLn*+T3|ao1)s&FMoZPyU1TDV8@6)tFh@r|N%G+R zLo-53azQz~wLmU)rXo7T8%Tr UsSTm*SUmMnL?>rRU8&$jaq(Nc$P)e4#r%zx zK_9!Nhby1Af-J#-n3-TsMe~qqDU3|IPLpuoJWJ3OjQd!bCa>E2xy#e2CL}V-_tIrG z&=K&*+H_{gnN >%%r{vElKr-6QeHAl!$D=rYI@+fNdT49y~{yy z;_uqnWYTRr%`A2-Ebr>*=*&U*V-{bNcZ4xmyF6q!a6Ru`A`tfRh!a24*m&gK*t%Kp z2SO8Wm$%vVq4WnDQrq3(->3Ia2cy7*J`TzVNKc!Xt-q3e!S&ycF#$u)tbW{Of{i&h zJ;8wACQS&kfg3_oqPzL@?IU_egk$uq_5>aTu;Ry}Ka5!q-FFnz`G`M%5S<=86W2(2 z9OgI;48w4o)E33T!_jg|kVoOc#L4jKW=BZJT48keP8)7E_2IaxYUo3di%iL5xln4d zBqDvcAZX;~#7COGj<4s~TG^#z=VZ2)d#@ajsrosVn^2aT4i{2(+CYcFbcUIZFvCtm zn$?th{H==TM0#`n_oc?Jn#ntAF F#TR)#4vc`OKR`Vb4FfEyvsRCo{S-9$S@S6Jol5d;7mIZ^Jj7ZgvtrbP zja&8Y9LJfy@MsS@LVFXsw@mo0ItRai_dCSG1GOKqx2KgC8e))&H*dv4kMsm1VtUx@ z4ZkboOyN7XcQyh%4w3|P!J$Dnug&LPB)+ |qa?t?i37)?XKLxeSyacWcm9POINHh!9bW2aiqPuz05I+rX zTC=}+gx}(XstRTRC~2=OX7>l5wjOLCtR3j aoS6PQN>WlM)Db{rm=S%) zWIY4dVQ17>0;`ekn9o1bWIwLWRPx%f<%*RjQHlTz%1{f*=AG4Z4t@fz;U-t91=U{{ zASIGG_k;r!#p9 LD`SuZ0eul?B3a?k+~|I491zbZHQElGn0KVwk1_QK5c(?S z-hB>BTctxRRyF(`><;r?l;i!?M1im9^={?bTRo}N6JN33?BcWY-4p8_7;OoaBEA;* zLrq!en%4=k*SO!1s4?vdWJh=`WkNkfLf%?F;;bJ73F?#7bY;?v|n
uXDUSL#Phg6+N)nHrWl+XIXOqxtK`E4P>$ph)TQgYPJgv#K-@TodAMd zhqlRg!jB63 u^u3-LV`1LH={m*&plUD3Dlj!r7UaW;ZbwlQwIEfQO{YjVkWm? z3(&OF*Fnc43{RQgkR2
2>ePH~#4uhh;D%{?_I^9;PlL zD;MHZNc29S%Gu1M>hp9=9sSa)H(~uBc3H25!n*T4L|2U^#QN4E=sJn+Es23J_Xf&D znAZ|Hf>Luu)Ghd~xK)CR&iYVAmmi1i8Idwu{tjs^hS=9`POfM CP8{}K42}GT2$Z&8|?!j*RL=(hwHp^tmTragBq!?ez=P-wcJvK #$ z%age(R}iIk`(J8)7`|;UU5tCV>^cMADQIzBN>*~rDAOl>fNDhjy>b2<3P7_P@#_Wa zuano;*Vijx#DJ8`HqYo*U%h%&@nk_a10E!R>8|EEQ8sJZW|K}%Rb|>GZ&`(kG=A?6 zx9v5j+-*Ggz!m|VEe+f_4-4<+*oQA^7FCnQQN6zf-q%v$dyQhYCdY}2g~Ds(yY!@2 zsSqyoaH-pLy^iOv?@|(Sv?ROO$jB_S!rOg7{-Bk411LJ1SXrfg&X=Wu?Ewc7H0z~+ z0YHkw47wI>&Pd#d9Pvn<{r2~c_z#Q$fW(f={W-R5Dwi%rHy&e r zITXOTwYAk6H}dP(!xSZNu^4{Ul!xEnTmvZ4nRP`|poDa%B16Srnol*rH1I@YX+?$X z{z_q~h^%aa+TKsr6a|m-4KU)pqQxp8`^It&3WyK%XWwc6GDuU>j5;HpC1uzCd@=du z%lE|&i#=)Cc)Xv7KcK>ub)Qzr-3cHF1Odq*HVzJ9e)rktu 1Ht#VqGPadv>QZ zuCcy-Tgc}=hFJFO+0m}9u6|gN=X;QpZRi>N-j# t;S^lCT<2UVG`Ql;=m8lha3vI00%ISSJCi9DtNTlyQ =|b&&{3!BaZz+6pE(}O{rLmfqS`Q5a+oa!qvBU5@ zB{OvLSg48ezlRG%C;l|P#arNDnuc`IyyUs#@`fb>mX;(5(O+I(&T0oVgU6Y8Ppw7= zXS8hP8D(F8X&$A$;2)qmUlqX&I+N@l07h{f_ii^K0t5Ou#WBxE3v3?>gW}QdRSfd{ zw7855QfLCorp3kcS9{J)vZ}qC>3l7$-;Lkfw4q)D1S#z0r?#IxdsfkeEPaiV+40_* z-?X9ANc@AY0_jTupYM0L5HJ{Mp9g458iyP7C9V7mcFS|wJ@z%{#ghXU^o(X{OKc!= z7_81ZzQ%7}YDr}(O`9ZXS@T|eex5MYM4oU*e2K<*QsK7elQh&y7njj0R_VS%d45VH zfM|OaTWRBmI)>)4w5Fz}hFV(3%x>Ry>fWmgsz(T`JSzodI`EDUvB0LeJm%X^y7Hml zT#m({YQ6O=z=MZXsF2x>sXDLyZO7!3ZxSORU<5Pq 6kR6+Gyo$!D;lL(z^_Ww-;^(RGYo>_*IMVM!I-rm6 L`N4yqI4ux?Z6V353#qCoWrUB=g2U z5 U^l1Vs z4RdLP@NX`T$eSLn0foF!-RGwxoHA5-h9vWW;_x#3I*a!8A(>zW43_D5I+UvMuoQXt zmrW|C@aNtGYA=zG-&TqE`M5d5XQa_O-% 57zFS-12cMtr-vl7Z-2q7Hv=*iv3Z8q=aw>!#_xy>#WEYmZ49>RN#q z-@f?&&R>DTQ!>0voCB*pq@FVVFTUg7A&?rUIkm!U%+nKNKEd}VANd!JHzaV$rJT2$ z7m*N(%o57!O=&PIS-()QR_c*ZH3geU0qN$iRn(R|8x|BY`l>TBK~qq_A3ujXdp=Cp ziEqRJol_J_)1^8yaqyHIzhVx@nJEv5Y^^qwbO&C9xP`<^ER#x9Z#th&T<3P5XnrOl za-kpQ-!DCWae|zurdJD2KtG$*@u>KyjwlM(l{qi!s3$pL5tMG2cTIE;=_AN~LCbhJ zINd(5yjesf=S{(&Tq5lQo(xU<$_9cE;jZKBPvK&%JFKR)b?O%8RkD%BB UuFFg4zLcezrrDg2nW;2V%egCXc<5b87Ps92RT3e2P;e3V zKAc+psQpHfmurNy>)s@)-Fu@e`O|E-t6~3w8C<#GNl47xZGNA-u`6)@0T8?MoQOo} zqBbF?JSRa;EiAH D#)~ zj>)z}M&8J37F&2?##O9mCO7jsA@bJyijxuRJWJ!Ori99^dBt FqG?L%2Nm;$z1DW4t`zBo%B|HG z1M9tcnGKMOrBG){0n@yvNd`pM6NJi$M1(KT*lE|@#@pm+MVAW?jUSek^=!&p+*_`R z+2_)kLB5Dd%2$p&Wq9 #KaJ!SpSblm{~QBPka zas5Z+hl=8?Vd`CW6|>EUVz V} h`Wpw?S z`AX@pU>3aLKzYzMZ5~xFn9vT-4YH!=$@b^YvP;O?nz#TQGkxa- yc>~nEKqGh+aV8IG5GSQd6 zyPj8@W^mC%#>w|=RF-j6pik`%7rqZHl7Q$gM9R5qcVK5a1(iO_1-tAC=Y{*ef4J#j zz89pg``+7D_}zy5IW*Nz^t}$;D!qN3N Lui$vjWo1ZZ@UXvCp^d@||S#4nA`Ne(kX~GC`T>_IKk=>m0 zHX-Si&RZ_sZ;X27)w7>oS&t9I#%Zt#B(QfmJdoAAWkyyz4MgmiNPk(*e@!|kUKJMp z1uZ?fjg#y`oO_ipGkRv!#e*%ezQ>~|zp{IRG}HKezp$UftSv!WEk<`p6tU2jkoxK& z`NYRoqdQMBi5(3$XBJ`V 7;1ZW z-68;}hEurMJqruXIsncaUcXKQJy@?Eca4gQ5(TQKma(z19|6^PM#cTFM|E{{GCzE{ zQ0tEc%5i(x#R|VoTME4cu ZW*&8SD;-$ Amb>%hs-@F3Ezg#_{8KIvh6JRXRIjzL-OdYjN*?MOa488{O;J z{1AxP^^z9le;b)yL~Ul;Wisq@u&ZK35``SpIeeLKwV_>!KEt1nIfWkrNi6#3zEQHZ z5uqVHO)@90izGLpmu1%aQLAf2sPQr`&wl(HxFENFgPCbjsyok%5e~wv(c5!@usm(& zzV 0{ZLCnFbe3r{Opu*rX1IncdOs_4yHE;e5EIEL(Zhxof`3Rt<=X*WBA%FbH z@m?K%;SJQrOs%aYBp_d&ggxwervp?O#$6RhGt{8>EGZNnLE0%DoN^_jsV<6%wFV5; z`(yJye7J52+us(|)Y3Axv&*jOIV}5mZA>a|s?^-SkI}js?oxO4vRj2p(gen?v@FL% z!eqaV>yEQ?o|dcR$L5blj>Ry$?>v6Qv3olv`~If4 Tj;wwE5L)Uf>KVTka5RXQs{prR0H5e4$rpw UDI+epUN#?3(k&Q& zttYo2ouMG&xT(~oYf23l8dG2k0P yRT)1E{MQEwWMFKo9*?@lG@r|s2Oy1+$DbrT8=9a?_xfnBT3c{+UtIUq<*L` zrGKDzGwXY07p~Q1qzNg!t7p;}7;iiv;%a@yUUb5VsB_Q@+&MtYNTiP|m%V1FQOf*v zXqLhtyo7Mf6d`|7cwM>voF<{&*kIftb%l;_rOVxr }>cLR90wPSfjKhB^U0?niAWzsj0=h8#KNV>fId=Kugi=dQhchqnRwkH%wMR #6(d3f^-kCiGXnI#^e;h`J z>6eNtd}T0yE&xcyDX77Lj6;Q82h+L_FCIPlCEIG`IIIx~D4qk}6(EDjO~KUdZI`Kj z8&2Voz4(GVBjv)}SMsi$1%`5KuNW}}4VO}GS>3V#_?C!C;t+TODEHf)*l0|;#GkX6 zzq4 Hejo9c_4S7(s`u9r-2rhl$0c-zm==M3g2CO`$n_r z6#h8#Z_JLpS5lM&VfZyB;%0oh_~6{9flk9G?7bwdw CT)M0 zSRT{l?!jAMUS8g&v+Xyo2GRq%2JyHOfeXa3^*M|Fzz&e&xn*Nxqc5-vrG+u!g4CW; za)-?=Ep5?9b}o_V2q6)FK{Wfyvi; zYp>X)5=N@Jy;qJfB1-=DZXJ*-v#&+LE_wf(>ybBy!i~dMG?+O|ad*Ao)0A5EttsM( zTtG^SE>hJb7cisW>$?(}x9wI$_FcNp*Y1t(`TVfR5{12~&v;lGyowGkO?F_++t)(w zR6z$s9vZ1Ncnu6!a|gg%`iVp@9@li Lhln1o1vaAKd1aGCc|@ qX&{2gW2q{1b+!SGd^7 zLt;(?!xwEt#owGiAJSRXw$~uze1|*s%44ExZw>*P6JbIUohtjtXKIBFNv&!e?mghy z%|~RMG1k8$yYBe7yeA^SkXO6v$FD&5W7$C~%xnzy`-hVXiI-Xuz_dI*OUZ1~hNhlO z&JFOddbxs5!F4o9F03b;TKFHcze%6_hCWjl!)3tLHc??@B~CS5oVC{ZRrb6>!d&k4 z*W$tu`e(dJ30JG!6@Q$J`^Z zJgm1Ab5v!htT$4%Hk}#s0vh_|ZNBP~-36TP=$C)|(4W5ZLKo6LP_#TRs^-mN=A7LP zHe63~)CDQ08{AZ3Pn)?)4ynm_{+@-cKqb~yS7lwn86J(4#^#qhvi~?4<;$PbSQjpx zV1L}54?E|6eb;?-04qBUnE_DqnFUcyU_eH~LSVdlA|k9Iwn`WNGt`8Ta=zAEB++Fy zd#N0=sf)O7vfE=k(ot@>HwY48>)Jj%a)=9dKn;3EQc^PaPzP|(2E;m135i%hZnU&E zR^C2zx%DvVM%e^I=3LY(h7#_G4@x{$M#PvW2Me`14;XK&zZSTm7=up|HqPs&gDVuP zndvj@CO($46TPCWp14U|Tb0^2DVRt&*k3bQfDK*sMm&9TKJoHxcL)SwP5*A$Iq&TR zcuMd1fO_Zc2UERLkBP3#!R3)YqrQ!@qQtDw)*lXQIKgJWQNJ#caV=M;n%hSa>jU?@ zMzfD~JSniw4E t7H(EnV1@&+qs-K^^C>+$UNg5?p4> z^X~Z;1+I$;)?;swJheH2{|k I=v zj@SBM4te6I1Qj!vZKKgUb~X3Yhrt*#S$XN$-NEF#n-LqUQV*ArCrW8Z_|X%!`C<7X z=f5vt=2ax#ue~>7E1*ey!>PT=w#udFy @qKT#X zGBw=U`62+PW2)SybO8l$LPElIKzH_mL( 6KGxwZjg^7Dy`%E~@K zH{FJvAOB=S-2gqfU5EJj^MR803frwWmxCMkS1x`ITIfowa2}BWs#{qJ32eGIZoE%P z;l5Ytlvtx?-^KRXdSSV8%X6-e0C3c(#fpF(r#>}6i3hlrv!~J_Ae6A=;t0gtJhym$ zu?%|Pv#A8|w2K>PKqNgLP U!JZEpCce}8F9Zt&zT2ij2ezoSw`*7?wnSTE*N6&)Z4C2eH+=S9H1JT7Dm8h%W zW^hAtQ>iI&{ISQD0*O$d%wK=N^9nFQ6aAT7{0C6?0AcrO^uVnJ)#o~?+KR6`aJ;ry z-e3sipKBwv#C&}Q;kTJZmj`IJ=k|e0Y~|&tzP`*bc;j~)prm=v62Ol9i6D8mcQuke zv(2 gwtN;f$cHVmp=EM$bikmL`8wReAYjz#1+* zyh)7VlF?c_HM5wx@p9(nk0S&?^*OgsQ9jNWATuBaf9f9VHkK<%`>UlA0)+i0WHxb< z1Wfsy5()|UCNixS7n_w${c?{{1Z< %yatrJHDLY=QTb0 G2* z>wa+rqv`GH+Z#s#r?bi8nC641x0;E!x)xH>yX#}C0n}#%F9dR|f5*|l`zQ9PS@4Pp zTT)ndc6O+~5#+ON*qK2<3F+RQY3;uCvvZt@3OF{R2m2lSn;js>&UnGOGAT@9aARGa zg+)7ZuN j4@XA$0fv6`7~L`Zd|`VgNkDiU8$j?oK^x zh_7+p>JT5d*z~#n!NH#u-~SLMQlQ&PVG%bz-~0Hw4# ~qF=(DjdxGD1&?EMR zn;VYgEz|HPfojobQ{>ER15c#WUVf& ;lZmLSuc@rXvo8eLAJn@Z%tV&gC z<9}KUE(422!!DCK#S4Wt?+o5m2kkv!8U6BCkr+@ h?LDZe!#U0j#`y_(IXNZqa)!UIj3U$9 ^nmxmYCfB)7GF&)!2;;zIt l93@`Hr|A=?T)adHYI6TUWm z6b>n^Y;2rfen)c?g!k7z0s+DTo)gxn3MxcKBg23j_g2;az+-gU^Y_|C_YWDx^i26O z_U`=N2Tv7mHK2U^t|E4Q^s~lI*TvVU%_nM1Q&uw$yw-asws{FHEiIx~t_;oV97G>! zC~YDG(&nz7o-?=~NEsm0sXUtoEL{7`DT^70hKAcfbyk_nuOXo1$o$=Xppt!F|9eM- z<^>_4NY=gl|MfWEgPu1rU+z6r0{_94?h^I7oG1(_6Y;}riJ8sGFX@n$$46fS1%tw= z{})@~!u;n0OWKaWSOIzdI;7d-<-jRbsyBzF-TxhHyE+pi`-edT;Idnde@NYa_e1 zp=3HN^M0rP7u{3-pUS|087lty0K0Frq t6&3_69+HBq&0&nPp1*EV>~a)uAVswU zu!;7E{Uz27y2ZuC?QKUs1F(dFf#EbV5D*>7+BDPb|4MbQ4 +1DXMp_YHGmi;q@~@W80Ji&!$o%o`})oe!vRO6?H 85e1HI$9U4kQ!F2$L z=%e^Wp77tzkaOh*dZ_p&yn1yF$ef)HCIY4|S%)6p6d(rHppP^2FJ*)S%8VU_*42yy zK=>i5rj`ycuU2ecVIgbxlqw2`Mo|*36(hqaF6PTMziAKRV6-GukE!z!>!fkg%^k&g zF;R-WyL09}GB^MLfD} Uvl! zVQZnAjh$W7AYFxJ1SoQ}^&D*vh6BkbQzN5uC0M%{5I7z1rc`L0_j9-kq{WCmCsb%j z^Br+fO(jl`9-UIYFiJ6no;x8nkF^JMf^!dI2r0=DR$@M|rrry`yVdRiVvha8mAuPa z=DRVe)7RH$o6ykM=J~x%qZm&ioN0xFkV5c)d z;X=Of?2T{#ayJ1x7z|lGNPv+_2|+fL++VeyY$__Dx7W~BObr5L0i#29(p3X1c7bj^ z?8-C>c q-) mwXc(yFlcMNbb|LmV80 z$6VyZWj!s32|?-BNa5}SA`aE&&D76Z`xZ DAps=YUfb< zJF98@1Nb2ShfkI4g2|8ZyvOMX8p;1Ws7SX-7ccs4=uq*5Z?vzSF2xOFGOnSn-Z~hN z-dK`;)u2t8Rx6fQ2SMCTty=r`O5nVy=Vs?7zBNFM2_GZ}vo6`7QSe?#s6hi@Mau4J z?spkD4e9;+vmT(JD&pwqo$(6C*GrGtGlE_k^miZ=$qQI!jD6zf-tFJ4i3rfYj||;} z6zI6Z;bf)WkXz8;bvKnsjTiGx#b9x<&*N#P*6(ZUJL7;x`Sv9io|KrKzH@TKT_Me5 zn!~?idOwE{4C#&+)O!Skk9IREjc31o`z*kP0 zGXCkL z{a;uX12LHg)O-`u*TrKbmyJA+n-Pdi-VNmYF2^o^_&v(g5%?>>Fg>1!?{cm5O8ZO6 zHNp}Aof{oJasS5ed-D`Na5Jz4RN;7A+}juW9>nNAP#TElN~JpCNYNz!H841+vAgy> zslj+JRKiq6wuqK<{P!6Fj1#0ss~=1P;kj@EYSrt(1Yd!v1nSH7 GHhoAAJ=50s*KPVewK&2 0?J+AW8mdd%G5JiDmhyDk-IuKoI%>d(H*K#D?115hgRp&dyALL=`urOJQ(3 zcg)PpDA|h6&Q4jUL6Lm|7AXp-`z)9>GJe~~!A)o_i&dWeHV;B$Be$fQaP2|1XD@hH zs&DL67S=AUP$*$(sY7)=wnGd@_=>qvvd=JUWMm{8xa(5ui%#eK>Hsk3bE?wP@nRP* z<^!Csjt}rS12HM75kJT1!Lz$siiqq813X5*12(kg0x3{Gn7o;$ecc|uOuq?+kF#R- zwr0tnK;2{{S<|cQbBX#0sqgN*M$M9Vs0 z;QV&R!6w$IXbCx#1pF^ n|)Fr zPXC*}m$(1V=hA((@}QFpfJYYG`U>3Izmw&kb@{uD>obA7^DAEcPoH0_2JEZV$M={1 z`B7-NcD_H;jOo+W-F_xkfX8^?OB$;Sw=D7G{*yXes(RVy&z?W8T&(^2q( f<-2 ze|)ijmvF=S>Hnwy{nVe_!~d|!e^NQ{0KUSR{RiVWrF4cj{s- r(vwbo0H|lKv%r<&*46P5z z|EdEV#(VfbdH=t~$*2BLEO>l)M@B}*f+I&<1TR&l`~}wZpR_&z>y}^_mllg=`~RoY z-#%aY7uYrZU8N&;^*?CG=EmQ^!wRO%nzhRJBYOOOfAID6cfZ8=`0~@!cLKLG_Ql5@ zOMmw~l3@?9!uTiu ur2_tCgSsruN^?|97W*?ce=>-uox&wwHhBzc;n($^7``-= ea&^~kiZmXSNIrgrW^Dntzn0h~W>R >X!Ha {~N$ 9D-fZ*-~3mzmuAh=6#_r=|9kpPQJaCcaI@kN8fLXag8+%>o+K=6<2 ze!jPknm=dPOjmVRS6fYtx|%!=76ldp0s@Yrf{Z2t0!lLi0+I{{@+-1TnK6!lfQ+E7 zqAiQi4M*sn$LofYk&)4--3kj!2@A&y3#SPyL4_S5!jOGoI9wRME+qw&k^)H?0;K@2 z43Yw*NqOc;#lJF4DjqHs|Dq%%rDOHR4qzt71hOZRg zZ3sCxoZknqK>+{|z!3m&j0ZSE0G@dO&u&L4DMu+yM=5}#RJ^06)PIGJ@s7Y(hB^Xa zj-YtQc&KAM%rOn-2nIQV^BlntM=;D00&;|`J9ayI0sx+l0MA#7kM~T2c!K9Wq4A#3 zbD)wG&`=5phzB~R0X>00PcRS!1VW^M&~+dz4LA=6&Yy!cH9?L_ARqt~4+o{igTOEl zbRGnK0m0)z^RRefsd(YEcqu@ we|)G?-@^tUC>!mIl8CdrE;lmB1i4 zI9?bWp9YSf2ZQs#U
9eF#7b0sue&@eoI0h$jHz=?U=! zLV!{bU>XD@^{N&m4GIARArL5}8wP>FA@F$!{2Ve5hs?h~)*+DfZpivNWc?hn{sI-2 zf_ATWgQU9S0o`f9?mR$uURpPJz8enzkJrz;*I&B#Z@bUWVNxJi9sri-2m=FPU{4qX z2!qDMpfFhX>jQ(q&tdcHu=R7;?K)iPwZWubErElfaF{0?mIjAI;jeU_2S4wIzr4(Y z9p@py`R=rN7 Ywkm&UJc%#hwSe| z_xI2DZ(sTL911<}&O2X+oWIiT`mGf2t(5Ssq0%kD@D_w{3(mWRdEUa}Z(-2eb QnOBVMB>_#Y&z? pxuD)y?0--qy|wq4w>B$SaEbKh(q8;y+P3FMDTe1cBSPn6D+6|CMOD z+Iaa|cvvHtxV`)*{^oxlxAz1%S-gsRAhh+he0zm4{)6=_JY4KuY!Uh>e@DGy=>PY= zw+Fx);rb=~`2UGXyE;2tyLchoOl0)FVrc(~Y1?}_StC@Q&9ERK&><+wNNW4#opc8! zQH^-BVC1-@rrFb+@>Rk#Hm5(PWe_G2v3tro%ATHDW^Q`;w?;MidY4<=spK?)F*SZ? ze^rR1q>19Nd}Pyq#2C&&j!L{inw4x)B@j~XL54At`dlodm@k-9S(@R=!0oc{rXuBP z7riI=%egjeZLVjrZN466*Bu3{nV6)f>!e>N_uhABa+|qyG-Vh%RDngCB3>xPQcTZ) zCMa0#D=tYbzOKs&b>NKHXiMGZ=~P$l+in-sRo2m_d8hxw6%uW)5eWS@CMVG=h_MbZ ze?|tzyXX3pI#z)h7_#;x!7N#Q4`(=Zb$W=Q2pu^8$o2lz8ai~S#Q5ua=BvmooIhI> z?0OA8C!Zk&@bl7WI(-ZN@mxRA{&B?YCQ0W%Sp!{)nla*)W(0!^PyY>={LRVJ*75Dh z-8+u$9?Ij^bMHGYw#|5VID*@?%qs2q+U?$XVDJ>cRJf(PV*xs=8DM{Z Wa!o%;L>7a+3 zgy*q%afNdie@ gU!5e#81E3oH1Vpbz6KBgV6r;U(a%%}&i5k`RXRJC=(F7sQ)kEnD5FE;vX zo5Tq`zw8dmFGWw$GyXgqL^CJ+zIpq!DgV4A|M>Q~jud$9AfE918h8_Ms;s)2&=7uV zv=Q`%2LijWJ#*%tZ{NAT=U^++!_G&Drw*z0zQH0 ?Hj^|_iY z==p#QJlOiBq0AY?A|20W{L4jZ)M52qB^bk7tB?1sS_5ofN7EhLgoDtV=Q4^? FxoP<2>S_QCY&Vf6FQ$Y6b}YHi5U;{BO#?}LfCX6JFtlq_dD @lgs`S;$t8xHcwsT0O@9NPI-b83*zu7z^nHTAAT|g8_WXj4 zIn{aKQt!X_m9^_%)HvzVQLlJLC#^Hg2zB#mv}d~TKD6>HpW4?Se30J2ei0 P4r9uQ3;>lz%P#nT)IhAIk4jCN$p3 zwWO ;x|Pnr!?Tv^WU74`ZnPILc_`_q;I_16~0wlzVo<2cW@A`*N2os;2b z`ty(CFKpsVx2TKNnQs+1p?`CC`{Y=)!zc6%}CxQr;G*y7&^P_6}EXhK{Ez7U2W za_NFYFqsJPCYLr1XultOei6M?=%apl!R^cZ!d;M7yAg7-pcB)*EJk};B01gw=DxWt zca2u6LHa|R9~TWss~e8P5+a-x7r)N3UU@&!Tr2i+`L;B{;f!Ql5yg)E<-rwQ< MVoFm3hSBs?IbeLE}i()O8*gT&@F8HE2(KX~eD)^%AwR-7)-KNJ+x3r&PYGGna z|JFZ#1M^9^d_E$jji*!msl _Ok~Q0KY|;!c(y zQZD3;eGmtinmj3eQeF#%`QDlB0H+@IsyLX`eC8V4{Mv%~e48$x>K|Ql;CYYdiPi=; zXl@Ycs?0ksbLYq~DMZ^@W8Bk7PDfl*oF<&$0~Ev}Pn!|;MQgV+lAXj=L9dk^c;CjF zLho5?@K!7Juium3-mdu^^U~SSJV`X4ka>J<0|B}N1Ycw5Tk!Nmb~9d`_F5^LNJNug zbF?3?fFqumBhf*mQ1`R6@7i_$+u#G~SHrt~i^bw}O}tMMU^?Q{PE-Z1#<>Mf#$pe0 zJ3!Jx*FcM&Vpeb^6P}!WLYCT}dwKC4MUrvb&+pKmOlNmoE-G6pmfGjVLat8~Lxu|N z`ljm&O!{7Y5qmpHGWKOIfl B_PSV*!?u(1(h{Vy}PJf ziGb)Q{m4-g*X?2{q~5Q6IWl^WcO1XU@Za7@j4|SrQtiW38PmWA$z@>0WOAYV7upZY z6QjWwrg`|`2ClTph7O19^u!qH?3x{EhL~L5)2u1Xw!I%Nn#;Afn1aeQkez-zT{uiR zJooX=uIA7nuP6J#JpVyp7T>V#OdNLmzS5~^*UMp(PZrA)H9qggOg#}=SoJmML@TLk zKi3s}Ry6vK%riD+mMhvmcgJWlK5nETxvE6TAF?@1`FwsssTVqlLol-Lz%S<5CFoDn zI %zbH+(G@W z?H9Asux|f);1P+fXF|NLwyf6cw1cLK6qh{A?iowVS1(7?5{+O&?o9ChBwf$vIPzV* z!Fjrmbltw5|3v55vC|R~f_$mJ- $A4@%4uJyHs=Zh&(>eq zHZjidr+=3QXU4tSmvDSwr#FSrt5hKW6$v}{axsFO0s~+wIwVjmqYh(!m&i-}2~DJ& z2*cTX1z^Z}8X3!1M7dm#XHGx0ogsZYTY(w=)i$4of}-;}OSRxiiC#_hYFs+Whc%zF z^O`lci>IqSW5&h7EXoi~sgrD0Qx{xqhNp=FNc*Mw)0h2%BZBBfp5$L{4iAo85v|Z~ z`w6O?@eRcJ3V>^XC1L2a&-E1+f&w}b;pcK(f25n80_z|y`M}YFJ>ovz`dxo@qyi@S zE{Z!Hk4>~9UBFOt&S-OyO1sz N!~0Z_ zqY7tTld#A= dVF6tU>C1p6l}>ugj-*=|5x6 z!v*pUKh|0&fdn|y!L{#a$OSOXOJgX&QVLo(3(@|%>X{TP8xK>TQPBKahRo`rYsZlY zIC}YpbcD%z*!3oXJw_XrPXxEKR(!d&(y@Pzd(Vhv-WrJ0;4Yd2=eLIUC5s*75vKx5 z-KoibmXk_6pcHtEmzm& |etF~oBKuxy)I;uP5T>NAuBSWX{*?ZanYJ`CX;zj5 zA;Bvd(ElO1*F9ei_g)kV4j=xBp>~9aJd#ZC_{ItE5clyZRIFxq^;>!018ydOQ%#7+ zkAvKNRhCrm3ij}867TfJ%@s=<-xm-Aa<#`I)v?FGGBu4LTMN}5n$=D5gAm`K3u#)a z^4-%iO4DN<$j%?DpsUJhzbL)+KI5|4>T$ep4~c=;qBf7nJS9_4KM18m6Ye1OlWt#3 z$8#r}&i#@o{)n*9oPNLJ5Hbu{1 yd|vdbJPiFClRYgi(>7CpjbJCJiqRH%$XBjAu2KH q#}T$Ce!j7bqd(3UkIV3+SIL0NC#G;Xhr!B(yuUim zgLS_*=H)<#_KFi_wZ_eV$Rdy1p;d29ng^Phc3M7bKy1YS-8ytxFfMjbx|{8AnQN3e zRQ?e@`6TZa{BL37U;PWPnfLEd_w?shc~J#LyefC)&`LH7mI1j*KLT7dxxly0dieoy z3m5LKsZ2C~UZ;^-zt8~lyGi+q=P=%5cjQZ}EdC`7NM13y5;9fk^W4!UUf#ZY_3wYL zE)CAGj4=_>OQV{Kod&QG@&CFT{mz9@f WlL~ EHj9{^?){-UM>_sCB z7oCc&uWmIl(*dL`h>aN<#pd(dt(N?}f?jkyV*O{dh(t;fy&^3YlM>NPTCEPz{1?1& zxj?K;PRG3dU&X%-ptBwwDXt%9185s-m~zZy$~^+MeQ?vDV)Oe~5AbmHi60CcSUDyi zk;j?jvSuf&N5cv3Hh*IR@(8g;McG@8Vy=xpi2zb$r%+AZ2 UFczpAHtS zsfpcR(n$=92*i>R7R93=bf=7{IdjfD__`)y?5>2syyjmzJyB|i5=oF(QYD+@BVE&( z7n28FOp=9p#cBhHTPyLCyLXplxaD|D8zS`=rn~?Dos_~vbElmSUlhs8pUUL$6a{NX z7~RmTHLI)$9h>iHGwGPW2=mOQaY350znq9n5bVZzNwdQXx4Y^>Y0A9SRW1-4IMC`e z!qdIN1m(g|u#T1z8B8FQ^P1y(O8r7J9q%_dkU~YZhwOer7)X|y8RS~5z9mpu?o}=j z7(J$NzPV}fC_mM6*r2Y_Wz|6iNN2cJnfEauf$5k!3+Z&^!!bm>FFm03(wxZ53D&>4 z<*xwxwQ?Cv+38l!52k0)YvzkMb(!?)edIM%HKj@xAk$=lH=(hddSzrj`n>VlayN{` zDB8_ERZp9aReK)RZyZGV;2}1v?0og@t0UZBd@Ht73MXXZ#zO)lv$Mh39$iUkkMz6E zy9dVb>}_mi-;X=njNPzab=;8cel@j(z*RAIiWet4M5}O}&u2jOx1olpVD)g>3$*Q? z^a1pta@|ZONQU8iMy`B!o@=ugcl%3QIhHGflN_`7U#)I& m>Cu*w?oxmE zD{Npt8BixYv)X0orXy8lvHxZ?@*!ko_)4v-eg9KQ_L;rHa4EMRJLShN7PYH2tL_Is zvq`d%k&y)35)TRdT8Dsm9%^mkITJ~Se{9hjUua3Uh#!2tJ7FYopA(%g1<%$7#e(CB z+H6Y=7Bt7v;+h@MZ>}eL3vB&h#{ztR8-=_@wm2+s&5ro)2lqHzRZq?S@>zh$53?;N zQ@(lCzez;MYnQR=r4l#M9A+l6q}691oCT5dhRN%e )!OPeTPsc~g|NDmMnMg^B z>qt|=R)#*!rZ0=uU8~5Cdz6^qg+2Ds1vRBaa*$t8kLUNk+UK6SNHLw)9r@pqZ$1Yz zBwsjs>Z=UKw-wIRjK1@?O3YGnIkll)j*tsVI#O$Knah^p8g>!AZOPt 7r5~U=7 zIOgYtuDOb2*U~LskVu8;cRw~N%i=L6QIxL8pe8sSt2Cn|TG5VW{se)enVzch5%S*1 z+8bHuV3lJxCQh$|b`Av6mF Ud1j95Ljb+nVMr@7`Dg|w*5b0+l__RGqsrh6)8>=-ild>D~9vZ4g ztkb0qF2i%X+RbBZSqGC{ K%tYY&@^Sg#4!kbX zzn8e$1WBVWBU(aW89T8Og3OTYrmEeA9uFg_njTFyCef5}vQ#6)2Tb6{JbJ3A3nh`I zM(XkRF{A8X!jSw6FNMC)X$8c#o6nK 5lnR6LFlz=c^9;90pS%>juT-tA`13?Wf5 zq~~4I){Nt6?s5U|u>dI~qiUPYa#=K)JphKc0hC;TT_TN;qc2P1R|`-DdlY0L*HYik zBx3u!0cTM0kDgYy9tkfgfkeZ9-ut1sWT77>H$gn)P)vKogtSrbDpeKRya37r8;>#i zULtseCr_Y_mxri#07t3cB2Ictoky|ptTq{4+{)_&lwFWY%waVEM#oD_2p#zlEnM8> zp&NkD;|r>OJtOf+#;U0#^7`zzc09->@J`>PrjL6ACghIeu0GQrRD8=4{45fBN6>-V<}f1IM| znfesfmr#}t-iXE_PDgt)|14VVNA10OjID0nZ~du_N xIBoR b=>mF! zH?Z*MI s= =q508ASikjsZhG#E{c!mv|gI!sccoOZOH=4?J_>J2(Z{( z3i}5c5zS&iuxSfJ`|R9nHD*1T|8bzK ^nm({Q$*FB9b?-m9BObng z$E%)Q^f0aV35#iK<4QIYl~FL5ty_mZqfyX-4Zpp0%gUNj87RR2&q88Z`^@6GdiJ%+ z$bW-vu9QF4iK&Fu_T1Q0aH745OJSdWYu^;HKZ$x$a$KPiViMBw7m2CJ{2p}-H7?8G zin0PLX&_ZjyG`L+9*4+YbfOq3S^Q2lhf;P-pL)NckEMTt&Zz)dwjY4~FWNq}YnGQq zO5t533zn`|>&53L;W9932CpP0&O%W^{r*Fc>H3-)jX7af8X43sVy|l6KoYHX zxgUYVm9YnxIlTcXd(s>?gq+)!2R!#U)e(ka2B5;p@Uv$6ZYU`)xj;@jt10Gusd)-Q z`jd?j130bOK{-VERqENI^aq1x?}%XvOF1hjobH(Rsg!JSFG$LI|C3C YQ_YR@d3H&6~hLTRIw|&Gr*_F0Q+zWyB{ R@!Cp)Ff&NSP>?as^ z(5gGHjp%n%Y%!}T2A SOoh9f}Y<84k3M( zSKS&?SjQKwLfs3xg~ hD-yu#w^=wnFDCC^)@h69OlN-mWdbg dotfu<6x`29BnpAJ!}(s+tSB0loUe;g(6SPYyi3qob04QtXDu=uv0gmvim z!h|$}h0!Tn6F^ENm49A1+4U3~p%p^ukJt3# @Qh0gLA) (prO?O^BfZG<5xWroJ}h6ai}D{jDiDo3%6;gCP>9c zxSaT0Pl0gikd5rOkO~@P(%KD6F@ufRXqzYnWs~Y~3SV7|*hXarPk{L(`}G!wGEfPX z2v|cI>{*y8R{Cx5dxC3JiWOV0v9L>}I`e28wJ #&31*;JYwLJ;g+yukX|R_LJ_oDFWA@g?HNS>9n3<%>Kk?PjEi~uD*di)JIjZq zF@764UO}X$`orM?`e>{m2LNT&)lMreR=VlCv5XQmsMl*?bP}r7G7<|8sE^PFV44>b z5Sp+rdw$^^51(J34#F_VPAB;BBS#dAyql-^jYvKC(|P>R4~@KxmC;YF_pCyuoXdcG z(~4U`6YXN$;}An@hyZW0Iu~P{98xlRUQvaS=?IF0(XQ;&X9K}pe|pvWZp(4spoI)k zn{Mv~#^#}x^-faT8AgCfRs@rk+|az|cv(!W#hz&X{0GX1{Sj;U&c|@_mruM-m`f-6 zm)4$6N4$9&H7)7HGOj5I`5xE0-^4?nxU!hV`Er@gyDwpsZSb+!;f-E=s}m!7MXRkp z1$Ny-Sxo!1*<7Enk5k|p!v{6g@9*GzvdvAjt?#^cMX!%O{5(E>|DE^fuSoaD!;3=< z7|&P5^x;cCR#%oW+gTOPbkQiI?|NwAoD==nBF&{;IxB>AFV0<=W>B6ShOG9y!aSOX zqhcaTtc}iFr=jLN^Na%IKho@dqi#b`Z6Mz#>1hk>Oqc>c^02j>9^(be?$E*a)WBMF ztq7 5i40WL77xck12S@1y7X{u?~mxXbJBNgssd#6;S@ndl0_Zj?qq!540{>_q? zi`~Ke7oR^IpV6fV*@>nVWA2{5cq%js8N_kbPLE=;1EcBkM97Ya`HD%