From e6ffebcf9b907316ecb1b5e1d8cfcec748fdcf14 Mon Sep 17 00:00:00 2001 From: "linux-hetzner63.in.pspdfkit.com" Date: Mon, 25 Aug 2025 02:02:11 +0200 Subject: [PATCH] Nightly 2025-08-25 --- CHANGELOG.md | 6 + analysis_options.yaml | 3 +- android/build.gradle | 10 +- .../pspdfkit/ConfigurationAdapter.java | 65 + .../flutter/pspdfkit/FlutterPdfUiFragment.kt | 121 +- .../GlobalAnnotationMenuConfiguration.kt | 62 + .../pspdfkit/flutter/pspdfkit/PSPDFKitView.kt | 156 +- .../flutter/pspdfkit/PspdfkitApiImpl.kt | 15 + .../flutter/pspdfkit/PspdfkitViewImpl.kt | 41 + .../annotations/AnnotationMenuHandler.kt | 250 ++++ .../pspdfkit/annotations/AnnotationUtils.kt | 12 +- .../flutter/pspdfkit/api/NutrientApi.g.kt | 256 +++- .../pspdfkit/events/FlutterEventsHelper.kt | 12 +- documentation/annotation-creation-mode.md | 193 +++ .../contextual-toolbar-customization.md | 143 ++ example/PDFs/test.docx | Bin 0 -> 217264 bytes example/android/gradle.properties | 2 +- example/ios/Podfile | 4 +- example/lib/annotation_menu_example.dart | 59 + example/lib/examples.dart | 20 +- example/lib/main.dart | 2 +- ...ient_annotation_creation_mode_example.dart | 70 +- .../office_conversion_settings_example.dart | 99 ++ example/lib/office_to_pdf_example.dart | 135 ++ example/lib/toolbar_customization.dart | 12 + ios/Classes/AnnotationMenuHelper.swift | 274 ++++ ios/Classes/PspdfPlatformView.m | 13 +- ios/Classes/PspdfkitApiImpl.swift | 11 + ios/Classes/PspdfkitPlatformViewImpl.swift | 122 +- ios/Classes/api/NutrientApi.g.swift | 224 ++- ios/Classes/helpers/AnnotationHelper.swift | 18 +- ios/nutrient_flutter.podspec | 4 +- lib/nutrient_flutter.dart | 2 + .../annotations/annotation_extensions.dart | 40 + .../annotation_menu_configuration.dart | 65 + lib/src/api/nutrient_api.g.dart | 1256 ++++++++--------- lib/src/pdf_configuration.dart | 5 + lib/src/types.dart | 3 + lib/src/web/nutrient_web_configuration.dart | 24 +- lib/src/web/office_conversion_settings.dart | 46 + lib/src/widgets/nutrient_view.dart | 1 + lib/src/widgets/nutrient_view_controller.dart | 22 +- .../nutrient_view_controller_native.dart | 18 + .../widgets/nutrient_view_controller_web.dart | 13 + ...pdfkit_flutter_widget_controller_impl.dart | 1 + pigeons/nutrient.dart | 141 ++ pubspec.yaml | 1 - test/html_pdf_converter_test.mocks.dart | 4 +- test/office_conversion_settings_test.dart | 81 ++ 49 files changed, 3309 insertions(+), 828 deletions(-) create mode 100644 android/src/main/java/com/pspdfkit/flutter/pspdfkit/GlobalAnnotationMenuConfiguration.kt create mode 100644 android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/AnnotationMenuHandler.kt create mode 100644 documentation/annotation-creation-mode.md create mode 100644 documentation/contextual-toolbar-customization.md create mode 100644 example/PDFs/test.docx create mode 100644 example/lib/annotation_menu_example.dart create mode 100644 example/lib/office_conversion_settings_example.dart create mode 100644 example/lib/office_to_pdf_example.dart create mode 100644 ios/Classes/AnnotationMenuHelper.swift create mode 100644 lib/src/annotations/annotation_menu_configuration.dart create mode 100644 lib/src/web/office_conversion_settings.dart create mode 100644 test/office_conversion_settings_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 12402348..6b0330b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# Unreleased + +- Adds `OfficeConversionSettings` for configuring Office document conversion parameters in Nutrient Flutter Web, including spreadsheet dimension controls. (J#HYB-861) +- Adds annotation contextual menu customization support with `AnnotationMenuConfiguration`. (J#HYB-683) +- Fixes iOS issue where signature dialog would immediately dismiss when entering annotation creation mode programmatically. (J#HYB-859) + ## 5.0.1 - 24 Jul 2025 - Update README.md files to include the latest rebranding changes for Nutrient Flutter SDK. (J#HYB-842) diff --git a/analysis_options.yaml b/analysis_options.yaml index baf99231..e0aba684 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -8,7 +8,8 @@ include: package:flutter_lints/flutter.yaml analyzer: -# exclude: + exclude: + - lib/src/api/nutrient_api.g.dart # - ../../core/Vendor errors: invalid_assignment: error diff --git a/android/build.gradle b/android/build.gradle index 6dad59c2..778de067 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -60,16 +60,16 @@ android { } dependencies { - implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'androidx.appcompat:appcompat:1.7.1' implementation "io.nutrient:$pspdfkitMavenModuleName:$pspdfkitVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation "androidx.compose.material:material:1.8.1" + implementation "androidx.compose.material:material:1.8.3" implementation "androidx.constraintlayout:constraintlayout:2.2.1" implementation "androidx.constraintlayout:constraintlayout-compose:1.1.1" - implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.9.0") // Use the latest stable version - implementation "androidx.compose.foundation:foundation:1.8.1" - implementation "androidx.compose.ui:ui:1.8.1" + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.9.2") // Use the latest stable version + implementation "androidx.compose.foundation:foundation:1.8.3" + implementation "androidx.compose.ui:ui:1.8.3" implementation("io.noties.markwon:core:4.6.2") implementation("io.noties.markwon:html:4.6.2") implementation("io.noties.markwon:linkify:4.6.2") diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/ConfigurationAdapter.java b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/ConfigurationAdapter.java index de80c727..333b6dc1 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/ConfigurationAdapter.java +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/ConfigurationAdapter.java @@ -216,12 +216,15 @@ class ConfigurationAdapter { @NonNull private final PdfActivityConfiguration.Builder configuration; @Nullable + private final HashMap configurationMap; + @Nullable private String password = null; private boolean enableInstantComments = false; ConfigurationAdapter(@NonNull Context context, @Nullable HashMap configurationMap) { this.configuration = new PdfActivityConfiguration.Builder(context); + this.configurationMap = configurationMap; if (configurationMap != null && !configurationMap.isEmpty()) { String key = null; @@ -935,6 +938,68 @@ private static String javaToDartTypeConverted(Class clazz) { throw new IllegalArgumentException("Undefined dart type conversion for " + clazz.getName()); } + /** + * Extracts annotation menu configuration from the configuration map. + * + * @return The annotation menu configuration data, or null if not configured + */ + @Nullable + public com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuConfigurationData getAnnotationMenuConfiguration() { + if (configurationMap == null) { + return null; + } + + @SuppressWarnings("unchecked") + Map annotationMenuConfig = (Map) configurationMap.get("annotationMenuConfiguration"); + + if (annotationMenuConfig == null) { + return null; + } + + try { + // Extract items to remove (now using enum indices) + @SuppressWarnings("unchecked") + List itemsToRemoveIndices = (List) annotationMenuConfig.get("itemsToRemove"); + List itemsToRemove = new ArrayList<>(); + if (itemsToRemoveIndices != null) { + for (Number index : itemsToRemoveIndices) { + com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuAction action = + com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuAction.values()[index.intValue()]; + itemsToRemove.add(action); + } + } + + // Extract items to disable (now using enum indices) + @SuppressWarnings("unchecked") + List itemsToDisableIndices = (List) annotationMenuConfig.get("itemsToDisable"); + List itemsToDisable = new ArrayList<>(); + if (itemsToDisableIndices != null) { + for (Number index : itemsToDisableIndices) { + com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuAction action = + com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuAction.values()[index.intValue()]; + itemsToDisable.add(action); + } + } + + // Extract other configuration options + Boolean showStylePicker = (Boolean) annotationMenuConfig.get("showStylePicker"); + Boolean groupMarkupItems = (Boolean) annotationMenuConfig.get("groupMarkupItems"); + Number maxVisibleItems = (Number) annotationMenuConfig.get("maxVisibleItems"); + + return new com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuConfigurationData( + itemsToRemove, + itemsToDisable, + showStylePicker != null ? showStylePicker : true, + groupMarkupItems != null ? groupMarkupItems : false, + maxVisibleItems != null ? maxVisibleItems.longValue() : null + ); + + } catch (Exception e) { + Log.e(LOG_TAG, "Error parsing annotation menu configuration", e); + return null; + } + } + @Nullable String getPassword() { return password; diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragment.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragment.kt index 3db24e24..67c16b6e 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragment.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfUiFragment.kt @@ -28,17 +28,30 @@ import androidx.core.view.MenuHost import androidx.core.view.MenuProvider import androidx.lifecycle.Lifecycle import com.pspdfkit.document.PdfDocument +import com.pspdfkit.flutter.pspdfkit.annotations.AnnotationMenuHandler import com.pspdfkit.flutter.pspdfkit.api.CustomToolbarCallbacks +import com.pspdfkit.flutter.pspdfkit.GlobalAnnotationMenuConfiguration import com.pspdfkit.ui.PdfUiFragment -import com.pspdfkit.R +import com.pspdfkit.ui.toolbar.AnnotationCreationToolbar +import com.pspdfkit.ui.toolbar.AnnotationEditingToolbar +import com.pspdfkit.ui.toolbar.ContextualToolbar +import com.pspdfkit.ui.toolbar.ToolbarCoordinatorLayout +import com.pspdfkit.ui.toolbar.grouping.MenuItemGroupingRule -class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider { +class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider, + ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener { // Maps identifier strings to menu item IDs to track custom toolbar items private val customToolbarItemIds = HashMap() private var customToolbarCallbacks: CustomToolbarCallbacks? = null private var customToolbarItems: List>? = null + // Annotation menu handler for custom contextual menus + private var annotationMenuHandler: AnnotationMenuHandler? = null + + // Toolbar grouping rule for annotation creation toolbar + private var toolbarGroupingRule: MenuItemGroupingRule? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -67,7 +80,7 @@ class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider { */ override fun onDocumentLoaded(document: PdfDocument) { super.onDocumentLoaded(document) - // Notify the Flutter PSPDFKit plugin that the document has been loaded. + // Notify the Nutrient Flutter plugin that the document has been loaded. EventDispatcher.getInstance().notifyDocumentLoaded(document) } @@ -99,6 +112,47 @@ class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider { this.customToolbarItems = items } + /** + * Sets the annotation menu handler for customizing contextual annotation menus. + * Note: The actual menu customization is now handled through annotation selection events + * in FlutterEventsHelper, not through contextual toolbar lifecycle events. + * + * @param handler The annotation menu handler to use for customization + */ + fun setAnnotationMenuHandler(handler: AnnotationMenuHandler) { + this.annotationMenuHandler = handler + Log.d("FlutterPdfUiFragment", "Annotation menu handler configured") + } + + + + /** + * Gets the effective annotation menu handler to use, falling back to global configuration + * if no widget-specific handler is set. + * + * @return The annotation menu handler to use, or null if none available + */ + private fun getEffectiveAnnotationMenuHandler(): AnnotationMenuHandler? { + return annotationMenuHandler ?: let { + // Fall back to global configuration if no widget-specific handler is set + if (GlobalAnnotationMenuConfiguration.hasConfiguration()) { + AnnotationMenuHandler.fromGlobalConfiguration(requireContext()) + } else { + null + } + } + } + + /** + * Sets the toolbar grouping rule for annotation creation toolbar. + * + * @param rule The menu item grouping rule. + */ + fun setToolbarGroupingRule(rule: MenuItemGroupingRule) { + this.toolbarGroupingRule = rule + Log.d("FlutterPdfUiFragment", "Toolbar grouping rule configured") + } + // Store titles for custom toolbar items private val customToolbarItemTitles = HashMap() @@ -157,7 +211,7 @@ class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider { // Load drawable if available if (iconName != null) { val fragmentContext = activity.applicationContext ?: continue - val drawable = extractDrawableFromName(fragmentContext,iconName, iconColorHex) + val drawable = extractDrawableFromName(fragmentContext, iconName, iconColorHex) customToolbarItemDrawables[identifier] = drawable } } @@ -192,7 +246,11 @@ class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider { } } - private fun extractDrawableFromName(fragmentContext: Context,iconName: String?, iconColorHex:String? ): Drawable? { + private fun extractDrawableFromName( + fragmentContext: Context, + iconName: String?, + iconColorHex: String? + ): Drawable? { var drawable: Drawable? = null @@ -261,6 +319,7 @@ class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider { } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + // Check custom toolbar items val matchingIdentifier = customToolbarItemIds.entries.find { it.value == menuItem.itemId }?.key if (matchingIdentifier != null) { @@ -284,6 +343,7 @@ class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider { private fun isAndroidBackButton(identifier: String): Boolean { return androidBackButtons[identifier] == true } + /** * Sets the Android back button in the toolbar with the specified identifier and icon. * @@ -300,4 +360,53 @@ class FlutterPdfUiFragment : PdfUiFragment(), MenuProvider { } } } -} \ No newline at end of file + + + // Contextual toolbar lifecycle methods for annotation menu customization + + override fun onPrepareContextualToolbar(contextualToolbar: ContextualToolbar<*>) { + // Handle annotation creation toolbar grouping (existing functionality) + if (contextualToolbar is AnnotationCreationToolbar && toolbarGroupingRule != null) { + contextualToolbar.setMenuItemGroupingRule(toolbarGroupingRule) + Log.d( + "FlutterPdfUiFragment", + "Applied toolbar grouping rule to annotation creation toolbar" + ) + } + + // For annotation editing toolbar, use only static configuration from GlobalAnnotationMenuConfiguration + if (contextualToolbar is AnnotationEditingToolbar) { + val selectedAnnotations = pdfFragment?.selectedAnnotations + if (!selectedAnnotations.isNullOrEmpty()) { + val selectedAnnotation = selectedAnnotations.first() + Log.d( + "FlutterPdfUiFragment", + "Preparing toolbar for annotation: ${selectedAnnotation.type.name}, UUID: ${selectedAnnotation.uuid}" + ) + + // Use only static configuration from GlobalAnnotationMenuConfiguration + getEffectiveAnnotationMenuHandler()?.let { handler -> + handler.onAnnotationSelected( + selectedAnnotation, + selectedAnnotations.size > 1 + ) + handler.onPrepareContextualToolbar(contextualToolbar) + Log.d("FlutterPdfUiFragment", "Applied static annotation menu configuration to toolbar") + } + return + } + } + + // Handle annotation editing toolbar customization (fallback) + getEffectiveAnnotationMenuHandler()?.onPrepareContextualToolbar(contextualToolbar) + } + + override fun onDisplayContextualToolbar(contextualToolbar: ContextualToolbar<*>) { + // No special handling needed for display + } + + override fun onRemoveContextualToolbar(contextualToolbar: ContextualToolbar<*>) { + // Clear selected annotation when toolbar is removed + getEffectiveAnnotationMenuHandler()?.clearSelectedAnnotation() + } +} diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/GlobalAnnotationMenuConfiguration.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/GlobalAnnotationMenuConfiguration.kt new file mode 100644 index 00000000..8c135260 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/GlobalAnnotationMenuConfiguration.kt @@ -0,0 +1,62 @@ +/* + * Copyright © 2024-2025 PSPDFKit GmbH. All rights reserved. + *

+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW + * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT. + * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. + * This notice may not be removed from this file. + */ + +package com.pspdfkit.flutter.pspdfkit + +import com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuConfigurationData + +/** + * Global storage for annotation menu configuration that can be shared between + * the deprecated PspdfkitPluginMethodCallHandler and the new PspdfkitApiImpl. + * + * This ensures consistent annotation menu behavior across both old and new APIs. + */ +object GlobalAnnotationMenuConfiguration { + + @Volatile + private var configuration: AnnotationMenuConfigurationData? = null + + /** + * Sets the global annotation menu configuration. + * + * @param config The annotation menu configuration to store + */ + fun setConfiguration(config: AnnotationMenuConfigurationData?) { + synchronized(this) { + configuration = config + } + } + + /** + * Gets the current global annotation menu configuration. + * + * @return The current configuration, or null if none is set + */ + fun getConfiguration(): AnnotationMenuConfigurationData? { + return configuration + } + + /** + * Clears the global annotation menu configuration. + */ + fun clearConfiguration() { + synchronized(this) { + configuration = null + } + } + + /** + * Checks if a configuration is currently set. + * + * @return true if a configuration is set, false otherwise + */ + fun hasConfiguration(): Boolean { + return configuration != null + } +} \ No newline at end of file diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PSPDFKitView.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PSPDFKitView.kt index 01a15bc5..48b4c253 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PSPDFKitView.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PSPDFKitView.kt @@ -20,13 +20,13 @@ import androidx.fragment.app.FragmentContainerView import androidx.fragment.app.FragmentManager import androidx.fragment.app.commit import androidx.fragment.app.commitNow +import com.pspdfkit.flutter.pspdfkit.annotations.AnnotationMenuHandler import com.pspdfkit.flutter.pspdfkit.api.CustomToolbarCallbacks import com.pspdfkit.flutter.pspdfkit.api.NutrientEventsCallbacks import com.pspdfkit.flutter.pspdfkit.api.NutrientViewCallbacks import com.pspdfkit.flutter.pspdfkit.api.NutrientViewControllerApi import com.pspdfkit.flutter.pspdfkit.events.FlutterEventsHelper import com.pspdfkit.flutter.pspdfkit.toolbar.FlutterMenuGroupingRule -import com.pspdfkit.flutter.pspdfkit.toolbar.FlutterViewModeController import com.pspdfkit.flutter.pspdfkit.util.addFileSchemeIfMissing import com.pspdfkit.flutter.pspdfkit.util.isImageDocument import com.pspdfkit.signatures.storage.DatabaseSignatureStorage @@ -50,16 +50,20 @@ internal class PSPDFKitView( documentPath: String? = null, configurationMap: HashMap? = null, customToolbarItems: List>? = null, - ) : PlatformView { +) : PlatformView { private var fragmentContainerView: FragmentContainerView? = FragmentContainerView(context) private val methodChannel: MethodChannel private lateinit var pdfUiFragment: PdfUiFragment private var fragmentCallbacks: FlutterPdfUiFragmentCallbacks? = null private val pspdfkitViewImpl: PspdfkitViewImpl = PspdfkitViewImpl() - private val nutrientEventsCallbacks: NutrientEventsCallbacks = NutrientEventsCallbacks(messenger, "events.callbacks.$id") - private val widgetCallbacks: NutrientViewCallbacks = NutrientViewCallbacks(messenger, "widget.callbacks.$id") - private val customToolbarCallbacks: CustomToolbarCallbacks = CustomToolbarCallbacks(messenger, "customToolbar.callbacks.$id") + private val nutrientEventsCallbacks: NutrientEventsCallbacks = + NutrientEventsCallbacks(messenger, "events.callbacks.$id") + private val widgetCallbacks: NutrientViewCallbacks = + NutrientViewCallbacks(messenger, "widget.callbacks.$id") + private val customToolbarCallbacks: CustomToolbarCallbacks = + CustomToolbarCallbacks(messenger, "customToolbar.callbacks.$id") + private var annotationMenuHandler: AnnotationMenuHandler? = null private var isFragmentAttached = false private var methodCallHandler: PSPDFKitWidgetMethodCallHandler? = null private var aiAssistant: AiAssistant? = null @@ -71,10 +75,24 @@ internal class PSPDFKitView( val configurationAdapter = ConfigurationAdapter(context, configurationMap) val password = configurationAdapter.password val pdfConfiguration = configurationAdapter.build() - val toolbarGroupingItems: List? = configurationMap?.get("toolbarItemGrouping") as List? + val toolbarGroupingItems: List? = + configurationMap?.get("toolbarItemGrouping") as List? val measurementValueConfigurations = configurationMap?.get("measurementValueConfigurations") as List>? val aiAssistantConfigurationMap = configurationMap?.get("aiAssistant") as Map? + val annotationMenuConfiguration = configurationAdapter.getAnnotationMenuConfiguration() + + // Initialize annotation menu handler if configuration is provided + if (annotationMenuConfiguration != null) { + annotationMenuHandler = AnnotationMenuHandler( + context, + annotationMenuConfiguration + ) + Log.d( + LOG_TAG, + "Initialized annotation menu handler" + ) + } try { //noinspection pspdfkit-experimental @@ -112,11 +130,16 @@ internal class PSPDFKitView( } setupAiAssistant(context, aiAssistantConfigurationMap) - fragmentCallbacks = FlutterPdfUiFragmentCallbacks(methodChannel, measurementValueConfigurations, - messenger,FlutterWidgetCallback(widgetCallbacks),aiAssistant) + fragmentCallbacks = FlutterPdfUiFragmentCallbacks( + methodChannel, measurementValueConfigurations, + messenger, FlutterWidgetCallback(widgetCallbacks), aiAssistant + ) fragmentCallbacks?.let { callbacks -> - getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks(callbacks, true) + getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks( + callbacks, + true + ) } } catch (e: Exception) { Log.e(LOG_TAG, "Error initializing PdfUiFragment", e) @@ -126,42 +149,78 @@ internal class PSPDFKitView( ).configuration(pdfConfiguration).build() } - getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() { - override fun onFragmentAttached( - fm: FragmentManager, - f: Fragment, - context: Context - ) { - if (f.tag?.contains("Nutrient.Fragment") == true) { - if (toolbarGroupingItems != null) { - val groupingRule = FlutterMenuGroupingRule(context, toolbarGroupingItems) - val flutterViewModeController = FlutterViewModeController(groupingRule) - pdfUiFragment.setOnContextualToolbarLifecycleListener(flutterViewModeController) + getFragmentActivity(context).supportFragmentManager.registerFragmentLifecycleCallbacks( + object : FragmentManager.FragmentLifecycleCallbacks() { + override fun onFragmentAttached( + fm: FragmentManager, + f: Fragment, + context: Context + ) { + if (f.tag?.contains("Nutrient.Fragment") == true && pdfUiFragment is FlutterPdfUiFragment) { + // Set up toolbar grouping rule if available + if (toolbarGroupingItems != null) { + val groupingRule = + FlutterMenuGroupingRule(context, toolbarGroupingItems) + val flutterFragment = pdfUiFragment as? FlutterPdfUiFragment + flutterFragment?.setToolbarGroupingRule(groupingRule) + } + + // Always set FlutterPdfUiFragment as the contextual toolbar listener + // It can handle both toolbar grouping and annotation menu customization + val flutterFragment = pdfUiFragment as? FlutterPdfUiFragment + flutterFragment?.let { fragment -> + fragment.setOnContextualToolbarLifecycleListener(fragment) + } } // Process custom toolbar items if (customToolbarItems?.isNotEmpty() == true && f is PdfFragment) { - (pdfUiFragment as FlutterPdfUiFragment).setCustomToolbarItems( + val flutterFragment = pdfUiFragment as? FlutterPdfUiFragment + flutterFragment?.setCustomToolbarItems( customToolbarItems, customToolbarCallbacks ) } - // Create method call handler to handle Flutter method calls - methodCallHandler = - pdfUiFragment.pdfFragment?.let { PSPDFKitWidgetMethodCallHandler(it) } + // Set up annotation menu handler if configured + if (annotationMenuHandler != null && f is PdfFragment) { + val flutterFragment = pdfUiFragment as? FlutterPdfUiFragment + flutterFragment?.setAnnotationMenuHandler(annotationMenuHandler!!) + } + + // Dynamic annotation menu callbacks have been removed + // The annotation menu is now configured statically via annotationMenuHandler - // Set up method channel for communication with Flutter - methodCallHandler?.let { handler -> - methodChannel.setMethodCallHandler(handler) + // Create method call handler to handle Flutter method calls + // Wait for pdfFragment to be available before setting up the handler + try { + val pdfFragment = pdfUiFragment.pdfFragment + if (pdfFragment != null) { + methodCallHandler = PSPDFKitWidgetMethodCallHandler(pdfFragment) + + // Set up method channel for communication with Flutter + methodCallHandler?.let { handler -> + methodChannel.setMethodCallHandler(handler) + } + } else { + Log.w(LOG_TAG, "PdfFragment not yet available, method call handler will be set up later") + } + } catch (e: Exception) { + Log.e(LOG_TAG, "Error setting up method call handler", e) } if (configurationMap?.contains("signatureSavingStrategy") == true) { - pdfUiFragment.pdfFragment?.let { configureSignatureStorage(it) } + try { + pdfUiFragment.pdfFragment?.let { configureSignatureStorage(it) } + } catch (e: Exception) { + Log.e(LOG_TAG, "Error configuring signature storage", e) + } } + } - } - }, true) + }, + true + ) fragmentContainerView?.let { it.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { @@ -214,7 +273,8 @@ internal class PSPDFKitView( try { val fragmentActivity = getFragmentActivity(context) if (!fragmentActivity.isFinishing && !fragmentActivity.isDestroyed - && fragmentActivity.supportFragmentManager.isDestroyed.not()) { + && fragmentActivity.supportFragmentManager.isDestroyed.not() + ) { fragmentActivity.supportFragmentManager.commit { pdfUiFragment.let { if (it.isAdded) remove(it) } setReorderingAllowed(true) @@ -233,7 +293,9 @@ internal class PSPDFKitView( // Unregister callbacks and listeners fragmentCallbacks?.let { try { - getFragmentActivity(context).supportFragmentManager.unregisterFragmentLifecycleCallbacks(it) + getFragmentActivity(context).supportFragmentManager.unregisterFragmentLifecycleCallbacks( + it + ) } catch (e: Exception) { Log.e(LOG_TAG, "Error unregistering fragment lifecycle callbacks", e) } @@ -255,7 +317,8 @@ internal class PSPDFKitView( override fun onFlutterViewAttached(flutterView: View) { super.onFlutterViewAttached(flutterView) // Set up the method channel for communication with Flutter. - val flutterEventsHelper = FlutterEventsHelper(nutrientEventsCallbacks) + val flutterEventsHelper = + FlutterEventsHelper(nutrientEventsCallbacks, annotationMenuHandler) pspdfkitViewImpl.setEventDispatcher(flutterEventsHelper) NutrientViewControllerApi.setUp(messenger, pspdfkitViewImpl, id.toString()) } @@ -266,7 +329,10 @@ internal class PSPDFKitView( is FragmentActivity -> { // Verify the activity is in a valid state for fragment operations if (context.isDestroyed || context.isFinishing) { - Log.w(LOG_TAG, "Activity is finishing or destroyed, may cause issues with fragment operations") + Log.w( + LOG_TAG, + "Activity is finishing or destroyed, may cause issues with fragment operations" + ) } context } @@ -293,18 +359,18 @@ internal class PSPDFKitView( } } - private fun configureSignatureStorage(pdfFragment: PdfFragment){ + private fun configureSignatureStorage(pdfFragment: PdfFragment) { // See guides: https://www.nutrient.io/guides/android/signatures/signature-storage/ // Set the signature storage for the PdfFragment. // Set up signature storage if a signature saving strategy is configured - try { - val storage: SignatureStorage = DatabaseSignatureStorage - .withName(context,"nutrient_flutter_signature_storage") - pdfFragment.signatureStorage = storage - } catch (e: Exception) { - // Log any errors but don't crash the app - Log.e("FlutterPdfActivity", "Error setting up signature storage: " + e.message) - } + try { + val storage: SignatureStorage = DatabaseSignatureStorage + .withName(context, "nutrient_flutter_signature_storage") + pdfFragment.signatureStorage = storage + } catch (e: Exception) { + // Log any errors but don't crash the app + Log.e("FlutterPdfActivity", "Error setting up signature storage: " + e.message) + } } private fun setupAiAssistant( @@ -320,8 +386,8 @@ internal class PSPDFKitView( if (serverUrl != null && jwt != null) { val aiAssistantConfiguration = AiAssistantConfiguration( serverUrl = serverUrl, - jwt = jwt , - sessionId = sessionId?: "", + jwt = jwt, + sessionId = sessionId ?: "", userId = userId ?: "" ) aiAssistant = standaloneAiAssistant(context, aiAssistantConfiguration) diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiImpl.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiImpl.kt index 8285f480..374f049a 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiImpl.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitApiImpl.kt @@ -28,6 +28,7 @@ import com.pspdfkit.document.processor.PdfProcessorTask import com.pspdfkit.exceptions.NutrientException import com.pspdfkit.flutter.pspdfkit.AnnotationConfigurationAdaptor.Companion.convertAnnotationConfigurations import com.pspdfkit.flutter.pspdfkit.annotations.FlutterAnnotationPresetConfiguration +import com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuConfigurationData import com.pspdfkit.flutter.pspdfkit.api.AndroidPermissionStatus import com.pspdfkit.flutter.pspdfkit.api.AnnotationProcessingMode import com.pspdfkit.flutter.pspdfkit.api.NutrientApi @@ -876,6 +877,20 @@ class PspdfkitApiImpl(private var activityPluginBinding: ActivityPluginBinding?) activity.startActivity(intent) } + override fun setAnnotationMenuConfiguration( + configuration: AnnotationMenuConfigurationData, + callback: (Result) -> Unit + ) { + try { + // Store the configuration globally for use with PspdfkitPluginMethodCallHandler (deprecated) + GlobalAnnotationMenuConfiguration.setConfiguration(configuration) + + callback(Result.success(true)) + } catch (e: Exception) { + callback(Result.failure(NutrientApiError("Error setting annotation menu configuration", e.message))) + } + } + private val instantActivity: FlutterInstantPdfActivity get() { val instantPdfActivity = FlutterInstantPdfActivity.currentActivity diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitViewImpl.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitViewImpl.kt index 44e2fd44..99585fca 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitViewImpl.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitViewImpl.kt @@ -729,4 +729,45 @@ class PspdfkitViewImpl : NutrientViewControllerApi { ) } } + + override fun setAnnotationMenuConfiguration( + configuration: com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuConfigurationData, + callback: (Result) -> Unit + ) { + try { + val pdfFragment = pdfUiFragment as? FlutterPdfUiFragment + if (pdfFragment == null) { + callback( + Result.failure( + NutrientApiError( + "Error setting annotation menu configuration", + "PDF fragment is null or not a FlutterPdfUiFragment" + ) + ) + ) + return + } + + // Create a new annotation menu handler with the updated configuration + val handler = com.pspdfkit.flutter.pspdfkit.annotations.AnnotationMenuHandler( + pdfFragment.requireContext(), + configuration + ) + + // Update the fragment's annotation menu handler + // This will be used by the fragment's onPrepareContextualToolbar method + pdfFragment.setAnnotationMenuHandler(handler) + + callback(Result.success(true)) + } catch (e: Exception) { + callback( + Result.failure( + NutrientApiError( + "Error setting annotation menu configuration", + e.message ?: "Unknown error" + ) + ) + ) + } + } } \ No newline at end of file diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/AnnotationMenuHandler.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/AnnotationMenuHandler.kt new file mode 100644 index 00000000..f871cd7d --- /dev/null +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/AnnotationMenuHandler.kt @@ -0,0 +1,250 @@ +/* + * Copyright © 2018-2025 PSPDFKit GmbH. All rights reserved. + *

+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW + * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT. + * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. + * This notice may not be removed from this file. + */ + +package com.pspdfkit.flutter.pspdfkit.annotations + +import android.content.Context +import android.view.View +import com.pspdfkit.annotations.Annotation +import com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuConfigurationData +import com.pspdfkit.flutter.pspdfkit.api.AnnotationMenuAction +import com.pspdfkit.flutter.pspdfkit.GlobalAnnotationMenuConfiguration +import com.pspdfkit.flutter.pspdfkit.R +import com.pspdfkit.ui.toolbar.AnnotationEditingToolbar +import com.pspdfkit.ui.toolbar.ContextualToolbar +import com.pspdfkit.ui.toolbar.ContextualToolbarMenuItem +import java.util.Locale + +/** + * Handles customization of annotation contextual menus in the Nutrient Flutter SDK on Android. + * + * This class manages the customization of annotation menus by: + * - Adding custom menu items with icons and callbacks + * - Removing or hiding default menu items + * - Hiding the style picker if configured + * - Handling menu item interactions and communicating back to Flutter + */ +class AnnotationMenuHandler( + private val context: Context, + private val configuration: AnnotationMenuConfigurationData? +) { + + companion object { + /** + * Maps AnnotationMenuAction enum values to actual Android resource IDs + */ + private fun getResourceIdForMenuAction(action: AnnotationMenuAction): Int? { + return when (action) { + AnnotationMenuAction.DELETE -> R.id.pspdf__annotation_editing_toolbar_item_delete + AnnotationMenuAction.COPY -> R.id.pspdf__annotation_editing_toolbar_item_copy + AnnotationMenuAction.CUT -> R.id.pspdf__annotation_editing_toolbar_item_cut + AnnotationMenuAction.COLOR -> R.id.pspdf__annotation_editing_toolbar_item_picker + AnnotationMenuAction.NOTE -> R.id.pspdf__annotation_editing_toolbar_item_annotation_note + AnnotationMenuAction.UNDO -> R.id.pspdf__annotation_editing_toolbar_item_undo + AnnotationMenuAction.REDO -> R.id.pspdf__annotation_editing_toolbar_item_redo + } + } + + /** + * Creates a new AnnotationMenuHandler instance with configuration from GlobalAnnotationMenuConfiguration. + * This is useful for creating handlers that automatically pick up the global configuration. + * + * @param context The context for the handler + * @return A new AnnotationMenuHandler instance with the global configuration + */ + fun fromGlobalConfiguration(context: Context): AnnotationMenuHandler { + return AnnotationMenuHandler(context, GlobalAnnotationMenuConfiguration.getConfiguration()) + } + } + + + // Currently selected annotation for callback purposes + private var selectedAnnotation: Annotation? = null + + + /** + * Called when an annotation is selected. This method stores the selected annotation + * for later use when the contextual toolbar is prepared. + * + * @param annotation The selected annotation + * @param isMultipleSelection Whether multiple annotations are selected + * @return true to allow the selection, false to prevent it + */ + fun onAnnotationSelected( + annotation: Annotation, + isMultipleSelection: Boolean + ): Boolean { + selectedAnnotation = annotation + return true // Allow the selection + } + + /** + * Called when a contextual toolbar is being prepared. This is where we customize + * the annotation editing toolbar. + * + * @param toolbar The contextual toolbar being prepared + */ + fun onPrepareContextualToolbar(toolbar: ContextualToolbar<*>) { + // Try to customize any contextual toolbar with configuration + if (configuration != null) { + try { + // Apply menu customizations directly to the toolbar + removeMenuItems(toolbar, configuration.itemsToRemove) + disableMenuItems(toolbar, configuration.itemsToDisable) + + // Apply style picker visibility configuration + if (!configuration.showStylePicker) { + removeStylePickerItems(toolbar) + } + } catch (e: Exception) { + // Silently handle errors in customization + } + } + } + + + + /** + * Removes menu items from the toolbar based on their action types. + * Uses PSPDFKit's setMenuItemVisibility API to properly hide items. + * + * @param toolbar The contextual toolbar to modify + * @param itemsToRemove List of menu actions to remove + */ + private fun removeMenuItems( + toolbar: ContextualToolbar<*>, + itemsToRemove: List + ) { + if (itemsToRemove.isEmpty()) { + return + } + + itemsToRemove.forEach { action -> + val resourceId = getResourceIdForMenuAction(action) + + if (resourceId != null) { + try { + toolbar.setMenuItemVisibility(resourceId, View.GONE) + } catch (e: Exception) { + // Silently skip items that cannot be hidden + } + } + } + } + + /** + * Disables menu items based on their action types. + * Properly disables items by setting isEnabled to false. + * + * @param toolbar The contextual toolbar to modify + * @param itemsToDisable List of menu actions to disable + */ + private fun disableMenuItems( + toolbar: ContextualToolbar<*>, + itemsToDisable: List + ) { + if (itemsToDisable.isEmpty()) { + return + } + + val menuItems = toolbar.menuItems.toMutableList() + var modified = false + + itemsToDisable.forEach { action -> + val resourceId = getResourceIdForMenuAction(action) + if (resourceId != null) { + // Find the menu item by its resource ID + val menuItem = menuItems.find { it.id == resourceId } + if (menuItem != null) { + // Disable the menu item by setting isEnabled to false + menuItem.isEnabled = false + modified = true + } + } + } + + // Apply the modified menu items back to the toolbar if any changes were made + if (modified) { + toolbar.setMenuItems(menuItems) + } + } + + + /** + * Removes style picker related items from the menu if configured to do so. + * + * @param toolbar The contextual toolbar to modify + */ + private fun removeStylePickerItems(toolbar: ContextualToolbar<*>) { + // Hide the picker item (color/style picker) + try { + toolbar.setMenuItemVisibility(R.id.pspdf__annotation_editing_toolbar_item_picker, View.GONE) + } catch (e: Exception) { + // Silently skip if item cannot be hidden + } + + // Also try to hide other potential style-related items if they exist + val potentialStyleItems = listOf( + "style", "color", "thickness", "picker" + ) + + toolbar.menuItems.forEach { item -> + val itemTitle = item.title?.toString()?.lowercase(Locale.getDefault()) + val resourceName = getResourceName(item.id)?.lowercase(Locale.getDefault()) + + val isStylePickerItem = potentialStyleItems.any { keyword -> + itemTitle?.contains(keyword) == true || resourceName?.contains(keyword) == true + } + + if (isStylePickerItem) { + try { + toolbar.setMenuItemVisibility(item.id, View.GONE) + } catch (e: Exception) { + // Silently skip if item cannot be hidden + } + } + } + } + + /** + * Gets the resource name from a resource ID. + * + * @param resourceId The resource ID + * @return The resource name, or null if not found + */ + private fun getResourceName(resourceId: Int): String? { + return try { + if (resourceId != 0) { + context.resources.getResourceEntryName(resourceId) + } else { + null + } + } catch (e: Exception) { + null + } + } + + /** + * Updates the annotation menu configuration dynamically. + * + * @param newConfiguration The new annotation menu configuration + */ + fun updateConfiguration(newConfiguration: AnnotationMenuConfigurationData?) { + // Note: We can't directly update the configuration since it's a constructor parameter. + // This method is provided for compatibility, but in practice, a new handler instance + // should be created with the new configuration. + } + + /** + * Clears the selected annotation when the selection changes. + */ + fun clearSelectedAnnotation() { + selectedAnnotation = null + } +} \ No newline at end of file diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/AnnotationUtils.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/AnnotationUtils.kt index 889c9dc8..d94366f3 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/AnnotationUtils.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/annotations/AnnotationUtils.kt @@ -109,13 +109,21 @@ object AnnotationUtils { FlutterAnnotationTool.MEASUREMENT_PERIMETER -> AnnotationToolWithVariant(AndroidAnnotationTool.MEASUREMENT_PERIMETER) FlutterAnnotationTool.MEASUREMENT_DISTANCE -> AnnotationToolWithVariant(AndroidAnnotationTool.MEASUREMENT_DISTANCE) - // Some Flutter tools don't have direct Android equivalents + // Image stamp tool - can be mapped to existing stamp functionality + FlutterAnnotationTool.STAMP_IMAGE -> AnnotationToolWithVariant(AndroidAnnotationTool.STAMP) + + // The following Flutter tools don't have corresponding Android AnnotationTool equivalents: + // - CARET: Exists as AnnotationType but no dedicated creation tool + // - RICH_MEDIA: Exists as AnnotationType but no dedicated creation tool + // - SCREEN: Exists as AnnotationType but no dedicated creation tool + // - FILE: Exists as AnnotationType but no dedicated creation tool + // - WIDGET: Exists as AnnotationType but no dedicated creation tool + // - LINK: Link annotations are typically created differently in Android FlutterAnnotationTool.CARET, FlutterAnnotationTool.RICH_MEDIA, FlutterAnnotationTool.SCREEN, FlutterAnnotationTool.FILE, FlutterAnnotationTool.WIDGET, - FlutterAnnotationTool.STAMP_IMAGE, FlutterAnnotationTool.LINK, null -> null } diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/NutrientApi.g.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/NutrientApi.g.kt index 2d384301..82989f56 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/NutrientApi.g.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/NutrientApi.g.kt @@ -269,6 +269,64 @@ enum class NutrientEvent(val raw: Int) { } } +/** + * Enumeration of default annotation menu actions that can be removed or disabled. + * + * **Platform Support:** + * - All actions can be removed or disabled on both iOS and Android + * - Some system actions (copy/paste) may be harder to remove on iOS due to system restrictions + */ +enum class AnnotationMenuAction(val raw: Int) { + /** + * Delete action - removes the annotation + * - iOS: Part of UIMenu system actions + * - Android: R.id.pspdf__annotation_editing_toolbar_item_delete + */ + DELETE(0), + /** + * Copy action - copies the annotation + * - iOS: System copy action (may be harder to remove) + * - Android: R.id.pspdf__annotation_editing_toolbar_item_copy + */ + COPY(1), + /** + * Cut action - cuts the annotation to clipboard + * - iOS: System cut action + * - Android: R.id.pspdf__annotation_editing_toolbar_item_cut + */ + CUT(2), + /** + * Color action - opens annotation color picker/inspector + * - iOS: Style picker in UIMenu + * - Android: R.id.pspdf__annotation_editing_toolbar_item_picker + */ + COLOR(3), + /** + * Note action - opens annotation note editor + * - iOS: Note action in UIMenu + * - Android: R.id.pspdf__annotation_editing_toolbar_item_annotation_note + */ + NOTE(4), + /** + * Undo action - undoes the last action + * - iOS: Undo in UIMenu + * - Android: R.id.pspdf__annotation_editing_toolbar_item_undo + */ + UNDO(5), + /** + * Redo action - redoes the previously undone action + * - iOS: Redo in UIMenu + * - Android: R.id.pspdf__annotation_editing_toolbar_item_redo + */ + REDO(6); + + companion object { + fun ofRaw(raw: Int): AnnotationMenuAction? { + return values().firstOrNull { it.raw == raw } + } + } +} + /** Generated class from Pigeon that represents data sent in messages. */ data class PdfRect ( val x: Double, @@ -478,6 +536,108 @@ data class PointF ( ) } } + +/** + * Configuration data for annotation contextual menu + * + * This class defines how annotation menus should be configured + * when displayed to users. It supports removing actions, disabling actions, + * and controlling visual presentation options. + * + * **Usage Patterns**: + * - **Static Configuration**: Set once via [NutrientViewController.setAnnotationMenuConfiguration] + * + * **Platform Compatibility**: + * - [itemsToRemove]: Supported on Android, iOS, and Web + * - [itemsToDisable]: Supported on Android, iOS, and Web + * - [showStylePicker]: Supported on Android and iOS + * - [groupMarkupItems]: iOS only (ignored on other platforms) + * - [maxVisibleItems]: Platform-dependent behavior + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class AnnotationMenuConfigurationData ( + /** + * List of default annotation menu actions to remove completely from the menu. + * + * These actions will not appear in the contextual menu at all. + * Use this when you want to completely hide certain functionality. + * + * **Example**: Remove delete action for read-only annotations + * ```dart + * itemsToRemove: [AnnotationMenuAction.delete] + * ``` + */ + val itemsToRemove: List, + /** + * List of default annotation menu actions to disable (show as grayed out). + * + * These actions will appear in the menu but will be non-interactive. + * Use this when you want to show functionality exists but is temporarily unavailable. + * + * **Example**: Disable copy action for certain annotation types + * ```dart + * itemsToDisable: [AnnotationMenuAction.copy] + * ``` + */ + val itemsToDisable: List, + /** + * Whether to show the platform's default style picker in the annotation menu. + * + * When true, users can access color, thickness, and other style options + * directly from the annotation menu. + * + * **Platform Behavior**: + * - **iOS**: Shows style picker as part of UIMenu + * - **Android**: Shows annotation inspector/style picker + * - **Web**: Shows color picker and basic style options + */ + val showStylePicker: Boolean, + /** + * Whether to group markup annotation actions together in the menu. + * + * When true, related markup actions (highlight, underline, etc.) are + * visually grouped in the menu for better organization. + * + * **Platform Support**: iOS only (ignored on Android and Web) + */ + val groupMarkupItems: Boolean, + /** + * Maximum number of actions to show directly in the menu before creating overflow. + * + * When the number of available actions exceeds this limit, the platform + * may create a submenu or overflow menu to accommodate additional actions. + * + * **Platform Behavior**: + * - **iOS**: Respects platform UI guidelines for menu length + * - **Android**: Limited by toolbar space and screen size + * - **Web**: Creates scrollable or paginated menu as needed + * + * **Note**: If null, the platform default behavior is used. + */ + val maxVisibleItems: Long? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): AnnotationMenuConfigurationData { + val itemsToRemove = pigeonVar_list[0] as List + val itemsToDisable = pigeonVar_list[1] as List + val showStylePicker = pigeonVar_list[2] as Boolean + val groupMarkupItems = pigeonVar_list[3] as Boolean + val maxVisibleItems = pigeonVar_list[4] as Long? + return AnnotationMenuConfigurationData(itemsToRemove, itemsToDisable, showStylePicker, groupMarkupItems, maxVisibleItems) + } + } + fun toList(): List { + return listOf( + itemsToRemove, + itemsToDisable, + showStylePicker, + groupMarkupItems, + maxVisibleItems, + ) + } +} private open class NutrientApiPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return when (type) { @@ -527,35 +687,45 @@ private open class NutrientApiPigeonCodec : StandardMessageCodec() { } } 138.toByte() -> { + return (readValue(buffer) as Long?)?.let { + AnnotationMenuAction.ofRaw(it.toInt()) + } + } + 139.toByte() -> { return (readValue(buffer) as? List)?.let { PdfRect.fromList(it) } } - 139.toByte() -> { + 140.toByte() -> { return (readValue(buffer) as? List)?.let { PageInfo.fromList(it) } } - 140.toByte() -> { + 141.toByte() -> { return (readValue(buffer) as? List)?.let { DocumentSaveOptions.fromList(it) } } - 141.toByte() -> { + 142.toByte() -> { return (readValue(buffer) as? List)?.let { PdfFormOption.fromList(it) } } - 142.toByte() -> { + 143.toByte() -> { return (readValue(buffer) as? List)?.let { FormFieldData.fromList(it) } } - 143.toByte() -> { + 144.toByte() -> { return (readValue(buffer) as? List)?.let { PointF.fromList(it) } } + 145.toByte() -> { + return (readValue(buffer) as? List)?.let { + AnnotationMenuConfigurationData.fromList(it) + } + } else -> super.readValueOfType(type, buffer) } } @@ -597,28 +767,36 @@ private open class NutrientApiPigeonCodec : StandardMessageCodec() { stream.write(137) writeValue(stream, value.raw) } - is PdfRect -> { + is AnnotationMenuAction -> { stream.write(138) + writeValue(stream, value.raw) + } + is PdfRect -> { + stream.write(139) writeValue(stream, value.toList()) } is PageInfo -> { - stream.write(139) + stream.write(140) writeValue(stream, value.toList()) } is DocumentSaveOptions -> { - stream.write(140) + stream.write(141) writeValue(stream, value.toList()) } is PdfFormOption -> { - stream.write(141) + stream.write(142) writeValue(stream, value.toList()) } is FormFieldData -> { - stream.write(142) + stream.write(143) writeValue(stream, value.toList()) } is PointF -> { - stream.write(143) + stream.write(144) + writeValue(stream, value.toList()) + } + is AnnotationMenuConfigurationData -> { + stream.write(145) writeValue(stream, value.toList()) } else -> super.writeValue(stream, value) @@ -679,6 +857,14 @@ interface NutrientApi { fun generatePdfFromHtmlUri(htmlUri: String, outPutFile: String, options: Map?, callback: (Result) -> Unit) /** Configure Nutrient Analytics events. */ fun enableAnalyticsEvents(enable: Boolean) + /** + * Sets the annotation menu configuration for the global presenter. + * This configuration applies to all annotation menus in presented documents. + * + * @param configuration The annotation menu configuration to apply. + * @return True if the configuration was set successfully, false otherwise. + */ + fun setAnnotationMenuConfiguration(configuration: AnnotationMenuConfigurationData, callback: (Result) -> Unit) companion object { /** The codec used by NutrientApi. */ @@ -1317,6 +1503,26 @@ interface NutrientApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.nutrient_flutter.NutrientApi.setAnnotationMenuConfiguration$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val configurationArg = args[0] as AnnotationMenuConfigurationData + api.setAnnotationMenuConfiguration(configurationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } } } } @@ -1635,6 +1841,14 @@ interface NutrientViewControllerApi { * exiting annotation creation mode was successful. */ fun exitAnnotationCreationMode(callback: (Result) -> Unit) + /** + * Sets the annotation menu configuration for the current view controller. + * This configuration applies only to annotation menus in the current document view. + * + * @param configuration The annotation menu configuration to apply. + * @return True if the configuration was set successfully, false otherwise. + */ + fun setAnnotationMenuConfiguration(configuration: AnnotationMenuConfigurationData, callback: (Result) -> Unit) companion object { /** The codec used by NutrientViewControllerApi. */ @@ -2040,6 +2254,26 @@ interface NutrientViewControllerApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.setAnnotationMenuConfiguration$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val configurationArg = args[0] as AnnotationMenuConfigurationData + api.setAnnotationMenuConfiguration(configurationArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } } } } diff --git a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/events/FlutterEventsHelper.kt b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/events/FlutterEventsHelper.kt index 1afbbc12..8f65708e 100644 --- a/android/src/main/java/com/pspdfkit/flutter/pspdfkit/events/FlutterEventsHelper.kt +++ b/android/src/main/java/com/pspdfkit/flutter/pspdfkit/events/FlutterEventsHelper.kt @@ -3,6 +3,7 @@ package com.pspdfkit.flutter.pspdfkit.events import com.pspdfkit.annotations.Annotation import com.pspdfkit.annotations.AnnotationProvider import com.pspdfkit.datastructures.TextSelection +import com.pspdfkit.flutter.pspdfkit.annotations.AnnotationMenuHandler import com.pspdfkit.flutter.pspdfkit.api.NutrientEvent import com.pspdfkit.flutter.pspdfkit.api.NutrientEventsCallbacks import com.pspdfkit.ui.PdfUiFragment @@ -15,7 +16,10 @@ import com.pspdfkit.ui.special_mode.manager.TextSelectionManager * Helper class to manage event listeners for Nutrient Flutter integration. * Handles registration and removal of event listeners for various PDF events. */ -class FlutterEventsHelper(private val eventCallbacks: NutrientEventsCallbacks? = null) { +class FlutterEventsHelper( + private val eventCallbacks: NutrientEventsCallbacks? = null, + private val annotationMenuHandler: AnnotationMenuHandler? = null +) { // Map to store event listeners by event type private val eventsMap: MutableMap = mutableMapOf() @@ -73,6 +77,9 @@ class FlutterEventsHelper(private val eventCallbacks: NutrientEventsCallbacks? = annotation: Annotation, isMultipleSelection: Boolean ) { + // Notify annotation menu handler of selection + annotationMenuHandler?.onAnnotationSelected(annotation, isMultipleSelection) + sendEvent(event, mapOf( "annotation" to annotation.toInstantJson(), "isMultipleSelection" to isMultipleSelection @@ -109,6 +116,9 @@ class FlutterEventsHelper(private val eventCallbacks: NutrientEventsCallbacks? = reselected: Boolean ) { super.onAnnotationDeselected(annotation, reselected) + // Clear selected annotation from handler when deselected + annotationMenuHandler?.clearSelectedAnnotation() + if (annotation != null) { sendEvent(event, mapOf( "deselected" to mapOf( diff --git a/documentation/annotation-creation-mode.md b/documentation/annotation-creation-mode.md new file mode 100644 index 00000000..57226f50 --- /dev/null +++ b/documentation/annotation-creation-mode.md @@ -0,0 +1,193 @@ +# Annotation Creation Mode + +This guide explains how to use the annotation creation mode feature in the Nutrient Flutter SDK to programmatically enable annotation tools for users to create PDF annotations. + +## Overview + +The annotation creation mode API allows you to programmatically enter and exit specific annotation creation modes, enabling users to create various types of PDF annotations such as ink drawings, text highlights, shapes, signatures, and more. + +## Basic Usage + +To use annotation creation mode, you first need to get a reference to the `NutrientViewController` through the `onViewCreated` callback: + +```dart +NutrientViewController? _controller; + +NutrientView( + documentPath: 'path/to/document.pdf', + configuration: PdfConfiguration( + enableAnnotationEditing: true, // Required for annotation creation + ), + onViewCreated: (controller) { + setState(() { + _controller = controller; + }); + }, +) +``` + +### Entering Annotation Creation Mode + +```dart +// Enter annotation creation mode with a specific tool +await controller.enterAnnotationCreationMode(AnnotationTool.inkPen); + +// Enter annotation creation mode with default tool +await controller.enterAnnotationCreationMode(); +``` + +### Exiting Annotation Creation Mode + +```dart +// Exit the current annotation creation mode +await controller.exitAnnotationCreationMode(); +``` + +## Available Annotation Tools + +The SDK provides annotation tools through the `AnnotationTool` enum. See the [AnnotationTool API documentation](https://pub.dev/documentation/nutrient_flutter/latest/nutrient_flutter/AnnotationTool.html) for the complete list of available tools including drawing, text markup, shapes, measurements, and more. + +## Platform Compatibility + +### iOS + +- **Full support** for all annotation tools +- Special UI dialogs for signature, stamp, and image tools + +### Android + +- **Most tools supported** except: `caret`, `richMedia`, `screen`, `file`, `widget`, `link` +- These unsupported tools will return an error when used + +### Web + +- **All tools have mappings** but some with limitations +- Some tools fall back to similar functionality (e.g., `inkMagic` → regular ink) +- Advanced tools like `richMedia`, `screen` may have limited functionality + +## Complete Example + +Here's a complete example showing how to implement an annotation toolbar: + +```dart +import 'package:flutter/material.dart'; +import 'package:nutrient_flutter/nutrient_flutter.dart'; + +class AnnotationToolbarExample extends StatefulWidget { + final String documentPath; + + const AnnotationToolbarExample({Key? key, required this.documentPath}) + : super(key: key); + + @override + State createState() => _AnnotationToolbarExampleState(); +} + +class _AnnotationToolbarExampleState extends State { + NutrientViewController? _controller; + AnnotationTool? _currentTool; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('PDF Annotation'), + actions: [ + if (_currentTool != null) + IconButton( + icon: const Icon(Icons.close), + onPressed: _exitAnnotationMode, + tooltip: 'Exit annotation mode', + ), + ], + ), + body: NutrientView( + documentPath: widget.documentPath, + configuration: PdfConfiguration( + enableAnnotationEditing: true, + ), + onViewCreated: (controller) { + setState(() { + _controller = controller; + }); + }, + ), + bottomNavigationBar: _buildAnnotationToolbar(), + ); + } + + Widget _buildAnnotationToolbar() { + return Container( + color: Colors.grey[200], + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + _buildToolButton(AnnotationTool.inkPen, 'Pen', Icons.brush), + _buildToolButton(AnnotationTool.highlight, 'Highlight', Icons.format_color_fill), + _buildToolButton(AnnotationTool.freeText, 'Text', Icons.text_fields), + _buildToolButton(AnnotationTool.square, 'Square', Icons.crop_square), + _buildToolButton(AnnotationTool.arrow, 'Arrow', Icons.arrow_forward), + _buildToolButton(AnnotationTool.signature, 'Sign', Icons.draw), + _buildToolButton(AnnotationTool.eraser, 'Erase', Icons.clear), + ], + ), + ), + ); + } + + Widget _buildToolButton(AnnotationTool tool, String label, IconData icon) { + final isSelected = _currentTool == tool; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + onPressed: () => _enterAnnotationMode(tool), + icon: Icon(icon), + color: isSelected ? Colors.blue : Colors.black87, + ), + Text( + label, + style: TextStyle( + fontSize: 12, + color: isSelected ? Colors.blue : Colors.black87, + fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, + ), + ), + ], + ), + ); + } + + Future _enterAnnotationMode(AnnotationTool tool) async { + try { + final success = await _controller.enterAnnotationCreationMode(tool); + if (success == true) { + setState(() { + _currentTool = tool; + }); + } + } catch (e) { + // Handle error + } + } + + Future _exitAnnotationMode() async { + try { + await _controller.exitAnnotationCreationMode(); + setState(() { + _currentTool = null; + }); + } catch (e) { + // Handle error + } + } +} +``` + +## Summary + +The annotation creation mode API provides a simple way to programmatically activate annotation tools for PDF editing. With support for 35+ annotation types across iOS, Android, and Web platforms, developers can easily add drawing, text markup, shapes, and other annotation capabilities to their Flutter apps. For a complete working example, see `example/lib/nutrient_annotation_creation_mode_example.dart`. diff --git a/documentation/contextual-toolbar-customization.md b/documentation/contextual-toolbar-customization.md new file mode 100644 index 00000000..1e16e90f --- /dev/null +++ b/documentation/contextual-toolbar-customization.md @@ -0,0 +1,143 @@ +# Annotation Menu Customization + +This document describes the annotation contextual menu customization feature in the Nutrient Flutter SDK. + +## Overview + +The annotation menu customization feature allows developers to modify the contextual menu that appears when users select annotations in a PDF document. You can remove or disable default menu actions and control the visibility of the style picker. + +## Core Features + +### 1. Default Menu Actions + +The following default menu actions can be removed or disabled: + +- `AnnotationMenuAction.delete` - Remove annotation +- `AnnotationMenuAction.copy` - Copy annotation +- `AnnotationMenuAction.cut` - Cut annotation +- `AnnotationMenuAction.color` - Color/style picker +- `AnnotationMenuAction.note` - Add/edit note +- `AnnotationMenuAction.undo` - Undo last action +- `AnnotationMenuAction.redo` - Redo last action + +### 2. Menu Configuration Options + +- `itemsToRemove` - List of default actions to completely remove from the menu +- `itemsToDisable` - List of default actions to disable (shown but grayed out) +- `showStylePicker` - Show/hide the style picker (default: true) +- `groupMarkupItems` - Group markup annotation tools together (iOS only, default: true) +- `maxVisibleItems` - Maximum items before creating overflow menu (iOS only) + +## Platform-Specific Implementation + +### iOS Implementation + +**Technology**: Uses native `UIMenu` API with `UIAction` and `UICommand` elements + +**Capabilities**: + +- ✅ **Remove default items** - Can remove most default actions +- ✅ **Disable default items** - Native support for disabled state +- ✅ **Style picker control** - Can show/hide style options +- ✅ **Group markup items** - Can group related annotation tools +- ✅ **Max visible items** - Can suggest maximum items before overflow + +**Limitations**: + +- Some system actions (like copy/paste) may be protected by iOS +- Maximum visible items is a suggestion and may be overridden by iOS UI guidelines + +### Android Implementation + +**Technology**: Uses `ContextualToolbar` and `AnnotationEditingToolbar` APIs + +**Capabilities**: + +- ✅ **Remove default items** - Can remove toolbar items by ID +- ✅ **Disable default items** - Can disable toolbar items +- ✅ **Style picker control** - Can remove style-related items +- ❌ **Group markup items** - Not supported on Android +- ❌ **Max visible items** - Not supported on Android + +**Implementation Details**: + +- Uses `setMenuItemVisibility(View.GONE)` to remove items +- Uses `menuItem.isEnabled = false` to disable items +- Handles both `AnnotationEditingToolbar` and generic `ContextualToolbar` + +## Feature Comparison Table + +| Feature | iOS | Android | Notes | +|---------|-----|---------|-------| +| Remove Default Items | ✅ | ✅ | Both platforms fully supported | +| Disable Default Items | ✅ | ✅ | Both platforms fully supported | +| Style Picker Control | ✅ | ✅ | Both platforms fully supported | +| Group Markup Items | ✅ | ❌ | iOS only | +| Max Visible Items | ✅ | ❌ | iOS only | + +## Example Usage + +```dart +PdfConfiguration( + enableAnnotationEditing: true, + annotationMenuConfiguration: AnnotationMenuConfiguration( + // Remove actions from the menu (both platforms) + itemsToRemove: [ + AnnotationMenuAction.delete, + AnnotationMenuAction.color, + ], + // Disable actions - shown but grayed out (both platforms) + itemsToDisable: [AnnotationMenuAction.copy], + // Control style picker visibility (both platforms) + showStylePicker: true, + // iOS-only options + groupMarkupItems: true, + maxVisibleItems: 5, + ), +) +``` + +### Working Example + +See `example/lib/annotation_menu_example.dart` for a complete implementation. + +## API Reference + +### AnnotationMenuConfiguration + +```dart +class AnnotationMenuConfiguration { + /// List of default menu actions to remove + final List itemsToRemove; + + /// List of default menu actions to disable (grayed out) + final List itemsToDisable; + + /// Whether to show the style picker (default: true) + final bool showStylePicker; + + /// Group markup items together (iOS only, default: true) + final bool groupMarkupItems; + + /// Maximum visible items before overflow (iOS only) + final int? maxVisibleItems; +} +``` + +### AnnotationMenuAction Enum + +```dart +enum AnnotationMenuAction { + delete, // Remove annotation + copy, // Copy annotation + cut, // Cut annotation + color, // Color/style picker + note, // Add/edit note + undo, // Undo last action + redo, // Redo last action +} +``` + +## Summary + +The annotation menu customization feature provides essential control over the contextual menu that appears when users select annotations. Both iOS and Android platforms support the core functionality of removing and disabling default menu items, as well as controlling the style picker visibility. diff --git a/example/PDFs/test.docx b/example/PDFs/test.docx new file mode 100644 index 0000000000000000000000000000000000000000..0f78747968dff4430d091910a127dfabb3d5ea0a GIT binary patch literal 217264 zcmafaV~}Re(rw$eZFAbTHPhy_ZR6=_+qN-n+cu|d+j!b{-t*ma5plnBE2<)LSL{Ez zVr5pYUAdLzz#%X|U|?WCy0npWK>m+`_Sbf|cQRqNbG7|x>SSqW&g5Zh^G8$8Zk+{1 zK;+sG=7eo&r2YaYzQH1{KtdVA)(a$~fRgMThQgHE{G_16ZN1@O)g_#V{;|dtH-vJia zkTdgD8y`#-eD-;KcF;S7pb(cJB_kjx0&WAfu7^xWF>AXJoJiG2BJ3cL2Z58QOqUky zkdewCa0JMQiQKQo`k7*$F+`&vSm3J})`6h#(Ep4jLmVFbF`JIvrZ9V zPjvY%HjvWYV>zjcu5#ywK_n&qNwj*Nu|($^I_{byLj82Iv#QCv4-KQ(lVsTw1Noe{ zji%M+u!fGi>4m*x&ufonDok3z!;P_aZWy#3CvKy|wxc08oM`USv=oZ$ciQYuzCGBo z`uMU2+>jR>g>$r$U?XGqN&H+V!Ska*NAF8YqnV1{`TLn@o2{IbQ+e33#$pBVYmw8$ zkL-A0=mnXLexk;uxpge8lwqb`%Z(*#b<1Nn{RUaSmeY(M z+PQucaJi-(LLSfZ?y)6$7yNYhIn4KN6BpS+F2?{+WjSb=Zz%KeUtl00SXdw+%KvTn zp#D32oK0O^{sxcpKhaa1vhI}0f)bLOcfB*$H9*>&$OQbH&WLzpm{n#$46^T_idx+V@hWQaUm zLLfTpj_ccD@fbqgQZ^gB6bjWo4Rmr7T_jl`U4Oo3Tm+0cL($P}dleHo(qq2597S6| z$`x(l6GpLPC#ZnrQQi{SIjWpue2OI2Qin-B4Gr0c(#@>eo*R=r+Mg_#b;&3WqbnrU zvK_+zJq$&vVk4tYGKp3^YXRl~!@*B}l8HVOcrxD91A$bAm7#e$rn=tRC`h z{ic%+=t$)_EZyAI!eSTD*d0pRk$A)=lfg!6O!Mh}b6p{?F5d9mCyiV0$sx1HxI>{U3e{!osOSN|lw z3{7dmoABifb$f!MI)4K>MKp9K-Z{ncA3f%mJm8<~ju zwkh7lY_%N+9JUreKbCR0A>tM^lLl60GN)nGnmvJExvT${NF>a+Mm1Q#5#QQ~j&p1} zA6DT`t^B0}H>#)8p7!k;4c-1XXLb$)Fc~;o4uE%%i2u0 zOEZI#E=F5hOLJ>36w*{M_jZFQZM?V?fnYhH`rMAkj3cxel8F`-jK zY9G8vaT5{ygrwf07mvw(z-+$$(hV9$T%bu!_%HpWVEz;R{#W)kv$u2kZuHZ}^dJ6J zC2z+3!7q)(MP$81kdvA zm~Y<*=jzHJ388sI^A|5^gQYlFH7#5ILeTsBt*4V5*tsx!T$!in(?-JEVP=P3r{ty0 z&f(f{1QmrdQ|!R(d=!1H+GN{Pq%{XzRu89TS+7lmkEqJw&Y-OH?$a)R1XfX>p(tG8 zJ`}4;0A6FOTQSA(qqg#vu68i)o{k(*99D$222V(c95J|6X81-k2WQF=b^}(uuPwR` z<@&MP3ksK+;qi8GLem@);sm0qT~)4c88+V@172J&+8k|2&`pauemGb@pS%_>b>6i1 zSyyJ!kFo(tq_$coX_Cizt~xfurwy6|zvFleVC z4N7?}vzY91(8>3(;jq$(Wn%Gbky{rGytJvu2u^-^#mjTuI1G1UZQD`#gucHT+*3i1 z1bX+_dToh?UnaOEPm)In`k3|^cw;Qy`dIwIJL)KReMd8xG!E z6)$fyA*h&~Er?d5JlYu5Q}{+czJJfuc#ox7{c-a`esA)fa*pLSmYkd8yT{1TAoC6K@7;vVN{ zfxLc|`XU%hb7#V+m>add-QH`2EEd&#rVr&|aN!btqgh);3}%BesUc{?ytp(<8P=1E zRJPM=`5TRwk&^)2*{QUG7C0ySWs;bdpf95Z7LUMd6DD-YZf8*>jJ7)$w^2AhwRmV= z)CFn@ZBv)jJm&#^|IV5QE#+hJK0&8drjtD_XnUene&+XdKQjt*-wVHgf%N3)JH7T7 zg5|$J{r3qU`QIQpyLj4|{wv*Yre4~uv0#MM7(V;o^(erQ8kaSmg|;jFZnwN-+S$SR z8NZTpDZKh;W*VCm_J?%*5|SSZ@f-h$pRdnPrfU5?i`rpPG)eQNn~gfCG%_rd_AITQ z-0K;tC1JWeQ1Pg}^roTt_V#y|x^&s5=vo2`09`3-hE~3+kJUO_FgKLvGYYAPn1w6qi4-1`Gzo|&%+q{dprtne?<4;1Vp;p9eG)9!#xlB|ktvp0@P;3Mv z+NMXQbB1uS(m;PG6)%_ce!t0|RIDi4Kjp0!g-tJ<3Hh)YB`&e*7epoXs1jTS;@Uv! zY^TAzPP876i`1}|Vb>Acd$6%J7?unyH@{5ZOy4td*2z-8gIs-g|o@Zx<=fe#MU##Mu zIDG~Tt0@%h(p(WjR*|Me_I98dz1%^Yu>DkQpM31qaqdUP;|MG!k-Y#WQ`1J__AcYq zcC}0;hb~$Cp5xIW!Tqn?2zn!x<~c|?S~>fj-M6MO*JumQ8R6-xbTTVa-=Fi!u0qjV z58N?b^{G?IVzm_kX5NLPg@I(TTP>rBzR{cAc;r~DDo2;2KKRA%^QvCd)F|70G~Lhf zgYMLNL)+-PPgo2aH4wV-F z*hJ4iCt{?Bf}Sxr2napKe~QolRgjt38@t+?+PVC5AYSU)s%>zieL_AHf8Rou`VDhG ztaAjW1Hp!EB_kSKbhV#6oMOvZUzB{{Iabq?V&iFsU^2B)&mAoG+h#&lPF?83rGjy0 z-2fX`jJ<#Z^PK|c;t^cjgNAH8F>z;odF*^2#4^w`D1GOELKBVf-Rm{B<=&B^pPzh# zB(C?78(t}35r^mM(IqVb;aq?eHZ-$N8TXq*d4hh(A6q7aP_o38Sz6OY2JZpCFBY1i zutX9KAKeI#>^Wsv#-GNSQ4$0TaY@kIqMWBK7EUTitB)&cL47z7%e2XBaudzTP+V%v zCQpT-X{M9QnG;l95^ysjgt+v)8St1gl%fTkN%|OE^x=Vifv}Bazp)fTYFA5%WkP6c z1~nZPA%6H?i)GiI{o^SnVIj(406Im~!r9@xaX!noMx^l9vt=_*m79w)N17 z?;w#3yFq#Aeb`%WYb}BJCOpdR5=4*{07#Fpu#82U8rjJyV5S!7dB;wYzz*7E?CjQg zI1Cu%Hb2VYTed26s1-`l+?^<+BW&#(wLV1RG8=cR`S~2XEp;EbU--##>8xYZw8}i_?Rf3k=qdJL zL3Nd0H+9S?b%hl2GU8O={fF>)XGD7s1&S7PPJBw*;gyyvLi-uue2f2ju^1jDyo`xiisuo7+)`t`9ceGfP#K&_kyJcPY zDT%Ce3>{#L!3R7?SPa_LMMw>`mwa=!&kGDiaJkuldd1iBx?h<7gjX#gaG@(+;f@gRchFGxYJ(kHTOfm@%h+yFrGD%UDUK%s{X>$)+ zr$YB%n{5KK2-FZUDYKC)n=8$AXt)_h5)##OQp7(!3z!3a8t;i=?%j-VNR2v9v?s&c zv63=1is>yVn}}VaW?B2ypWGCZ!~|D#BBgik7qi=1WsPJCA3@~hM0-WYq8zXRq?x3~ zCc78es5xmaTJeE)#a%>hPiw2^>Lrdj*5qujU78C%DNN9_WD}czE7MgRyo^kV$DMtdGo)zBZkr&-gF)Uk zYZfa~*+%XmUCD=?8gM1&;6N4}+dF417rLYAAL|e5R=FTid>FEa^R11MA$f#{y2q+; zkQG)CAy--KvKTJd$5D*ymNO#&^J#GeXD^yNU-tPHL31`An!oERYfPbd$_bK_R$aMD zKE2b@`pSvjK1>#U?)lELp@L~Q`G5}c5j z9J9ryT|nDWPH=bVE3+MamM&1cR3|AeWpF88%A#zLo)eHQ&`#XmVh(%| zgD!c|3{)BFOu&fHK@@l$zPU~d(?z`e1lvux>q9a z*}y|;;g7uS{BAMdeTO5WMIn^McZ8L%KDWaj!8T%MgeffXAtU~~v5z^izss5WS!jie z7tD77qV1!}O^G5yS#m8+g9xF8tWHGgCv(goQyXdcx|-&8eYAfcgm#4Pi+fhe@LH?4 z1$sk$9P3F0vn) z2FFqs8vu_Sr#%Np)r3!}xg>XO<>}zFK}?u>vT;VJ>g|T!77fRDW1||58x7Mh{WDQp zv|t#Z_~W_1Mq5U9-M0N&`t&ev~*w*2_vBUh* zzCWuwJ32Xfqe)>P2f~nuitzdQb^e{6Qr%#`Z|fHaDB3;-L=yFy_#d8T6WAS60)I5k zJENF3r2vEJ*Qc3J-bAz(h>Ss^i0bnmMkc#t^=+4pCCBy1YQb$-lH!Rf57l+A8>8+G@Fef%qS71!JPK0ZwxV4AmwlRgm?4i%6nC zf>;Pny$<)hpNd+_B<2gVN2qfz${Te;kskgd&;%z~vAK^QHkx52z%2?%F1eC~e2z@O zQJS&xC>VhusvqF_rZS8nG!OD_1oZ~PZ(|3WHyh7YNq1p#UY-63?8Phr9z#cCds)K%gTL}jl8bxKUe z}(SR?Q z8{#d%5A;6d!%p_jM*9EMKv7nPfQ-WHSTXiu63KQ&EkJ?%KnthUT-pL?L0 ze4oi|qZvMU1LV$dJ$G?E=Qv;S9Dh#pq*9Ybp^S^`pak+-ubE3SO|M9z^kd#EZqMuQ zbg|t(*|mN_UGc4(2buf00VN(JC7bB7R*W6jJebtyk;xV z3{X`K>YQ5LO^NNdkxnMYX8_sFS0PPxa;-rvH2Z!Ik@y$u}p4)dpi?n$+Ita?4+9jdm>E;p#{6Llu zXj1$Rj8|i?8PQTcgXY!HVsm-urp?!tBtn>nnX^66fs7%3DG9BKl!8-Xm0D|D z;|b@)mw3HCKz)d;1l9OK^PlRPibSTSI~(AP*rZp0}7ObB@scD+5&xQrW6SRbvrko>2ryHRk4|wE|OLNv>%d`&} zBA6#UUQ;43C$e5sklD8R%lt`^yeF*}!sNZd`CAn?*Ws zrd7Bz(F8){&XGM`d&`V))^ksar3CYKLk67j5I@PU~`6prNR8H7Rz%T>3}b3QKE zvz>@lqNxSRx5nW=T0nha{f?wm7h(3l6*##NeZnXWFgh#+TyICe?kNocz&t&}Vi$#n z;JcRdc=DDx7BRj!KXE+TS%^lmxr6*bssv*)Z+$dT;d~Ib!&r_2bVc6j?MSH-f(1Mf zYDBmio?CG?!(#G{SE6$I1O3w)K%1;Ym^brMUsz%{%Ro5?5}{S_w<5Mg%nKDeA*5#8 zq@n##B&2Q=PqgFc@p<;He}a197Y|;)2JX|Qx!$3S2tg2L`>n)b<}}wqH})U=v6NE1 z9~*!bNRZkbD-8TF;Ss5jCXjeoNw1wfnBzP2VizD%B+45xK*!?W2ibI=7t5-hI}Igl ztw56k)%1KyDnwQ!wgx1{bEoz`j}<;1s3-`nJ~45dWiKuo^h&8`^P4HQ>C42939&tq zc)b(6BKZbO-EtP;)(i<55^r(&(P}-0{EpL50txoHq@1R_sgpewQrI}bgvl{iZQ_c zBKb7n&I#{9?9vZ@#DxHqOK|1;j)HxhDZ^JHV@el*&uqm8pmWLVqIJ+VlRYi3$c-YM zkHLO3nWMlzs>Av*yd4H01TcM4dUT^RhTg^&R-pt}THq_0WW{ zO+j0%TyP&g;7~Oi$WQ$E1For|-Wj@y`N9*w?lout*nhJ9DTS2@(^JpFA4U{YlJnjGYzv{SJ98yAm$$-m;mW4 zfbczHpP8bpmK>^=So1tR&(!>p#lukNo!}<1SzPJK1a%IsiyjnqnWEd+n;mv$3WP@+ zU9dL?r}G%Xp^(}Oo&UTL$b1VeQsBA6sgzsv0`Q~)e&$YpOEbcsOibRJnMSI;yq*cJ zZC-7_ws`;a!J)|Im&ki#nElqF>PB@0>MWbJlL@O=+x;7Q8=4}DI8q4VmMm!&o=-BM z^`cU%ifZ_qf3Cvkoap-t0`?BnMxa4&F1kEeQQ$*-*MX$u$fVKMZW%YWqus90=u3F! z6ysjAW2$q{(bT@c^vt3C?sl$fMm^QxYZ9{BUitVUW;yhHtEKgPx3or)LBgk~mu?;k z2K*7+H2Oxu?j+5`O7_^;-#gPOe!2sg8gxr>yScKHp1roc4oWha=mT(Csn=S0ay}{p z${sl*b#Y83nx^r`@tFp=h7@ywELWQKB;Odg3ZLJ&zXPp`*D9)i%qY8;hyL;YgZvx0 zd|Me%Dfqh&FPf^za^b;J-MZQGYH_2+Q=UDaaq*iaw)OP_X|}xi@{iLsmkQU^lbpG( zipb-OsW#T*_^fB=;m35Z?5*P5lCN=xL5Imvu8b(eVFQKZ3?h#EDMja&7uyMu^W-I| z%CBZz8z!B2Ml0(k#@fgAt7ZW+@2#hj%dktGb$hoMJ(J~?x66u4oy+63np)!8ZCk+P zXQ#kXnVarK>$GFX{&ma@;WppTHp{jMU1K{xJ4ZX$tF|_c1ESF`zUR7)W9RKjfjx1> zU+fc>ZtdB{)7r-f=B3WPo@BAP)KhPATiKq-hXR?;R$I`X21g$UqD;Rg4(XgE^s1^M ztNoU(mes0L^{x-Fk2Q{44w)wnQUL0o&F}YjHIqF&Upen1_XeW?`mgK0PpRXCfeXV};Ryev``m*PGe1z}3jcOq+o_;N)}uBN5tjjlafQ@WJQwWlZOy z>Z#ci+vBaPaBFI-YwNm;)gVJ@m;Lq5cc|NH8*W>BJMG$M`$xBq&ohwdUf|e!VEZ6< z|N6FP|7#Jj2q5c)mj-M1C*MI%f*uAthOUO&AZX>gvDj(LBeOtg55R`1f!)ID6at#u z4DGDWb%rfS;hi>}^(yA>@ld~g+DnbtrvLm63`LWZv6K-TD@n+vOikU;!DFzcxuoCJ^m08NY`n8X zPL`NJO7>OlZVo8d)OB>##I}PmKy{SlC7;oNqGzstm%>zQsyh2)VgAtbC;zO}`hb(q zs=MNGIc7;;^G#OIO0VpyuYLJ^;cVjUcqvy6Aop>P*cq}GVv9I}x6CQH_ zB*Qtw-d=F=eH-hCoY6#7%4doKW3CeQLf1lO39@33@9UQ~VO7T(+nV;;m9<7=Y@^U3 zQEq;^A9csQLbBuPXA1YxAviTp6d|D z?dB}v2vZ696&e{~EHoq}$KX`2&HC`X!lj}bxUk>*n_8o*^9(RBysJmv9gi(Azcj*vsds&>*uj{UZt(VwVY%X=%ZZ%)o2Ch%9 zHM_2N+iKW!SgsSU6Kyh{+?*V$Xl?OSZz?U^_A8@hbo`Y$J%Yqq*w z-?}eTZF;=ks@AVJKL?+%n|qo*MxX3kzS;vD#2UpK2AT(23T>o5Vqys4-5J&$mtt)B zrq>-0V=~=08usf5XRbYrM|KGfu7Rf1tF)_@8|gg_7UnL;583zbOq)FQ&I{A`e|tyn zo3o#Y~LT{kb8G; z-mmLl>EG&K>W^&oZryB^bU8mgUFkKs?{5isGjF^-@tiqhWjEYr(a(53Wfi{73hoL% z3a$%oci;IUzL{O>v|MNS&Ro5@Z7UtKg?mV$bx_f0JyL5U^^)TY^UMGJr09KJ)0Uc%R%tyeUeg_ReYXp6KnIa{n}M1 z;9Z*e5B;N87v#b7S)}4PfP572hVgPtd4Qcu1wc*)5S*>Puz(Yp*ednCz*twWu#YJ) za$D~Wq4x{}0?n1z2fvL-{v3##dmbWlcow!2m7c!I{DO5<`x%Fr?QHlt7(j9vxauW6&b{KYA zxJw=|5Q?nCcOh~zFgNftkTS4JoZ@5gJ`4POZ3LG`w3PNh?+|(-<`xRMr+2~FxI}Wo z_Sxbb`$Zt1Q~F8KLyjD`ymMc1zz)@!R37S#GcC8%Nkpp1)FB6D?)y)--%foZN#Qgs79ExWW`aAj@h4O+RX)o z7NG55*^tTGcrKjU0mq_{u0-F(mg80}1g)gl4KF9fj|=G?vA+i=d*H4q9OXscik8W6 z{W6fe;qN5S3--D}(=`9#0dluPb8rbihj^mxBG3+bwgVnFv>kIL1rU4A^X_|9$}61} zniV_YeE8-?c(;W-tD{WX8QLxRC1DUy0+3X&;2pLA8)8K!pA>QBMx1b*Rt0Kj*6%K{P1q!iAMDBomr%%`lia^@Z%Fci zVkuv2B`9Z@{)U7|bjAqYi%2J5))(~bF0~fCE9~;bv<$(ZPw{~{D^!2zf z_XC+LkC~;zej%uP=<$SaBh0UNVUF1Y>J^i4q+ymjCs1)`)r0aC87a@+fv_FdYC?yV zxGOgD#-|J(Yge%ohj|FzflEJfIbPrAo0e!wf?y|+J&BkJrB*Okf)QH)SG-C+o;{WM zE~5$Jmh4i3s|P+0zSZibiNLDxw*&&A@VEBxny)AAmG<4}a9uM5sGnH^#mn`ey0? z&Iz?USXZW+Oe4{HwCRA?NuWFVJ$OUdZt!{UEib^&er~qJ&75;sHCvH?fm!W;_c6F8jGRGeGQj`i3B_2*AKddhjIK9fxN~`gG$Sx<}Tj z@#`%_46Cg?-yjCf11u@RZk+iTsTmYIdclPABnx}L3rhn`>P_0}BtbtlEk&}H{Jb>p z!k7!FUyrap1z18~rHOjHJedhp8s?;~84>#^0xGI!WT(s)R1_ezQ*Mj=Cz;U^JN&4M zQGFQ{;?y3!6f zJ%1+guEEgubSyLqqcQ@}(mkPpHiXA_)FKvZ^tq)dhHwEPJ||(qb8*kn;5*Xk`i_46 zgFtOg5KK!LOwj|zkc@5&t5v$*pfhn!gVdWBNzL7<+Mgw2l$$BS>FLTMGXd@1NIO&f z!a0!AaC5pyn6+qDhc-o`Rz)Hsv(G2cE{G%(u_x5M;qV|vNCh3B?A^glBC|xA=RUnn zg#NBv1HX6tuNyilxX8$N;!(o$MVCOa1ft#YVHS58h>A&>yg)t(9Zm&%%gjL?fi#4$ zB;I8p80SH{d$392-D22c5FRLdw=e#dJfr?hpb(v~zi*ww&}mOlNY1e>@ORdD{EOda zaR%*(WF@G|Zr#BZ-9ROa@&I6GTj6SscxS_>{=#5b`yhPmAnQS8*pan30?^!Kpa}6` zdt;!;fFZcbK`nn-W>CDYD1DI;&>xGM;M`@#@hB*BFdh%A-;CjRX3=`_@Vzh{K3#1_ zkb3jsK|?=7?rY(X_rV@$cLMRfYq6C_p-Q9>KvFp^>#i=p8ZfAP}^FRj45JAE1!fG3GtW>OzNcL`i}as_#l}KzKaj+x0Ct z(gXKt^6s=yjMevXJ*cjF8$b$=cG^$`j=ghSp(<&V(VZvc5*0to{NN+M>=>wZ-u+>Zh9bZ z!2>;!wnAryj(6|1e8iTsMY*xIZ!m$fKA7Ejdcid^WcViOTs!!Qnj!XmEqm)X2Dg_$ zBp>Q-_`8-spqm8MOX9GB)PCow`J zO)iQMm*FfYZ7Pac6eDt`JfMRnL2knn5XX}ywI5M^L#}2{VjsxDAh%v)M4(hr?I1nDhwml-DQyBKxAM zNmw2|KR^t_uvZAjycRRPCw&PcppqILIY7UoeTni>{FLh^F-WKxT|U6SV|*cgVM3K7 ziHRd#1&a8Q_9SeNIywbJCBmYSJC-rBh~;(fu;_-2+@xcaam=T=NcNhrq$@jz;joe$ z6-7nGv%^V_nXs-#MX0djNlu)k5lGJ9;E;c(G8^vK#Kku@Cy-~_H@U;XPMpDDu^S%n zz$M-{2a}J3Wet``Rhvv=DW2pgiJ~>9OJhMdqD!Zv8voADDbJ`jvdE4oPrfk7!Om#I zVMfk^@3<;GA-O949>hH+Y4dHIEi&CM?4-+v!o1LptiQn#>n8)gJGu(q9*r|rLx|Qy zrSY`c5_}3X;ngJ}!3o~Q>Ge^J%X8J~9>N2%`>py@%tMUZt@;CUHPPi^^n)8R;?qrk zWT^Md*yF!`qQ_j*+7_0VB^~w`jx1&X- zD?G)T?EWGqT5UqiDkd3!4X!nz*@aAfpOBVf3k0Z)WO-}&zC=-_!u zEwq_}+ezm&Bm|mW`&B&8kiipLa-6t`x5@w#j`P;ouG&$Afb$O}|5mL7D)@kRBLB`e-ZP0tpp z#ubTwZya!{1f%DycsKtnZdIT^>1Q`SXHcwis$Fy)6?H9BTz1(-z%5f=`nt_;nddgj z!|5_!5#nek3QAb0YAC&?Izop)rN-Q7AU}0Lc`hHA4#QWJT_l|cnP5(R@(#yb^Ti|0^8@krxnMVe5nhs&cd74m3K`AAsf(lVm z)>)rHct*UH)N~@UD=?DmP`}rp4rQbN1+ME9s{X)qDGR4}m|vCJ+$VnS?rnKqYKv++ z&=@`2%)9Ev-&p)1kQ75LzAm~p@2F2~YbnHhd0hO_nUtG)cdr;zQDlp0Ti96a1S}&E zr0a>jyH#oPNg{5l*_L{Fp&=$d+%NR;Ns5h~e^zVvlbumIeW4W)Dn2f~d!yA8Dn2iD z`ADkH9ltJp08jGspGQ{a1(l^1K83LO%FAqa*%IO1CLtt7m`xeSEpmb?&k~Upl0Jo| z{UAwZmp(*LkPK8@CdqCK(leoBvM`99=H_LSM?l!OK{ryBFOKN_P|Ukbi=Tgle&mLL1C zE9fxW`Zhi;d=p+Lu@!4%EczFm*+n`s>vU_9mYIvry@@;Lt{v1m$hKXLk8?{(>mas) zjfiv2am^Bqhzs8m>bz=8-93uDEm~X5Z-s|{{{d;RvA`udy_9*nRm~s;ob8OBC3g*c zhz(?&obBch8Y7#Y-U2P~?97M|`bz)Mt=KqFf9-X? z--bjULPdlFw-1erc5d!qVX>Xmi_$`CZl(ljEHhn=x3sCYj>(bMOzhCIEgQMn1jYwW+8-*RbfX;N_`_m)*SxFq$JTukxLc8Kr zq5B!X7xnR+5D)U|*+M8)vF1%o@)p>0@*JD-tXB&Q22I40C$A?9wb7?<>O5NBbFbdMj$CCbiUB++53bWd5CZ3 zz$0Q|G5B4dE;V)jUX}kr)k|<~hRajw^o?qt?qf^o6j;vhwo{vgPL zi+k!DCW}{)5L{*=@x7jm_nxImK236s<&SupRdd38MbQIYxf%WG^N$Db4BS^svy++v zyx#>_Wd#`-lQz7;zBg)uPORnm)iO_i>!rM=t!@Vt%X?P=QBRGP~eEkeK5&?Fp0iM(R{%i z66e2@Cjo-)VwFEp$A$j)CiREF|9mizdC^e)Oilt&9{&GLi5Cr(&wpGzH2D9S#KrH0 zNr0rgSk+IJaUt0kDcUcZ!~f@|fx?T1+UK7n1I|MYg_j>{e*c(LtyGRhVbwJSGP?Qa zl=91RY1Pmf7(nueH<%AW(PeuRw!~r=I_hQAk8UrtUv?LlY{+ksqoAWm#F!L$RY2ezSgm5^-6kJOq9X z(nH>MpzI|%A(IKpiqSA|vQXK?g%qiVln$*jzkfsRjoGA+d9CGpvcKxvU#NTIBg+M5 ze1vB+5FNiGO8$-m$0XzUsSF_|0<><@s%qXzvW`ruP^Q6z6O0}CY?3J+r+ucvjeina zSZw7Ej;F!k-0I~|WKGRf#Yfs^6*}4uUl91?WJx77WL?K}?g+t78i< zu!0V=!M}Iu#7##LVfjtR-SSHU@M*ZBL@h12 zAQj(t_~}0zfC8s9E-q3y`pQ3ewNPTDbO09G@~lkYu-V}p&y8oq0oV9o5l{EZ^Qoug ze*e61vOHBktuCSxDVBFs$f`tfG+Y}>WLm%B$x-rs4Qyztc9r0-Z_)IqQa)Q<&QM=- zv$Z%vN^saX2xcMN3d5@}FV2i#E{ty2E+@_m5Jc%%P&f77{ku@2olMKa?d|y5xt8s} zOWch8M8a5-4-cP70tO9Z5e<=foD}Pz_)?253}Ft7W-ky;0avdrs9`#_af9?@mCvG%OjNa|jjROHh z;AU>IEL>i>)*vHdd}o}DA72G*g#PVgy!Mwr&D)O?v4X+H;Vz!!Y7Up88;yRteT6+D zeH+Zuu0Ivye^|Xe&E2V3adg9RhZrta#HBtod>cemajG!xbRv*@8|zfM6~qxesv}?9 zGjM!z&Xrg|IZMU^3YyJlHM38ZbG*0lOl2*$u~r{i=UTV2D3fc9!VDZ+dCHa#T60Vz zKv-eiz?3@51?2ZIrSMGQ8Q1L>5`Z!Zg}*5|iERyPLSAw)>bQ-L7tMCx!Cw z!auj!J`HzXyFWwE&#~a`kBJCoTxP!E*y3cmtSy0c9tbeP9rivLibMF z3;)WjW%WS2@}qy6;&!h1K%bu2;j>z>uSfUjgMxl)m^CD06N6I8&=Cn=VE5b9?Ju>tcmFg%AjK zwBEnr>%;5(-*dVjaHyrds%YtP4b4{vsG zkOtx%HH?&6G4Rmrtm5a_k>i_W%`!RaJQbp~UY;XP18r9Ipg82CZmMRK6Z=ej1!!(- z8DtcJjN^>TVYi{v7sQNL=?&%XdRL>%e;h`;adrALh$H*AXg7f~$4Mos$c(M*3 zK**a7+Hh^QG`N=)DZK2q_zuXoHXVHmJ^Lir1aWm=)pV8e?e1zgHqg?aGX`~CS6eWx zx2iF>X)hjr*iBT@8KAR&G2&CA#d<*qN$(DD!aYeH*j@8ltLJ5NGEuoYIoPXW}IZ#y?!UtB&gkI(A*^)+B?K3*S~Q z7or`_%|$*Dd}Gr8v^$neaE5+pROLPLiJY^U$W|7CpucDDiIqZYvR%8`_;q`6FYg`} zhfIuLUxY(a)w<-{zGiL>S2Ez{UN@|@i-`+4YD$|~W%zV6Du6FTgMnNaf_;<%dBTdV z6f%1(niW&Q&kJcjIgjmXg$Zwz>Ve?B+@{#)-zo3g`pTDhEomXu`kynV8t!C|tzCK1 z-r~zEDt+<*w+o0(kuRMI!Z!g}6S@_Qxg&B9cUbl<(9Cq8d|!Y zJ*%t(d0e}!?%(s1jKyO7{9uVXo!1&!NFjrN$-N!x>1wY0#=@y@u=2UeU?@g2?owYr z>XWmhgOaDx@A*3GhQx*nR9H43RYJxzkY!rsBlt;0FHBFFul5FaBl3 zYR`gpuVx&Ol9laa2M?SQ8m^X!F#D@{CHKc}b z+#9F~Tl*qvBRrH#9Js=lqoXp?iO|I*X3zNm6-00=Bjz+5s(>Iwq2Oop`RFY0iMfpi z5Q|>O5h&O{0Z>Y%R%a-K2H)lgLMb?Srz9Al#t6Z(xMNc!;xih%j%O82M{0+0Pl(xFFcf~5Vjn|E?BUp2lkNa8J?6R zWvg)w_-}>YIqw-9-jjdw?l>}=A^MZn?9Y;z@VgHE6oUp zsV~^@KLA-kroZ(-Rn=S`7V@}j@)el* zuht_Li#QxfhA2;IZnLj9N?lpTW=Zk-68!3deeMD;!M0rI*j!@pi6ml-m2yRyt&(Jl z#UY1du(o#8?r>qOR%M!GD$lJVp)fy3ohO!S1;R}Hh|-!VldHkyz-|;Cs}0LNVwfCp$ZAGSz?&b;3IHa9U9*c*LK< zIbS)|;=d2T)Rap{aE_E97zs6Xyo}fy)+*JW(^fGZU7wK+;~8 zzpj4PZPBXP+!)WH)zv+Z6%tj0-BhR7xx1ZNZiylbkW!_pvEv0-6o$$O(_Gv3;_95D zA#d}TOK-&_;PYKPpV%wp3I$kc9(d^^2`g0~)P9D9K5Sr44{hAj!WDCRIO}0}+>8t_ zsIb;I*QO0*W&VKEVn_QVcBQF3zj=$_-=fi)F_-X-dVObAj!!1fNpF@qvs7hfTTm<% z^Y{$OQIu>fDP3lFc)&agah`e=4^6zSFlVw;%d^>6l$YXE3bV1Dgh4~-H29yiix=i#49?JK zb%Z=E$*_2RH?3;DsLa!0_Jz|pX~kvJ?tR}CRVpNWZmdS?H5xi(xU*+}X_&z_gJF*U ztp3OA>t-{=VbQhbSKm6r;iUUpuG(P(Ee^fo{v#4BJCyNgYhCspiK zC_|^5#{!sR!J;ehI!kP0Mw(M+>o0dND#)$a5+1leT0LKq9{bUPWz33~@ib4p%BaWb z>F=gXFfJ}EJg{sUei^i)inVjrgH{4;o_?maPa2bdD(ANG{~zq%3-`jzfWtmi>uR-V zgV~t^zty_9xM8j9oT?WF2A^!GUo5)kH?ufbX`SP49t#B9bUG{M5x_q~PnE_kSC})} zqzjBfN!1r^K)qr6t-tZwN zOmP$Z&ym=%*iTrvSK(G^rWrjI5=km|2#Z#vD$SOyofSj*DmQZ@S#TUNnF^CYkb#L& zt7~#i43hI_USD3;h_S;Y^MDQdpn~|4`#D4s`P3STktssnV8CzX8+q7l$Icb8H*L%u zd+d`-f1Xzno@nf+{GJs!+ zJvxi&I?n#)9gJqP6%{Y>+gMI%19#hT$)mADc4nPD_WCD0^vQ{5KmM4jgGhWBIIiZj zAV1q5%Bo~s^d@!`PP>&QZYOP+a8VOPS-ky=M}Ik&FG@?-N)$>i2jj8tE=&=o2-IS^ zlFKDyzidcLHA(A(Ro!;3G*eM*ZW%IjO7Mw8j8h;_P0NsG3eBSNUzw5=5id1OCKQ@P zN2A*ED@)22eEJ{ zRbeu%Usyg=pf6HMeq>0NJwqsjWKpAODwyaeSGHd@ZCX9SM!h_kb2$c2XpMiti9k%s zK}CPCzJC{km8V6jsfEcrk|I<}gSNa2XRrHbUERD)hP^Mfdw0z|o4t=G)@ygPuv(JE za7l{AVC=36*NMc0=;ihMrg^5@oP~s$)!6vru%hAoa_=m&(~FteO-(QFk{1JTmlDS7 z2%R027p-x7rol>f7YwmGf$zsUIRVhuALk4qJ~-B&Puj%U~ivQg6?BkrGrF5yGa_1JBLwVqivNb$O{2y?#Ag{;Rs ztDtGK&)=riS|I3hCBjUnT3eqFI4d^^+Qe3cI&5(iiX{?AK1hzd1aNja#9fRPiVU+n z#&F*qQsoMj5O;GeR*1X%=E|)tR!by1TMM`<5ZE;_kHV5Eff?#mY+_W+dOf?JdmhX% z3v8H7YeOLuGsXXe(;yX`5uF@A;(dt z(HcoC-cnJ1eS7UqHLb&3PD4pnP~+&ZtEwSh@p-PCoa!7)I4etyac0A`va8#omrmJ@FmWSu>a^(X&==8Q-OJ)pPgjs1qc?vf(Gb7(> z_6RctVzH#qhUbkroel_6TKjpuO@kJ_LzDtoAW6@(uz3Q^eFnFZR(2+KgK=`wwkbtk z$Uu(Aj^!UUA8k#|aoES^wH&NVEgCK^C=rVI+(x|H99zq+jQ#R*OxAI6Fj$U>%Knr< zLa<(~u65$qUS@5$3bNbHoMNO&W>0)}`|6b21y9zJ__nTVO65O28auiJ(l}j>!(W&# zz})4rW6M)TR?|i~>1n)zQ#_HPatK*B$u$_-bII7mmYFw3%iCB^mx8z4%PC1zkiKLE z$;BIEq%ihD>=q4K6Z-*%3tQ{RarQTTt%TmMfn2nLR7w*SWPnLlkSo9YR~{q$A6^@K zM9)0%p@nDokp$MPop=dI>{+p%^iS;U8z5&v6gdWTo&`F;uOQdn8T%UZV}9(%)`zh? z_8opS_6qqDw@&;z@e1yWT}L!T$Nn42SS^=<@v7wbNf??Ma)BmsZI6A7d7WaDRF#Ux;s=f*I;zT z?kOtG05^y&#Dr(yYc*+Enc3yL3QIFGFb5ytFpQ2T$;@zSvWtlm&#OMCynKZN$}wWn zD}p(#udR&TKIVnDwU z?jiO!)pUgnc!rC4wY;Pg&O%OK7Ziy1^rJpGe5b<~}qiMF+RSlIrj{U%t6%}2# zp!bPJm;gs4msh%d^UNj}H>I?=`1<+t@2akz$H$o|cCEHP*IFXW21jw3Omlrq+kY_8 zYt@ZzZ>vV5!$habjyiDH6@g$eA)&(1O#}WeXKs};tHNRLF73X|?+Xy(_xUdCB95>U z$~i2TWz`o1TGeVTL`EstA_NvoOYEFWSyzXs;RCaT80O;ZVxLWj<)l7@g`t~l6RCKY zX$jFX7mrsz9D4?r9>L%GCJux48o~ef0TnkySLNv%pzFZ!2eE?Pkq8-X`yj8gw6I<- z7jSt7t#0--S45%6BC%h}i;AvZF!*Rq_3ZRiL!RrRzQPsm9#Y^K|CYR3WCg@_noRRN zfu#U>6e@w?qkT6*u6BJ-1*_3Y1ia; zC*!{opE;Y8yAI6Tx$XNaH~b?Ssu5)hY<}OZYX%>wuAY^elH+jf?a6I6IcoJ{XSQp& z#xqhOh}{^7N~P%>t~p0PyU0;2l`1$K%%n@bI&BsAF|Epb=g{2ON0u*tskOD2VVa}S zN0!aHBO2`>Vv!_haL=+a;}3|&AbWq*Ap+6Z?2 zYjPzf_Aar3bAf7HXC_ZhWMexw^_EXgu)mlQm4n~U2EQ*rHE0p^J#&}#%pI~R?vJOg zktyCUO+GjN{yC?W9|{Eb&+fbvLaTEI;yD=xZze)og5we$I0vrST< z@y#+A9I+d?wj6z%$5knpi@02yKBwL5ipXW6X0BePuFZo?N}R#rMj1PJc+8(;pmz8TLBcrCJ00t zb%WF0p2J=nHQGip)6t;S8nHpGsRX% zexL0BUT>3tj?Ylnsh`YF2(wi8V|{<$R;7TSB9@fr7i?;+-%(Vw&}eegQDn3&EG!tnf?z}pg)!Ht({&W-^2Iqi_Fvm&Nb)tB$ou#!ymt9AY`(KIdR{m@ z;&gfmu^3HV#U(qc=iE_MH3O0ji>zhNF^7UCOrf z`Et836WlXfB6TUU?V0JB_{n^mbxCpI8jq)(U=edvs!7c>D&$4x(sq?93+fzAM=3Vy zQd3hkQk5xPAi%qEN@|)xm1Tw-fgnvM!)5bzIXM_-Yc=yD#$rT3+xIY^bDu>%Sj8yp zv!0=CouDJwpCi~oM{C)XE%^Vu7*6>imv6&1j4v8h#O_nw)xpfjj=gr4xk+zu5@Iu%=KBhJthNH~ zJzPmBkjIQFIDXR>ee#AC?kaswoG2`QH-!j+Njdvmrx*Mdg=H3I+i;)~Oeo}s^4N?TYF9az< zD8%QoGCo9QB%jya8ygeg{Or3`&6?O*H)Q6<%t=YUqmsmY_$DS+yY+$#EZV~I>)kZZg$X%=Dft(FBY-$JX^!+jtlU=V84(^CmYDHc2A zmc)dyaq2vo~# zGOr{vozD^C`}87(E@wq+#VUW^%F>3-1qCHMOgNc>bYr$6kuznb%(<@!CJsX_>2IGrp)}9TB%P><1-wyMpJF$l%NG7x? zbDWvN3}!1wCBb7cB3 zb22mi4*Otj<+jLAn%qpGgqz0Y)~0CH>W;9&sd!xJ`~qM94nFH0t{CT93^P2X`|4xv zvJFK=i_Mlij78ixi6}F}EO&I};x~dToX!Bo3_0;NTe3E8Ov~?jB^(gHSUc*{`{a6is+PwQ@I+~b zvloTBoPw-$i9=y-&o$Q=vh(G6QnOTSlDfR9Jx&@w#jm; zj${$2mecr|-rVe*6g~$NF3Bc59+c0SxteSpKZPNfi{Hi!kHZya2rMe0oX6!84j}?g z3$~lHBj(~=RnLWneM*-sGJ{~9Hbs&q)ul^BSdfvXl|GOn;&Qmyo&)?udXf40aId?d zU7uqG?TgYhB8etVD4ghfQD~7#?NY0sV6|M~SE&kwFUWjqwO=NKI!+^(2jJ1+RB>*W z3LYsj7NqgTsY;Ke1H6q770)HyuORv~Cv%^WjZc3(!B<+~^R!I$w4I4iGP6H(D^E%7 z!71gta~~>ww{Wa}g?^g)gEBUv5KW0bCt_UnL~ZTt)YRgV;#+$=E)Q2Mv)ldYsVSV; zTH9c4uu+*M;qja%V`r(p#%L&!F+!d!GhM^1>3n#>ybUXZb&9t#b;_0Nca&_5$_)UP zm}#i0dUR;XofYAFhBzJeRaKSyTdK;|PQ?5bgt*M+d7j`hXKo-hE#0ii>@?MwR9=|B z8gTNG#Cs2h#NM4jdfJ;xw$rM7zKz&pM<=kz_to;}TUwT;rAEri@92Kn_NAvum95~X z1nl;n(7zIIju~)aQPJ(A%WfzP6%%|o@sdo7r?^9_(_(URN1ew&;DVN8N#qPkuF1c52Y|PDXyB~s- z(v;pJE6`*W>K%oW#8xvy_{JQOEi0=eMONX+sj-&tiX?s}zbx@Hd6_KJmPK5@&LLRk zNNg?(|BW*QnNA&kR^!af5U@YRQ&pHu)jE0MI#0GkC`|15ctOh_a*EGp{o zKPa74=pSTM46eMNr^(K02OP$l2ubmxgRkQCjO)SU~*nPh1 zm(RMQqOewP_os5xJVk|f9w~@OWf>3`uN3F!WH1bMZz&#t%Fg=GqxqSl$A9J7%r2-%NCp0&2T8wo_dtDafCiGpB=A8k5o%r()GCJ$(9$uQ`S(s<5GgL289Q!nN zn%BFloxV?k**Ew(Pb79D0O#1)I%P7ay>`bIx086sH-y+6j%cyP7JFU8%gN5Jb~%eA z;tYcM9Jj}F(ZZfPBas;b-G1A(N^WLGrX#1p&cU{c;XH3Dsr%q-d!tTk!dRD;U1`Jf z_XpWc*0Q4F8@j*x;AUN^O6?GkBOf!aCFQKvR^3S+*<#=hCiPaI4l2V!#q z6Xx(@&o-L&#XkBi_M;XzL0JKxUM%tAur~I%0^u_HL= zz*)ST$qVcoW3f8U+dTIFen8=nDfCCLbR>R+Gnr6KdFO(8O8;DXO1{xJ%WDefxZIt- zC3ja=&B{o_VO2KYs#mg{AiWQODkuu(pi4oW){sCbi{-3w!T~L}m)47peA3u2A2c#uH82 z(>}4v3;YY2XrMWl_MRqR_!Ub0gegd-*8?9tGW{ZngZ$&6T_$B zmGMo++sPl9c@v3XqId&+bLq>fa@k}C$@#nLw)|)E=WsMe(_rJ5<4^aM%-rU7N0ill z+%$!}HEeFwip6G$I-A2`$nuGjmBkuMS{k2AxY^3Ax*&7YWtbBi$IEm@K!S+?cgumM*(m;j-J2{yfBObv!moDgat zknkl0@(}_AYzWo#5U}>>&YV43t%M=>yTAN#{gdt0vvbP4^UhnQJR=cPovY5>k-509 z_2*4nuH62RO_`YfjM#|Uj$n5H;PvioKAmD4Ex}IN(rgY5A3Ml=v}d_dtF3T4 z(>krefIqp?TAcx8i3g{;nBC5#TB8LRce%tT!vtPh56-Dy1mSo?LmwQ*GxuLje?gv)a;6aLZ}O)4 zKTQ|$`E%CZ{P}ZHyfV3|q@!aBAN8F(t_Eee7RH_uqHNy z!_|C2JRZMdXvrO!OrMbXf;MZA-FB796=I4mbvirUkxG?P`5o4 z1$e(<*20r{U*RZkMb0nk+1G@<-sym{D|&I+pvzUF|NBQvZtCj}Or(xGwl&z^lV<$vvB>su4QW%bgkHk*?p%!CML)$Ngr=QhHN8mf_E*E zM!0}kOPq^vKSG`&(&(Edymt1SE8X-*0AD~a;UNau z`Q}1x_+qH8Zg{A!VG(?!t{)CH)Gc855`kO5H^c_wU+icXttrS~3rCc|ZP02l_e5fY z4u_8U-jm8%_99}|F73r~BQB-fUEr?Z=u`>y7yL~Ws9+;oFo@Kn`HKm+1vCThq zzVG$dU&qg-po$!XU*YfYTn$+gn0n0*Rqwomu1mvV@*bip|J{!Gu_xnj_%PnVlSJR` zFZk}{+3&!=iFXJaA1`vmc9|xS5jOluoB0*Ba^JbkD%}5jh|h`d*%IQJGJyRT4y%8! ztiKO@sD55qe=l|3_D#$ZaP{_e%wisZZsKd=R(^<$_jBP;F1d#p>)&jO*0P=9E}OlG zyyd?fA>8@vsZyK=5f5{ znw^KwUj_HM4twN{WoHbXR{!E322t^j7m%KuO?*xE@Iy!&)=y7h@5)=xJAm~BY$J}4 z3-|`~&4%eE>^B>Dm_HiwZf71P*780^_tzCZ!8=F8m8Qcs^tf|}cYJWld_K5s4id``~j_jQ;_8KjvM@fm-B=gHXx&T*vj zCV;a6{`_oF7a^vE!qQ-1$HGjyU8_|9AQKX*xs?fwub@i)!z8LJ(4?MAS*%Jc; z7f1G#o!!xKOJCoVNb^>tU(W6w(N<)fs0D7L=Wz~ zwXbh4e(;tp&v)<5e6i;|P>P=V1@i#$4u2oFmja+*Pfa}GV!D{8!Go^bzN4Q0>%aAX z){RW@33CHx4{k zjO^c;2>~_*;fJCTk$|SOlv1l}Ej#5ZrItq7cxOhv;_5`QPNG#^e!8Zr&!CsnTA|VA zK8x9V16fmCvLSG53WW=8rs#p6-4a_L4p)L3$nM(A?PIr`z6(B2xNP>3%3C}3R=46~ z4S7#8R}!!Ct5Af*TcpnquB1{pi%ZT*KA&ae8{kR(QWSsHNpz~qPt$B4k!ghnkN4Ek zl2B5jkkVSd)~u}xY`a*g>2o;;Avj4xD{U$-0u#8YH`oyfcW?i5u8?Jm5x2dki*$$|sp$!q;ws5M0OX)G)hH zIScP}qL{dzE$3DPWFp|;O*b;X`z`1J#P!Un%p~}khFwv5IoVA<%-Rw)yP}kh>*2?Z z4AaD1TMQ;!0Bi-zi-}@z0kf4s*Imn?>n?@E#MG<}BmNSYIuu}S8059Gdz49ZPdPjP zz}_{6?n%J*V=d4ji`cOJQs z{1Y3&m~-z4W_%g)B}BnzvN3wm+HfZ!E|+JUwus% zTsU=AO$Yka4F|9dS_W+7dg1{dF|*4EFE}C_15;}PL?`|i{^7_GrjNDvqr7v-m1GZI zvysaa+$b>3Wl=E{kP=@7n8g=?%D}TV+csujMQ?Hu^HAWm%I#}`?eI%ShMTTG^3vhK z#(j7P0`Dtw9Z938Y6P!`%#H9Rxd=9v3)@qLb1gHmAVC+72L4#teDTM{rb?%?HR!0a zm=l)7>Kb32)e_Z8P33k+v)>#wSW}krjrIN}yFIa9WJ)_6tpQ8SV6U;qQQ1bDHKvo8 zDjd$1fH|tSmRrqnv$fXkN6B)GIPn!rLZdMPiAZdgTSG>zCSm=vIj+?jg#wX9;V1?M zjV8gw{$z=xVgiB4rm_|pw3@i}FX%$8K`0Pf6mqjjECohX5XtvE-X5}p9KfsM767%^ zpYp1~d4x60@X8jzaM9Exq?k(qbx31<3}~23(G?xM^GPe&j<47TQh=cJG}S>I@K3!O zhK8b!>~GHpC%g+bG1;e-`a?+W-8?sWF8K*6FUie|1JvGL+~nZzxkvcf=YidedH>(Yt9vE|vI9CWk;k0RbVGNPR|=T_B{sqA8mb70av-u-91axnF{@y9IR3h=24Gy7@&uoSNb4E5o9_XxE;q`_940^q*Yr3jd`n(|sf?nU6i+Xh- zr9z`sDvPu|x{yMNJ}Qc`f-ZD{F9bjUT~OOywbF|(2%rlt?!y=0-BIWQL$N}s20CJsv*$J53XX?j9p7Q?KH{4#-<6Yzb z(RNaz)|e&;lf^QacGp;?CaFj-w$!?6QH{fVNEpoKfl6|?hE3ObaWj zQ6q&Z_H7nb)hu(lgT(0zrp^Q|e{!jpofVVQDv?-4E9C$b`+cjc{K@4$UkST*<5?5?n7t9vmux=K%9}W+mPJ?}u@GU(b9= zOtRl&&k|F+y~u-t`fo4z7HH4@_H6X6`5ySMtO)nni;$;1serG6^WS8Tm$|i)`Mi?3 z%L^9m28!K8{|8_zbHN8w_Y(c+IvX=Vo`yqQan=XC4iZt}z5|8OvX z^GWjt)PJy4izwPev*aDV5{ZNl1*Bf1P6u3JsZDqa-S!B57N1=())gQnpD$kz6jLNYqb4 zTBvLOS#|YlpFa$9HLkt1WA(G$T}S{ypMPy8b4lm;y)$yUWnk>yhK6n|r_3#$DPWOU zHR`yltXZ$q0+2l$EPVt3S|oB?3{J5`jQ8_=PFzkNVfiXFc+3iQ9D;D8|I{h$r(@_7 z*;0MV_+^KpdzS2~Eo)|8S2HK8&*}JC2l+m8H?%RAflb+W!6b7n00-BsVY-h=QjHhr>RcNU!kwN(sVlvn@)bkzSPjoY1S)5wp>c z{0>3rl&TW5As~~<$o=tgj|W+;Fft(J(IsAQ32U5IB~1~vTCY{AiuI-vWQEiUMF{od z>%jr?RE|9ZutBodPoau?X((czz6Fq%Kl&=T!oi%g<~1j?f1Egt`OR5i1#{s}(7O14 zZvgi(op(NmqZ5=RkoU8kBKDl@a%)rYxG?*d&F8QPQz&kL{g*s+@t3yOR(xvv)8!9c zcIeUvFK2A;uK3pW#>EFOsaSDn66|AEf_?je>j1bB8wh6N0Q1&<4rAUz_QHtl#Z}Y` zJU=hNYvOb|nbJFP0_euGfHMM~8FkA^mC6scrPO@BIyX~=?MP0+C4b+)WPfid@LsTN zwd9|oRQOjb2Cv`?Zaeqh_hqC|go4XZ$)G!w0vC6r1$fm@$RPf0*-E`&K~tF-l1cwc zT1pA{VEsLRf-n{7J34Xnyw2UVAkkKJ?Ur+%B+0+s73vQJdi-WvV<5WqBeQ>$c-uZZqE-dV)G+#5@k^O~Blz+II zVzwJ6Q|dYQ;Km_h$$Xf=T}DP?LhLM_tg2pBR8(g$ zI)x~tLluca5DOKZP?e-(;4KtS-gMYkr*Rwx` z@odWZW6QGV%|`s-$*6_NAZ#rQEBN=q1{)&Nt%m1cj7FA@%B|CU7{j zDyViVj6tQ`EEb!z+DxpZMy-}({sUuY1gyO=nMgvQ(r9Wz#V0hEjRuV+I&IYI9V=gQ zZba*rYaB9KAr@QI>N0z{N~w|oonGIT*mzwmj$CQmVCaPAQWr}%u z{cl>^7K?<@Wb&pJb=3W!zPjfAjVtb~s%|6zj?<4s+4vYo4om7PTukU~ECzrf@ z-!t$&@c3vGQ$pZ9R|2q|Tur1=EYGX+{~)`bv#K|rjOPce$<+^0MzuPImpo~GN?q6x zT2|h@Ef_4}-_19pWY=jZ)#?07d&ceRD(*pFl)^7m*0jN3mq{gdg~lt#6PPve`0i${ zC9T)no&*MvY{on=;KZkD1 zqm(rMz?=ucBRfd}R6&Fv{V3_+RGnapbb@S5``&b-H1 zUOT6{pfkntW)i5?L?_`g8LO?LILCPh?l3#6^m+>bRlr)Q2Ik)EI418G5ERWrrv<=}TC;#uj5Qo1@cjWO&-g+!I zUOSV*ymuVV2P@;kgj2b@Our2lA}POx@bi(Bb$CQ`hHb8Z zY7YB%Jh(ffku$@YZok?AF1YNg(ZyReN+B)REUc=%Yb|r*#`_%)fX^LowiJ-gNo!-V zOP4He1#1_Ne0~1*=JTo-Toy~!L6H5~!GmB=0qNYpjny?B5Zr|4gILZvT8G}4&&lI| zKyMze$m2_R!{Dks-jK&9c@1D;9?#_QQQor!xId3CMS3@jH|OyQUJsJi3~tQhBhycS z1v5DR!#qCDYXudk$NQOf@(_}&gTfq?&}K$K1&y`pJkIYUkn2mE3Yq;h5sM|`ncGRsTt{MA|Nj51Q!Kk6U5DCA z!0FCPa6N}#&Gs4rrz3x6drd#1#cYImd^PW8<~O*8s1MuOJXz1}$3lN`B%I^;i=_Yp z$nhfPiy~%A5%XD5sV(wQj_VJ|AO5W^`z5o*2`(m|I*R@rIQAhX{v-7Vn7xPaTe7@? zti}qtx4D_s%zoCgV#^`odc=O#a`fjdw1}%!6kBKxZ_DGOC@&bxeRlxHfyd-C`M zF90^=aaSH6nZ7zF9gMSjU4)@_t zX(Q%E%)kBe{9BIk9>8`O^CeQx)71zU=cEH6=tH=M5o3NsgiE+K-^d(9ILlf{Lxf9n z(w{yRRON7#YdtW7qnQ4^>Ae_dT$trBUw$=j8}s7KeG2diUMTw}l3EDe2eW`lb2Bb9 zonkpQQz`J}a^{oGXL`HQL+pgf>~`;q-s~-h!Ap%Vays(}s~d7oHy&bj zBZqh9@k!LCxUJ=k8FT*S@zuPOnP>9lm*?>@-mh6{VP?b|=s3a^-2ER18#(*}dQl!< z!fONv^Z0lkALZQ-w&d}qJie4yT!5$Y_{j8KU^DWZgQ%5ysekaInB#tdZ|lb!zrAi1FSU`ONq>p z)H!_r4dTX})Tjx1A}_V&yhjS8N$2r#UJNYa5!3fh-$YJPM|mYEyB=ia8OLH#&!@}4 z23e~?`C+Uub^O6f{oHD)x%?pjNpsRk3j|K%V^1y7C#-(wzM&0Ejf1D1u6?O7V`KF_l~D~B)5=_J)e{1J_mjbnzW0Kj+ za!gkJcs(MKG8We!-*e`E=1@?|q+G?E#l;sdlWO=Bf4(0DGLhJ(=-3_(r=`cM<>4sXljqr59wAC&hXzQ-+b6veVnwMi}Hje|5swp=t$5}iEj5^j+m2> ziKITAe>A+yrLS;U>kZnt{Rg@IOrZFGW$n~xqL%VfNn zHsH79+h7@rBp>AP3uw(u8^Hdz#%EfF@64ATk*sdkknr4m4Hp>!%$!fT8g z{GJv(3K6f9Y!)i)_N`-en#1%vE ziJog~YPul^dNgI0eJtbmAhU_(6K%vf*^1ezjd(nf_z^gfDG^1^P>~k- zUE|66y?w#u_ck<+$bDlK^UR91Orv&4wF3k(houy?9m^fcT6kAZgT5cjqjVk}U183n z2RW36-8?UEFKX#hAffs`T+%}My+cs0#;lb%*?o$z7xHno3kQ&z#)XAOpUyp zdWP=<8@T>+?=-{VtEl%m9MwM6z@clXPxGZmdAINYhi{?&k}ti~&Y>uKelCxWT*u?e z?xcQ^N5_5t#4MrA5b+`P9+Fh;|GSY0jzd&`yj>G{K2f0m$?*x$&eDwf_X(z`}nwwW0-k}yU%O%3WWQ)_W6<>FOs6TN6e>?_4hx-j%1)b=Tlss zabtGTeEHS9{me_b^5k+pZ>BtoZ@$RBjx=;7!heo5RGE`HrVYz6l6q5=8f*@L$`p658>+N#r z=iLS8c-70t&s_X|G|0wX; zN_P%$%%qT|`1Z8%a+08m_`Z4KDlZ}9GP9I_?YjLeQNDodRCDz`+=p# zt_hUQh=@-?kuhe}1hHJ$no_T$UR$2i>&5CBsj!+_#A)h9tfsPjpsc2bbEU`iGbq~& za_Horv1AvaUT`tl%b}hU+>{m)bbK1qc2N$k3@+|I_>oP5APtH4CP<1Z$bNV6ozv}yW{Us3m5w7NEvz9Z5f6U>ipG#Wv=$CnPbUQzfzMe;yelv@{n7{ML^cEh4 zBr<^BG7Ph zJXaN!vr?xw|A=SB1gO?xIVNwOB|yEsF4ND|>>O>(Zf^-3*Rk?uYR8Y}YrPD`RoCZn zNgf~L{hUW5oMlO6btcN`%w|?+a`=}Vj&Gs0X_2}4}j;NKjRU9siTwV{&mHj8({R@E5&0qUET2Nw zKEEo0_&#%Y$@^VnS6~*>d<=Y9F7KWw9jI7k>~PNQmIpip?Y7e*J5!{ zADOjY%+6*}Dy<>6XE3W?st!S7}eq=N`h?G{rTN?X;U_Bq9nK8ioUy!JcW!< zx8!yX=H4r3wF+0Al96ZlMvXe^aFxiUV(=s=2?jSeH0_F%R#LY>dsL-V0GOFv@sM=8$!Ccz)VuTdF~aVF>gs{Ps`_54ySfwh*41>vg?Q!fcJeiH z0rd(huV=4_v5~2p&!=WS%7{y-D+^aI#tO((a^f#sjY1c$Ui=!^%%+w=sLN*cpk&HuY6^sUYuB5Jgj4sn1w#!yGU% zZ-R!0xBdf69{`!7)Cs3T!}rJZ1P@H@VXnyj&-A@m>P-c^SEu$Ysi~P5udN?_udb!1 zA=9=1?~-Do@O)&)Z75Hj*=NRuXtP7FY!m|BFBU6HH5vm+nN;dx9pAq&7-+Sa9RR4+ z@{pMV7eazhTTCXWNF)Nc03u#7^Wz-$Ys2znBT~D&z}T1|F8}hEtn)+}5mffI{XA%o9K0UsUQy zn;dD2@Jr+Yex@xmTWZ~|h)gYm0L7c>?|tCcMx#h1@fupm^b}(bN~KZ&v`TG--IT_00~S|NTCuN3=Yt`D;!yhAsQ zmqwr#OwIIcs^ByH%=YK&ge4x&vYPNv$ediATzN}XRfp`cDVy!BGmhBcS++NB0DI~q zWi<_@(dz7r^^r(zV`*76nZ9dkZPikz%L4#kuwNjoE-$}f8JW2&Yr5+$;!>cAR6|%( z7DKUnCR*?r_c4_9k$3P*@%+!yf`Nuv5)R-8vR{j$e&32JLs(xL=m~B))Z9FxAiL5_ zUHFMK^%~MgP+wbn5L-Z;u@cvyR@49ZSsUPt01)jF1Z(268F0WGxhKz4$BjJcF=$oWdQ znz?k@AAdnUhLRn85@PnBFKF|lOImMg7R?`lT695 zwr8Irk51R~&tZ2i>gU)Yx{wqx`_wB!ds?qE1K1u(omi}tmufX;l633zWh(MB(7@NJ zRB?Arhf*ztyCKCl8VzQerZC&p)B*Cy^dIsTm|M}pT>M++&Cg)$GUlI8kVk-s`4|3+ zeAzAJmncU#bEXDF>dGsCk$)z$8C=36z-i>O^ZzV9VpLh;Z;s7#J61A7kSWdKO&)$r%pBJ$BcX72!t zD&>P*?~cO1oN`LG7-y#oQTDTkjeLUa=?N%q@ctK1i6pFk=3GDg-GA|{$dzxuE%>h< z7m2*Uek40D$3=~`132OS6+r(h=HqNH@R9LjFJZ}HdEpVFecYZU@}*;O zmVF+OFLURSvg@vBfbZ`l1_AR4oD58r89^_~#PNc+3*oCO@ZOONv(IK9yZImZ4Li_t z-e*txE6OpFIOoh_(ayqN#<9cXSi8KrayiB~Vn>iU8aUyxrltY0&=U?{y37xh{*8~a zzq^XVmt=R-E~}+Kxg{KzN+CRvc3G^w@h#z)L;}ciD?dUm=IB${K%wUH!M7$D=w>4RWVQ67v$X znUUetjDIGm8<@{-h?EIMB!3BWbcw_qD!P1K15h@c_&}z%TQR|WIw3F{4DGOrIBDu) zb#rlONij@if4}^Zw)W+6=5{bFTinv}_$HXl{ysig6v}WX`(1(hMLTOTQrsScAMY6y z?PRwr#B;^w_XBP{AY51sUI;Q@cb^_9t&z|Iky_IfjqP4Ibaf`P%IA-Y`BHn4uH40B zgW!c?Uq~pTNEykeP!w8hvvo&Hs#GdD1bmVf81$A2AZNZfLPk#OXuoqL)_!GU<2IJ~ zx1=bvt*LomPi)=q7l(&}#1Wv-be2UnB;sR^xNoGmxZiGbA^mqa`-?(-_GHZ^^#hln zNTMIl+mXFUYZl?X^#5rxEWeyPKLmoAGk>t8W?m3Qrl0Ipg-x!W;;z%8Wu0b|3)2OP zB_&?(n&yh7MW%>OT4J*{dmU*r6l=s9H8Nxb$lec0xm4;ko0`I=QjO9k8CSSe#tMh8 zOs+tIAxWmUT1%Dq*qzc)(dN3$c^O^B&UAWpAP_%plA9F|(08kNO?Ym*c5qg+a_abBL{7 zLB}HIvNs;*>_Sc>zF2;+xn*4TFCZH-lo5uU1R=bgA1j60=oXbVaJ&bii)wiTKlMm7Jt(2I~UqSy+>lTfYz zu%d zZ@As;aN{0%IY~Xz6=+`|!-Ud$~(^=5gKv2g%X42qx zGJ$8vGSeTD<9si#mgP(?+~PF%V1whI&Xb&>9m#2-dY*30rOsXi<#JWISKNPIES?cT zQM97szAZam?CM-9gW{5C?CNn%nMSOnNJ!8=v#HWjwYj{?)8_Sd`Ma;Ks_G^nrB|zB z4o7!5*`e1dC_)(WAf>GDRci#~8@?tx%5b!b-iq`U{o0McX=zyii3RO#FPx-Zhm73% zfKaa#Y9%5a>cUc_KrYR%6%TvjXWj%Ly^lud~ zp9|AI|3bI5)2T2EMFN6Q%cLHSf7t(u^QgJms$(PC z?C%^VfL^OjIU*x2cL)^KE^)gfm<}CSUB2^I1>-Wg2#92~S|W974PLoSE077mA;1^Y zI)%t6560v&p->_%^@8D30)8)qj-YSns4rtShZM?UyJG-LrH0u_-i&-fIo>hBR%(t6 z*u!tALjP9Sxn?+gwiAAQ5XU`^61i5w7d1vAC#1liZBv;5Y-7G|zP!3-P)K_N{*zm8 zR69{ROHz7;!lOLDXvph{mZbZw7O%vQiLM*NT|49P(Nb{pUH|yD>WtRb+b6qrgiERv z4ic|H(wa(iI=|{ng5ND#g^} zK>3(Z@9~^6+PF1pP3UvS%^9?IF`mV=8cof?V-J&U3x1KVXoA4+)g)}l|6e`*0lAVr z=_k!bbjLmEXMQy2pBK#`LtRT8$BU7cI-yW4Pk4)W^bA~BUNLMnx`i15Um;Hy7jNs_ z{&2<~)2Pkg7zhyxB&4R^s!&2E6+l1{29Jsq3q)R{ArmwQ*AxX zU>StP!O%$!<-2N`bq(iKR;~2;iXk!7=^Ktj*4%cZp-gWq)dWf*begm=vn6f5@vmo^ zQ)X|y4w-$RkRZ(sP86Mq86KuTB7Rqpjm^~6pWCW{SEK`ETGwwGn94>gqT=gd@cVravRqdF9wIq&S}t zW%))pN#=O zV>z}V_q_E>|Dl(pe%QURefgo$iR#FW_05;H*PdNddqPntPC~QM*c@y>Cl;^gOSZ3y zo>*0(a7e_Msa`JkC{HgM@p)qe;di-5qoXCGZnsY$8mz9mtogLS4TegqEv42Vks8%< zzpi9uQED~$*#8<$3YEGlRD5E4X^-7erqtJ!MowFB*&Pw1Po<<}B9T>N!W+a?C*m{V zRwS$XEM~V_Qc>o%gcLF@tq|yOkK8%^3HdhC3~Mej#_J5` z9+)=6{zyLRJNBygtX}}dRo{&Al@`nLj*1m!CVj|YHdA~EM~TVTUYoj>n9TmM`Q%V2 ziaMnANufj~mj`svgQAB2VJ655vXAHF)$o3JYT^9&AwR*FllQ!iN0t&atx#5mOLq2b zeY&-6TyYnWPpU(Pz-YAdv{;lq;dlztZo6Yiy)CIX70JRvpTj;{S5&T4Dj-rLO4oQ^ zP0hN1zZ4R^t*uXOnsPvyF`zIS0p6s(y1MF|McVQ$;gSj{7E6n4-^WjklvYFNwpd!c z-nN`AUO+}sjq3AJP~qm!<0(_#InD9fIc5ZS@s1ZdI>w}=s3eiNX^keX*I6jaYcf?? z)>iF|meoOMGn-oj!2y45uU03fNkPEvTG14&(_2h%nnXd-wPZIj(9!Yx6YcBnt*c+8 z##^6VR!6yB?-E~cY$_=^sWsYZvG`*{@iXa8vWImtNlqTZ0ZCrR^MfteHTPjwF0*sxn68b!jiH1~0q2SXfP~5-c zP)$uU@>(dus%gG);B>&>1x{tA&Pbo1iZ=sL>hX+(QOi^^F7i&Y73CydC<4gme)D_N zydCBKIqNoc-h%UAXLp%{pAP}W(3Xel>w2U#Un-0H1M6Grkwr@iCUp+6Ktj-bTIe%8~WuJC$Gg<_pg8L@dr!16VOScoDUoe|vzKtABxP38_h69BKMmUnbKwK;uCWqM7( zk5Z2iUbvTiR_@g){hIK2D6yg>G8DKrvaPXkPtU|7o$iduR`NP*mYIaK&~LMMxLiqb zYDIA|K203g{&|w+W~<|l+{QT;oB7V9R|O*R>+&AHi}_-o-6x`GKDB`PYylr4W32I> zzkUeFhj#v^v0;H+32pyU(rTgCYFn5l(^ChuwH|ZI>a4SZ&lpYVXmM;wsBfE*38Ff! z>FxQ$wjKZ826lYAqw0i6q}zyfPmi?Y67+U>AB&R@>3Qb|&gbr67a#d`aBiqECzYQA z=GMb~$b8*0q2vol!fdlnw3Kw(?Qxw5`NXE8_AN!hv_@^9X@N?YwEzXAC`uubxb#{b zNg)SG!6b7y2~m8glFGbB1&YNfiWCBo*I-DI6+4*hh0$G^IuwUjp^V35YV`UW3`Q#; zQl%xQG}P}dPi;)KUC|0oXR>F=>Vv^ykGB*6pViXjaFmI_2y?qM<#aWp_`vlbHAT#|I>{M}6P*dda(Y1CuQbI? zK`|wzbyDxHMZ=dTll1~f7nhd)d{`xLn9besSgTeir;3=Vptv-VxPEfOqs`5W6$*P5 z;~@y8TwY|AYG{FopdgF}%M}VSZ2E{VroPB*KsmOyq6HFF$>bFa^`ke})sGt{i-+9q z5Clao=U^$o$A&CBkjZpHqN%p_fi=tdGVr;<5Y?b~Nq}NMu`Z%vj;NC^R}a>emv}sC z9rYq!V^N1s=FH0hMNqkubM$OZneV9iv3TOVKbv|*C3eS9rLEEeBnGL>D3YqFn?``L zA8bVtle)$y){9FW8F&40H0(0rWRuggw@zrj;A8lA&W z5Py?MF+p))HEJzt`Xj0Y+0j657m<@r71)m-Q)oY!(OP$YP5A6^TdqmtTxm+jrv$!Z z9?z!AHW?oXg?@))w6?6r=}hTG0js60xPEmYP^r-vX&DKb40E|A6u9zS=eZbX|*Pg)zav2#KbSZtSEQ78q8)p0j)Z1%%Jy+wtu(*Zhi;1+Xd4{ z$zSKrP0aZhY;I!7=zOB@|476FjnvjtQqpF$IEYvADLpr?UvYDV z!7tNjQ3nU7;&)tteBgf6)9~rgg>=O%-6oZqe^N5-{ONRv%rIYwi(T&V>S%*TtASYN z;HdypLJ71ARorXqjMVfS3@C$85>*uy2eu4eSzW!{97v_cRH1Ww2_-_Xyz*K}S@ z>nWjd0>b**nqQ(w^66=YT!q@8jF*|+S;MKApN6SF=7GMG>`=qV;aiu2F$W?hgrt0OiFx zePcvH-9L4?sm-qoYn3*c-3Q=1uq+fhsZL*J2n___1;^sRZgnoLNbacazPX`c5%CW| z#XX*GYhba@pTH}pr$0w^>PK}lu&aL6n7#yPqo}!s~b#ThMV^iO+yJH>T zO&gq7xdV78%m^Moy70#Ci+?ZB!eYOPNaW%<^lKMF|NqN$Af6=3Qp4 zX6JS=`zO1no|~V_g5g@AsRd10=F``hEwAAT0_JM48qeR5f5aX}H$6?>kv~5M&kGd} zM*7u6VGnit$$Bju8(-?{TP+gS*JkdYyd*JtcUiaDq{rvS1XrgoW9O4VRaNB! zC$GP?yu1clplh>aDT(paoBz=w`up~y-23Oqhq%yFwYhl#;LK4rVYh*^xR@Gdoj|)B^fQ0^XK?cu z8;iBfhfA4rK=8}t`p?(G&g?<>Z}>>|7jRAXYPdQ(IrRzb%08Im4|h+0Og=gB*N?7K04}?R#R*Q{KM?Bu~_%D5bFqdgnc35xfNtXAUOhy1u^4%5ztFKQa zQVd^y)60q<2LjaSfhMot?3xpP<8G$TR0!hE_b zwlbcqMDYjJ&K&KK_{t*Jt&c5_tY&2}Dwac7>~bv%gXfsaRrl6rT7g2A{RzSKjHTkERdqCa|$lmnL*qa4(>?iFF?SIby^sqz~pnpa%7 zJY1tvNhsQ5b&Qm^QTM-oEC?zp%I{de{JK=Kk^r!E>aX~C8FNcfS+B+6#^+TL({Ceh z@fCWqf@hzZ6`b?zc`lB^*5Qm*s9K)j@diJE#EyQb(D7D+`b*^5QI|A96SPR9M@GnDN@ui&5Mb<}F~ysgwSBff?=21qSmoOXO7M=8N&1K<0*dd_Gyz zLPLST>vBytw{8lBs#48SE|k$EpN}HrB~9%og^TO-dh4B?1PUM3az%;5 zXrcH7Apo6_Pf<#_tjK0@2xtHiGzA__?MS2SK7i^P#&oJxr&OE)cOe}bT^iq-POl3F zV-SY?zBN^qr$Yk+bZNW2O0PFV=rS2=ZPus^OsmW7wkm_c0-(cStg_nTNFM8u^*En; zfTza$qn0}7@^=9zh;iAGp2!Ib?f{x8Cb;(bp59eLzQw7j@G$)#3O4?kxtUG`{FCMT zyPi%jG^k|M{h%z7xb5VoQ{s*aLv}5!2KQACSj=X~w4(IDX==m$dogN{)A(9md}f|A zA66!FWQB!4wEj55V|fDm0{5A_9zMD3wiZisxOh`b-=(Qk6aP&?#NljnEx)d&X4K&f zNl?Bn4kqGvoqW<$t*s*xDD;+;{^Ehkc8yv@LcZ7G7|+zStJDGt@_kOnD8ayvy3E>O zASF{E!@XnFUn-NyXw6Vf&EA25hev!+yZ*V(u5k#vo11@of_CD;=BB~7VALO2R;Ddq zUlc-3lqxD(71gFz1^gw*`&m){)}sv2!7Js}&9eL)-{<@MUiDmSH$yNw3t1uEb8~~U zB6k#`$<$gD>~Yuw1mUpS`btWcmoSTO{?=5cQYtCF*JQ4>ztQS{(45rrB@~Lz`F@kR z+6t^5Rhh%yRZ`Mnvj)V9BCEBdtYXON$Q^i>Js$wEL=v>SOQkaOJGkWyWh?2PU zNT?DKj&NOgml~?s?CPP~z|^)wK(>b%diU6KcopIFmCPY>7b?R>blcd&uQ(r(A1+JH zM0EAbI{>c&Zm*a+@v1#pvWZ4{sslwK;8nvr>zNlk35~}3CXxL+Xk-pSH?f$x+`BB1 zSW^^AgAaFSFD6nuYHQCzw(UXmUN56({&+n1MiLMwg9vlvDPQNuoq{Bs!Hk=XI{P5{v;yqIma`JYb6sRNJ2o}9T{u2y=bW>7f25HMEo*FE z^ZIGntMsa57KzzL({Z<_*X3xo+I-Bvx@v2$>rHH{Os^{n#tFjXQkR+o-41&YeReuW zqS4i*?bp{Y*vJP;VX4F3>NMAwgi2a0BKZ-gv)%cq6TAo@2~mC)4F;16rBou9NBxV> z2nPKqCsxQ~KJSXU)QD4M6Dz|=BO+CcU9OVc+^Zva_A=lpl}SZFEagiCQkTvjmB~Z^ zJj&x%A)UajE}f0?Mi{|X=8Ho>2mZYk$Pba}>^Qvn*mLma>^Le5Fe?H1UcniPUXTlj zp!#Jn$ovkx&s@V?cUBwo`5~Za278!w&t z$xTzwbn(SPq1|9?i&^!_#TO;w?Ix2;><5-TKtZONm~XhaxX*6)0&oN`_1f0le0Ar? zQ+MLpQP_fV@5u%^>X;g*BhV&ietGEg)zOEuE5A6z+y#2z$EbP>vv|^KxPBQon z#k1?P*fm-Y9%4T4WOjD4m1_g%wxM@u2M?o)-O7v>NVITW*TF+m!>IHg@UuN+8uu{t zdMtAZc{o>cCetJj`H#IA0GFYvT}3Q@`|YXQh{ebjIhhG^3!jG~jWDlrcF$OTte4Z! zncfN1ximQ^RDxSEl@n_*6k7fMGZuFPRo9vWwY9xcD75$kXDwdH99_8PuA15&xOj)R zNGRkJLXXAR_{?@sKp+GZAwbTm5jwTQcQ&`IHZse>UiFgZ=7Vc=Bl}xh))>K4Ohz-& z-0~1J0@oQD{r-gkO=3LYsf2^ss|^i4--3WPKIZqb>ldZW6XZ}%wuSNZ3x^0@`LQkg z_AsCCVXk6D#XJG+#3(BUblv&*gw)*Z#!_`Yp!UrTsEPkYEi|53oh)n7>6QEx^F>OW zuByCaS!^=eh#HF!N+8hcbj>j^z}&s|npi9f#A4=Vq?I3_`#+F-uY5F(ED$)re0PYH z9%8<`>hwL+SDlVuj7;N~nz{{Lbp+Ms9(2|GSQ=k>2fC8@dHI{0H(phE^=!4!9UyNx z@-;o^4qPPt)0sQ%zrYW8SAjbg-d0~fK#?`c)J5&vn$})vDp4xrB;Rc^)i`&M>DQ-j z0HJXBg7Jkr{C+=5+|SQm4gRV^1bNE3S{Zs+?geX&&DYf!Q9%JT9?K2;nl-qitDJkA_F#B2|`f+7(?l4_Zzw#W&81J5eA&Dp|X2He2Lo=gwSR(H5Y-2z4#PEVnKWR z?@zY(UQruc~kysJdWq zVqRK+z5`v|%%_KdseOnKNz$bCo-wv&U&0)c%hh}ZABx3cw`XNTaZ<&V+q9KVN5+JSkliM8o!yaCAjsj&7)>?^+-6gq!=A)rhi{->yPK@c z#mRL)h?0>{%T-xVcym)FyR#n+-qqAJ!YAwwWwD8Q8n}V#lLny3KF<%@tj+F^qs&*< zs7j?I)3^)$d?LLzr1LA7KCp|~4WIT^s8t#Om?QW^Jw++DOgg58Od|_j{S%x8+)1W* z16aW^p6)s0Mr!z~<2?uSh4p^N11|&l1;(V!n6hz91|*GXE0SJgnZf62@r_*;k7pzU zls!jp5E~8n>aAtu?FVna{ot_?LT2zuM4~*sL6M`@XtV(#{Wl?U{*{=*0x*x|C=Y;H zudnd}0@q{^^$I`PhyBdViL*Yu-}Q$x_Vdm%n5j{&mQWb4QwhZcNdOSGGtY|y4*PH= zch)SGh$pTZ+x~1@+lY+d(^8R3AG_n^Mf;l?hh|Qh1;s9fSFH={?~g9=dWs=;#O&DK z@>C5Z20J=`zu8`OVm#R4>==PC5sO_h${jC@*S@3Z;$n98CiN5X#ry$_x#w%s#MbPE zU8Gnjvg&lzMQU^L;8|snMuXle4y?Hn$QRvMQ}h2c_Z?tz6i1`eJ!x~!Iq%+H+IV|8 zpLF?7ryNewamqP>NG3^SktKqO27|#wVFVJvM2l>av9U=eCy`{s10(J1>+ap13zD#( zzyJHcr%xx{)YSBJS65e8)pS)2aBQq1yrLmt=R9RH3Bxd2r6C@YVztCMP+B_O>x}^L zElgKboIIstM+Z_%KxM4*!UfY#FApU-_AS8LjOwt(TB^lmvWXu&M|Q@7ADracoY+mg zx0sU?CGzGj;hTqnrf*9hD4F%ky1FioEiWrSqn~XTzUexoboga5hGr~!ecH>yUxFLa zDtt(o0^+gQ1@i{BR#c=Q7!ej-M_CL1V38MGJkaCm<{4@ZG}Y2XnKx`YGv zOFWmpirCjy?Y5+ylM``NjYNHo_9S!f?rW~ueQ04(bc=((VKuC;31}KY&m&lEIFW3xSA%7EgT_xfbDy(Tb{9Fh?Vso-2&KsaoD59m zffKoUl4NDA!XAK6j#z6FEPxgMEmT(rWfAjQ;K9A0) zmRZ%#{_GY}P4U8hb*8paY$k)geKw zN7B})(+1dYC^Rl-b8H2&d5>>+Y1e4kg62eQn555Q@Wo74$%sD+8EkV=0IeRw% zN|mbI7fx&NSpsa=yp;Qb`6K%bHKX_yD>Khgyq62P)bhIzX54VIB`5{q6}6|#8c zGC7j9@H<{6FAW5iO&K~Z7Mo%#M78 zY8T859D^cOw-$wmF*!LQQr-&4OsEebQcToMG8uZ%^AIvfSVqQak|iE5BFm4o-RIvj zd-;`VPeL!(OZb6);ou{H?H_?O&Du<%GZznSi^b}tKeAe-GHkcHu$qDoO@e(7n$=fbfgmU0-y*{_9#z8TgGb zk7Q^^|AXH=2L?|#LD+@bdIv`#5t%o+tqhLj`X&ar_k^#rw*&VDy|G6sZaXE#mE#Z) zqGO}~fqL&hwk#5Uz&qlnsI5wp&)Gte8fbn{aHbZ1Q2&fHJ%@fh_J*+co{QefzTLNN z*GIRM3|%{T>Q*F~9u%gsyAHiTr%^xm3Y}#Cc<2c*GCC^UP-q{YmpFR+BuajY>9q}i z6<+`Cy0;&ByJGDrpPraZ-jdk1G{~s|D;z|k;X=3>bsiVR=7gUB`{X;*roDsv{|Aa< zA?kmaoU}!BDDX^iKT6`AY4WB-(`cpBqu_>vUp=nwJh5`hOm!>JwMkr7eZmu53be~j zzOYmRm^Pqq;muyp>R!kBW%@>13UAFW23){h@yoTsI&fLE*`U&7UxTH9#+CP6!dh@y z&(=h&QHspo?9dR_oM7$^M1$K94Z=8c=V&3WYOG_}1z(g$V*>!RpDqFF5UWwED*dKz zpzhJ3y@O`yAkYLkrNz`=YXGYcG52VCHZ80bJ+@pqtyn!?T@{zMx`wE=vTe8TCFy442u+hy7|>!PHr;x zOx+fsbr4>gT?2O_=`tPiD&EuX7y7|{b|eCvFuM!(A%j#V(aOwmz0eEpt2s7a*$&b!dtd2< zng9b?+W$(WM6TCQsRo{`X)UPS5`qiByNK^@fT6x9;yu=yHkq727zNjOoW=?xVnwce zLph=^_(Jf3sBL+6xfm7F9M3=PNXyUtGG?kO8rXmn-kvJ1+}A`pCn%p$#^ zsXX0nv6$(riwO$wxmsa>>1KbV7Env`6iZB^nD4)#*f^pcfo|Fzp4(jAZnaG!L3>73 zATZ=hx1JJ@H_*`M^~_7pHg=e6?2qXUMD?WO~Xi@|dm4*|WK< ztj%_32{;ShfADFT)d$ro9YEI1n{q{_qGC&faM?!8e?g&-`3L(f;=g8`1@A~-Y3alK zP`Hj`kp)BJ(m?<*ImHD1?(h${aQzU=aGcBTnAOm@&>u)@wI*(eFS8?X7N46{e^Y zQxx%X5NXNF2rnPOjW?Odle~C^bwAm#2xg8-_$ZBbYu4p*4!2KP7cHqb8mv6cqCak@ zYhnA;wI$IygVFL3q$LvGVldQ1d}t8@nnAh%&GQm#9)v6nhL*!$DvwTg=rhHStFPZ! zhC>$OWu==M8&9n=#gA{O-&9_PK#9__&5cc`bsMdN<>m7N{!)Y$49+Vp?bI7=1Lfs& z@fl+n!=UI?csf;L28w~l z2CUN_p9c5;&m}QnmVkXi-9ZC*MTo)w^FN!-fT0F*Ynds`GlVYr=p#fEJ*LaQt4KVi z3yvoYd~)zNgY5L%rVAe)NrFyDG+4~JNEh-9wsdK<5FP?A2-=PDnFY z%(dt(WEq4lvC8#mG)(SuwuCRIR#6vG*ATyuID^G7SW%c1HQk^0a*Um!;m5S#NdhW` zYcS^TCNtwooaMP{tduh_7v79xDd`H~r#2R_G%e#4VYfFZLAo;fvzm8WEUo4CrMEXX zPgkvB7>U$pDLr#W)$EYcs*o7u?xD(gSJt@WI*pNC!*Vj2&s=#CQdweh2A=|lYa!3F z3W+A>(_1*61vFqkv8CA){4l${fkX!nZRWDWlQB zsxH&Xl5|WM@ycyVl~ZZ;0hdK?R;XMmcx_3i-R_1T!kVh8>z8Gh2B)~g9gbuj0DhMo zAG?=3-2hf4?HyrnR|H;DF*6iwbyT;qpE5ohLeQ6(vd5r?l<2|vTSan|WJl zmhm!hu7s0Xm8Kv7B@x?{Xb9*{0i{M46dr5Rl-jKI-lbq+`4lW8ZD_y0kbNKNji=+v zzb*XusmUi)BdgUvc?qYE&H#zS7$86U`k$H8{G-VvJ7I2Ts=_{&kuYgmDwF$N9v@HB z0LlH20}ye(lv9>?>{gPsAdRGhHdAJtx3elUMNvbuNRsLT>$)RtPDiCt>eSmhN(N4= ztgMw)^PX_{#9c8%NbhNIRW4399^gC@2VOP+srh#%G)kd&*0xG>NU74Z4+?uA z!yu`ecg><53*4XGgX}(OKV~8#k4q>l-X2L zgUlFF75%hkDNc-T)@e(P#(*6AX-lSuUA4BlzJj0DQKm6j0Nq*d?TvUl{BRfX`MS$N z-kZNk*uk8}K0~4__2J2~dMq$wl7o;I9fLHyY4rD<)AbS=P19^Sr`M=UozC9M+7`76 z&8?mb$Ky9_nt5q`Ju>Dh?Krb=J?i(B!lldr(y*gqzpIWE$~y7G7!7xf zKG@K#RMITX2R!bDZ8!*5335y<7QbZp_$Q}!&Q;PK~4BBUH0qf-K^(ru;y!k@OH8$>O?MocECS&!n;5Y zEIKhk{KYBEK3yVBnxe*Vf2i)bI{oB~Y&?fU7;9O5 z?%V=KCZmSJ0}q=Y(hacsr_N&69!pUY;dbFEPD)N^C#gPaIduloBJQVNM)=8b0-qo6 zrUpm7qt6`mnWNwNFWz(X)+Y5}T*?o~t!K3gWzcHzNF^Lt3(RIqS4DY`!x?})xfLkf zS_e!fOHXBaH@Y=%Evu3#BX)~hDrM0fz24H7z<2z@2Wwa*y5%U|GMg;j73h{Dkp1O) zMj=&3o#+;6Pp`A~C(x@L0pX4ftX8fX*9()it0F#xP=$kQafVaBrFcuLF%PD22mLMU zSd~;2cI4YzkDBXCkQ>Z*2ES6R)!-zY(RPc?fwSaVrwEUaflJyfc4r=(eFtbg3Z0R_ zLroT!m%yiHUjkaULT8$UKUH{0?Nk^n1RQKKyM6g)m~Zr`bzL4Cy%b@)UFMeT`@k4b zDK!M{uQz*xW379XTH~ZGd!Q+*}6IxJ1f4l(1nuPlgJ-$GA zxfygDmtWDch>k3~ymetME&K`$G5645k#LVdU(i19^w;n|u>F`v`>#4=J?7DYtLS-) zL1mqASGIjbc(nmcLmF6wNEw{xEWg$P4}#`#X$QkWT>W#r2aab)z#m&R46?JbZ1Wcd!o~1RB=4A^%kbV1+Xif-TNqLsH?qW!;0JL>sx8?(;)l_ zyar&{?U`O#HOqx&jG}XI3yYaFGl2RL#@W+5P(SpCoy_6EQL-tB+v|kPOJB{D`y7X)i&*qIKStJp~B`LEbTijl^k#)M*ayhDuu+T@+@w5#*HSQ zV$hUyno~|+LZ>qDDjj&KQ%JzgriRn%>sFOSDj_iFHRX;q;HMCzEMb-20AP6}vZkr& zoH<5Mhu2bROf*8ER47Yb;Av;MQZ5I;q*H~Av9~Rxt*9;2>GTD**0bl48_K`Ebfbs~tNTgXYT1-FTRKbJ@PQRF8 zaOM4jOKdiUR2mJ1*7sY^dSjq}u}YO`Zh2>{a(RzgOTLp#c<GW)$KdpblHoLz5in*KaZE%)rv^wx4 z>W3B4bt#Ej!?|9`dAK zOs%l^$tS_DQ0K3_`z|1?hEdes356IpRq;$TK50viio)~H1JTF9Ey9Dsi?LPNCrd%a zYe2gi4rK3zpTlRe55tZF2V3AE?o}J=)kmmTVk@-R%BhRMyeGgq;hJ|^db5v5LG&_U z>IUZt$HQ`{6xM*9|2VW4oKJz=>!>HLvFe@VTneeg3pT6}{*?v%>g;O3{|U5|X7?;F z1ko(ZUd=pqAbU6d7Q7!<5k`FwpZ6A@-`pd7{s=I40;&_3F9S?8`*9E44(>sexK>y~ zcO4L>q353!ZepgR_g9X8e}46fi+eoZR%OJ`=kVZ~?C>GLzIOeqfL&v7`6WEf$RI0| zNbN>rebjpD{f(}ePG{kHnYEe3CIDAeU}1`#b+ z&L~-&O0BQ1-`3o8Y&2(%0yVm4jl<1NzZ{(No7R>Y z5@cia=e}SbM_ToCYBQ3I8SyL05q-2|#rb@PIZDP%<;m_6lZl?FpclQp_&?GHQ)+Zp zJ6#Ebr&JN+fJ74Vc!paVmqsG>Mw6XSN}){ZMT?w|wHZw&hN0OcEtTLyf@Mxu_et?Y zkKGZFC1nbeskbVg)vhg#rXef~hL&bB8{)#_O()l-RwU3q;vR@bX9PfpvC-%2Kne-{6^un9 zs~Q@%wFr;)UfI#HrK~Iopx^0oz}rBFyu#_M$4BOn(PwXVy2_=(ec|qatHJ4M^@a!W z_pH*~C(KREAk~euN0H)3cQ*P$W9iu@(wd)0XposeXz`F{{`g|QGT0RyI7VY&8HJ+M z>ziMfm=(0g46z!S0a2YZs#!Vft1_re60<_0vAZyksoSL%rb&Ep-eqUVj8Qs&|eCO!!hG%;`8H2-(^c}Oq0{vGj92$*Z zKI_QM{&v$6zJhd*}f;7qtPYM+;e5X_65N>tIKX+k`{gZrVmGelB)NAs_rRa_9QBStRdFyXl4=q1)y!{qf@ua`i=3q>*MPhk9&oq*6nEUIm$G0 z4X;+hj8W-MM$a2P=K6-lc`lunW&pg8QJ9SVjd-n>mlzVx=+fHOQ~HDDayiX#!UuAf z$2Az|-gTmJ&~ea3`xRWLEHw9oIR6x*5iL4xECOF2l;db3z=&F=_q&(%$HBY8O~TF<`0x~50O^iY>XiB^SnY&w5ViA+`S z=Jj1vo#~SBW|wOO&IBJ9gPQ;ya(iaP6VtuElmTg-b#<4`ntE1EHOXY`5xQ}OWFlMg zDp1~o?F&svl8dX2SCS)T zHw!6zhTJXX-zM+6Yz}jb(2e=J4XyZd(27ry>Y1T&lq~Wpn&9B!pWMb&6ELQbKLAcD^;kdB+9W&&AX(VnDZWndV&4_*9mkcH;m^IL(JdVv zSN8)$#oTDeDaoOcgH~WQ>XR;4n{NRqnOzb^DvBFXcMy&E&uAvgi7h;yg$lzsLY9ay z&Q40N6i)H&>>0Iaq&%Mtg%-xkr>Or4{a)8 zo)>O<641#?_fR}FXm>auPEOTX21c)|%G5!auBy6a{fr%TsXjdqE_>=D68R=Dzbe$fR0j2LXh&UoK+l04Pkw-F6(xkJEW_?%Lg3^X6cvWkay+t~csMKf7=`bv zgjQx3Q;Y83-<7`)a&_eX8M%X4^Fn*rQ)2Y}gmXi9{~U9ollbV_f5L(HD`m3g#>QRC zz;jvQt3UrK)o-yHcu7@BWJS$`^e)g?-|)L**WO-N-@*W#DgnT-$1^)oH|+KJaoqr_ zK9?hN9>x_eMnoP)EF2umH9%fIt~X;@Qww3*Rq*YB)02r_hdm(ILY*KOHF~rlO`RF* zo5I(N`IUD!xAaRT!SeEpM`qG0h1_d0roHqMwxmoZ1E4e#UftMuZu|NV*MoJRt&MI- zrn(^WYBmR$?v|E&M~822YU<;_Yt}lKv&vvF(m>DvKIQih;A+UoLO6}HP+d5u`nZz@ z;^8V&QP&W~;MmZ_&8U!reQe_n9wGXEY|keC$QgS4)xl-A57m0BEef<*8>HHl$I}^_ zvM!3&tI^J@Sd}1Xc@;#Ap_0ozX0;L@KzUjCW<+LE=t|7ZOG4plz1{+zpUcodqLoMu za-*4L@u>|RL<%xK|Lo+I9H)Q-7etq((#M3tF<{h5405?u8HlM+i%D_>;grmhXO@5^ z&n?x~`u*K*cPY!e^}3LXc`2Kf={UIpz=}x8>e|}Pf6e~WQfcAjEdF5YHk)hgwsQGJ zx>~P?oaA6=T7uWxRz%rT5N{0PuRD_yBOZZ@q0AAF{!Q46ifJssc?!lG@UQCVJvEW& zLwqAuaVp`Ej#D$pg0<>&39mxUFc2shxnAFztQidjD_K5~N?$enP~?`l$Q7w%h6bMiXfv6cL(vXT)&-AA*n)zz1Fz3lzimC$L`EElrdTRf-w-?RnfG9F6l>dMOF z>l;SH;X0$y&dIcz9A#kTv{c4wWKxStZ~494V~7tOYtxrI9o?0)jt>TW5PSfDTBWY= zA~wOH^RGjwRw@1F-mZmqy9tE7-nq%dn&jZM{h}xXIKrE4DSo;m?dcT zYp5w`U9rV+k>wT46u%Q4Hs8SsM?L*W{ub*NA)NPtEZJc&DA6o)5b6v-0}Td9vy6t5 z8w^vc@GQqzNo!-{9V5agJ`j)fS}g`nk`6~kGq2Ot!CXY!m$)cC%jc_rQvuF7HdMLN z)#mj!T9Fx7<#N_J)>f@3FQ00(HkFhtZ(VgQ(mo-04?w5Q-WRVMvf9kx(06ZtvFOHW z{gK6)suR#iUlbNINi@e**rzmpq=x)R|NSueiNkymNc>e=gN8xMCy>g34j5Th&PY`1 zL?}PqTzhTZmA%4#FDP?Y8w>`HD|NX#eIL-?@k0dXK%m#?>%x785`!_K0~$|fus_o4 z^;YSO3Ad{^Huuy>Bn-j3NTJne6aH|D1Z`xW96vw`T3urDouoZc@#)721fAV5Z ziAgvMQgD2jnI4{h9WIb%)_Rst?N}R)HkgbyiHhewm1tBn$8s8_GGN8o8vyu2_7}%7 za+%CywRI-7_VDPAs&tpt;#TxC&mWraX|TIe#%K&6Ay&4jsqq(8qt7luYgSk9_jkJ7 zQHIwk7@m=6rObudLC?zihF`=JNX`EcPOY!Me%7qJd%*K}g!|A4&qQHexK200 zBaQrUF_t1DrcPoTjapqYp!Ze}om^gCZ#39sfzd^f!9(}1>TX|CTH0hbIV4Ic zlJh!R2|2WSHfze#9W9;Z^OpheEy%=Tr%vg(xcO6%ec#{ebXA$kk^q#2 z!z*fQPRJ~LWFc7i=ptQ}%iU`HA8f%D_a6-?|23Yz z8!6a#uO&X;m3K#Jn&tFr*RtNJ8_IBE7>7i~DTRYt4o@HXdS+pGd>99*4cUv}CajhV z2mI}BSG5Ia^hc&B+Hy{-CR@()OLTR9f0xS@Wf&>PDmb){p+5f&&B-X5lk~X#V4lFhTJ-2bP0HnJve`o%XHrX$zN(hctS}SYfoy@h zki4Il`;6JZK7(sdcbLW~Izi8z;8{!-Pjw&WUxcA`f9UI7s+LP7!jCGTmc@g?#no}7 zdE(^SY>7NoYD_v^QzBg#Hq9Kod$@CJO?-A}XoWr^LF*;rsM%|z8|v$Kt)F$rEHLw) zSygk~ZZ8Db=T{n?6$H|@?bVJ7tyT~G{+Ht=NI`X&TOzaGKUw&xc2hb%S~`0T@j@Za zX=es;l*H2UZn_BxNGIlj9?wK@ZTljJ)5x>ZOlfpud;2+c9i2B0o$&h5&?+S>uWxR8 z__(>ZwYANavOI_81xWaS&EEDRNSBpvtdBNtE-Otsyl+Mv01S3^K6^sxu}@9y9D=Z{ zvf{$UmBW=FwlEg1*6P%#r+4EujCj0soRm5WUyIHw><9bs65bPuoIa;Q_3Z`D#r3vcwVXeOc0H4)bV+Egl z@IfInF|OFsJ621B^r(;>R7}=NQrwTX9SSN6JK-P-X@ETGmh^SB-@j<@4_!tbXm~0%vXiOi(@5CMxy~BWwo)o=Gytoo*5Wi&ND8T zA>(OU8IHujC9AJXrIN&=yKxn)=(gD%z-qPhBpc>9>^7X8&t|c7#!`J&ix~ii#nKiA z3$IM4>yhc2O#OOe&9bN?VK6tBmaWg_a__=+wp!ZJC#g^Y zAx>kp&28&lA7$?bhu(t`y&LVIAmnhgID|IvQ{B4KQnYjQ)geAup8Jw{hJ6}KEE3UN zh-%MFF87BGIa1p>!*ND2F;IB?i8Ok(UHF|D^xA~GXpS+|g)2_%tDIL>Q+I6rwm(nn zUh82v`Ucx?Ot;wXrs+(w@!>6vC)LYi$0R$Cv6~ENw~*{Sb%#tZt6AhPK^vY<{gF}! zK<||1U903~`HoX}0#np5|ChC$)6j&eK2d7{h($fqV=AW_pXoght^Xm!(fN}rt0}RH ztB)99V`9r>GMdL%e;F^l=zn+qH<|yuHh#UbAPnH8yBW1y;Wb)pNIJ`CwNe?fqn({+ z9`L$7!*#7If}skIV{9(hf~JPiU?4h!#}~s*tt&#oG7eoh@x{tusO)y0Rw)%hn-x23 zcv_)Qgd8}8~SQi zmqe4uU=IY2$sX5Ry9Qq&dX=ne=&M~5ElK3@whtKN=y~8WnkseuCe)T4*>tF35B;mI zLyNH{ex|C{g_`Z@7DZ#lf(k?Bf(lw++t|2Em!>tiM2^C)F_>5uSF$W|x_V52rTuQ# z>`bL^q^bGW3rjmrs;J07pw(&XrO*0CK774(5qfEo`QfLN{X5>Mkr>$DfQToDcUKj!eRguHlz;uZQSM5XugN#|LEiuxT3G*wJ zNS%fw%&$r*ck6$Cerff%`PInL?^?87u-Q}dGX9d2056reEJiPy89ZHv%yb9ReSq0& zn_lOsGO8`S(q+&my=bP*hyg6tzACp}BEdzt&~`5e*;B@`h9RucdliSXh9hCrI^{pd z8XAXGjxQ`Ktqn7Y46(*5dDdW&-gAICi`_$&Q^VA8)P;yUsOjdSgR{UJ9MN$n%_SC| z85Ze7{|mE!?oM;kY4OXXJWXqq>Zm<;xy=Qmk=eRed(E_zf={1@|DvcgG zA|Tao$0sQLUhm?%#E{d8nmG+zd}#W(sniEF_&n!fQ|Zo_RTk;buW~e%5{cBR(K!)F zE|Zvqx5ZVy8?Ewd*n1~PP@IDgB>y)gC=?9Y*KAnivS_M)rY+8*C{icvhjKZ6F z(&DP2pEJwY9F-=K4o9+>Cj~T`CwwS0@x`>U#k!D_GskY+xVOE1rh=A5)2UlG&A+O# zadE(3A(zNGxx6}=x_aHTt2&K=DFIvB5$|=_gV-sYKC3y{Y&H93I-Jk9%<1ZjHFRoq z91Hn~&$pP7!@iD=hgX?aJ=)nh3vJ2q*tVXY8~f{~KRkc_ZOzSn00sjuDvcb=02si< z8%pO!YUf+`MyeyrnKZ6t-HDk2olmWC zDtWD3;nKQ$%Lh(~ngeo~;t3kEEK)}`alb9Dqd8is0yOV2LzcGIIy?ah!vFxXHXM}6 z$`M+?TB)ZQTBW6VyPlD-);cGS-osdMZqSyn1UsCuIsiO2B@%c+y*`N5P%Gkv>bRxW zPGW(Nd5DzSjEdh;Ntwc!3YH^v6)oDaXri6)=u{Iw7c9YDiRN62vOcA=6m0S#; z2JVQD6}uWUaA}di;#mN=;StuNGq*)873T8DV9ET;Gno$A!>mrDO$Kdgo7X=jFnmcW z+2~_l^HdqE4xat9L!?PJanF)h%K3!9YPGVoL@oGvGy2h^pYgwgR{`5vB%_va}_+L%ZV-JGDE7DVJ$4bMDma*oOc@2f6@r^<@gHT#gJco|ovQ z0_CoAo6*lU^h1B*u63Kx&sOvU{f((sq>|}1Q49HP%IBbx$EkVkE|t`6ws?`kw57!r z195MY2mLF1<<-&zgz-3Sc6x+?Hn{P3aMwmiI~Kuq*a{cj0JGn~5kQ-520eJC9sfB* zwc$T7Gz)MXt5Ydd3=MC+=%SY|yb#=Q;f1e=zu`R`X8+9GBsm62u}Z`j8Jw}Oi)Q^P z(cg$GjA7l&Ki(T+5Ty%eH2TweV=_&nA2>667n~0J1l#ixxyvZKNxt8O&=NB>@!wnsZABxj2AB-jR`ba<-wwRN)RC6pdWvSQW3I~GA zn@gG<&Wu~*RBOV=-hTU`I~hiH9>Y)&Y-7G)`nhkB27#PmV^U=bSCDDAAh|3a`1^q zQk3_-ox%zVMNalb>o@`=65Bs1fZ*$sQZ~8n8nPvY!kN9PF@^AilyhQFFsRiW)A%_g&xdE=a4 zO!-CqG<#<>I*j_ak9nS%$9<3bS2xkGH?e=gWWnG}6@4^(A~7L^gPFHi;xU=hPTYI_ zgx(8ht&~~QW|I?GjixGxv&tx!_>6{9twzVNev_$O!`=&>B}%1Su2hzwq0P42(a=nG z``qDjTzNg>c9p5sI<%R#qNR$qU89j@A^3lwFO4YjGxW_~b>nkKr!RmHKZJeRrSM$( zOS&FctHJs^{h}wk$OF&ay_=$8DKnk9lY0Q&vy;46yg3Mn(VpM%(y6gkW=>6(5P5>r zSHAuX@MTYP*=%j0$W*)C?X+6aZ=H6BXH=t9`Sr-qRH!vdCH_sRP;(Ew0A3XO!p&xj z&0)26l!RI>7CWxZ95VP3rb@2x=nX!F0x9$gH=-77XSOj7>^>yV)Pzg)XqORrh34SU zCt#QGwEA?NJmQ&=Y-fID2PJ0k%Er|-tK*<#8KU<`%s%Eg?tMh>rk~@Ne=A%FRhZ3t zc#jbu52(a(GP^;htZaRC?eXzg3%{0A$z%?ltIBTAxWe^Dla1NLstG7wJecK9iLE_*6~+kP5^v+zl^!XJ)9t)XkcLLD;;{u5mU_$WDrLN(6V|$H8KGDS{5=zF@8-*pdSF0)lN5rZXoKY+oMxTZEm%r`6jy zBZ8KYFEVShzsY40c8#E7?q#1wa06*&1$C3K2loZRdzk?QuPDHm5ct_bkoB{>5ZqXR zZxmia@ZSm+W(L|1LOAM%!0!>BAoxw=@Hw!oR7tQC6R?+2D=`IfccWg`b7vqpB=8fm z2MGKiqP?8k#)K#?k%!~T6FCwow4XZ-!KDRwXHG!vSKx|N1YcHwZ^!tQ1<`CLcLsuM zWO?{;r2U;ZzKg(ZAp$={-iv#|T!-P{%mV&71dhMKujd};Lf}F&suQ2vQ|vt&D~F#$ zScY7VxrbcSYr|>yZ)Vp`l`#5}J9$imEtErWl zhOVPzH2+6f%v^!*gVp3ddX~A5sYCbUN$p$iYy`ckfXfzngAbz?xB?AZzzhV(nU#0(CWL)5 zfzPM*fSVg8Ql>S=a`*D7~vb!GP0R8nWo<8%(i!Lplc zYnvfVq*B+e7{0Wss?Vwl*l-27$|J3gqjBd{66=QXiOb6l*l_K4Zyt5(J;X9g!{i^n^-(84?GYE~? zZxAne^3vfW2ZE9+O6=>1Quh<+{L@rqe!d_(EQfb1biIP2=+D_t&~<=Z&msAN@l$K_ zZMgx0#)K~VErJy!SfsuV!Fnj)_AFJgpX`3rk5qnc{GF(`@8!N>WoU-O)O_J|q6N$c z*OFF}LKpLA_5;+)MuNX&(LZxJXrVu%ui`A|U2Dho8{UmtRTWms{a`L`7s1bF-$C$5 z0e%yba%iOpmywl{-_1F&31UfCD_l+ZDunq8L!UqzLGF3X-P}wB)!;VZ^z7NxC8Auk zigIyY?lCZ3Tty0T70t_?52lDS@P1(iFnolvi`@D~fm<0eS9t<|MEc!AS;1t_i_EEWrJU_j8nApm8-&1iyuhV`lED+;Y;c z5?7T%@Vy22zT8HlXX(f)E$Dm*{z7gG*7*<|t&@VzHwK@yM^mQ>i#aF(vILG8&3-BD{%3Ox8n%0!O5O_ZMt-~UnM zYnzBYLMgyh5&L5id*n@BaZlhoimL`;mw`sIV)Ko%@kc0oTf@#_tBt7O?Hb-IV)W z+)Wo!3qg%2sjd|z)k58u;@%q;u}7%cL>tOu|4qamk#hy??U+jo*rU{kB6bt|T>%@z zucWXJM{2E-)^9Jg&J%o6Gm6mo$$aY(MB{t~QOwog?gBQ8xjJ7DiRgz<=dt~`FMEZl zWETzLT@*(lK}mk65T=ryB7}De49D|`-Z>xf%)=bE3Ec$m4+!rNejeOfc%JO`xu*~u zYttd{aN+q}euWBGjgzrFSjyZ;<)!Se#z|QWUqmU3+6(`*h`)u|4_b@6J$I&vzlFKD zC;`}S`45Zuuov;f!aP2EId@}mO~c;T9EH}8izN;byAMg(I||q-?oAQ9?~9cM z?2VFyh&@1=i{nNkIUr&WJW?F@u@aw%jW~52P2U%>XZ*Uz4`UKLoR`>>#yuvvLs)W; zjhYGx*AZQ{D07!G4^r4Vnq3TBGB?h)}Irxdnh}o7F)km z#O`^t(06td|A~m*O;v(ap=~2~kBHsTQV%w5t5xa}hfI+eCFGTFFw|*+pgL~i*Pf^Wnb8_7-=E5PeXI}4Fs@C5&q zh`)t-A2eZn1V4@2AmVRfZpk4XfLfaSobwWEAFp@5yICM)7UE#hxsz94Ii;N#vD@DVk~^=4GWAEsU*`(PelA>w0d z@)%z@pYxKn_ho?!za>;dE1$iXxmLtq%GBh2Z^A=FuP^%0mNIuzVWPu$iN#seVV1Ht z=PoMR0i^#nksDfz8WN#qssMk4^goY3D&k{qSSaEvMEqf7yW#$8gh$z_9L0nv_W=@B z4d%mo92cOz65Wjo*AX8|2>Vd5bpj3$`EC)e#noO5)+mC*yp^g(@CV80qy_xH<$VYU zei6a{{RH^g!nNbQ%y1^PwFt*Kvk?Ac1^C{)?*ieE*Scn6YmI1K*G|y7W`Z50oj)V^ zpNN)qdjb9vfuD!q_mTFWEWm{$<5TB~_&dkrQ`_@CAOzn<@K4Ueb9rBr55boc{QC=V zU*1YX{r3_4n+tSv5%_%w|7C)|rvNwQ_gz7Q^QIvB%L?yp&mD{44T2tL4MA{u0p6E8 zK9?)jXG2=1pQ6T9(X>pe*f!p67|zfWgE8S79^pN$a6r4svuXRpqMH9wr6yI?r2V@` zM|U53XM9~vFjIJOQfW=p7Zd7BIlHUa7ynWEVxAEH3ZL_QX?nYw{PEl@Zxb_y+Awm_GNJH1*8H^ zYBeLa`l;s?n{dGPr01#EfV%psw?MtH3w$EnCj55ZFtc~}&Yimtc7ovR;f206kfZ@o3o6kHmX2Bu&5P?4>w*T;0`-nybj}G~!oAD#E z#Bn|GPZmdEqT#lM9?DeEsT~o+rD3x|`okpOyt(Z8Ur6jNQTZl@?9CzHjsR5!=Q6(?`=-wvmpb@F3eNrTLyG#pP)i30JN-@ z6aWYa2mrlW4qE^K0000000000000#L004Jya%3-bXk~3>FLY>SZDlbocx`O$Sxax* zHXOeX*modwZ)Mq5>I8L)*sd?*~cw@|DAgp?xAG<#F3`F4inWVvqYY z4%*i3LH|O_LQ>(_$Bf6MZB2-@uB?Cf!DYOrLJ|=K^s!vSZ7WnNS+i~F!7`Q?c|u}% zHsT_}3Z^2keSr^vZ^Z0+t+rxEn8p^0aRh8{jYiZXXppkB)~C#S48CF|(*=)-T`!ZU zQ)F0w&q;seM0S}#``2MBUm1Y&6fkH;( zy#;g{&oVM4WW?DuBfJIh)-(ZTC|k>}oIX~|axKF5xab2Q3ocePMrx9f5%vJr#f%OG zO$FdJg0(04k|!6IQdvlPf+nhMeVkyZh#BPNvmakRdxDPcKRvqt%h7`eNB4g=P+h}u zpi{m0{)@jKeTx2i^4*JvUzzbz$N&D*XTSaWr5UJn;PbB^|MB$k^KU-?^M{89_=dnk z9X_BDk?1BlKs!7F!wdq*P@Iio5MruRY{Y@YF-~a==$;BI=$jMFumRU0RS(_~&;m@r ztK)kWg?B?SR@4Bz9!3@57U!(Ph0&(#sVvSA$Oie7i zA*raj%^>7BATd!Wea80)F_7J*wBpw->Ip9SNTItFbucx$WI%_?OmvM#5SNKbL5O$7 zH(Pg5hcgrVO|oA_LRDa9Vo6xVjaTtl;mD{lj+lOXNC$**)bojy zCYoDfQc?Fhv<`FFx7Z}AB88%RCgcswxsKfAd)*L6iBV@7hdTBnxd$nV(Kc5`C3v+$ z(mBKd$4kR~hZ1$R+P+PL(3~LYld&+B1mV?soUjolana!`y*i@tag95IzKzejaYL(o z{_UgxQOn){CzxtxzELm3&9~<+7e0OayYnU<$J+!7;(c>|-<;pY=De()&%Y(ly0EPu zv@!#%hcE`EoH3Qnx(nNO0zX@Lfs&ozDjUb>bYo06wHX9`aNeb4a*x0kyF!R6k?wkmNomF#vAdb zdnP5$$H}z?C)uxjk!}%CsXeOuAqS12xLoMw2(2~)JcxuVY zY+5|yV@1Sn=pUdV8;czbdN=dz@~MPQU!P6{9 z!?SUzLpIaYvzO@pil#Kq(G>UHH6_hlIG;BB?9v3gxWFjQ(YD2f3ORJ4B&1$nz`mc! z0=*EFMXC~F=?myoSF%6rTRD%s$pxX>p#c&UI-LpyA=|33^8{v2UEdz3jEX)}swH2{lG<;faN11@M`XD9pxLJC8V3Eh_~6ofrHyAMsCkynucW|DJ!9_6w{mY!nq>$vO`%9~wg%-++w>=c1|1(&JA<6TyG$~Gk) zIaC67r+-~R{@SyYUH=DAO9u!cTB3w31^@ut9RL7OO9KQH00;;O0KHlcTL1t600000 z0000003iSX0C#V4WG`lKZgg`mQg32!bZ<>>Zf`AeWoLD4VR9~XbY`r*2Y8!B5;wlP zujJljS?-qAWy`j#Vl{V3mU~>1INgb5Td^JY-qJ`yO(Q@^AUzOBLP!AuIP`kdqt~Ma zI5^6|9S0mFw)~%0S|>8)|K0OFUtV7ATXtt=XJ&shvr+=W2%#{v9xUKTw!~op?2=@*1=3D1~x#>k7+@FB^(xy&l&ovWg?m#H=CWQPOTAcko z@H_%ewtqlN$LPvuCx0wQ$Z$PE?l)Uq&gP)bwOe64&_u>oco1|3tKdEn?q#i=10!F` zeuVKHpzrrXM|YFcH1glo2n8Qx?>n6%JZ}UHXniZiL8uI2ZMF_YWLj zanmY<;(&j`Ej@j%o>sptS3=)!;q-qHPhWYO!?H(sdK!g8ip5AyawK}ZJ&r>MAcJ`y&K_I056mOfWIitlg^bfI`pPY(M5 zT)m@M`nG`=>clI;bALj?0iMTC|BI()+s`A!|Cr=Xz2#RD&9qy;ussHWo*G86c441(!_fkgx-MzFAD;L5@a?2rQ#mhtoU#_3 zK<#J`x*t7;n$cEt5_+CM&!U^qc97^Xv>cs9L#PsM27Q%*t@D7|UUUlHZiaQf8*PCR zFQPZlY51&%>oIgU+JeiV$2N2y(9!_6B6JY#K(C@YpjLq%0xms(6Fcz+oQv%^5xh$V z{S+|MG_Z>r_#6c)=g=|ebr{`0%B5J3;`v1j@j(CF;r6uKXtHhYd( zkEVZncs1`mvO&Y%W7Vaj$@5tP$10Hitj99mqtaucKRU|jkw=d{&$0Ipj||qoLf9c@bs5p>)FR?kNt0f^GY~p<}-Hb7`}WBc8LOupQ6V$u<3n&cxdQRM2~~) zfe(PKpFr1PjC1f0I2rDK#+oT5SbQ61@%~M~zJG%Z>roAU4xPq#PrfkKI(g01;z=$^ z#eAXxt*JqOM)1hP;D-)aD^7F;NLzwNKwpFCb~FLAwSa7k(Ghso30|@vyx0l8xf{l* zkqY_?(MDMHhv6tjNzn5!tg|$92f7QbfkTI`2OsW(d0V0H?dSm*#{&%>fol`G7TP1Q zddI-?w!-@%;C4McxdJ@BdipD{fC6nmiSVQyt$=n7c()QfuNUO4gH=!izV-t82>hWQ zFufM$V1gNq0iv`(pA~2qtdAk|8k)pUkzDs(?)%{WZjTSLGdqcH1B^3+bX_nv7Dbi; z|16OF2J{(lR-orV`}d=J!S`nZ(^ttKj>GjhWVU8@S-48QlSJ{b6SXK%C zzYw0}fu=WuB_0I3o&&u-3@fk8b2kQOHH>6emUl%SgYjt|dS~JJVW71YXdMP>?Lf}~ z^!9q}%HrO3@X{{0djKSR(SwS&!;@CHo}ncG9!bU-U>ZbE4^g&bn`c74X}0GkDjZop~Vn%()tL ze>=?L2}UL90l^2$W; z!}qZmXX6@t4!@4SCh^2fN=YkOPkv(3nIp`noLWvZXBX#g&TE{1aRay_?iTKkem1|W z{9gCx`mgpspk%LPx^_!d8W?4tp$I9lj_0s|Z`fAdkyS=Y17vjQosW%fE*I5q~mjAnGN7 zRj^C&MKnKpX>?2UV=?hDLoqkS+!Grf+Yx(3?5^0`Vo%3D5&Lc&6BiMe6sL+a#g)W4 z1Y5#_gjER}61FFtOn4<>Dv_6HNZgco zYvP&2zb1a0IF%HVl#rB`^n&mn;p4(Lh2JKJCGQu7i1ea0qC=wh#r+b6X#nkpTZ zZj^49?vdUpy;u5}jL5=d@iK)>C(D_OSnvR7pv$o?VwQI6yx@_hMP z`6Ke@veRw<4v?pHji_^aZ5#TSYn6mDg_QlZo-^Ofbw z1sl0dSCVTw2`!pY1`6n zO}iuQp0r2Oo=bZ(?UVF^^z!t&^oI2I^r7@C(zm4VO8+dQE~6o%J!2^2zKq8+UdnhU zgYs)E}w8R{sRaS#V}_rZ_V_b4%v#%-b}9 znkbD(lcq6hY?>;~VokHAM{`E=h~_!X8=8+aUuk~S>a_XVGVOltG3{CH<%}Jj=Fh zzwE~Bo3p>oiOXru`6f3Zw=4IRJW1Z%ysdfv$z+G2_u{-o^E2oFP`AA9@dac- z>4Jd;*DQE^!D|c7FMMK=U{T$o`xgCW(ff-d78fsWU%Y+ssl~4>{(1>_N$rwrm&%qt zz4X&%Xj#s(-er60BkEVxAFKatdDL>p^0Uh)SJ+p~ThX*)_lkcs-0b8zuXTRcxTx`s zrqZUvP5*7KYreDj7gvt!_@5s4yIysD=$c%qS-Gwysbx*eXRRr%FSWhA>PUN8`vdJS zw13foI$rCH=rnX1y8OFVcAe__y4$Z?(mlVst^48b@47Gc%Uec$(8=;!uF z^e6VG^dIa$+J9gF!~IY9zuNyn|L6VR_W#&FIS?=qF%UZ-8b}$?444NB2TBKO1{Mu8 z473mQ4~!2yKk(YXdjp>jd_VBtf$71Z!N|d+!IVM6VBuit;QYac!S=zS!3~4k25%ia zGI(ZiV(^K! z$k6Gbhll<$^v2LfLthX5G>nHshGU1N!)e3%;ez4v;RVCa;m+Za;Z4KahxZKMIehQ% zqr)!@zcqY*_@Bc+jo^{ck+>20h;}4zq-Tlj2s)87R4^(Z%^EEntsGr6+C17bx_b1Q(Hln(j2<7ofAopbmq*_n{m1Bk$C$D3 zv4k<@n0~BatYU28SkqY7*x1;WV>`z7jvXDlckHRL*T+5@`)cf`aWoz>9y=}@*No?m zmyXXLZy4_w9~s{?zI}Yp_#NZ-j6XX5!uZ?cpN@YweqpuW>d4i?)vDFT)sEG*tLs;{ ztsY!`#p7Zk)W7{@5w$-t1yOVse{l&Iz+qP|+ zlc}1ix%sQ6YF+HJ>fG#`bk$YQ7s#s(!9;bGXzu33$6Ibzws7^(0s zIaIQ+Bv_nVsC*n5Wg?5X)-8sQ&nPckY}N)OG(bz@r%F5;Euh^3hYEmwE$9V(X!oyw zmXim@(GBC!k8VOAWn3TIk=PO2F^F@hy}KR4Q2+;AtdH_=-Y%7cHyvq`HC>J4%7O3T zeVkM)6A|hTa0Y+`@c;4+w+vM%SzUb|e8dvac)Tj&cg<=)Xcx^#VN;ohjQ!Cv=1{`9+Gdmz)| zXL?wlXSVA=nzZNe+zveVvVfk1u@fb{e+kHn?miOYIO98eSLTaH^;Z0n*dbq(3+AWf z{Ca+QX8E^6}^LE;ISdZ7bGs-}?D|@+|^{mqEo2zNZCy zat&!$zZDVG zqAoPp(|UWWXWdMq6Mze6kLCt zM%3DkI(ez}Z+6C%ya`H&6vsC?#0kcIcp4pkTKXB zQCLo}kl834DKvyqGxj(kmxF}IB=90nh9KWJw8wnoVhFpKP7tRr!FD)Y!G;k}F_fJO{q+iZAA=2)g&z=bQcgl|N z6%`|fY&N2^+vVQX>d)7p$}x8_|JOgd?V#-2qU-)=_9%EgdHsN)VaZt`%^MCKnN|se zlL1R{{F5Qeksnz7XTyj(azQs}Mu8E#a7M7U{b|D-8ZwJ94Mw=iztv*k+^|=KEBn_* zM7?-7K|-8~JE5-n+2hNu>DtqHgd4XzjHoxo8e=c^J!*em4MAQDIuPrv$UGyigd)VJ zjnH{vuSD7oiCyFFqdWZUj9-_0jOj4KUy*~433#U96o!vqyY6`A^FrT}vl&9zhP(me z1Z|l5^Q`~=tK}!Zz-oD$fn+Pm62H0K{Y(x+{; z95UYw``Dr3y=N3JJl`;WV!0Ud8{g~bajL=$bCc9;lP|0$DayaAc~7nLgVhw9S-QUX zr*ke{?%nzIqmW3)&z2B8R>p;X@p7|?@h7OcGWk1vL1^Y)9|EknKMkeAloV(sh;2hD z|K<^0S9lF@XY*)`1VoF~CJ;mG6yQf6=DXp$0m$9|n4+iDdZDZQ(fTgG#vih!aW#J| zToBb`UYk%7$noy}al*(pLk%!czzGwBlE3)G{_y(@cm%0^5Agv_Z^lDBWa0XmawDgX z4WN|L5n@v;rj)Pp&);P0;(|~m$9Ii(WA6D zK<}m<{fJ}z2)zV&K(=@2Iergqs|yq)|A^EP^%cSRp@M8jw4EIzA|xOTwLMd$9(3UM zhZ@8(;h44ih20KX793|4gu@BCXb-l05P0m^4GFhsfSVnIH{FER0mos{Eoub{+wddx za9gW8&-O<+UN5+xu){2y*-eDg ziL48#8eH18ym9u+O1nXCN3-o))A0HONk@zmZu^YxMZFpDl*{Xug|R|##uH(CXMoj- zfeJih}kTNf5>-8cboo(|61+Y@*VCI z{R_o6xGPxecIz1u{mA4xa)1qeN}VPRVCbiz({3;mHb8-%^&|cVfajQ)V1@+Zc9sJf z0n3F*f=DP%T3A?`L|D>DSQb@SLQ$MbA(kahmMJ9F2pMh$8Fwb0#^A>}BNB5>j8)tp z2MN3pa`5~Z_0Y&=2_*X%14SW82`tKBo3vpVY)M4yP zeiRJ>%m~qNEa7at@iABl`Pc~btU!8xY-C~oL8NnjWI54Aet=UPo$a_GF&_5SFd~)- zF)r4dbp$c?3Z_^kky^avaKk=VEzpYauPM>*7LeQ(86$G+p<$a4-8zG0c8A!t5hMpl z?3`i75Lwq)6lQxUqFLU39S3|)sY`N%7|0Q@{a6G+CoeD}w0?3nx*Gf7NNOwT9L7D; zTc#IkcR;(O4slgH`*0c}<>q538oofm9nwpRm(XOq+=%JE*!dzNZ|`KMo-uqdmwM`WL{vBwb9nQJgdqJ1~grCo`A@9DJYgJEkw$kJ2atvJ@zN zAs|CBKM^J#%E&d4LbO|$nNgYsWvHJSN}4FX{}<3mv_Aw3N|};Lbdmy-G`=^ViHa;z z!juV<^_x(KNtwHlptUW{JL2bE& zAdXR3#=h}i%%c&EdxRIX-gIhe!F6RV6`^Ze^IYfqPW2C*A0ApCl^{jBrhk{V{l==c z7Unk=&P}b)9pPHuD>5bvJ1^;cEnTHtlgoIASCBl}%VL0V-stxvw;*uZ79%YFBDE&j(Q%21%XTZ5qOq~EkzlPlHIL+_O}eTM z?c|G#+((yx9oqAow0tfWH>{%6mRG9yr`9^a)naMu`Ausb&#K#;xy!Os_$oB6cGcr+ z@w_?`&Wk9gM>R?}l< z(|u-k=y`%%8-m}{(9s=`9gldAak!5)PuHZL2%ZpU zkZ-?aMn@&qsBFYs)ug(<^wiQsi`d=Q47{_05uI#c@279I+>H#XI4U+aE;1`UWEfqu z+sfMbokVG-w6p8VJi8ZmEF2xA(z|20yAlDJlBTAHb@4P7#H`lq?$)#!vW0~WktHX# zdtBTeni=V$#{eYsn>o@5c79Seu0>@7CuptWQh#x+BQx2g^75?Ft!e8UW*0@*3~b95W|JP5 z6uC4}tS9OV_MALcXMMO<<;31jDEM&?iqf!5i>#5Xaq9~lj!SSnsJb$5XOvp*6Yv{s zlQM7Tl=wVG#pGU&De-v=vP4cy6g)H%bkGZuMNW(rUg{_|Xe8OgXD4!<>Wber5<36Q zvdh0hNDc{{U{c`zys(|0PMTa3KeEiFQ-U;a}1Vqe(i zeOTXjSRe8(gh$>sD0I4T$#LV_7TsSsd3|qRnGZ6tDrJ`X@pL77W?EJ3FRyi-nPqlG zY$Mrfs<~xOMPehf(?vaPZbd+&4li~+UME+iN#Vlme|)oXx~I}aP1je+HLI+phPd7p zQ7;LO*88K<#171HZl2+U$@kA3w!;20KZpCU2SfWp~$r+dBL?nRvD!2Fd*e3!7(I zjBkTZ1Ut(#c~>@t+)d}S_YO+m8xayhD<>14*{EZKJ`&#Vcy$Y*hT~e%24(sD+}6=0 zx}LMcn;r^lo#ne;&CD#aOfRA`IZn(Ts1|47{=_4;EZ5nyEO9jZ4(H#i76EPP=Tok4 zt)80NnWkL7e>rKwSXa~+7)Elfo(7a#5!{2#AO^GhyW4=`{M;=1XS{JwmET$yDTCY2 z?#!1FP`aXi)UscbYod+TLibsq2&MXZmHotwIqeHo-K}Y~+d1oS)joUFH z+X?|B+dk(mx!!_BIC)eV%dXOFr7sx>$N2qyxQt&*L1$!catjj1p9y3v$6F{k9Uc%-4lEh=y;%D|GdPi>V?iW)7*yLUoGa8Ag~e4LwFS9*N~HcM`q zDsX8iXVR>031nd(JNAt`a@qdOX!Nlj$}N52 zdpKp6!Dv;=Ep_30*!MEkequWWP)R=qTRHt;P;fRNx%5*8y4LExBeJt;=D{*;#E262 zZJaCjD%{jAa`W$TM`WcgwssdA*XDOgGNnQvU1FM3{6y#4WKzSADcv@JW!?3tMCS+oAhBKIk!d&{Xha3Z~fq0669Z8m_04$KF`bN?o z4I16ASM%S7M1@8@M&I5&-Q8i_xp_==bbI=OcIo(z+En#Ombev+$j8zo7-$(bWvTC0 z@&zYyQlo{jqyyt-Q!hTPMwjDq$LA>$Cp4C=hF9BWSL0(fQAhiYDEG%`scnbH$GhXZ zkb&y6Ft=AmeJML!$(VZeS`Dut79c z+oBy&XpEv)?lg&RB!Dk4ypbLLj;M=)lB{3S$zy9{=MxSsWIQ}9EIeA&$t_mK7Y^*$XEG`!bEvnXbtPNRwKZEt771f> z_2%Z@jf*HR?k?V0l5P3!&r^Ex)9w@l zjIUS{hG0I-vrfW0Ovqt||da~sLQpgL* z@4js;Z?E@FOfHn+IqMO+TE2uP_riVaVRKnY8jgTbq{=6n`_xL_UqVO- zf@w;DI$?5`eL}bAw{osX!8D5+_UNA|=1>b0aXRjNa1d+}J;AH2+Nqjh-p!$cW(nZ5 z2E1Unu^#SAxEpXhT#rz4usSb|#OFtOdRSne{Di|v)$BRlCb`G(c$-4;>jcxm&FXi) zY)ip=vTn}we4QS^g+y>@MX33}?&-_pwM5Zy@5G~fxY0(5){stMaxbf>25*mY=cwl4 zznV;}Y=ed#{q=NjWarZ)S)f9RR^eW`Mzit~_1?ZmcSxSZ*Y;=&`AR5&f5s>f)MW}y zg30gZbIOy+byd0cI!wI(SYjNJSq^+XWqERVnIX$2QR{z>cCd%Sf8^L0gq^V??&V=hF5c$WZ8NsG+jbbJ0!b{(qA zyUU}Ryv`Qr1{0>)H6!^Kp~>k$Fup;^KhM|Q`1E%e*7V-+=(^`7Xr}|PuedzuMQqde zQ@Law7>8uldD89XKsRO^Oxy|k-R9>&&AOK$QYn{|iG~{}d(0RLpURc?0KU-ZHhjon zfT^UhjH+dx^dQl%pcjC-QSG46ReUvK?MYPWH^4{DjD;*-)KkR$Ejg7ba^l& zKmNoi^S?LB1&acMf|dCq{?aSfG%ZO0*Pk3G;CKgvlFLG*zX_2%)A)S&ZwPvwy0d8V zM-gKl|9EV<6)VTXWvim!8`Al3T){`@68R=9nA{&*_o?m?GYJCe_g3e zN|tp?iH?cfV6HO;i2dFkzTQGv?ATu%k?p-zEWe~G8V9$_KL3%*2UamE>Z*AQTJ(y` z(b3U0%f+SjLvKXP=e=V~&BqmNZ0Ww0l^^K9Oo0Smt93n`$;Nsi21RNmP1=<{hP}G% zExu`6)Hsht0MwW2K+sBTv{p1gPX8&qWr9iL6vuPMn|i|;;d5v+EwywpzqIvsWW6Mw zFrT_pD-Vn6q;jln#z*8u_fPcZ~N}gcAs_j8PhiQ1Nm4+*v<$2ncNR0 zL}w_PJYb$iNs0Af?&rOe<2La)&fk~23K%&q92iUM$G(QuOKBOtK;wcjJxe8ud64M1 z77>vmH5v|^rl~a3I=mFa<0Z3OJGsl={(P_&twq)Pcl7WI^|FQa>Em_@TdGhPIV5Nd zbR&9XXh4ZxuK!^ly3{|xsxI@F+X)YC2^_gZ8cm40GO!MtTO$gqdc^9meXG`I9G_c0 zoBhuZjLtpL+A|;K<8FwKIQ4ZsFYS<6rcRG-)XgzOfb^z<;w)u6HRBOW&%nzIxmrUe z4Fv`GwvxKoJdmtTlh?p_GfTO=eaWOM-LPq+4!JqOkLJuz>PI$A8r2JRO~N(84n~$e z|8H75{!g0jF(qTtbkJj%#qIOpP68eNd}T&2Uft2>y4`Ag47?6B<}J_+fPg7?WL0+@xE8vjMAaMM={n=Gv`e46vE!_A z(6w_4HZGm=At4Y|E`u09c1hm}Px}F6bA|v6R{NCi4Zhuk){OU6YmgM4Hh z{&)-WLq_M_NuRVBd+3KK_b|87tVm{>B=NY?8;6?phOhm_!`rfRC&saL$aI3l}nyTepp^aOrs_vn_c71-A0o=NB!G0h3RMp zHRpg$$nr(x0M$D8fBG#{3$eq2tyyfKzeq@6RMxO%g;UT*50J3(MBldxmWr8~#<5O2 zaU=w#rE?hwYb5_BXJ*iz4qCgexjHs)s(?=HeU=O`f5Sk6i}q z(XMH9jipBFS~W9&uu%z51kr8U3XEl@AnGO*Vo|ZN=ZB0lq73~cR?1!Y7;v{fafd<4 z1w$dsK^jEWFVIvXMm8sQ*HmzbBiO#EVDSN%_ixd# zaZKh8kyUP-P2&F$qSMb$c5KEZHWjz;p17zCDIK7NJ2?Ch+;oVn}GbCX3GYFlf`gu$A-)D_m+%=$=r2emJw)G?jxJ5 zOhyRZ(|z|%JPWt-_Axt6^g3Iwt;J}9Ds4)O064R`%8$H*=GkLY4=oS`|8yb|{2hox z;CCCx2xriD#oAw_a}il!H1_El(ee5>jY_qs$ovDVl9c;xUhe}-?B;zmH+Lv0pFseUn^D%7R)-Qg@~J)Vsa8In13d>LrV8x)9x&Xj;Hs4Sw48(=kyxx5TZijgt_Hb%G-0c4=YUw>L7E>e6ub$ zxLnoIs8>u#r}@=3z@Ku4|4XH>b8+;7;f?kZJe_1pvNF>cJSDxGz4ZAlms0NZidb-* zChJy)w`o6B1~Sb-wG^2NoYG-{Dy?0Mjy{oP`0scj{K9CSd&^_qzxVp(d)czH?3Hw8 zLX(Q(N@>|eVNr{~5l5DC+5zUqh;S&m&I#!y^;Zt(nPK_<_Pe zawzX|928Opsdc1TtA7N8mX@}%8Ss2VheDbA3vHT_c;USjORJe!+ex9J6dm$4!pTiM zoDv)$toMgpmR+J|MmB`B7>Fp8Ou_@?1|`b-H0h@q z$(|3dq*2TM=vH|kJvCRERyyLlO&GBOiHU@icK4M25chJf1Q)&|;2GHrgkrU{VA+>4 z3>ygbsR+Emxq{dIG9xFnL#3Ynbo`^e3psB0+eS%}WURKg{su~;eVW5r+Q7x(jxT=Z zHfZMj#SpAA9?o%9I2TNsA$euuhCEPRdN7~@hgx=Ycx-H#f zimm34n~$T7H_@q#zOL4f5eA>p4%eTKyP&;)&efxB-g&-2hm9w+W&`lKoMt?(37SAW z7VB2f+)UXjV7$5)3@d5+Y_qi32%HtzDvU2VE`|^e%m;cSu0yWpq>Y3FMbp!3cC-Rja z#)J)U24LhuL#3d?_xFUxB7zJ2`$w$azcSkSW+@BE$)7!PykhxGODHt^7t0eVueGNP zMF8Lk_fH$T>hj9U^20i4sOU1?X`P&ouZehKr&a09KQM%`c%N}-I$sVBrr<;odb!HW zsOf!u9GxEE<3}u5fiB8oOWnr$gj%(=8y7a)sD4%wztDSmc8mD>?1*0$K!AYq06QQCqot%B4r1dr7aLZ)E6dr<(0#$$Z^<_JwT$^iISJ-qPe zYDKMh6%SNP1Fb?bIPeIjNs6^rDw=>3D=3PbA*rfKH1oH4PDJ|VtLZjCX|4cMh4<=& zW=i&_50~!BW%V%ar8F5fkgO`X%vVjT-Md_Yfu#UbeYU!J|8h`u7=lG+vv^3Itp`XJ(2`}EB9dW1D~%zeh`3d?0skI%R(qdz9#))Sm4JYJ`d3G$>(MRo zQ_;EDfcztX=DGTrIg)Oba2&dzxJg4cI|jX+ajP z^Hk93Q0lokFv0>wJ4|{gR_62~@*Vg{)Y$~q)o&@CD~0$Gd{t+Fy~FhURBLN zf92#lHL||mTe7X3IB#6XCXrtPlFrhQUqjF&NTdddOgz%i?aI1i^mBv1c=Da6?XT9q z^r2^fTu1Pdom`i@)zE;JDvEP1M@yhh&Mao@w-W)kyD#kw?tapUYU#xw7W;< zfJ1&kaK;p8iS(*YQkxJ_lIYM7J%y8$>rP%v-pk8bIgBmS?>ou6TbsYC^99PqiUqT1 zgZJ*I4yyEw=g%|#?+wS|Pd^j#izM3-XIan3ji4#!9S5+X}wpW4!!)U${8?-mjT zOA#TB_3s`e1*O&1M#QX~>z4d2QB5A|SII9)D%NW9KY@uT#6HqU3LTi;H;SFJ@TUgH zUZD~gqSXr~nBpTv=*4KG&4F}Ia~t0@Erb}p489R%yv2xK5KDSXyewrNxE&Re4IMrnzFeW2eUKqf2Xi=n!t*nQ;+|Ph7ot#?h za@!6Zu$lyCa8`-VFNiy(1aa3zqJ@HjS|}($KvRh*C@`(my;!Z7I~gqpJk`5wsHw}B zhxC1;F`U90{goXqvGRohG&;5D1a*=<8iZ@qjhQbU#vP%Ubrc3yQ!tA(6!j+fS0{WX zHR>!LAD^-tipG)(?O6>3Pdze7{L5(r21wGmD;7E>%BAir&;vx5Kmg2QGs0$<-2(PP zfmCVO`BR0KS8lNxUOCSnhrW+Se`wcwPG-mYY9}6EZPV#9SGN5!Y82$a@~bC5ZOM+a zzB;wQhxFMIR5FXxN%EG0ieUQpAC_McVsCPJ(#rm-0$p2T3|(6`iqBjWd)#XHU+;BC zI1RMio?o@E-X>Bx41_t7hB`#Z5|S{t(X4DZw8QlAVf|7QM2-=I&D1JnxPqb=7OqvClJX8e;APLs#yo=*5X z=mIAGq%wPTywV2t(0(GI@~l-ub3z!bPLx*7^CPhgYnt5#crBI*w`2o zQe#nJ;cIaHlABAp;mil_1X4u_i7<10hguF5DoX}3bN5&Uq#gN2XeN}LY3HxDpZV4C z7vmt8Eni0z61|6}9JxY5#6(22OeFw(q!!&ON$V!m$6`h1Jg`_Y4IvLb$>X6~#5C$NDt-|-Eyo2H_XdMr|C;>FI z{6h|FEQz)`4#1IcA%{DE4+8hf%P?SvcB?(fq{X(%S{_k%=KiZnD!+Ona=*HEIt@p$0gT z@W~=0mRgB=14I;N!mfvpC&e|?IifQ(z*>UcF-;CjTFbvMR4}5Zjq1Mg`f9Q>?nAgbIpkH%{H;N0`Bn>Of^1q$oN3>D3;nY_|1kcv#p^=+lS8Ulwap@OX<;uFw?Fq`C^mzSti|6 zanHE#Qz|ROk^M|DKmv5-r-<94kpA z@sM&Nk`_-SgB4YAdtGD`D?qK%XG?=Mh|dFQ-9Z}PaPEul&H2mFe#B_A;fTO z#RUHWASqDI9{CV35KvGC70JYziuK_8n3*X~v-Z>o_UNmpBNl|p(In75dwe!%MiO#y z3HM`&|H*weA5E|k`vHq6d`FyTU7A*Z8bNJ=+cBDOuO8wm0d*1^D#1PkohvHK_}JwM{50u(s`+s<)Pribrv<=OnXQD1aD|4Uk(_K>7WCK^K12MA=#J^3|1g zZHi`^{B4dlIcYVcdkf(#>hb#Ot`U9!YAoDLBe_#=Mg{1F&7>4UM~SDEQ53rc2!d$6 z`wIb?xaccHkt_BAV_>(&g)L`uv&@qsx5SRhr93`*n8|%`_j_amK?Ora2e&Ug4h>pU z;lEscuZC{q&;zB0TTR!Zjt*CM_j=J7K{eD341~>!NgS-zt>oo@Wqtn=rfTKV@U%Hq z4Jcw_KmrBpd1wenl9FB5KUV7=Kj-JAoh=gB2xq9g**Zkylo9cJ)QSopQOdMZv+`URKUK-?89$o2$+u|Yw4jI zm(=HBl)C8q1Ye{KXqsp&+LkP+sT(w=ToTIJ(O4vRks&tHM&A-CsZ_#hhiVS9!Nf#= z-6rf>RBoBwk$G#}{|lK9v`llsz`0<;NL;x09@t6p+%ZZ?Ovs&>*hUTLQ#+Ls-kMkk`d#4Ql26$B1p7_Xm2*NK)2o% zf0}FTf~Rej&!+T!j#o++gu>O=vQdhZrC(aQA2ZOL+EMkA^>+jca!GxeBD-2b3LX}a zQo3?7eGa^Ye#gCu($Iit7Fqm&{(yvokClfjXrrfnvCR|x=hDzs7sG7tPg4TT0DhY`aiH&wMtev_LX?beUrC_*Vl6jRmjsAc zuyS zBUzzUq!u#zI0RQ9R#~2@OzF z1GPig1J&b6wEHu_UxjL6mCMr6!lFi5vvP4lp=7lTqg<&(5yrt$?n%qbzk&MiL&di8 zpHADy%hXz^;w$$0?H7Yqfn0B7&LH##gR7-+{(i*rcDvc8nCxlQAS`KLy>eG-;W6Qh)GG6~u^ z8^zxeo1oj;g;HD9!ecTkvbo37449@fCo(0~#fh;aC&~QWeBqt2-gM(!qniMZr8qvt z#=1vI=R&?Uv*wo0_CG`tgMEd7UL%EE^>yB^r|KRvc(?PLZmo>RRzP^w>=||Zo(z#f zqAb50MN)~9qUXhjsRJ{OAifu3Le-ouv+oV7M$l-!dbm0dq>0C#6T^2qP~AoJac5gd zFDK0K7le6BuIg>$X$~UNL}@~}4?a?~Y{AThMLNNH-lFd79Q(8u&ZC2PKTnQ0O;S>> zLcW4STX7ckWrAPGDs{X^=v9VQw4-`g^^cWtoevxD>s*B$pYkN*<^l;?h|K+x>N8sU zo)3=z9Ww2rCAwt)sH4@+>a?AwY!vVHcC4S@ww}8X_z;2|)Ss8no}PSL_QTb+114i3 zgV|kwz}mfsW95p2Tfy7zrJP6uQ_G6)5}l7nxfkAB7pvaQOnlFP_G@N}%+?RI{Bxf& z^=;0OEwIj6UihQ<=i#(Vu?67^pL-dv{tp(Ni_Ji_z1>*Dy#0j|W@i}jg#?rPkPb<=($O`Ss0roJ$tf5?b#(yDpEY?RLt zB7CK)I#-PZKxwIXRynDBmeSV9ZcL9vM!pv^jqN_8!Syj2RCp0@V3`*~9}?0`NhMUZ zprt$I#ls8d?0)so>8^9(CC0L+1I5y0Xg&$z4+0w9|7b{9yh_(&^#SDx_@or$KLCdOPk@%C)A~ag z)_y(z2X0r3iFPD_BKpKyKh*9GvE$rGVYEa6oyvj@TT@}-sd~xZ!mr7ee}I5@b0tlsx6XVnDo2PLn%BCds`UdnHmgD4Yt2y3i6A}H(BC5y=5jI*Lxy~OYc!d zrUn<^zfqX%avh~oa@Z~$L9=u9tM&JU!G;{P+U#9#sXOnutj=vPOS*Mrf665A+dLW` z7Qq|X(eHIPau|Q#yxhugS-Ui@xDN81C2SXIkJCw%_MP8-hg+aq^VH=I}1l)nO{@0D_>7#s zdgPOFs+t$;vXy1{1j)^hC}46g{B8`x9d~5oOMb{v#ECSR9|A(5pl18Q{?@XQ^YC0> zSizLZNU?F|k4MT)lNPW7Y0pabfflN_%grf9`ny^IJ`xrd0G2+wc-lT}fgKBZp5Epe z?^G*c-#agSuo~h~l#7wUBPEs(*0DL+t-noO&Dr}Zk8AV3GGFnbx9?|K!v|$2zKMxR z%Bl%TiBU#Ni~IYNY5cr0B-2ePb5jc05b98$#ULjsQ77i_fH#(S$f?9@lEf1~cIs)e z$FFYxpG99IDtf+;6D-?I2A=04nKdMF9~fvi^!XWH{R!@!x_1X(FlRF5YOzmDFwjiA zJ|Q<1BtbJw_--x|pH5p)Td4_%y0JiwSj4Op%q)2*wVN9WX(ty=b1xy}c50b1S?W6* zti+mF!zm|hvAq}9<(NJKbUT*#i#C@FgROSC`f=`k_eZ$4yvcUv0mO^TjqAd6t3#~` zag$BE%Fbuh71#iV(jfM~UYk}x_kgawkP%h>{?AwJY1!`Mk;RW^uFI%PXPd_**ydPb z6IHiO$f^5ovZp82gxqdyv&~92*4)w9aHqKHo2J+2<2 zX5#o9NAEIoo8#QrcAp#hEX8AqIq?CQi{SrEZr-|%oifn$3Z+caYAtU*LH=5l&a&JV zXT3TKR&^)IP7Qi-3F6-ldqDWy@yv!_P#auqbIr?atBO5$LkT*Odg z6eqOW#Lo~15FaOHt#ZjFar{Q{L^(XJC~7_QvU6U(wvGk#T1uOT$<>!7pf zg>@6h@u%3HUuRqarSHe<>~;r(%svn>I;DJihtgC?fR zC+}v0#hNIlatfMz4M6|p<`#^%5zw}e##F-rYEt>&EAcT@`UzgXuR!9eIFOu%)&=*W zvdVeVd@7|yeoP6%Wbki~c}>BiQrzR?Qde@$&eFP96M zK5g_5ckhTj0=rH6yDqkU(1+!1OB=ye`#(Qn^RPJ{(%*P7d+$E417w0n>QF9Ko)4kg z!=VO-)?x6Sj&_Rhj4btQfiI6tI*ePge7il=pyH97zbAeD6rZg$Veg5jaGb09)Nlqa zN=L*}0O!$oE^XL1pBwQ*9n0?MABpi3=C|)18JO>1NKbg%3b<--&yyXlt_zJ%I+u@~ ztEH7HSK_(izvK&^HW?vcF%7X9AfVLjVCj}2n!0!WVJbuCaE4CoZ%OTueM3>W?XB`V zUZ>WzD_jIQK5ySMkLWEYF3VP0lqS=^Tlz_E0??SBX>gfaV5x#*WT)=a)uF8d+UsDa zf_rS!f*Ao{Kdsk_i+bv<=b6Q^s|q1CD&SRWod^u0hSPOJR}3ZXEJ@tOsr(DJ zoOIiNeg2z-YaJUK!gEPXY}v+ModZ!tgnyTS;IpsA!%ZW=G4#B~y;iY1MP;?SC9%LA zybA<`Fba=kFmVuN=RmIg^BExu1X#3Sf%#t9T1&P=`nWPHPxzNMw&)Fv+$jD0*CrR4 zwT|5^entP2Q6Vb2NVar@j3$Go4t?Py$QNt!&ZZ(twyd&)QnO*<8yTC6v}R~5r14ZJd9OKYfr_?)nCp(yOp zE4TV4Oa4#(-Ma#$a_`4Cq3N$(+w^O(Q6MO5=kJaBM^SO?^2>RYdDCDly>$)8X zU#~aMc<;6&U9!Q%7l!3uvHcQI$og16 zp>BS7cajNgwbq??ai{(I48O|OCc-dhp$i!}#GZj~vKLgb>g*BU96Y#t&mWokHnV@l z&4THSj>~oA5=HJzLx}&aBq3u&m^E}TD*@x~h1Y-*UM|`Ghi6l>e%ipfts)5^QXvvv zeq7-^)2XT*DqX55VNBYpsvWCbs5p`@0%gBuWbn)ebldr4)3#@_uYvEBA){+VNxz+$ z%5j0|TjYlNJ2hoyLZf$Xl&-h#8`*%-vZF8xyY(FT7h%15;48dq`VCO$#I>=`q}1YH zG(Ht?udK2-%gNQ8vUGBo5L*D<+3J^vF&YkwxNuS&eb3-*ZXPXLR-`md!I3saS#4g= zCM)RU1L9#yzrC-7Z=8#h_PcX$-;kYHxvWO65MX9NI$4GF#(mwITf6|?u0=_%8%KxQ|WLQJjZK+LRHMduzj@}IhQ}Mmwos`J}+Bk^?i;{Bjvsu}D zL?2spo|!SjqC)8pN2{fXep!g_`FYLrlYMm|$6t^4j25(Q?_*0b9qh8+LE8CWLG=tQ zq(lthS_eJ&r_5T9ERP~Y(SlRv$EfaHqb>$yL?()3yYm)y98pg`<}r~qV050zj*m9TTvp11`5R%4;#S4JijMuvWA%+vtvq=1>|(K zx9e8TkQFW^B>9w8J^d{xU_I8h#rIfRSdssF{f(+Lv!bzey_#xV#mX`XN*@FAPyRu+O*Zj)m&(ik!Xo>u<*T9Y^*(0TqpwM*5UB?q>uia7}`joodjKeQCnJp2y^y& z;IQ_yTY|eBRCyGBhgm~?R6L!hRo_$A_h7CZSxSDZ_yz^dr>8dQ6Pqb z2}MgDp!_23r`CUFPm5%E3=;Ato3$aA@g{80r9ce_2z6;5pb6ys7XW@hfxi+8&?&r= z;Ab?00Xo44WFk=nn5|3^DKfKREk^J9@lWm=XMmf+)G^I73hHPWKT5@yfJ1L z%yDp*nlpS3wG@i5J3&WVqgWC=APR&?`bFXf^pY6hD}Wb+i9i&~{~+3f4A#Kn_W(Ihz$h-A^t~Oy-KB5Nu)(unNKG7NamSp42l5k zqss9wiG$2%7`6(?*qOL!GKhKV`IwphCZ734Vn0z?8GCu_ zj_T$Vs4ZSWh*RZ=UTE#*myO-&08dVQiZ$DmS83-L5u3&>Y;Wf85M%+Jrk zCBy&j?(SPVe+l)`$rIH0ym^aq^K#Xq4Lo^HZfCEH>4eCpUAYVvSnWfkr|X zB_P(rQNEOMaN=BL=I?(B9Jp?y>KZ)|V&C8}4oIiY2=|$kZK;%4A1l)}Ih_Mx?=*v{ zSYk){t!ZvtXSLenwH1}$Uc2JC%F24JhHsT=Lt=})s?0FmTXK78MX%mraae7u>qN*0S3Dc5tXIedUX3OovAYt#3wD{bg<_`-sFmV~!QAdDpKqC2t5k|Y26G2E z*Spszw+n@O9!FllRrAyhL3f)*ZE%?_i;5SYiiC>-KHvTsv4wUCebT_Tpsa77U*!_X ztzwBys;TpN+tg~k#%Ng9hHXAw7;yW&-dnqid(CREm}3;#7K2*8hF75EY8!pFYK2&n z%awBkdV#sS(O#nzsdBgqWI?0GD2(KHYesq9PWnsJO7Pi+R4j zyyEPFg-?{1*P-uzjGe~+kc=Xpo{S~{;ZGEy5=$$Uy{v(-A?Q@zq^b3s^IM#`KLZJEK= zY_)WFt5@1=F6{S0OPx}s2RvQ@Db)v|%@A_CH&+QP)e5;LC%3?^GD1)o^?J9Ck0;q~ z*m{dw_fD}}SJrtw~e z2s9z~9cmiQzC)tZX)%&MYITi!9V#WOaYB>>KqSImqgi>tAD3x^Vylm~X<{?gI(|s+ zFlkiM64IA2y#7j(u7^4)w8}lbUT?izE?4unjPr|(RspT{@~1|UwKAfsEQA=SDc(ydD~?yy4;CsO$1V0jwvP2=+! zA+QGFR4ZcWN#QK8Fw97&o|jHNm+=Hx4RM+chusKqW-^!YpToal<8P#5^+m{^IKh&W zBBFrCuq1$ddx0#D98&N&=otBQdS@2^U7gcE9ih(s;SXTsm&Z0f5sgLxh(wE?*mw*K z&F=p9@ny&VJ-d4dOY9mRhO6WD+ParktyuMPU0nyja9Apu6^CvMR;te1=(b4WO=-N3 z!K5WEi8rS4`LNz|(|AJ~pUc=mOWL*h55RmTaYY*M&%((x-ZOrPmP{I_C6kqs%v>m$ zfN_p$CNvX#3Iaffm}La%O>XcK>Nu5y$KzmBA?Mqb!eTL36VSG7wA-A_^P?XSX4chq z!ae%IoX~V7U&v-1&CBt+-Mcywa}bn%#2jSHU=I3P>Cd1Q!Ztu#POHn7eyvJcOwO3( z8xp%@=5}kg?AK`IP7xv^`u|%(Xl5gJA8h%Ylq4v?lWBZj8lTHJLd*Gl%8Zzh()eP= z)71Cj2$aKGyhztVmhw@eU1ZusPX?vXuBKANEwpy+Q`pRNH;-+{W)g>hf%*-49U5aG zq9KBDh&uP$YiOj={6w_O<)%uohL$0khlrNByp&AW(=wgJo6>mS_>X9rPT~z|d@iGL z%6tZ3`bk`o#{08yGL83)&!J_P#%bA2;=SWPp=I|eC|BB~T&1FlzfP($$dtga!XYq_ z*+Qk$NQ#WWG)c20v`VZq?O9S~uGPvMLYjXmUEa=gx#lru()tncGW~{K0`dH0dw^F# z8^oWW$`PLu#0yeA`)%q^5U074*bInslI=Yn29XJzPR~j09ep-_55lQvCJyttK>hCe z^iU_PPrL!!sTktTu$?$bxnWBp^cXaUz@GTw!}zX56tM7CY$!44e#o6Td_TsW{t&7k z&9OxHA1@^by|f%8@y0YhfBY}B4m$+PRZc&jmnzpSbh(o0JJa|)#&WuyXig@2zTl_w zKS0kHNxUzO_rY28$uvGMjn8Eqq({uP`3%7HlXx_Z_l(~UR>6@p1o1bSR~hys=f{M3 zY0ZivzdkMsmt+QcX2t&WU^bVnO0F}2M*x@0u_!dvR@dUvHIJ9Kcb1owzPf+!3zg-? z&tnFwd3$&FX3}kS6`5AGPTOelIj~#K%zw9==hwS7Hn| zCC;cH{}ypO^M4s;Mp5z{DO@OtvO=HPDf1i;MA9CftkYV6PHdiR5onte-AFH zD3yLQXinp0X?#8d2ki)l(!Q3Kc2P>&@1v!iW@)0OQJl(WH!amkyf=-{XK-jMXd_jF zSe;Thw1PVRolZS3oq8_g7O*;lC5e|jM`WOxl9ICk{^Td%HAI;7>t8>IM}|So0}oIy z4v)QqBV9s&kFJFz{d80dnoo(YwKP@QZ_%|*;^k?)kKqQlr}5G>K9_MCOq(K~0hoRg zm!YS_!~7Fsg86zLCp_uhNS#UfdR8aUzS-)qKf)6VOWj|`@PysN^gF!= z=S62~v_@8{lm{|uJH&W)vh=LKrSV>dAC#lgQ#a8pRHZj8y{xb>@O86MvQ|@7r>3mr z%p!mTt~{5=&z_>V9ATI&n@^Iq>ua~*d{wLs=j#QkB6ZfBrSM7B0hy+!xcJs4M!H9K zrt37waM81P60b|+^B7NqnGmP>t>{@mo|2Fq^em9X8`Ah(#!h+`zc&2O4KP}-& zyey5+XV~Zwk;FM^yq{sEWr1eEV*VQ9>Qp|v7?KH`m6O6*pf7(`8fB$Z&t>dkD6Y$e z1qSjb(ch-go@4SfdNGam@^a8#HMDvVk3$Dz0fVvN>+R_OS1ett3=xUekS&a2k+jBX z`R43hdDL4pdzV(@I6RPK@8U}RDs!hTOI)>4g)S`n=Dc2-@X{o&S4>74Q@md3_HRtL z-C*8e8vV%xigkWDKaKL!eKikSEINqOu}#e1K)f;4<0A|yvS$#-7Tt&16n>PJ1R96! zmBd+KzE(+FMXiXDD~&E}W~9@y(s|5f9HZr9KGchsSyIBn(EW_I`LN&6{Jq;@`X9li zo0;ab4Ur*|K8c$}3zh937G&+@W$~8~KYAlRJ}!1E9ScioGA){4E7E5(6v=ZQPuOT` zEqlGj7#0hCI$evGCfFi=Gz@>Jgv`oQC=hkYmL#c(L@e-V*AhQUR3vGbM0|0niOM63 z#1bi@VS=@y8Mo+`)YEM+XS;L)W#y*PK2}#6%}Jy4*{U?kPNQ>gQcjWY0BaKcX&UX% zK!2A;dk!noXgrPf=H){Dei5#UWpIoYUeD<>#nL!yh*_=V#W>%tFm#8@=V(+ag@W%^ ziAp70ZCKm5-sbTYdcC*Ks#)t%y2T*>4DL|61v0sw)X%R;fKZ!^&u6pl&&zRGUHiLn zeEEaHK%tcs2Q+zy5px+eKr@$>qxn3!ACR1AZam9aCoR@&ZnJdA6rFB=V|DD?E8(;g zh-43Qy;@pis9kNO8P9e&{e_u?XW*~(3rU?l#dZe%z3Qdf+IGUXB$PFzEpXLj7b^M! z-Bs;H-q68Pkimrpjs+c-^$~WG1r7EH%}+-6zcDElU(8CQtTZ}zg(8g}oj|cRb~o%j zxauNGSd8TPGDB*ld>!)_TY%k4{Vo2?GjVaD)-tECWS&l&;%AC3a9OKWNzotmOi+Ls z4Emv}NeVEPQdVgLMX>baA0xgo_9|E+GC8itEnqh+X_6i69hL>GnDC9E^LZ)!^Arwi z8;qsVf232-Wjw(kuFD0=dvFr{ZW`@*8Be1Rr_tW%KM_kAoIMarnFY!AH(WJm9zUW< zyTE#xollyx1x2lpmYPv)C{1eyee-BcBnaGE|kcDm;PPX(z;C_gofcQBU z0X3`jd$eW+-yi=QN>3FbZnAXx#f%?O{{!*83_u830HwbKkR1Su6CY=AnF%IN+#q_E zB%_%*g8eh`A#9;1!Sp1x8886+JuGmFQrz>+e}y#HQ*fnWr)Lm*s)R@Bl}0i(Kb?BsHZ*I|Oks4+j%3aoB@-w;s*-3QV^$hv zrO~;Y6;tFez?ejTn?`$XlS6sh1ktC6$6+5-PIdMt6}ux&Ev*03p`J~XBxMe}tz4#1 zfk!!9j#XLqK>s%-ESvjqjUZ^UFONBEm2zWFsN}}vWvN=tO}7iO{P$(l_F}rWy+jUN zId2``LUa;wnmIC-sxNzTjXZJ8GD1#OSAZ7G>B=TIv$ifBTClCj*%zkktWnA9T?@7~ zx)&5>)YcNyP>=h3*h0F-#xgaSAynt{`LNn||E=-8VSy-F@s@)np*iGxcZ($%H5Tv^ zO-1*wN!FRe!Jd`|)y@G1T|-zG=C9zmiYDcxU7VH(e!4y8F>XP&P?C#`mI-$+t-sCnYYk(6OGfkc#^sBkkp@}YLT6r zMi>cVUTr$(Gvy(&#_aXdk00jeeF!=Wb$7 zk;4FE5`8a?_8cIRykyJ@;wU}$rG{PT#_VJ=G%GSI9_8@4ZvCYKo!GLfDVwJ(|Iwqj z6GuaxYK1Z9j0Gd( zr4BGA%Fha=%Re~Ymaf%Uy0-J+3NIhxG$R|`TZJiG7o^e8(&*fqm{X)3U`?X$rO}?l zXqKlL*66gs32!L_r18(v_*}+8y4ADO!@Nb4=zD3j=YEv;NjlCBr46O>zK6~`iGQBL z;m9>)VL`!Hb#yfUBVN zp0hE-q?KiCHK%;G#ft*v>GahOPqRv;TMUX^DwkMfkxGIFcMC+A??d~P#}jIW z0V%)rZMP5GFq|9H zH^u&S$K~1OG7Cx$zX+|2FNojaKVg2FIz0*H$AAY!*uTDd4EPhj zeDV0dn4eOg0}gtj*7HFrxi>9M5?LS;BC+|y_m8fnPBLeXNdEPukO2}_>QRa_z8AG| zZALpKtP^eg$wU(a@E+BQ!@frzp#hSed16JDc}fM_xL0Q@m59YEsjSq%sLTZg`OBmt)vTzq40b#dmG(|*8V;ZqL`;&_uhDhbFS??0^!jUdt@Ij6 zQB+lDwNAHRv*yxC?J#%G_$!Gir`m{V%*zZ7oLvL79|o=~Z_LDONJb2W zvg1!P$0YXDuaor5J{6*8mboO_QUguTJjVaar`WB(d3Rzdg;izpH4nBf(&`j6U-JV5 z3&XK!B=X>5qGEzSTAre9c1_SX19Uu-$Y(i`_aDx-nY`i??tr&1nMiU`jm9ICnd{B- zkz0sZSi2gkDHik2+=9}g;>T9dJkW4G=79a7`Ao2in)M+?Pj*pMsO8n1wl=%+=S^%RIlGwy-;%C$$ z)_OXUCy;eIlbw0uGO_9wppHtVD!<3FB*r$B%48~uL>M#>KdUFiLSfkAYld}MnvJQAnP3S@r>OxrJkFNd}6oRK-`u-Qh@6nu_ns+ff@o(JC+B#8o zY-z0Lan@F92iU`4;6McR>gTM>>9`}90^CSe*ZcNwO#G-QsT_;I=)^nLW$H_iLmlx{ zRw8ZbOZ_`Oj`^@c{x&vwOx61J%UMKKKNei$TH+W$k5V+5V6K?%W#I;gjjA8Ej#~J={q#v8N3xx>DMzxIN|Hzgt2lY`S{pKtHj?;U)4Q@g^3%kZYA#NkuptXnCDM>c_hIaWv^u&OQ|&m|$f~(LQ{-+JlRI zD);i(&~P9S3DmR6cR8g0E`w>PvL8JQYu<$;&TDG^_Qx1r3Ng-6!H2#Kzgt z`uRG&nke3sqjC$>+V0l24|YgaU#_j2rdA1@O0|oxQgS4>VFWZ71D4-NX5L#`QU_Ih zP)F%SB97c4&>Bkvh5KL~pQ3JtE7L0s3w=vfioGbCsQxJ;&Lb_HG%nrk##Z3e?EPhf^tYeY8}L0j$k1dDf)5C)y-!+%OWs{nH9iI>55E`fKU z`Stg~L7YE2MmfOuiF_mno1q?E$Wk+k7}F>0{!|2k+hmj16@&%oxr6XOEHLup!cXZU(zq&^9eIRa>`Q&o1 zR2L8m#hlzcY3^=|*JiP-9D7~TaxfGu0|m{&(2fd8>urHxSy?b}Tk1}!exjApc}rc8LY^aJow|wBKy7E~d?y=cdS2eA*SZ!*xq=;0Nlb?TXsZ=T) ze1q0NlFOTm7hA2~IB2Pio$XtGuB^Pus8`h39d$~Z9r)Td+Z|4q!@Rr8TB}rPRdQJ+ z6fp@;%3>0CvzRP?o}|QVER{)>N~x^E+`P$QciF7A4Q-BA9b8xykTL_hX=?+ui||6N zh#0aEd2*&2mu22uCQG_+lS3o3$`L?#$Lg>jQ{S7r4;IK`x9yz$yuDN;6!7^4M#-SM zLa8Kyoh19izjD>cWOBRJva%MOV4feLu5>-z(z3s(W2?(u!Y6a&T#inl@F_$N`3z~T z%{t3k-Yk1wave8A`;?}0d4{rlAZ~L$rF~&E4cpG*0whtSdT8{?{{YU2BamTu&l*!yepHdqiY4w$>3I#|j%g7`zep=)wJufl<*k5Se zkI0M6rnw~rrhKeGAb`49pw6d`^ZaJZ(gsDT5O8c9Bb-o-+z7P+dur20s<~>u!D!57 z4da+xA`X-Iw{3lPTR4w-Cm;+eRV{gF^h^4@@+QIqHF-~xZQ+K2CErkvZ!n(me=B{r z*WdJZU465~L@taW)?RNzRn?`n#m)*5kIyOKnB)VhauqG*roQm1>TMoxM5mQj*aEjq zyYtQ&H@gi!E}v_6IrsOKtzqUI6G&-7N`IHxTq2P+`29DvtiC4@j7d3pVqU&Rq;ZQS z4%G~4jmsqQoqW#u6p6Uu%Y96Be|j_FvDOB ziXuT{SFm-d!Jq~Il-%^=w$|>VlJYl>jcGBy%*Ioy+v;jB@0B#~3j|7J5^<3Mn0rnJ z4VJo+lKW6AY^G)tK3K|%^xU2qUBsS32BxsOl7ULt!c7+{DypihVpn#DJJl);(97gu zX{)=(Z1RAh-+$YzxwpF9PSRrD&{4mXBu(d__4+8$*4@%m$aE+AI6mJX4mg(yx8@3>G>THN2! z{{Gs|qp{c;-wtYYU)w!p<*jDB?WWnt?paA0iB0gS9<-xZn_d%S$$C;=GI?>5ePhm) z^kmsEPJF||!Jx0Guy9{nWv^DJt>{*%6qraXDt9l4bZKo?cVXfEz>$~FmU2BcGN}wx zK_ie$`M~#ii&|P-G)Vf3NS?Nez-JcNQ253&EP#5S?|tmL%7r`#MCrf` zIHx!|+h8j!$j#wG#VmQvU5pV-mWFy=;87TFgRsKcDEGo zX;}5cj*daMQ(kU1m&=`QkKKQuBebq~+MVS!n*%pdqx(Y(-QhWUg<7RjwgojYGjLKL zSZXxER)tboUs`(ajQxNKrDz1!`vmh%XfL4qg^`R1rdaVM$7_o1Uckbju_-7hdo1rp+X4$G*(2h~hEPAx0G*((% z{P>EK1Rs1ZD6EH5s8XToj8KpBt2~~yDc{Az%omWKCWfvTnqu~+7aN&ZRHefGi=LCq zpH&v=^mSHENF{@kFCuvyX%28)1U42wS74X%q-?1wq_)-R^ikqNYDsrD7)C=!#ugl7 z68ZUgYGGni;uWk0+sl>Z^7#bwn1C%)sk)Kp2(~_2^*9-`Q!`;kgz49b9)7*tCB5X= zfaoL)oXd`njw~_QaUwV5(oGK*^%#)=8YPC=k+x+9zMRcw=jG+8`Kxgp&tVo=HA)wf zJ|=OANucZKd>XzgPb6Vs80NKr&n;dw`z{^5U00^_WR=u8=qSbWM)YQD?K>9+T;Ge6GAZEDx);C$?-!pb_X8{}-_x zTKCooEgcYKYpAR}3)DXXqHOf9V9rHtslK95Z#4s{T+vaC%{kN#YH=-L`33^9r-sl^4%zD6crbcEby?s=B(W*b5uhp06lx z02f-4 zKhHVfaeLtJfjRz*S1)2q{efDEL?o0*YXg217Zxijy0@oiBpNBlmLv{fo5sdnCR1-9 z&}TNgVb4~>=Ppjg30@;rldCTalBLQq9Q4GMVRhMTtwtR$4u|g_f}c_X^b(H4*{-jK zihy^Pj`;l^09)w_lG}%<6SVgdv1p~dmng>VA+S6ShT@68ARi`m0xUw#U#0@}BJy{( zq#46ecvlu-xImE27*1%$_JS+xpHG@d&#y;L^0qZ*GYPGtHEq-vv?IErsOV(>zldSxi*4gZy zhK37$>#j7^clbQ|=>coCsxShwfarInCzzMH&9_T;v;r-4_6OK!C4F{29dKm<+_3 z=SP1)_^!4S{?YHlWbhka`i`~p^v>s`mbgwuKxrkMW1kQ>&XfwIHC|hwsMq3(Nq9mg zRQ2FA%z5lf|7=_HW@of$SgSFuYKiP=GSr%|)k&Yc6ZXXOG`9$2Q+krR{sO&4$|W_^ zH#r<7GEDX%^-)7T_1zzU&m0_+Qd#G*_9(gea)-&(7bIRulstPGi;uoGlipwwvf(q% zP^akKm5K2sBI)sU2A_3Ccr>2)H$A>ifl;P7IlchnEUdjX$uk`z1(S=(4BH%5+!}8< zJiTa!O09}Vg29o2z5~^;zKL47Mnf9c%mi;!(JhaM!+w=KaT?{i1LoSEVmL|#vC=9l z9LL|k_`$^wCN_AOimM;f>0!AaPenYD>4K-fv+=aBXX0zH`2S|gQ(wi<=^6S?bXq^q zd&k+TGMibMEChbgxax_L;hk|$OjKHRw2Xwc~l#>I_?ndhPMsw^&gu&*ELhBB-x zA%s#j6p2FJ;6+?5hf^_@e5f5#yA4@S186%s`+1--4kUd?3jKxf_edXhCZ4!3H`1z* zOQmvoTVyUi8|%8-PCvBoe)!O_M^GKH*IZ`vU?jTGYV)RUP3WMXtDEAf%(D#iMc&%qc-44grwt6__Tfq-kK3h>)JEOJbCwoB4o)24FX0%jQ zJ+q)?hs)`!EGl}iciwPM?*m0el|Gkq8zXfhbt%+phU;&9l#ukj30da?@ys3UP?qOn zsmBAS%UQdfF6Y{Kd@Y>BchBlM0KvFOBB?F(l#4`sz6dVsoRt!_0>i;$JKw6UZD^>i zeQW0kb|37k9b0$4RfCY4w=f4av+qtX{c~p@INN&%d_x*N_niG(&#D$`&^77}_(hiHV;^H%Rw5*};?l7-P z`X`Xj0v}T#H}>2;Zg+?$(Q1ur=h;I7p)60buHU;lR(HC0Xw572_3iET^{=dvEqS&o z);tpNc(>NbS`H+=`v+QNHCw%&2pXXequpovhEfN*gJ50eK(S`s_GA!c51VTg#lzrl zeJ8@P7@eh2Ym^Gj>=Np`pOy{ijigkpU)~J!UDxVr zH|V__46a!9GyScrO(s*~6wI{L3N1jH9Q+)F;JU5UuJa4kN~HNNp!o`xcyhnoF?Po# zxMmoA6F&v}FHF5g+ynnEpy!RG1rnGvOF(487`bnu@C^3(Bf^7;dOlkw5|w~xE@-3b zXm()BOa)J((JpCocztE;O`x{}b>jDa!+-Ee|kZdHn0c zkEox3oS(d05-)k_CxAtL_?r();@~Hg0}EhmsuH|{UWu;~?;#BQ1m(Ja{I5jQ^?NQi zx_fJC(sc4hw#WYFlDZcM=RZ+d*+?4H&0a&X)aI%xEj=^8?`&nP6~w(Z>*8XXI8vz) zdNs1B{vZF)6)O}jp~+%5Tb5SFR@?0!P}#A~=Jz-p_RVdBWnfAdZeh;X2r@+OglkL};%ArazW-=Sxy|VH|M(CsYCW!EdP*C*yJO9u>g+SS}R? z?~c9+-hlu(`kgH2(9Oe;oh#UwG~4 zo7l67R_xvcy2p63_W8+kSq8c)1_87k5`Txb7au;*2|j=o_#Rc5*;<(=8LVSB(J7Je z!-Bw6i(#s5$y5_-5@H)%$v$=ofB5+EvAOueXxwk5`iV{!1I~|bG$W*96ehi4DUq8v z$(A~>KXG(Hl6iJvYd9FVdtSWvSTGO?2ZP6YihZN5>+SYt8ch?leB7EAkZuv`-`wC5ZE?b zTC+V6XcFRb^l>|?{1pGz*gX7O=o@#W+Aehl z?ncL|QR8dNbdGLMY`$Kljh7b}Jv4vjks6{n@n?1c!D1Ory1C_`gnDDqiNZjkP(W=! zx$i=2uGIc=ru9}F$G;Q*LHq}(JW!hFq4J>g8)5lJVESz9jZJ^Y8^@QO7Isa14OZi4 z_(Nm8Ao*PkX=&OsOWSV)*BEcGzeU&BQwzYZ{^Nl_C=>`B?|++80ayI(qE4k!E>|i$ zir)@-+}j%(kPi*qGeRvgDpl1+vPz-UPS|hA_xyjf-_+gvJZ`Vo?b+XjK_mM0A#at0 zzILO^JA|DC_l&+7@_4q_*Kc*Z3KRXPmRPP)rK&cNF@;ixc39wZE9vKc6Z@?i zCqlobx&v{Fix08Vj`bFcgGJ2*Pcp3*>&6+;0h7sbzPhC3q5hqhE8$N?Sd3YHqr++_C&hQ&V?IVc{)}o>q-okNSHJ zilBfc)S;e_B~7&(65xIfo3JAu-^KE~-Fv#`9dNr`F1P!(c{6Wzy9?PD`C@TRFjOlM z3j|_uZ7@_LmhiDv;5$(De7N|zs;cH$O-=8tm9BlKxp`J&W$fI-UTNFmXr!tt5EH~U+?+8`ME^aZP|@ne)TeI)0NUdTgIcYg zRRpT3GocoRQce^XI$c{DmOf~qD!^%K4)!-Prc~&t6IzA5k^#p5Of?f`sK<)FCaQ6Y z;8Z+2&T%32Rs5xw;<9oR+3qZxr_*ZT*L)g&m58Se>svP49WFozK9($TnJbh;eE9tN z;n8|rXfBnAq`*k(2V!Gmfi|UB!e-r_$96egx6H(`WE`YcB`dc8JsS6Pd~;ITlD9os zCyqj8-S;%rF{9K?Putp7nM@WY;>l!M%%+uXsr#O)ic3!QZ@XAl4u8rnZkzQ$Sy|)6 zZBJ3JXG`Ts#TKuph`#Nq^Kd9w*4@;6Wtn67>rKs2-u!zSQnx%|^i84XVGq)~{4sQt zRdW4Yd7XzXbu&DfG79mW#CHM4E#QakTEgA4*{snM0K7KZwa<+dgL_|B)nA2TNz7YS z<&8f6Q|m5KywbP5GJ;g4?C zB<_MGrM-Tsk#X&6mK4aY(N87u_*bBybEnhcaygtkJEzCv(;dY^A)hZ47CWY6rvS7h zvAo0=^poq+lfnJeqI=O(4Ri@mPpXj*&UXfm3%bh(Et zRS+)^pFKM~T7?U(9Xal?nOswji-~^v>WkIbR?V$(#M?Q|C=i zr%NUk1@vmSP_1@3oi`z7w7&6Ah^<6Pvb2Ki;t8%T{EbSxHO}Mm94aL$EVwKc2|Ox= zjVlnufy-)LS#7V^C|x{`Nuq1_R;{#IokU3jIBR7JrBEPi4PfI5;A@nNB~ppJ!HYh1 z-sEt)#9~p1)c6D{rOWAnWyNSYC}qi0G8md*ANzWrEA}Dva{QH7z;_3Z2hm05!Q%te zUxBE&6HZzRrK+=-`YRC}0WH*XBctC9!l@EY&~BF>+@1IUPF^)eQ;eRU0b>VTFWk+1 zgE1p5|JUyCq%}wOZccjRVN&&6v;9CTAP~BE@i>>m^XWZ1T0%W0PnEQQM?8Y(vhs`) zxI!R{#9~cO4jU+`KeE|*dbv2LC&MDXBA11x5O5K7A^K_Rks<0vEX1xloNvyr0dxsYU=U77>8ks^a6Bp{0rN;jIBHYkoKb&(`R6*?cUu(7klVeX(o_K#L_&eGvru1e z!k|P!IU=5+J%Rk>+LBDID9z}+5x(H?OBC-U#d_)J-Erzq@%+4RgNsxH&36g^1s6|Y zE}cH{0nJDYbJ|7gi79hx+VV10^dMFG(#HL9Dsey|KM3s9he&mxe}R1jbai%8^v=+l zG|Qeml@p$7Q#_fYmCo^0-;2~!5B}hX@%W<~URqpx_qUhjum`}8DHrqn*c*5WEFyfL ze4PRxnM{-(=8aBXzXVJ9AM!ps^CjxZ2S0c(9v>chY2LK^;|p_g<^ePH3uv0(j;)7< zhVPTFQy`{NQI}!fGhyC)>0Lh;y)QK3FA4~**`%?OzyKy3`R!_B5 zDvkR*-hHzGoRAEl1E00uEDyS&Z#Jx}9r@7L1t$1p(6TF%Dv>M@$|wUlJFK#bu5% z=B1o~qYS^2>7X!C@ zJw7J*h%(?_kLS=3_7?Rjn+@nY+S*g6*xkrGJP`>K$!I6h#9T&-45H*hHNcu|EwJZA zem=*p4W4kQ?OYxgoPY-2fE#?0kbOe!JbU(DCL6A*G3HJT+X?v-c4>7=eQm1qEEE){=7%TcdYzIUI1pXi&BJ@b?qOA5nLn#lzbG*alwU zXm}#KjQSz)l5jOIWKvDw0>KmT!xn_KtR%GtCin}b03RQsUdJ#{221%aRY#cE>lt&= z8T(lFrYLQFBqc2KdZ`H+xMmAJ^Zj-A{K8*69m1!+anN4nkS=%gNfi zlp9Eu%DA$@GQ&yz7`Vs^r9H}JvvmfZRi>)sB-;#IGMvNCRf>gvjl?QY+45QJDVoj7 z6A0nc8~lcLkH15wv~gh`x>l#R!{DkBG>k1sa~YRGi0SvRSw$*>X6|(%8ei z!Z0(6Y5#O6n_8Nkj_k=a0nDN72@?Hku3L`01l7qGnob}V}mA>kH;+lAfLT}@37 zww-BvU;^;n41rJb18brYbS;V7VqFl4t_kLkFoSC&(FGQ($Ac~{iL4DUkso3ntaS*^ z_6oQ<34GmcIv}-%rz{;kjJyFu5O#h6GB#r5^Aa6GG9kr zap*3uKAYx7S4q#*T)WbgnS04v^xN4!mq2d5fw3{TOa*8s7jYRR)c4EIJA{6k? z0;9>avUTjkT`*sy{m@x_CDP7QoFro7^q%M^cYv}S1)rKE5hx^*v9RW~$LSG|C3OT6E(-ez~X z?6&m{n7d(}-R5-K?CY*NnE4@_b*`28UE&R|7b_WkqgPU{(bx$L);a=f{Q@mhbgloZ z8=AhR))AA%vSrrHEmjL$uUogynzl6$2T09=dy1#)Q`S$fn<2uDc zJPUSHH(h-N9Hchjg8!&dzIgOn_3`L6Dh9Q~*6{(NllTtZ4ypanR6G0^GJsvVbm6bP9( zehDX75+2_!*LVa%F_Xns3dLdFwA~(wp@7f#IN&1o3-Yx>{d9lb28Z1PC4iKA zcdxLyTaCtYt**jY)T33Zcf$E5m*domZ4$9l=3C$Bp!6*YuTUsGXk?xnmWZJxq^vL{ zoRJwyG3+g#L&?(%z!*h{NS@lo;|UaUWqSboKwT)+2ZUk?7>3me>#Xy_31`<{x7({x z3mho^NTc<--Fv&R4+68z#$tJ40GLEvu7S%DX|<|pL6cB!=7{+Dxw+DOx$PfOj$5TH z(Jbt@)T7>71bb^c^Vf`7jIE6Q>E4oL1&4o4R|P`XYv3t5$$Wi>gs$y0QC1JRRbHW5 zE9CQR3b~!nldy0C9RyYgc^0YM$`yz-Dv?Lsyv^nEJ8jmL)s7~e%*xAG@(i^|PHN%93Bv8V zr3-BBzYG5Ps8DI;@S)X|C&|g@?&KEai1TDttxnYzp#GBC4N3p`UN!;8dL12`FA0PU zR#BGQE7KA7jeKE11qvPo8gSww5b&X}L6OcE5IBAr-~?05m)`F z+TosFNIS;Z#PS_GmQzoR-sx?UOJK%4n;c3g@`*tSRXL!2s8P$S>}e;NN+s}WR4#!= zn{<-FdeL4oIAU+`cOe? zqmhI4j@pALzQthZ_D??)3YC#MLtjzF-EEG+XB!#@_|#!~Ul4h;ndS6tqatR+48_#U zX40gd^R zXQ{Oy_V_lG?+=MH_z~t9y(er4S!D*c3~a)br$OQm;0%-eDOmnzK;MeVl;MA8N$9=4 zjN^P0(_SEy-4wv$aFs1~o2s?Oa-GV}<8W_Qt90{9Yz?HT!D{Pa9=}P#=V&-w5uDtu zN}(yxrqbzX1qE~KGo^2CyL~-_kwcxOuCVHv=jdB3N}wG##Ms0*$as)J-!zYiFfw}&Oo54} z!0>PQ-KnstzB|=3z{na$BHkDd~Oh23kk>LjAlzOcp>%1ENpzHu#( zcqJQAYZ5Q7&CXYQevLbr23jF-X00ojehvbN&#mQUHhZl?p+*76)N5HE6CY)N{6Ti& z7tlvXtwOF=%N4c6->>On1>%P*%+P2#DYaKHv;L#F2eZNmr*nQjNdPu;x-EK7U`=myVK zRkgNORh=88Y;mBgTw$}i-8S3uO7K4T-#SYC0zmPwOO`woi4i8P4Y)dp8KDoGbu|pG(<~|k| zdzG#w+IZE1 z<;cuDxdJUp4oDjI1uI%b0#Ve6pO7 zrkcYEfok5AQbCXznR&+m1GP4`Tahh)UT}IOSA)c-PRGc?XM1 z%YenY*ZiQOyapIi+!omS7w|cH6bmbRnisvch$Uhm2B;&yqu)p#?jIcNKb!;& zf1!8rPi3|OK#!2SU^5PV@kM4i4{PyzU`|)STC+K!my_djnt7higbvLb8k%(|1~h-C zcT=Tw@;AR>4of}v933OEXBs#oQuk$JM6#!?m;*)RVGw?oJ_zbxr{A4Vlc3=Yc`&nr z{FwZ4W(#=@y3ufuK;F9u>IbkM-19u{`KN&B@AM(i{Px#Z!pG~G6I;b3iB4=C9i9t* zj><#H^}oe80`^> zNCa|n^F0<-!bT?Ncq^u9WKx|@-%=FaR?n*;S1~?k$YVgKF-%Vd`%6le29q5+h2o%A z=e~Sea!2#D!<98lP~Zbtul4kwsBN${&g{LGal?Jw{atkYXZ_$`26K|#R;vT3w7RyE z$n>p&0zZj7xAf*@?nh_Dz;NX7~Zw$#&y>$j&| zHAZV|DDgdHi_eC(_+F|5a&5&}t|dlyr7yM~FZQ;SxER23?b7$O>amd?slAaIK8;&y zFv;c0l*id!RMcyBN8zH@s+2(5VV!(O!a<$AM&a|-$gya-ewqco-c;nFg1{a_bP52q!0ch(~2Y~dmDq= z!Fa!n)6YQOmrnSsiG1=t#r8pZ=lhwh==>aaCNLj8OLBKPc-hl!;Moh|`C!7VW9NPGg( zGxB$8H~)E}1o;h`n!UrDt+4l^8;%o*0HZhg6OC-RK(h7K)YjBIvu)LJS6Gv<+1tW1 zwt0On@;;eNT^}vHyt!(9w5Zc;b!gpUr2+t-RxJw}&2>J1wa((r&&i=mCS4JZROR2W z{f+jH8EMCL5{p_+fS+emTc;O&DeD<1@mFiK zI<4B!S>&A+S&duzA+-xyT_F@LtbVNX2=Dl~0Z0~|V>zK57e|1kcb|&1MD{MMU+Qvs zc;tPtc>IpbI&Um3?SxBaaL8!1Ev!#hR6NpIG1F`|(fZtw%{EOny=YruRcTStHO=Ja zrKfAEo2yI9?&(us)|Orwj8^A^4QHF0C-Yt|^mrF0b=52VK6E4Hr}UfDKG@?P<{bn( z^^cu2E^*NL5;*e)-G5+k@a^8cg$0EmUo43_t&?Nqx<|^&D#}YrPAuak$gSu-JDh88 zDNZDASx~w-7;Q0VbT>6O)W5uQ(~Hf`y;AJIn5N3%*mhi6`UF-J`3TtmHhtZu!NH$2 zZVCm9;Ig2*D%!U<6bh8YV%L)kq20%x;bt6T^tjx`vYQn1t17Q6o_BL9Sx4YVijyck z7p)OH`xxVUF}qoYPDrhS7Qm;qH3EY~YRr+C<7O18F)&C=@g1UF8AtaD61iT?hG`V! zW|pH89)%@nSdSv#UBYryLStG8OEAF_5|-A@et!s-fX`L@BJ=xM%SKBG?U+g(gyshv zX(-x!H~$49j-rRMw@$Pd3x|DlZqQ`S5Kg{$V@~&EH|ojCrnSLPnLMnoaJy$Fl0B}1 zYL!Mc{FGc_m|vUPJGEg)s$qpwXRui8^Q%h_RF%(h`AWsPIpkiTP^i-djw$>XG%}ep z|2m0PoG&xzOtWIeyBd4%Yu;Hhb6?QqfyHtCqUm zfx*e?^aI_?9!=LYmsPYsn+D)kFnlXtN0$wFysnj#$`-m@{-DRbpk&pZ@pw^5Ds^np z!n>07#o)t@`1ZzbdIQx2`}2Qan-INkf7exhmmAfl2~Key|In0l`b77#$53rbYoD(M z-~g-*?=DyyU%<7zscZpr+j2qi%4}`==igdVQw2WWcog}VO~cW(m4AxzfUT1V!b?sb z5ffE}kn9@iz|k<)!{4C|2!DTk3iEr_$U^*k9gc$2$9j;w_{=SA06rKvHg=Jnw~7Ac zhU{gx4dAbX^e@}jGPm8=Z~L_+*Or%;pWZm{*`A&kdzv-{gJA&phRlzuOG@vYJNNFg^4ftSSij=b zBK9tFKb)Bk3UovVT02ag(APm~^p0v)ezjcf;h(G&rLvw8xp~Vi&w5kxj*8m&DXc#) zS6&scb%w)jHknB*wySK@Gum_b6lAYau8dku1&Ul5S-rEUH_*7zX|z~O zQny+kkm~io9}M+Xr*=-NzOus8>IU8pU-{OGl0~6Nn?bDwqCBx*ukfm=_cI^mt8=9C z!hm~WX>#kIGp}d^Dw!!yrT}uOc52jAY1>&i!y9Ne7|cppjuPFVfxO)V`yRbFRA0(U z=hztJSw1E%J)&`ms{l3$zT{cW?hWlNJEO*cL?i}e!0@O{k9Nx7Uztc#6EylI5{Xiy zsgIgt>R`AenY?xWJMWZro6Tm6)zVu%Wf$6pGJ>^>YZf{SgP^g&Grz2GdHLd(=NGRj z4$TS`Om#ad42d$JQ7Vc|OUsspLbYnCR~y~Yw(ypCEP2Fbcg!uTUSPM{k9eKV`LNZU zBk$w&S0};7bay&0I#8^QWu5v>G`u*;a9+v~@?1$Wb!_3E1n1Lp%zB+tX`J79n0zQT z1$LFi>{!`cG}~*4Dl{ela&z*GlE*A|658g9m_z5t6Xlz2no7U7N^7-|U*TEiW^~fr zWsR#$)|-J&r%2dq%Vt_#PSS4ERQrmqY;(7`gI$64d)m{>J>Fnmp2(?bi*?&IPLb53 zwX`ua-Mv^(*P|WOqA?BA#>UUz38yDMQTL8NsRXsA><{IAu<<;BK(Fn}6XiKH>jKqU zjrLxkHyXPteRalgG+kNs#CrNeplV;|al34G?~a~($jjXh=lt@kl~oRBjT$(bT&^a2 zm1}maXmR+IP%ONzVtFW(Rw+V;!p$vQHlh=vepZp=(L(D-&}E6Z-_`p?=-)w-j;2US}CXUg@u#t_97|l3~NWEZIj<0 zyxC;XR(d=YYPA;ijta`)ao9V^UneiSIWd7o6RIv&X9?bS`t#tC3jnE*%L>iL8V_8` znfxN55CDNdpcFl-QbSEdiF4&qN4_#AH=j@OK;|ca1e9DVvZ&;Koz_u0$89WBm>ohM z5AbytzD#u6ZG}>a7&J8$Y-sd#M#(2TuHf12Ap7nd7eeOcw|FWa=2kGBHD>MjXVujaaY6{e@ z3+g=ixp`2Hw)q>)$#Re*%=hS3A=En?V4cx!V}hF(Cg_0)>dD=BB+E#NSWyu$ zR=TQI_%)9FToE8Gs?#bBfYlTUB_Xp!mn)L-1^hw!GjzN2!EmQ7QX_}6Xic?qMk2JZ z7_xQFvvb|`R(qK~90z&1c?KEO3_Lx$S&OfL;%GP@P#gI#qWGls6PPX+9g`S;z-sJv z7I|piL+P4!lJuw^)tX7*ak*DDb!-a+3*>TDZOAz-+I4+RS?$BC>$b)xt#TSnHnVk3 zS;-!CsyKCG^~@({&U$=S`ZA9%2wJMEPtFB7r7NT53vC9o(|&a*WVZ%)Ppv-KNq;l_ zw%W!GUSAN^{Z3f-PPh_HW^WFSc}JQ0R^P;N+&*SfCLinB83_2?KHrwE$@`KaI50dj zi?%*pQ&ZPiS9^AQ_u*8knv{u7O9VitH_o_xtb$PGEdoS7{x&oh_QX8Hqx z?cK?h$>gd;s7_}vpeVd>BpimLH;VRBCL9UE2?Y_y>jjUK5|OGZTn(@3|+ zR-%LRe15((ZdVuTc+VWcc7HRh;WB);DON~?nHrA6){Aa=kMj-18qA4t$q8PHk8$$3VscaC^Xqy}HPm+vf&!m^b=~A0 z1qIQ9VDNh#Pdw4N5kBSj`?gLgU*h!?fWg-4ng{2u`%!IOi`{COk%~{ZhQi?H#pn%C zG#G;nRdHC&u+zGVk07NWd z2Prvk#{+bV2VS{nAoC!gG`v;hw9LLagM(Lq*&%u}s>>vDFYhJ(5MD1i<=^Qw7re6L zWUfK3idpS(rBZ#;<#5a`4>Vh}9x4C(!*7#CT8~7gfURjw(k?LExgHuYK(CP(qIWu1 zLa8l*t9r%*|9E#_qkdX(P_A)-xxAzHB5x&q1v&$lEGW35y?j+%QL&+F{j&}A-H*ag zS6##N8>%)JE8;85I<^-CQ>1mvo~@wkI9y99Ww%P?4fS0cxYO%-Qm53$bC8fnnqOnB$*bbFi8ZfFI&}ugr z3?1s*{a(+Cy6*UmQzk#q=5Jab@E3Sp`f3l<>9k!eIVH}Q^xs!jo+keYuC1JHQmUX0 zTj~xLuSq25!M?v7O6W%ZvqUc8Br1@nl|H#s37{eD=>^-832xm4n%Pt2VQ`{F3nr-$I&Xh-LW z`n}BhTyDR(8?voJXT+iDkxWura^~Qi_I)WH(Vnh-d~te5DcY;?Pibs;X61q*`n|U6 zl9~5Q_RU#RRSwExpeelWY;*GzzuUdIvhw=Yb+5Fx&8*=4q%uao3)IDFf)7`V|Dp!@ z4?~@ogf{vjVj0#=e056B{}!FCzGS0`S$~YXl{q#b$G6Y{6e)0rjQ;U+yql4FP9%FA zcDGuU?^J62Qnfzda?LMJ&38HdW`o3~Qrg67%@$~E7Z|NYapFw`Qm($$VorV zh!>xTK|cN%>gQHs8*zwukT`{QbN;Pux=Wp;OyHo+3H}Sc@%KrNlv1vcN)%C>BQBRn z4itJ^eX-Jo9(O>kkri6>UYSbkbvpY>lTa`D_Dk|*5wkTc6-$%~dDzO^`XA`Wql|jI zb_whRuTkw1!?{Z)vMEv>dZW%{FtiuB%G5GLPOe_6Nm!z-2EDM8NnDpa79o2YT~nrZ*c+Ibs1{ zSXW{S%N5E{L8R4SGJJATEq8`1SvNYiK#y8zsNm&)gYPw8^Nxx zxAH&w2JJJ)=+CGl6GdX0k@+F7cU-1(Fy$o@iuh}?;Nz@77_b6 zU;bmQ2I0iVH@?MxviDLa$rD_Wnc&5@_R_mG6g1VvPL-pl*imM16sx8BJZ0SB?2bn# z+dK(LPELNlEa9+rgyUUK2V9!Km10*s((3fbq`A4<_ooPlth z1Zz|w*9dZj!w1nF45cD$wIsC~w?vFEVu@R$O;{|23Z*eeARt=;kvV=#O6Bk>W$Frt zrcfK`aymn1gRLiNN!tVdPFJ|os56F~&aMFd$!M_7h}#<41ID<{UZRl7&00;d$rzQI zrBRcySgSRu6w;v9ST!kNO6V+crCe#!YKx5~h>%5$reclOESJjTHa$Lr_7y#e_qrg6 zR_yiBi6Zn(;N68hY0zuZL34pz=WcL!ToDWv8uYS|K~g6}Z)BU-`wPM|`NmkMQE$Le z{Gx@0*K~dJr{q+m@s}whEb!ja}_kgupQ%OBG91`37hRk zOKJ>`;WR*@oSpm_I{XLF!We#s3uGt28^7>T9!zLs3`9BhJNvtn4XI+M{bT+8w_r$^aO(*^pEtl*9wXX3Jp37J*8^Z!w;|G*?Oz1dvDKt+N)D*4B%Dd zfvI|!szM*qI~B^B?A|?lUfsPL+_8K2Yuq>3$I{Gis7G?L&Ej>r7gzhM zP3DwUW|qpl>rb8>evqQ_c2g8V0y*_Q?_U|)fzc~e$dTD-bu=v3KpYs2Xo&tjJ(;2`+&s9?AdAAAn;7E%ovaXgtZXa*#5{0~P&C%mv_EDfz zDUxnqi9)G367qRh*VnD`c|-gc&Yo52Lo$gRwk@a&qm%g-ld+8e;A`pt`H7$m`$<$| zw-Ioa3%(vSIxmaN=1X^Mu2@z!HSm2{n<>=Wyjz4kLXY?3$L{BN$JWFh^L~3b+;Wp# zrYQD!QVN9v+!*kBmZ#Ip;i`qc?Mj|8sa6}JVfTUxp$)|@fsnX^e+rsea@a$t+O15r zTdOO1GKtu4_LM0k(kbY58#J)s|6m`1H00TxkY{@4M9sJHizkewcz1payS`ep=s5q> z1pETIXU{^OCCI(J(>wOUeD|hp zf292;owm~HsMKnVMvb=8;jGl^Ow&P;%NYd`r>jV?_RJZ2jjLR((djhma+j-8qtWX% zno5_asL10iDneuC3+gJ~ll&K;&QaqYg?g2r4Hd~Apd%mYJadBn^H%isTP<#amZV5V z9W#KS`iXtl=n6FYu!biK=ruUM_0;cq&k0_`cbUH{;1&+Be^?hpUVddV$oLME$!ay3 zIzWle6Vpm1+EtBe_(dYsE+YUbppTNz5VzodkUQn%GlP%-G9zdob{?GF6~qAILcdde z=}eyBDF)$Kj5{Q01)932@9^231D}NIbUK4jaC=@(aUyv6BxEN%0B7naSgY|O&!A`D z%ls95{A;@Yw!y)%$JD>+BoB_jYA_#x0Oo>D+q_9ed2f&}!SrIBM!vIpg@pnSLE$Ly z^N2WD4e8jI8~+VRw=nVE&3Z^(2<`XT7@fnS^%%X6?xM^X?O@RVg6NSUe0u*x`(Kpl2BKpWV zNM9t_LU{;55vFGz!*mpzdW~Qkr025qy9ttQZKq%>r022p8woIiJ|9w-;e2Fy4E?t_ zpY0I;eM~p7_-;(Ufc7pC9bC=ge}(IbqrRbfg8jHvm%snRZ0%uN1*rBg{UGwCfYUsj zMz>DlI4!{GwM>jzm^R|{e#Qob>0F#f_cSaxoyX;O9H;Yf`VbR;0j4E5eLYN9;?zuf}OLPFHZh8*mzVb-Es>^`rF>+FJf&j{vOofs>5m;T`Z896(Zr9SfCHEAUlt-hHo95SCRuF11nSyeu&tmDWDxG1m zSkP8?)xx_=N~#jE*r7Rd_QqljdU?RA3|mx@31s2h#^QX)7Y)XVFpkyMaF**Hl_8-7 zK9|q(^9oQ8={N#}um$q@1g6g=?BK}1A=7M3Z8)m7PAKCz=7q2l=6fHL@5t9+-vqLI zvFu+gyKL+XSkCqdWf{*M7*9cHb3d<{K*rd+gD@Q=#(E)*O>mar-||7)y}{|ST3xOUUH^vn(J{ve{$JilVO{I! zN$9K(tZRHi`NtgKpNAvG#z?xr0IAp~JeL2*F|}tM!al-ruMj_r=B4TU=V974CXJq2 z!Q>T3`r&nGlgz*+wTo1g<^}wtf^xQ~%g&m0q{XGKBAZ)C0IKp@07P7JUV0r+jvBxA~ z8b0?fer^*r6HJ5jY9!GDJ*2uHU+8JpqMA!c@zYq|1vy;L%@uWVXd8#_gXo?t8jlJF-6ujlVMA6EE~^Qb z6@;hOx$$fGwMk%f|gG$mRNVt^kcZd@n)pPl1P&u^RmXD1h`IK=fRy1Lisz z=Ze!j#$s8GYxWV!iuGo;`fZibvgxIqi2pYG-K(;V#=+pe2xf>CWacm%rewanSgVEUM zJVu{o(6tENO;6%$u%^>v?bSsxGwMoMmwTa{V!v>R4h~{EvS&>Kw5qe>bQt2^L(hZz zS==u%Jq77+q36L5S^6uCgwiL*XjUQUr_M7oGNg~{Rz$yNj6|R1@EfV0f+?ItU(Mk+ zQZEoP7XLTlKeBkTb>s^$lg0l@@L*P^$<|M`PLXCTSd{2v^;`QtCLd=WOWXfK#eTnlHT zi})iDuuq}icfuaKm``tUrFBAsWExl6ZCq)c!wRl$qb+G8cwh^MevU)85yc$3l|y%o zd=8qkXki|Q?)XH=q3s-c+Q_fLWG?UX9D3SoQm)-CT)VNxzNFn*&Fw*&drYgJpig7_ zGplp^sb3L!c-}gJ?Kwv0BKmt{bo5yczma+xk0wS(@8a+qsb>f|ho8dXdx_mpp0ap3 zhwml!5H=Qn9*;f&JNiDrqYvTV7Ce-l1IX47p{5=AC(ivGhn_U@E*^cK;oNWI(39R1 zvU#7zea4_$M!v$M59R%+-~|rd^7R+ln&Z(YU`OBI@aSV|{xOGc{`co( zv7>JcKcS7vJmmqiuP}_^DziE{%dJi}QhP90u^lK_&Dw#8{?W)V!o$)mxYzR7-Z_R# z`5B}mJJN&fNJQrgFnt+)Cte+7XAL+upoGF%gT4dXwuw)hBS)|` z%b?%k(6esPapW594NLzi#yRy@l^xRIEh<@o&3LYcr-q~VtB)^ zq7HKSe(DBh-waCW<(QWSmi|1>r;Zlk6=v3Y>F3`+vLL$x5WdLaH&Tz``2brxn3wUa zlww{o_{ki;m$(wlN1Ch8m4#f5JtAhs*epmD&o^xRP_JQGZqw$M&(tjQk!H69BHNnKXWJ`AbdnHf) zWboI&{;sf>ROi4;FAZEcH5&NxOM30N$iM&JN(Lht_QtcA@ymp~`!MlW$Sw32fgHMCwPrfxI8sI%V{K@?JJlXJ+0s1m<80Nw5zK+&~$pH0K4DcSl z9jt$oK1;v+d$9iA)Aag3fLf6L9le1(Hb8F8yhxU1b`50alMR_6@)*JTp<2t-XoB4C zJ^-fvo<2{%`&%&e{>SMB<4x3T~qpf_Jhr{XD8oAi(cu z0MSA2rS^@!-KO?kcpkmo{vS|F2MEc9{wB!3003k(0RT`-0|XQR2nYxOy;=@i00000 z0000000000AOHXWcW-iJFJ^CUbaO9KZ(?tBZ%uD*Z!KwbVQgt*E_8HeoV*7>R9E&t ze(!x#=xtyMGcb)|8q+&{=pao{QN%I=0*ZhXOH{yuJ-ujRiN-XeNlc=q_rA#{n`(BG zP2b&Qliid}*%%o9=gnLYQ@-Et@9*QyedXSB&OPVc&pGGKa}Y)d#i3Eeprz%FbBnHy z-9iw;g>cnb*J!ct|M)~PoPQ1HOB?6-=lo;vB>|kDg!7WtRe`?thRfz4lr)MEzrG_d z&q^{%f+HwmLcToMp%;7*&b+%9vHq9#t*`McPCtkO^>(^&Sh|((Yb1H z-Hk2xzKIZLKSI23yL(#$+}g*0e)L}Ud{tmwAF~ewJv0uxq9?Gb-TqFK4IxqwdqrRG zz~CKouUUbR6B42;5SKlh z@sDA9!6cSVyan>yJAN`4$GbTK;jW8%h5DccFXDE(#+JnAevhIfLYJTUI?>FwpC%|j8$UVm7Vuk!2#SRL0=J0J zS#szz1Cg~Ior5g7uE9Vz=EMC2;1rgMP(E;klkgSLJi^MsxfipuMcf;>4j?HHx6Es3 zIb{<$Jv&y~g{-F8lfL!+13)o$aw4pgh-Jj6K={Vc)Rj z7_|HyJtimyeMXNN*a!+zA~6vluuJAM-EJ#7S@! zp$62BI?xd6MggGI1ZQ1v-iZc7`ylE=11K9=VC#kBcGQEG!%+|1>4u)Ip(_LMX@;x) zFtP#KWv~yzUK8rsi%h5z&I5GBJm}pIW4c0j703Z&t+3fH8mpKdt+;6Ph2A+J&-xIh zoc{yYna97)r#Li2mg1BK6yUEcCl?&efh+CM{+^8WFs>J^fIh9Ek$%uAtHa)qgbJkl zl|DOw58Go1=$TfRjKZEZo%2m&~H{^gHqkPl`G%C<+v=n$1 zq5`-wA8ElOmczA0s2nw-r-0WV(Y2G`pf`~Kbm2#rpf$kfkD#eS)PmHg2(?Up3&*XK zKf;}JXd`+CU5f5P+YoQ^Q!8W_mS~LvnWga4v=fL*_C;^Y+*;oWup2C;m$8iz53s2(XuwGvV{Wg(I ze3_qqCH8>0OaT4ab8MH7A^H_|Ig1+j&e;-Btcpds2 zZ9y%#7tcqxA`w`&7=4bPLw|-f;X}of=U^RthGdf;|HgJNXfnK+C*J^#UcC8H1zcSk z+R{Rr{^b_de0Xz!{=?hy>1_%7Ir-e=bI_KDwnn-=6|&I9TUY4wTDrYSH$i9%{CWf3 zUqUx)$cHZ8s$e&Twz`nTFWxX~f54v>lmh$Id|IcsMWN4mu(g73oCBS2q}wxqO_xq@ zSIjux7TzX54R7E>un{%>2R5UxaVI`YmgCDv1fGwd96yOg7^6GEp&tb-yAEVXp8Okb zKp4kQTsra5MC`=Z;}4VF(BFm1C!YWp_QMP3EE-L1R&{ven@E^@uz9KD6s6pMk3d zaO6csSh0!VPY+K10}z`t`Nd>#@^6!WMbA5k6U0Syioj#0Nd9Bm6ag*%^|#~LkmzD^eqL1>Ht|W zjLn8MS&Z&RV>lLlH+c%?%D}4Jg2vF(u#yYW@BEwm53Kqi&cKyuHR$&dh#=e1v#_SS z(EY$yHF*Q9aXaASQRw?MSZfe3MX%x>{6|ua-@|{zPU0k`cmmghZF7L&%doaCfti{> zKaJo$Pl5ly4k$Joq_Cnskd*=Jv8Yx7e$KA4{AnzE3cU$lUI?q819a_%mA)QOrWG`C z7wqg=E9`C<$*!#Mip+uWI7F`;uDgJi0%*B_S{u--2YPH|@Pu%0J$NY(&MHB&mJlks zCqKob2oo{VPJRni0$@Xy3OiyOcob_rGiaQh)tjK9LeT9o_=KLJokhe7=v@OyxI1)@ z?d^im?7kf2Wqp9%Yhgwh_)qPhf@i6b8piX`n#n&*zCKO!|G0hXr;G=r1-sk z39S5I?wzo)ptXZvw#@53Mp86+4o6z5|1<%5*_yzn44iX!wCjqjB9AJdZZ00pi5@#pp z5a$if=iGR%iCfBD#C?xf&AXeQ%J1Xf9HEbBjkq-8<%lmMIgtw^uZsLOsx|8MsLANz z=+n`kMF(RtVv1r0V=j$NjLnGciTyk-I<6(|jkv$ZZ;78sNKBZQ@M2^~Qs2kPo)$P~atUIOqRG+0^uOHK2sXwHDS^tjyQ~lTaaYKY5*`P3F83qlbhP{UU zhMNti438LIF#N;tAH$?E+9)!rjTU2$vE0~b{Mh(!Z@?lV1ZmYa=ckGa@fXI^OTFb|kV%zMoH%*V`kn;$km zZ+_kUzWH&G^S z?TqaS+e@~$?Wy)myWO5=ue8sxFR`z%zhVEt{)PQV2jhr$NF7>7tz&_s&C%!B=-BDF z+Hu%%+;Q4za{8Pl&WD}PIbV1F)%lt8I|vrhE}={5TJGw1ZF22&UF|yTI_~f9{Jtj1YSR##Q; zu8FK!TeGX?>6))=H`VT|JzM)(9k)(V=c=o!yQl8uy778py}N#({%rj>v+HKR*&uAV zq~X0rZ{u*|Q;mO}Gk4A_b5rIXoR=~$d)|_HSIm2&DWPdm(*yG(=ijuTWWn>zn&#Qf zTNWA@{;8#<<%LC$Ez3|a`r^{REd64ce%a`%(_p0}LYI+{+P3i6FeXGyVH`MpU>YU%*%2zL2-MjjV)z9?n z`rjTX8+dt8KX`8FZ);v!yMFEDx|DU!b+zj~>n~YUo^?%WWwVg82eHr%t}<&Aiw zY~#qrGaH}Yl(Naa>CmQ=o8H*;?WXg?WH@eEGOQW44(AS649^)}I@~?Hc6jUX<--St zZyUaE`0?SFhR+RuJp9k$Z->v1kddg7q>qd@_93Q!7^{d{LbbNH-EADht0t)ye)}a zBwI4JShnPBDce%JrFqNpEvvU|+_H1aHCv8sIkDyJmdCa{x8?OM?{E2h%XeEQw?=JE z+M2pmwbi`Ux7EM3X6yW|ZCiV{uH8Dab(Z-?nMnu5H(BJF@NMwgb_Mz>Yw_mz_|Mr`=-@X0e?ayt0efwXx|7-jBj))z}I}|&zc6fJ`?5N+- zvZHgyz>bj}yLVi-*-yu?s|9EKX(0R*W~W#-J;#<-NxOkcc0n)(;m?t*Pg|DcJA4~=e9lf z?Rk99OMA}k`DD*md*k=o_b%8wx_9T^>q7C4(5Dp1p=T~^%i-rj`xxYIJjiTfp)T`5 zByEPw>Jl`JNAOknC_aV1#*;)!JY)fRggj4PB!4CUVKBomkxV?JW_B}snX8zi%qiwU z=0)Ze=5^+6j)r65lyd4g%Q(H9wVdsoS2*W5A923tVr~LgkdD&}(#O)jN&ip!Px2Z? zv?4{3u23m56;_2qk*&y8lqd!jBZ`|9w<%64xk`ajs8lJ<%Ec<8idQA6QdFs`bd^z6 zp<1eH*Zkp!r-PG|6QSolu@LdCkfZt`gAbq$Q0-lXkKnsO{_{jk<$n(3e+T48)ADZv z`7dLxW{xrUFb^?*U|s|H5hs&l<&<&iIjx*N&N|2fUgf;Q`Iz$qmv9r)QF?y*X!?=# zZ_~d6`H@1P5GfQ24ajd-_@?DQ2J)YnA^*aV{D~LI-$vyhpPa-kFasXszfXi+Q*35Y zyRMC?ZQJJ5w%f0^ZB1>PQ`@#}+qN~;-*b|4calGOFP>y&U#+$FPWGezFGj2CU6#F2 z)!I~fQ~3{!a}?B0^ym0p!CHY<>QyY-fQBB39itA}PUw+XxlYDAT3oweAJ9vmTDJjy z;CGMJM5KR@f8TyE=WTZ_+Y#d#u2(f^euf?c*r~a%z9D%2{zdHC80q6MkC?CBgf84A~mM4e_jddwisu?y4=gLZ&sPNC^vJsg>L zj}Os9+YfsunDe~zY{A5|P^9C(Qn=frQlbbI6SkI&-*Ys0TcFIwjxdL^xPrP#*4q5SxjdgaR12do6pOj=kwT; zwxf*v?fART6RA8)g&Qkp1ndbEIm^ch%ojy=N<>ReXN=?tR^B;M3&$5xbn21yCufNI z5ll{e#(>QeyC%T18l%gf?Nl@i8ta{)7QHL#>6ENe*l!Tx5r$o8Dm7R)u>DJZRRq1@ zz3$g1xYumvYRFgAmO{g{(9HqvBhj=l!LH6D(zJN4p};>djQm&!U<)#v)02h|$5f7JkCM65Y>TnSMH{1Fk&_rFS(9tuni%6?4WuSky~22t{asvo#rCG_ zjeay!SK#+GVQd1*E14s5kIXfxTYSeDRcWVQUrmD7sL`SB2gL`rZ?*+RY$C;N z=qt$w(^n9$WKREg-wqQ^TCxnzLPXDqz%Id^U;2>@HQ05lQYUYyyO(@&Dlt{d} zDHRIP#}}wa_+Xqyajd57z69^WRHb1?daw-Qf;95z#vz>}0^`@rA;TdcK_Vdy-4y99 z!&?}PG~F9^RbUh@9`zotA;eqWS8(S5;*qXecxP|zl!7WyLgCLTjO8;$??T>AvDJhYN0@`lE+;r4q+Swvjo=ELG~!K z8iT9Q)c&{qiI72L+q%@*NfBS=uE-zu(kWy-Zbp3orY0CoIo1?ZsE(2aV=9o_m0t_U zz2R4!84|J}tNd>vQXxaq-(?aoOIIAH+K&XzP;o~*k9@m>X#R{PvwZ$o-vLd(XX!OA zynCCNdfR{ewf4O)1fsakaAiQT`-;Si+h_iw@&$OMP-H>3lrRo+n$7~d^A^3OX21@w zl-NUp&k9hK&8UvyBZ|2HU;yw)yTD;1si4JU@yGyBD0dbqA@E-m#IsKRmAQFz{#IT< z(l7Z{zdAf9k;~>>8&T|;fiRK&Hn38^QiVz3q#zSw)~c1bVy@u>*~1uf_2K687;g=HkS-J%#Pf z4|M=0oZA78ZwLCL764h*JJbsH1O!plZ$b%WP>=De1!T4zQ5}T%sQ|dQbg3141xWWZ z=)#^a2mXr_sS1eux-fc9Ef=f6vMDI;eF+ZG||Lb7=7Q*gKEyG zEqSu7cnpx8=OTWf&KLbOgxhe!Sy;iRY{ZWEe`_o6z(Y=Fk=7MBll6dWG-?A`pSR&10H8C;klQbRV0PQ^%JsqP3)~a-?XTC*5PC-w zrSl5^LGBCN6Fsx%cAI;rciZvG_o4p5|D_KzbzAak_j>b6@XGSR^+oXo;uroM{2kpB z@NtLpK^N(y{5oui6KO`90thnl*EHxfoQoKuM9&3E1PT^9O%w_e0c$G_DijiMp(<*JNEtlKR0s z9A9M}MY1u5P@i~7+%bk`7JU<~pLhR_sA<8|~8_pZg8{}J*x7?RxH=$mFU%X#p zjZhufKGa)GG{K?xz1}?vm%K0efpGxX80jK<8j*sYJtqBt(W?xY3bvvQE6Ttivx9;Y zDPy<{GKqddI;z-c7$y^mff5!KiP3zTv)D8xCRstiIBDPqqjeJekbGF8^`L11Z9|kraM<>=m?OJoC^0XN8PRaP0|#mmQ4F(H zTGJ%ADW4N`1CgnTxSyAoyxZTBs)}Tu+4VN|-m~j-#M^)Ckn513ovHvn;lQiTKhMkC zIqW%pnttyYuHAmBf17$*LT_%aPOmKVu#RqiG6|s?g~YpiSQo`GT3nx65URAcx4L80 z=dt~_XCGf6AUukQusi2xhf3$0xBCRGth{Cjdst~9t@(UsG2>b>tT9REdi(nO24p*g zyDZ-4AGWJGSkqGb->1kmT&%R^9_!4Vf*LKr#ROL2{Hqybi zu;bWR_~8^8J!?IlUq~(gA2Ja%?ZlvZXG`oOe_HXDhWMd*rOl zwWT7*adeUA=t(JncyyBY!JE__I{%{Z4_|6W_{@va2eIfT@3G5SSC^ZC;pn93qcbTt z_5NZ0&4Wsh;pn2sxhttUcK%7RonLB1{Oq+!&*B>#Mu$c9{3s4micA$EfjsdsjHi-3u{C`!-AlG%bWQ{2_4==^TIOHkr}7~ zW!P|12#LliX}&X~H(PyuD*n)7)w!W^=MXk9waelJx3=XeP& z=ajWOI09}8r<>Z}8U{hj5Q(c_x%c|m++OKizf`Gkid!3KiX9=&+&zuXd8zFU@UK`- z=J?rStIIq{5dplcv`12EP!a>}{cA|(BZ?|Ao*`*!ySz?HcRiT+3p~nn!YoVkJXI-- zx*Alz3f}fgI`_rMVX%VnJW$&d=0`4>AD1@6WL?luLF)=Btm9SdS3Yn0n-#ly;3 z#q@`b%59fPIobPp+4D}bzASsO_MF)lVoEClr7j zGA|=z98VKg#HHZ>_QIZ|i zk-F4dvXXC6k{;F1ML(j=jL1sz!#dIvdrMXPGD-URgsF?2rOJx-GU8!8d8@BJ*cAC% zzSu(mS7kRVzhpPM%q`1mBieK|KFux5ZxF95`N0M7JqJLz?RQze48mo~V0< zf{$^^9_I0ysC$|pXg@) z?x@G%BdvAi@I@d`YsvJ=!ISt{2K2Mv!r?%xFJ@}Q<7nip|NQlH>mGx0W_p>+4CgXb zt5BW<<>7<-Wv-b0od>_K%^7GiTI5?6YIx!LnNI##tv$)T&)Uiiw5vw#HlI3q;w{Pj zax-`J1Fk)^{4~fIk#Qf7`%7!(mOJWklF)7d_Y*jq4N- zKRIItWu8Z<8AIG%T`6X+wLM?ITP9`r=>D}_qD@0ZpS6;fS~HDY+T{A66*uM+5BB8* zgLYze)eucFYcR+=)5ThMg|CQ=?iIMWc1ORKd9Zk)xnrw>wx%_-GlyL^1;ybPiP&{A#Z<$Dgc@+M#n284KSp=;v%Q77b%M4N`C{v(>%cW7OacPDMBO#HidW5^cmiI|Hyan9o!>U-Wtte4#54GQF{nZ#Ht4?O)E4b(^Vf2b%%lXO3(F z0k(`}*d+0_@RO`8e|tHooDBgJBO;F4qr@6#Ts-yfVv_;CCh z`uofXwS^;FRy=2#2M_c!i8fVNe>Bb>%1TyuA9MZj9RvwZrNTj31a+hD4m(gv zv@ohK`;7u8ZR!$H*dwN5&2Zg;915P$2&P1%Y`9?uuUGGA$aITnm5Ch0}Fo z@ZLw;R2C2zq~g(=DSLebcCDg=oT>uxTllM487fy(y8{aKx*%86y7MAK6sw$$Jv2CU zqCu;jnelRT1i6TXe#=14&yPVrWwo7}+rlbrvqlpwgAsB6^bhUJ8%P365J4V2ogNtt z^AT`KRu(m}msqDgUQ<)PY1(pvwBNkmtUA?Rcf5T6nY@r%xnZih^*Vr8{p0ZVC`RX9 z%v*8s2Y+iWO0-T&D5>#z1QYCKHV#lzNo)1m*0cCS9;bm-tjKzQ+z`exPG zVne$wD;9X`Gwyue`gdTpDE`%VWIG0_czo-tPKC=zfG8vkjJBqAi1c6E3X^w`BE7qz z81)G?bCxUhB9U>?e4&E6lEogu6!HW6w+~eG!%xj&RkANrMi5BWZok5Ng{R7FIdNbj z-Ao@dm#Hb20yIdosr57aV-#GZyWAx^o|dT$mx&GSu8RgIHFFnDAaIBQsa(4zlL|9{ zoNKC_74cx18N*ZE0|R7Ltp9RiJU40{U(`EB#0!)N3!A*yjdvC=fK`9|{+`%d_a>gK zPZgzvM+sEmkX~`L=p#%h(gi?dk=9C+QW>YVW}P}|$#>{*5&}0{o14Z|plsH7j8-!` zYp&^R0cO{ON~-|k!Efp$487a3+~X*;{{Cf_8xlqgkmsos_M@5AE0|~dQH$(txwW+ z(z_XWdSVZYMHd(7ugP{>3y`~p`s~yn^UEwdgd}EG>u8t0v9UzQl{l4#*^WRR0cDAFs;NLpdG)3RuC|tZgARw#4EebFcu2_f4}q|wj=vi zB|y0tRzJVfaG zW0XbFwW)m0Jd-X_(xa~C(Dv4ZVa3u0H)blSsk_jAl*%P6eV5B8T!Z$|ab78*o-{`` z2UN?VOs$7~zWdT*Mv65Uf?zjQx}cexQp`0iQd&rbU*s9XS0O|`7G)E6 zSgQJj?vyT3xI3axEH#ERHUY?6>0>Rb2MY{3%o4{b3K?u8qyVyW4>?T_-Hd%axK-Zl_=C*kYR9}F! zab8%@ir%pzFbW}}m*-AQ&hq4`> zGviL2Lf#VcnnEwBVB+I@Kp>wtV71LkJWG{&x|0>^pf$n=$`TTv zXR9Oaqr5uF3s+Zixg%CwgvwO7vO!^ zyc``tv9O)MIOg|Vcb;t!4l~E%v%*uAVH%=*#tJK(d=>eG@2{Ts@`szne=?_;2jj{B ziVC$Qo2zdM9&fzI;G_DF**T;MTe-vBB}Tg6nXhju(End&Gwcpr>t6=^7`E2xd-s#us56xZ@Vep7euh;&umxXy+! z?Dp8bdVtcs7Fs?ViLc;Jt*LLn+E1vxhkZlMja09V24e&V$I2Of9RRmkLlMdM+jVtE zWaRO1cDHJ_al$D`_4*Y3%H^Z;PpzD5fx!W;Mum{et4T-oIx}$0J>E? z8hDdLC$e^Q@HmVXVQLVIU*r!KLcj|G$Z*yg8O`(}Ylf3$P(S8&Z~B*ngV^vex?69W z>cAyM_6ZV+f(fj0ujtcxlxTH0*P;7B_vIzCAZA@_(9mn6;|+g=;Sdu)cyE(TaQbFhPLT&)iAngLz5xF!i4LW&&Jaw0Wzg`WZ%vG2 z2;?*3$cFdzYX7FT3{^(-q7umDa5WbyuZxqI5@#$WI};VN&)gxW zJB&g>%Cm6v@01e1;o%U$wo`()zgX7%`q- zA{Da9Fd4K`0vP++t9I1%g30WL!ygtt8hUzkjJML*vEN!;nFk+;2*WS8urrr&|JX9x zQZ}^=q*z;5&eIm*riO#BO*A!|q~;XKnF|C-lk_XqD=@rzTWoDP&mU5L(E{(x;|=XX zSN)2ttZhCTeZjGM$EbVBSDnnoa_~wEb9V@kwcS{2JRZBh2X`PPmP<=2V6w^Pd$ree znV6DE+Azk>R_;(C4nIV(tsdiD*JxJB!WT#FFQ0&kYNEbHDsC(OhgczkmWsxisR{vU zkTGtxvr1Lj%1u#{U|?DAokiCf0PreWVy-yI8Zm`I3!f$^wXt4vNgucSNjpW5EExyx}{DOt8b2Gn)qbFqp7 zW>v!I2$L{O$6%cdn!;joW672Mhjdb<%4ihO=5n-ubgF9u(Nx8vn$5?~RELNGg`}w& zA|-2yq;cG(#>6e__~r4-y>Mp2B0tQII=Ug@^cVZ`7lZx9;+ZG4^^~VajPn}SWE&vf zFx7;fx%FbTxx*f4iEH=|r$BP*jyMGY%UmA1Ejj@^xu!Yx=1@c{*D z-=z%Y_qATTNysZIkW7KvM8AboghO{`9Z!sg;)b+9TIUH0&l@j_oH$!>fg`o@oS7BK*XtA1W$8!!-EeupkbO_ zK5uleMAE|bx#?*sPG{;Q&biDP9SpXsUaoBM!Cg)xhg(?IGvk~;>&6kFb+x0WFgL|G zWGkJktyzY2hJuW2UtGi}8Rt)i?9hb5VKc>?&NO%0I3ODX5xkj@l!QGbFDLVuE(88o z9L}Smbub8r0}EagtYl)T17rGJY2wKNN%Ag!KS+dS@(XKpdUI1qt1lQIM^5%#NNnI3 z?r^H%c(;d?(*sK{U+HOzz9)}xu4~+gPC_Q?n0`QABEV;}fA?*ILQefRQ+jB)0v~#! zOs}xXl4jwt*N>y;aQEb*$d`51b_9-o8cqBz< zvROL`it0H0SYgq%mfZ7eY`b@!gh<$m`DK0L6-p*{?AvF9X5{t|KlI_@WF_j`>!U66 zO}M@j_RAuG@wI6ld3cx~cn8Ag8-#gIDxRPkl`l^!UUA2lOK#HiGIbA>!|#YVC2zL` zAKxiX$8!Z9MVfOB#U#{@FjjW5$AQBm>1e{pj|ATQvt9|V^OLq23`L-Kg5Q_?73Aws z*b%bZa6dD=<@S$0PdqZ$`vp!P%rprjI~#9GK&++d-{ACL({~gO-l2rj)O7R3#?Vg| zTozxtk!{@B-fv>F5i1ELBV3RRgjZ9&ypDVv>xEM~$A{j$U$iuO_@n9&yoC78^6IIp z^4-WW1Q?0U(BWZg#A_pAFFFEWOK9(_-|?&<=-RzL_!dAE z{MwuxstHjP)%%Q_wB4LkYX#F9-he(GNov7SDP1u2DM%=4b{d>;a1P6Jv?KM`@ndFx z`gZ)D@A2~8@cAw9U_R@9c_p%Sx~5=tX0*X^{!oNvio)VOO6kZx6}rTt?@ftHtt&?c z{&WkKP7}*zp3DWMASk0+m;rvj{otG!$2aVd%MV4yy9kgQpFpp3`4^qL27*T%#DB8E z)?+|jyi&XmNK1A}2L^2V{7$Lv{jmg2Rn1xv9^NGb9!s6iUQ$xWqS-Nx7cP89)evPW zqmiR?7Z?{5U-X-yb}cVxsFzjgenkt=V;KSzFU{;aixox$fOFOI;Fu5oP@_EG{r6eB zbIslW$GEbLDGO7_V(E7dh3jwP7Hop}>nT9FLgB-kT$gY14u@U}`BB!fCt&&_Lt8!> zbtd|dv=E90Z+a*ln}(y`ut9IF^OoIjZnN|~|8jk@8F%MWMG|>(!dNSNWVL!gq)35w zn&EPM)*O0Tg<89_^$5EJmbo7{_omp@tzu4t78ULM>8cI3#(~QT>X{p`Lf79dDrExE z`&X%L_6m_Qi8?G;sWu4o5)I9h7(vqLlqdx>YTqC&XCs&3n=;sXf-CXC`usIFOt1sq zZ<<$tUK6JimgACS#Y{d;&?!}T*a>vDR)`f1!24ci=GU)xhVVEPU~;Qv=U3Fj#fC<1 zK6n0)#>dIT;%w4k_@GvAd()}Cw3MG($$(LJUAJ|aMZysk#q(ahYHm1RQ_aqG?k5sY zIt;z?EXS{D0$$WrRdH^u`WS_52p()A+5M7r($W0h>6qfWD^D*6^fAY`ec(HK6s?^J z?*{L6r6Jw7xtBM-^K40svYhq}nrTid@<{NeTsb(HEglIb(BOqxJMy=3M$V;*`G%9z zGy5P|?gK}JXdQ32X2lg%i)z@Ag*QKikV@$S{r-05$=#)$=Hu~saWBi$(*#y=cje=s zBiR-V3^rt1DWujz@WAHHBFi=yNM(ucA?{uJRr7{Fb1pEV!YK~j#j{W}iJ$NTBYnkg z!7KWwWu&h52;|YJg$cRC-=DY~J>SI-J0OP90X=R3J=zLfS|EIWcv*g*VAdfU2kBNu zAuF)HC)^ahKVeU)(*S4Mp1&cVU+iN=lUIvp)}2tN4R(F=KYRr_MdjgB__;Z7j`yuI0WF|PjTLWsX^D>$gI}o` znE{S{HMt(JiB$6kk3nE_RedRWc=MxBa^9T`6OG;7)`2W`bxP&OqNDI3fC=14xD3Nv zsv-lIBBufIFEJvQ(rp+ot_ua;5Qh5;XX%)&dF~!abpcJC&JjIMeO7KJwQ)9@k85d| z6Fdg0bZL7S&g6RM>@Gr}+2|b#-%OiPRYu%@_2M-u(`@O-R*v=O^9!o}7X)z^>AKed zqFh6Vt${d(X6V3BksH_k?4%{0P813tQ3pJ(-p&D^sLz}!fv4BQ7NmQSN<9jg7{01% zMe2G?u@W@~hhsM!IQlQ(ZZP7s@%>{bRG~aJvR4@xE=JFy#$U*SnRdDvwD1RT$)1}0 zat#zPL6{v?3ff`tl6?e_zY~%VnUC!@#f50T3@g<_$sA->N*^n(A{F%Tn3JTlz2o0m z)CVnw&hYaT#L{SGO?!`R7tXdi1EH5(Uvf}^5&N& z@{*!s2kPqT(&sOW8ylUYiq0%xVVUoL^&K7ZAG6$wLB3DL=K55A!umw|KJ>AB4Rh1W zV@~gt<>BtNvDAgW$%q6H(hJe6(@woS8K>V9BZ?K0QEV*CKh4eAJGo6mgcbxD%rDGi zUz!AxN6i$T?jN9F$`z|*pfeAgo=vj?YApln<^zyE~F!&by z{mQMd=wwBwE!PAnb`9CmL`5A{u%`Q z+1Fb8q>M?1Eg7$Cu&Fd}59X}O6wAt2E~rWr=|dN(XccQtPQxVh{`JKG5zmD$Z0H2{K!kBw&eJMEhy15f_-MVAa z(;Pghh}~O0E%m9+waT=Mw^MSpo&x?D?U&S&>M2SFoW1t_?Xda&%3~<(dpKs~LC^x; zM0X^BIU=~M@tMUn&Vc_Cpq0A%w(x)z)F*$n;?j#MPc|kaC1=LfbgY+6$Uq}NX_2l_ z`RNEPYIDU;yc#-lC7>4z+J_^_+h&&!!IZcosOlA^9BVm8+=yL1We;2gZ^Z)#&qA;u zZ}swG5S&4l1vmS?_;4qxfl_Ur4&|aMCRQgy*IX1~J^z9I+YyWb!mm0)R+ZZ8oO+o% zN?7#BszC<-Yl}CYa4b1*SzOeytxWU*;qZ8RpNToxyKG0JKYrH_0>GYY+8Y#wk;c)`i~&RuCN-_Iv(O5_IVht=8ChbkcrisJ%{Eh zLRg%}_9YXfd+YdLDN#DK)A4{vc+FzG$oqB|ZdgI}`rfKhX9{vMW(Fja@rM%hQT2wKx~!_LrCq1!^r7uQsg+a zqjMRyuN~i*LO(Y9zh*fj0=@4D-KE&h#d%iK{!NhnBcAw4fq{c_zPdKzvT^% zS}agXFjMJSC}8V3MH|n$Jvgd}X0}S;Wlk0K_BPPngHf*J%rTo&p*E2- zP^(uYbsbX)Nn4e`M+qi~b8s*&B^(g)EbiQ8Ct%ijXfDkBAQ6 zXI7GPHdZ+eSRaicLkfZg6b6uX2vtVJgdK}8Gi7mS6(ysVIgWhHtgEl$(NVKyN|}m9 z8V+S}hGQP2t(qs>lgc4up@9=-WoVVE9K%H3VL4R{F^dz;1f|hS&B6|?yE~kVtiaAE zz_~b-gMmb8QPZfE!3Nn&R?(*vjzjAtq?D?F6AVE;s7m=+Qa?&X#3l?B1#jWH!1i|ihNb1@EJ8~0nq^}BTal0tfQq!omdT-Z zacpdQJb-)%i(;fYi6)J2i?6|UOo@RfHJTJ%wW;UiXpjL7f@*p`F+p&HkoEX(g=xrS z>}r~dU&%nZ!*Unp$1dzRdEB=-&s5R?G(thz-Z(8JoT#WdYU%%}T9GoV4L^SCr5g~r zBe1Xccpnep=V7`Z1sSEWIjhKHI#oj3r)D;|du?6e`-qF=@6po(LsJaYrZha~Jk!O{V}^Im<6?QNwweyD^X`6xaPj z(m&d=#LN$g2m4H864Etnm?sxX<2B>)=_ue-mk-FLzMLJLYdxOIh<@Q{c91oM`7?oQ z7uwUjj^sE!IE!%*ADXoVu_9j|xYeO^T#30%D7?_`Vw=69dSf~&+_IWs{97Hb&<}RT z%9HAdV#buHksn%aLf)*QnZ+s`x2^XolGQmyCxGfkLqn=*=@il? zW!Hem1P2#vVf~>5{g}kq3XYnirGvG10EyAym8nFX@P?tR3VF3%*ThYYX_#EW*-wLp zuI0IBetEgaW?;jr+qv;-!+6?}p-q?T{J6ydo=DDYqMsV!vkkq(JiYI(JS7pK;3jowd`-JtW+nrq<{F#S*JI`L*L=yVcV_OS*OhN zr{Ew(L*PgN2_YNkN(~sS=fI2vz30@S`VCc`n92iR4`X4dHw9ddR3Ci*t^?A}q}Brb zvW%&mlbMFHyP&(#J<}e5sq+vEosG*V|E^8i)z00&sSHgybGq#@K$c*&_8nQLth!r& zsUC*C8ixFP$OG-t66R9?Di#|kmmozAHUw?01o{1p^|_xzO{Xt-6g>y_r1CK6Ey@Fl zLbm9-?91@O+3c;;hTW>J))btBnXIi@0T7R$Stywx$)yugnPvZ&JnR*@5ZyK_I&*i( zgtj&KoFa7o#6S9{7}Z69?xOdalAVQ&vGut5O?wvKl2Z*Vb{lhE;SWDy&89ZWx@^uL zI*?3Slwxw0+FDP&uz0)*WjjzFA3e0fI^ACG{i!-YPBY9t@NaIaDD*^KM{C_@h`Iv> zg~4}(Q`{<>1WlSTCHzp<)uc>GJJrA{sbPj}e(((5R2A)=)WrE-0Pejr7rJW%@!3eI z$=RKoo`QxexFeflI>%fhDs~}~Eadg)N9L=0phjh6VB;n3!-<29J!F=kBT$)HryA|@ z$Owgh`@w#L27N=I7Z!gBaO+^h&O8@bz$_2L$1D!J`^R89%EJ#c#j9gphaR`=z~_X3 zsQnrAdeuCOLkAW~-g7h=%4P^Rlw~pdwbM-+;K@7~*lqOi%r{q!dt+Hq6gSiI!{1M* zzkD;jY&p299<7^Ib;%1jdERubaM^g?_#{w`8B3WmpLGcfNsuLh2@x72OUd{Xk|z0M z35Bx)|5mK=M4OHD42*!HcI=8Up3bqW@_EimmkiMDx%s+#GuoeQ*wDK1+_0SCR#fAM zoT=c<_IYFCwVXU6%c`cIv47F`VATSq&M(y%`MuDtVctsERbsPE7capdw5RZz@qEzwJ zqAp^11e7##Kd~Fwt7^+Q?6Nl(5Wq*b)gn^hPDz8@T?7es?qW)F9+nnm6Mv{cIBWR8 z=FSJI4@>ur=?Pxhf00?{#Mu9jYx)k|jKsKk2l1$Qr7B_l5L>Tn4jYdDDSF%Mg4*V) z?*rZ)?lopieh-VVx1l34**y)ZrcCJTBc^$NzB*=pyg7P^4lnu0#vb3w5xJB1jjHa? zrck>ktkI}+J$n5%u^Lfl1h+V?cq=3k14_kgGSM>qKe%!V3IQ?#NDyz6`3PQ`Zlfqs z0azv+7NA6X@DH*%p&5n~DgQ@u-D1C zq01m7PS__cn`nVWYu4R4^lUY445%i|C^aFi%bJBV*CTAN2UcqhI)spJ? z3*1x&u3g|qLj9+Fs}WP34PGDkc1fD}5raKE#!&&MaMlkchnmJm^k=#ic;yboK`;sl zoI8G>(6}}Vgj2sgskg0!dBE<)c!voY&l)5sJj|BKp4&mi^`%ZrVzAk*7QY3#r=7w_U2lhdr;WZERoB=Mz8+ zgBtB+Brw!uV`jN)Bc6bkk!u4F6SQKm0h)YmY2EeMu{Ol8cm=+KVVXT6H|jGV0am8a zeUPtCQ_zoGzZPQ(`pGdw*QY$yC$=U>IE?)q7{Wp^3T|X2a|Zg1GEU#4vgUSZEV3&L zJ_bvE7$LJ|8pb>lKBJy+Z>>s=tz%&%?OsGLKAa6=GCaywP(pMe6JdkBGPaPs8dWuV zC$EHB&DHnu+fkaXhnV7(BHNo&_s)`&J%};g-nOsyT<7gyT~!_L$z;;L{*A|^Ms7CcBk9(j)Go=4hj>|AYXe6Qv42ojaIq z0;U5NltG+XNcy5!o@7iOPt7c){I4UxT#lAJ3`Z5~9+Jj0PF>ta7kL}jSXU`EoN1HG zQOlA`Y!g+UupS+&GtBJUZ2w+wk6J~Y*o_M$>fpk$pC6dLf9XI|I{ap(< z?V7q%>^1YCt7i3C^?Nzk1I4(5^je68`tqUq)m)cmgB=;xNJBpp6$<89x-4@H<|6yt+q z*aC{)U>}@5Qta7#Ng?Ys3f~ z%>}KG`(St!8@qHvK9zgbJsL<}1g2Y6a%o4VUE~iZAoc9~Ts&p61k2)NcObveb8G01 z9dCk4wW@~jXYEx+*Qxb_UPW;4DD4Tnh_@>scLilnYd~~XIAQna`s+gQ1ZTb>!58TB zthJnY=zR~8J%U+(1je#_J3YxZ3bG+G4&w_aMZAanC|`IwZFt;b$a&Lt(n~<%K4wd* z5(08L7?_u^Nl@C&5wK*8cLx@kwk{cjffw(4FbGQCFY!&o?Gk~_?}2>dqR%I-7JuXp zDbxJ2D;Q3_&>;j(eFsazb_;cjB|uq&Gp)n?$B##t&jjRfvzbo+X>3dx_Th$`&BIZA z4*U`t@=r#VyaMIK`2Y=(*`%n2V`SMp%Q1+(tHg-VzMr!ly)*yF9EMgEysq>g-CVm- zJ&ntwV_p)fg{?jIt^o!$tD+<|*80BK`Eny?ert0X;r$1C zK!v~VtnpH;Jj|?aeCDifR>i=-_6)6%c;51ME{SKNOUjnIT@fyq)ZstMm$==L8@Pm0 zF3We={UQ+;a!I937Pr%XfEfKyAM+3|`-bwR^g|?iD2^Wz&U%PP?S$_w%lOF0S_(!z zo(OH_{uAuuWTy1v>seM1${+D~VgM-Q=z>7bQ>sAJ>sy}I73*|Xn^v3F1oeelozln2VoJ3`;MxJ2^dEYqF-Bnj`Z7_Kq zqg~hB&WEqNt{N6#qR|xt>{l(=B0?*<8o4~*;fdzuaUqY?s+1)@XGEOGhpVARXPj45 zzS!vuaCn5qVCXHa9JT3fnHz=k>Z%?e9=JUm_6mgE)zwdp4%`t6ds>C@!onxkwI8l1 zU*YxU^SE-YwlyB#+0=e#dBsYEfER%!E|;UU-f1*eTl<`~27_Itkmp-KqRVV^;a2yp zEb2`!!#6{(+uU(*;WO1$jRfqdsC>9*=v;M8I|1iZRzA|Z{LR)j)cN(h-7709?rf>O zxwLed+Z{svHn)34dBvS9l96mX%gQQXwcvA+=U%lQ`HJm$ny(O~E3S#p+E$JS|I)L@ zVVZdwqq@qUxVb%7e?fj$9H{ahZ@fd$Q(gTel2kbC5eRy#s?IHm-voH{EjPJ1%IEHo+=30tgItyTk&xd{wj1b`q#e4|Oc)U@NG7P)BVB z2QnXlTd3;*_;zO}RRG>XcK9ao67ej(Lky2rf5pO6%~i{Rm`L|FVKJM!@>2_)&LBaU zji%20^oYw9+6uKwMZQt*6X%H_)W{VvgWfNeh{+4F`ShrC(B&LXM*AF&0RG**2&G?2 zg;p(>hqZ>NT%ke1Du}H3eef>1o#Dj*8lXrME)N@3+{J}y>PI&LV(i#kV6Tq4eeg*? z^>iz7l=|jcFhm_$4jKlZI|3e|dXJyMxrrY6kZ;i}A(pJ{;%Nu{;~*TgUx?#r37Uo= zPQU|458v~-_WfPI)V^`-&f{MmKYWb(qwep!DeZ63h1jmkyTQHG5^(RWVB`Qei9H0h z@BnqX|;S-db5kSw6_!`!43JlL>exS1J*q8BM9q?SADYJ=R3QP)`5e)W%q2n;R%v_ z=R~O6=j-t3tc`)hHtIX@rbYf%yB$RgYL35z_*Ls3IGC>Ncl8?zOvVx{+3LwJ$P?`I ztktYr@oHT-(^9#!){ac2Iv)4*u;R6bsZ(jiwcf$x@-zGbd*)kakr$*=6ono3f#RY=U5!iaHEJ=5a&fat zUFg9Hm4OFqxVn zVr||Au|uhfnUq=%2SUIh40nOVqF6D6m4!w3_4Gd5J?C^w>;71N5daSNR+9t7{QfoN zW&6tOjyE>!jYU(Ku%z?L4Z3EZZ;sXKfxxI#2Ib)I!7zXUmwPmw-Vir5xIN7#vr8$H z2DOFd5QIJM(NuDIkF(3~Z#9|h1j@dtGIc;ES3;myDk55q2d~z8mlBhAvEN{=V;z}Z zUp@WbtcICQe8IWa3he3sW(CEsT%di$+{9I1MlDPx*;=h-xWLopx7OM0MM{;D!>^1) z)~3oATCFDXJSUw_pBgQ`zMycC+Y@7xLb<@A47ZugZjx74piP@S^Md9YyRAg6Qn7he zk?7iFpRKE3`U?kl+#mC0~jHb5}*EPNy{S#d?%$p$v*_U_Z^0 z()+_*GgrN7;L-66^~tK28XE@${8%b^a&ZIu9H=fWduq+%ua}h85;Vuv@8D_ThgqJB zxmmsq!tuMOfy@Y2op^EwJPm$RS4-&$dcU0!+)3^yoG6cHReG-KSQ=A=VH$#^5E~h8*6{dKoNW@C96Z4j*RqDJ-+3qZb9r%gg*KVwbU3=AzFLh&50vWdLMa3`!bH>F<;s6BSI!Ys zuZJ1@PM&58hjUmp;1LGj!|lx7Kfrny3?rOg_esmSAuDH~#d4-u>F(nu5l%Al{|u~R z@Wb4p96rk01lD7mYR1fG49)>d5-jHKo45nHyZc!mfprL{IpVlY2xl{I(V%N^^2Z3@ zkEE=|Bb!s)aWjbHaD=y^kU#CO7#HMGl!CcqUk(mlua*e&w7Tx%vIiGYudn?N!w29F z!@J%0)vfk=3nZ9APCl=;_Jz$i&0o5p@2_{Roc~B;!;WAy4MAr2*ckW-5FWc@C|$g- zdd=#W>+0tK00~?Znn8}16NizB{W-iLhxfC_u|6`m zJ%MoI)4=Hs zj^thAFH+xqDl`5fh)dZTg|f)2jcN480#nBgp6X4>=3VA{K4iZW{+Qz=sX3LZW<&sM6@ngEc=)OF#Ui4a*!;x^4> z=~E{y)&{SmL}RvroQ>ERJHixx|37OK%@xR9h+2xrXwE9|L=GRw;r*<4Xq#C`xflz} z;>%cDsUIL~HlZ3`rhCa6W<(oj#B?T{-Eap`Bal1u&*o=d%0H98R=4&Un!E4pGdJj{ z6PcInu!=kcY}7CD&!Gtx=JF$1hp4As!=YGo?90>mSYZN85vdv4?}SJ!J9b z96rQy(DsnU8*+F*YwwKr*mL+WOFsiQJ*oorWrF`Y4Gs!@lAJ| zkE|q?8Z)hZKx8I5;ZSCA=&^9-?gyZ7?qle!G?O8%9TG-69;CG+i#O%)QI?zbigv01 zGau&gWvn*3blLkmbNB%3XouthBe?Uhknh%k-DJi3UOK6+Q;sZInpY@UsclMyq|2_F)l|C=eoa(jM zecZ3%aigS56*qfFOa3J$MmG1FOpF8HULZ+(f*b3AyUu9x^2~81%EtcRX&JLpV<+g` zAS<;+tRLs3c{f**!v|UTJVavh&B=$@685Jk8>q$W`ljZNuOcMkG95@FKC|n1)tY^f zUCKX8!~jXNQqLvWY_;NpvHgmW-m_>*j8T!E2f196_UB^2+4S)^@C$-L(RZChD(qD z85ta9e!YLo-93=IyPx$WST}>$P?BBcXQR0dv(bup&hVQ;a6U_NSol-JyLX(sgGi5o zniD6ei(?aS6WG7e&(pP0F{P-dYeTaj(zRDJrT&nveHJgz;X|x#;9w3f$>II1pMmxq zuFm1Zto1W+O%Csyq(EDieUbfV_Q#m(_#d+`DrR|#f5OGMZqCk7teF2bo?fl42>&x? zMmWZe2Ew-wg8WX4#ly>%mfb*0NzGW|N7J?7{4s|QvNizB^0b_~k>-#r`RZCkqp@pr zbL_KLm@yQS!N81a2|VHO!G48JC=vr;wW!iICX8B*1fi8H!n(%okw}^7T9xd3w7R;7 zukdR$aYM94Ba<^>)owE*I!zC*L3Ub%GGNGwc4>9UYo-QSf7J#gwx!VbbQh> z+VT_~pR#yE4)13@LT4RW+@8aSkqu4bjvU@M`5ihNp*bhH7KH1W_n!wnIlMlH_p{E< zxZjq;hf!}~8n@^0zR4ee`3R>uDrs#uFzrsTkbA;WIb~3^{rjRKnrp?nXHrOUK|A_OEhx59_B;3Hv{DXy4bh4BEkd zE{6^pc$h;IWoej0vm4LMEdD3`h5svpP0m*lZ2ryDY&N?9P%G6{{wp&)j`Lq+-%O2$ zoHbSmsrMNAO{GMUuuRi$>NEv*M`zemrPUg*P7?oBa!!p}9x-ae{aJEOb4;Ogin8RK zDvg$vYq6%Bv`6$K4BEx{$rK9b@J1Q5jw8vnF3L<<78Hl*eVpuHBD|5&k%w4nbU$Xs zY@~I^%-|nprIVkqQ>bGb!2MjjF5f|~!v80E7Z>$)XJrakkZiFHhL`o@#{V|_C8|l9 zU0tCm4oluN(Pes3&{CjRJp9v%HyC0|dy&=}llJP0Y__%#Lu^U@Xbk<2nlJ^W3Pp~| zvU&#FrA8|a88(nV$`nlT7fL0H5)Z|-7pat*9K9u~EoQfj({i^m^1X$YJI#8@5imHi zO-pYM<>$~*ks*h2b7=og{S-=DW)>Y*PoqD}p$mo6=%pOm_mGZ3TiDO%&_N9!MUf_| zffUi}ldodKn>Erf6%c3IFt=&^c5TY+oEs@^Rw}rh8#!8~s>G+u*P2bmmd+c)p|s#e zzRKa)wxD`_)RfR@P7wi9RHjtX#2O2e8J4qFZ?N)s_w$7y5sB<>A&5CgX?8}p1EtUR z;rX{!)G*B$T7%g!7khG1E|E%p6=mpD;F~?Tm-8bGi3`IhO8k(a6E*2c)X%>Lp{PGU zc6@Oh6-uX5m$|3?4dKx1%goJtsma-Fqc1X4qoMUBY#y6)72W8f^L2H7eE*87K&@7- zo%SfM3WGi%(=H%NXEBkYwxbzBX-%5HZ^9}#GCme9M%*Q zN7e@aA^o8O{@OtOmucK^*6{dG{}IootvG8!m&5;%Ytsvgn7*`?yB3ws!FZ1)U=PCk z={=fnbKGDxV>wULtGh8?!Tt+_qnbBVGN_CF=iJ@>tVdZSgV(UXo4b3soI#0?+3)1g zzIO=b-p%ZXbLe2jUoaae)sF6c1IelUe>VESaD{5FwQC~B8w!S)F$uLwUFExKOad&R zX+`sd;-Fsd7mLIaG2TVt5lf_5iqY&ag||whGhAbs0`rfmoOv=C0CK6=t;Sn1vfD5G zOg&e!zs$*Mfb|MXfN(%HlCA9DA$&a}!+)E+jPNR|0<(vr7IHIvj0p96<~{e(eHc$} zbol{2OzZ^7QX-aY+m!j%tu+) zQL-Irs4OdYOcs`99(ASJS@zK`>H#xYG(5#Yx(@GN`{6K$b&4|Id-mSU_fMXL`)@k4 z7ls)s1VDq2pW@9i_0ptU$dg3;K2z#U&k}dsX=EI2~PmjO1>?(KXBI zNx$3ANMa8iMQNP2Qh!!gbv-$hlSBKj*X7>vs~kEkokssNhxR?7rB5;VnEaT0oE4m6 z(f>z*bJhR{F>7vc_K<~|G$MPC9azwDps0Ar;Rx{wp*yCl_IrlXQyim8b8@c9?Bt%{ zs$YV_6ebl-v>Fmd0Yf+Ht<-89BAtMA7(Lu%8H7HUdwE&;?TzXsue5k7)G8fdI7jDx ztyWs(^R2Fe?z+q;l8!qu%P4f3i!O9A{G(8#kVlQhc&3Dw!$)*G`I)}Ze%6$H>gY@~ zE1y9bk43P0Ca)*!$mdxuRtoo=r`8T~XAC{0bNf24!43oHK^@o35ePh_vxeaCq|&74 z?!C)A{V7Hy9IjXrcOBWg)Hhss{VR2K^G`FPuor5nTA7Mu12~Tnl_jYG&q?GY37}P7 zwk=&S;`z^$C}ChkQo6Muy~uOvghmgEd7T~K-OC69$fTKh<~ohC=(7NhpboDT;t2F;7t*fEz-HTOIC@tSCI{JHT2ZP8C zhRF^FMRqXxG;If%=`%vVBh2XgK3d;t22lDf;p|&@_$@b3)tDDFhc0RQB6lw*hxTvR z(JY#u(kzhpH0#C2SlGMK+?(w0 zpmImE^4kG&=zr(XA!St#{XB>EZ(`@rcXH^ka2owy4(&TeB6-}2O0kJNg5^I<2WQ5} z)7K{aoR$y#?}rW?dsKFkt5eEjHtn-F8*99-o@kB%ltYR|F|TbwQR#}Xz0^QhmCv35 zk#>{bB{(qgw?LIjiBjJjBWUrKWTKbeD`+;U3T-T=yq9nsrpt>hayM(b9;b8l7!=`i zdu~U4L(EuOLf7M~3O{pj<=VL#aTn(zs!P2e<(RYCOoxk>1)Y^fm8;HZv;&~isLMT9 z##Kyq8mv|+LSNJP1Z{;4(%$pD6H#7L>IlLdm zCw2~hhr!XiEz{`ta%kVK%eyC z!OT)=jfU9q;}z6r@c83f?jor_{m}sKIZCgV_>BBDdedjf&rhv@K)oc-)UE<%?L#`H z&aGM^&JJ@FN{LJ3Dz{iFT+vp8(as*_C?#T#7D46;ceK@Lu(5w^QhL-<2>=#_-0HE~ zx&j)N7xnQlps={DmQGaCWo#RnWLDPV{TOCVrb)xL9Xf=rJxe}9e8K)kcE{kXbf#@z>|Ug6h|^2Bq%sm^_I9$HnT?ud09N2tzITv+B-!k5qh~bq>cZSp?3w#v4`p|! zfUIf!%!)e_%te;P$+hyYx)o5z*s(n(aLN1oLlq#=8DwpPoU3g_Pc?m_jKQSwtK^)kSwh>#XUyg&`%m=?c z1x)NeQU3+<@DJ9@SIG}a6Z?-@>?IaaWoPzrW=k_@i||2Trkj#(?H8e^Wwq@5JNO z>CC~&TW}lH&XC~5<8&L~Eu??Uwm@zVsfKEXL&!$V$OAgKGgn^a*hHC}1pIApNR?2l z^lY|UuP-)`_GX8xR;Munpi)Wv`kPQ1!nc{NKA}heRsp_1;LvF*{H_wUM8iQ}0#rL( z#ww)Qp*{bgs{)txgoZrc#I-viM2Wh@?H){DvyXvn?}^DC@Ke^GX79oT-{(Cc5S92x z+eXgRHa6}mZK`+*d5Lebwh(_K?jk*`ZIktrAE5Tw#yW`pAFw#oLYhgL=Hbb5-sDdW z_c&&c@TAh&OEVJ{BlMZH| z_K-W|0cGOK$xp~vX&-=355OzuXP6m@v1Kq1px-wui$>03#@;Y$sQvUhQwFR`MI{*O0~8P+m|- z?}fbPc@o*xw0L2}%w1{h8Nb6nnBIFp5OKMeRD|XS&B4(|j{P*Pa%wGpy>>Ie+=j6*15+213jctab~ z(K+-AtuXHU4bK>Km?q``bH-m4r2M{hb()aM?rd-`f3&o$O-wGST<`OR&<8n(cp?C* zOG_VHgxU@DU5O>A-85f)x(4VlfsqsZ@Qf2RaAljt&wtf18pwx8sGDHng;J|hrmg0L zQlZwVR0SrHULX+hIDCURPsehE(C4Y_60y;GS@HX;q#E&@Jrpiy`?H&4kc6D*uCFmWl~CN>iaGb0pK=3nz>q;T{lJhxzu#aO8ykaPKXwdmpxF|V z%#&QqI&aIKf%?$I#9b5TKZK|ggIh)W?Ov%DlztWmk~hZ#1;u*78NJzUxQ zvYc;(-gn-=`a(@@mymA{25%qnocE$XYr2Je2l_K}CqL@*Zfw4_rclcdNe4RhP0sXb$$@;p5nJ?=1CK7dmj6~EFk6+h{ z{z}#h;GgrF^5a`s%oz^9LFIR3*9%=Sc|0{boSurz@Yqx1PnOilWF&Xl_)?+H(2sLO5JL!lzE zkk66I%A?V}-SfuE%NDtuF`-DJ_9+s!j1fF%u4_>6xk8SJXVz#d0)drPhq&oa(#lNAG9RGhx3cU1TTHm0q0xaQ}(b&)mY{$<_O+B{Wy0 zO{8mmGfJNWD~sB0%+GHz8tgpCAw;4GYMk1lWnpun9(8~;)qZQ*AQ0*EG%5l>0%Z21 zX2-kT9Pk13AJ5lv| zS=e9*$}k^}RC*ASsE4iKN_lx&!Ozv9#j)6YyUh)OMk$Y3GM`w}3Z)tXhtb&N^~}NE zl%jT#bCD*vvmBMQIEX7w7NYAn!=MPyHO^)5T+JQ`e>MMfRaIZ!-^Y8^FFy$)`@sl3UXhEz+uT!%* zF}HgW`*m2HN*$f|WjlCBVG`mw!^+Z<$Cjj5M8YjPZHe2pAk}>^o?nnT3dR5t_jne@ zD%X0wAuJlP-$<0E2J9$d04|GlZlrjg*=#|!_yEd`-$5CTfaXZ^Fo#}}0;(v?e*GNa zbv@e-x1jX)?@PN0-2|7ifY(Vi(y0ZLACpxa3#*)FOP;xi{!H*DE z=+sBxOWp<4mPPXAyfLHEyWU6VOB^)dtP5KInF><-a z*+uj#x=4r3Ixj!AEZX&CQ{$*`Tv!*0tcdDL&E~XHr6Nh4LgG|~SH&*rzi@Zkl&6tMJi27HQh}r+S1K!_p!+(H$At{l;@CUtslvRV z(xBDajpVWi+1|q_3KZZy5_Gj@Ng;dS&CIwq)3~M>d{&YUq|Kr4*`gA)h$C!CCU=y9 z@2e+94DbSVvgDSMrp0`o+38r_@R&Rxm#YX;FOz%a{f-8++1sA3*J=#H1mC1IG(~z3 zm6xqafroY-qh3#JtDSRxVawKFs6^@{#X_M?YfNag0mXcMwa0_c+)Yu#Q>VFAI{xv5 zCb;LJi_hL+u5~-w0_B}*wTSz|voG*;ElBc!NEpS;KL|>+n~bh|)f|;n8n#;JCiAP1RYHQpR_T=-xg^hPvMngh#{;?q zj+^8g|A zqXx1ZLylZ)U%ff+8Wxhi+O)8Dx!UFAtI1w>*^L!NJIl&81cPaku$#>t!PeVSsah_- zw7BS0e^L>|CPe6DGM{3By}@kq5~LH^UvO!`5|_)(6AsnYKH9U>aMa%BcGqZiC?X(Z zZ}a&&>;)^?yfL{F)4wJ>-c|MS9=jtc*VM#f`+8O$jVG$qd2EqDXw{kH8jW8$PhaJ6 z_k>gR8nr>F&x<%6BbCFu+%7XX1~`14QLCwr_{-HQBachcJiu!vKP7h|%`jzqH`yHx zSLsJ0tsoa0Cj5q7r^Zi#kyUJgTGd$@o$E8HLt3Mm!-Z>!Q^#pefz0N@(m>36GWjPIF)b*Yva!loSD#FHW%e*-f!9bA@ak<9!6n7wbRckj`{?sEZSC^2 z<0Go5KD@G^<;MJ2vjHF2$ItisukY~Gn5=PGzA)kUZEQ|8X*61rWP>l&)wh(Fukrix zA<O8y24~~k!*)fS7NS6EcSVm z1fkdJs$A|iXTutY!^GnV3d7-@odtasvza(UrW46~$adJ<-16q?!0M+eE4$<*Unq3j zoW&ZgOT1HE=JPHti`40Kc9BrZ6_-aN+Z+A$cNE|QFzsf`{6f%wIG&%zneSYbr94L# zvy7}1&2nS^$^>QBqOV!`2l;>@^Sw8jljpU!wal8c`#p;_Q&PmAII zpvR+@&lEu#oI1ZuWDAGyUDI`-u&~!^^$BD`_p=VULYN8!w{_Kbp)MkqEXs^6Jy%)T zOgr~=RaJ+Zb_4bfxP$s~cf-kws&;x@e{&Jd9z@y6PE>+4KBulW*XO&^nx>ZBF-7yt z8fRAL&a0b>W7*X&$9l%Q*PpMfXcMuaK!_B5sG<;MF#+y%)_j>*$&vB}ezU1L*i*IA z8!8kC6;5f;XrDi^oe=W*dbu+!#s|Z&Aus0ft`<>Y@B_(6bJMG9qnnD0*8~Dd0Gu{^ ze=5_G=hG=d+SGNa(oKo{1)f`itIHZ5>02<~Y%kN90|($MQcIpl0zkmw>H{Lx^cOeO(b_MGufE=h9CHpiCU z?(wecU#PC?kjglk3mT;;;qz~5L1}xJtk~`92?cxI;A2XkSd}Q-m@e*>QE~8g-r}~_ z?`+%&;Emu$irU$9ps=W0g)ebz~>v3$^w_!f-)?U6heVduPY)8w^Lsp3~VW{*pZ)Kj{16LbDJ;FVl>$S zER02WR8`%WU$LjMa!)zjO-=04%%zW4i6duewYIxm6><=y{#{$|@wA%F4gwbX{fi^v zW@+vIs>)qRYu6&#+`@hfWni7yF7Z&x6&gE>-GLE>f=kTyIH}o7OmWJXbu~8wTa`U2 zWan`eBK!J|wq22E5f5^s@%*tNGasqZ;+pa{8&|Wzv8iyH9lXI zfC-;(c>(Bz)H4GQmzE(vR9ja1=*UU77z^%ro75x zv8C*n@yd!yg6o-HTC2%z1y|tSWNzF#H||dC|J2V}BSJx;E^3JC1VWWiW)zBKoTrw2 zV-dKX&*!Vk{6dw$WlUOAT{e4?e4ko7*aA*^JCN^zKp;9su!RD?QJUGE8Ha^%u~;Iu zMcJGqVi5oyt8Fg!F&@-fZy_J*&F&boant_;b@t?R){#3WW_o~ahIXU>*lIO-)^zzf zmCPO}lAijk@&Q(aHev{3^D6)IpLkM_S zky9?6k;?@Ta-nRX6#RwH>PG<-oSWauR32U>@=@>}Fmxpio%MMDW zD6uzRAsC$6v7bd2sT-=+VdMRBXYnCZ5W_ zGURiw_Q?uz%rGG|fX++jZx9>AQmfQmqL%9T8ZnZW+0s{J zbq^NQ51Ncxcpk>%i3e76-&In&(CLhdVtlS#RuPTt>|8ZoTe|=}PtAw5qbw$596P z!X!m5LGq8`m421BoWkKsdbsf!%82P{Y}0>dQ+e*pV28|ZMds&QNgjtI6Xn^}nj)7% z=9;@LU@KE>)dH1Y{th@SmY#V2+Jc5-Z25}do#V;W(hHk61FGZ!m+x_SKNPtpU?mI{b2F?)US)Sd}DKU@|}g$){j7O;pS&H!vmSk z@cZymW&^wG<5KF<&C>a`5?$snotIe3+n% zJkPEuDL%b$$y=QrD|noEfg-F=F7kTfY<^W)*`osk;|+}?g7cz^aClvD(K5Ho&E-|a zV%L>FYIw<2V^TO^zh$VVVTHqKgTU)_E-C|yA4sK&AdII|r`L7e7L%ET8r0(%En7O4 zpPvswemp+52$T%sGf9BOVjV269Wh%>s9y|(Lau_v%tK)<#H$McHbgw8OZ+xd|NQvG z^YDci#xv}5mp>pKUv`j=%O9W{QEPk$X&`>ae5FTn%=AcjR*O8DfwytQqCA&L;#4bR zMyD*@yC)h!qBaWGfTNd?=}r9Iv%0usQ&{84%aeekpgfg4*wS*m8m`UGe}T!5*#YKc z4o~j*Y{%4$F#Rpyfb(tVUj@!GRn%mv^ShcI?&zX;{pM)2-3H(LIV>87uU>vJ-49r!R7NV&3G17>2G+l5zsF{9_9>c->NAOGnad{hncPJZy1305@=cc zOifJ>pBF_sH?VWro})!wdcBg%OZxrms&})`A%BSMvGCz#L&s9dVgkV4j2vYqn8KoJ z6`qjA6{_ie)a*1L;pm>;`;#m?_Exk@!^D?f>@I*s{{UBB`|ZC$VE8DYZj-`v{0R4oxfUqioMF9knb^i*Y48zhE0eM5=FxL*eiQXy=U#gxn(N3W z09U5lD1^-J6J|S#S4{tKIAlpJm*DbHKYO&UVSOM_hMWsew|dk0%=p^X3NFdv*esTz z+NRB+V3k&5T3U?<4{cgqZNwWE3P}PAh$<3w5X>4)MaZ8J=b_YE07>v@`ugIcRY*A? z40(O4OG|H)zqZT}F z=?wViSS>C*hGv`N^EKlr`a@*Z_p_g7De&&6D_OblqCln>q#?4KOX2UwGgRA>S6W&Z z@i~F8zS>I_eHR=C9?HV6j>m7T{_P+|m5kW!7WO$1Pb42)+j&dU6jfwaz#;JU#$|S! z6=r^gbk1QP!7Z{FY1>+kjFp(0$;_pYsp+-O%zqN%>H)AEHT{g1$vzDqS$(0|(veK; z?`qqhh*$BC3X9zCUf;s|OG^iAwt$ci2%$Hge`?K!7i(*~L0aczGELoWsZr<({<(iru(MTHmm^89)G3x1ASrJwx z=I*&7XTG8%<5J8%c~3Ee(kBb0!6%7j(P)>|>LH*?r7rV&n@mP0L7I)mwoqs&Os#DN zNmrd-Z{%>|PG@g``qiA&=gv->)WG8*)h+h<2mK&VB8j1XT8Y2eVvgiVgC7e4?|l z5!@aFRr{#UV2N67z6VkPP)5B5enLD%t*|dCD%uo@ltIxa86HuvtEL8JS(6W;a=nVa z`PKQ`_jkW@5sdtd`de!5_?)6;-#$fc{SdfPz2n{Br<5Q1po}U9uc9CD3PohT1>U86 z;9b0DaPm{KC_7_XIlEo1nZB#i-el?sg-0T7U$3uUBp4S}1%r!%jxL8-$IlZH z+#;WE$p0$?cpnf1A>zr(6N!42S`GmEa6YKTqKQ8c3ZxhEi9ezn@pvA3=IpE!60^P;`~g({gxUk$pHTk0JH{`LcY^Oxap;9| z)Uo-_aCEnP1MsG%<a*JxLYt=hOhe-;4YeE`k&QGo zJiA2G^F&kQY7MwZ)yYR28!u37!l3OHJ0FDb#pxJvjd0+qhK72nKMe&@%#56Ra$=Gw1Ac+t72J1rLt)JUHW7RHOHa z2bt#~YaP=65PJT9m^U9V0LLk?r{h>@Nh^nqM_L=l>xbX*B2!SZIbplKJ9L38IyNx~ z0>QxE-uA6NZvX;tZ{`O8>NT25U$jA^(SmH=JV|auUzQ@TeyzM2+dsHsG^M`&$!`K{ z`@v+gip}nkI` zwS7KZS-Z$=){@i`19(J;sQ(sLz~Kvf!bZsXaND-HfwJ_=(!`FD27B=Q`1}P19R`K@->+JF#zL{ z=q+6!zujmwB8jn4ZaheKvI6uR0qv2}S7pK2)UV8$b4#OV3_V=Y2|(9?8~f@xdkF$U zrNX>rs9|F$gamBDr}A=nE~{-(UDXPIpi--I@+{TJT-eBJToIsU^N7)HsZfIrgtBE8A71PF`PHvMv}%LA~3E76Gr%ziVFE`k>k= zri#I7Y61LhtX`|p06-lF5Ko0*O)8-3@vd+B6uhtGAK>Q3`)3@@>6kSpq=4TvP?NTC z%LT)8Ke~dIfRtnjDD-iy*<5Vx+=&S&`bhUou7VW#{Mfm3W0&i%N*yQ*&J@3z^sa$+<*^~>YF+`7M4VnVXd{+eyl3Xzmz>U zw);>bUIK}hs^%YW4is-lx*M#`{RE6hBR9{TIx`kdzCM{D7t!-E>3@(-#IJC%v&RP< zL~Z6j+SmfVz@*XEL=1{p+eW{yKq1%glP{h^z3v0p_mLj2cVm58UgJ$lL_Csh(;FHB zg*Xeb4#pEpe7?lJL{WZhPhIV8MK}vVt}wW}vjMrnC?5MJEIL)8&0lXYSg{XOAy15V z56v3cz9J4>J+fV1kL+~8XMI50wl6gE^q`zA`ZzmYqgdBI(Q18 zL>>wdCWTyS)aml`*=#&U|LTjc zLLQqf=F3xVn}dTC9>ABr@lE6=IZCl4i4>-HN)2pwpuJ1K>SzlS-C&qV?atTi<5?SOjqd+8K3kc%I7k0B% za-K>gu`88EK9^5$0o-|h56KboEDpn*xVP4fDlByA^i{4vlT{m#`||l@afW5AG>UaR z75LZQU# zi}UQt@Qzw!E2~ky@LwD)V=L(?e%XICpTTtzN(1%nqVq*B7+!o4e7ECxX$eXn64B_M zMyhThPjT$J<+o>B; zXD_hR9xr0)nx3p>U>OSrHlG~%_TFnvJS`IWJ?>R)^ADAkRx0jbWjwEunmWq!%PtVp zCZM(opD9^nBY7<5)>2zYDOIyF2HYi<$wE%oyvnZKvC?Lf*&$Za4RG6;KKQ_i@_jWm z*y9A!9W~WA%mDf_qamsdC26$Gdgn)@J?5K-R-?7IWR4sAxocH&wsxlmVinv2oLQ^Q`21yZ zg$zK*fFBJR&9%-zht1}KFzRr&*+9ej$z(kZLtfvC^2FMN8Tv)DJG{)ta-&Y52L^%XrQ zd;a`>tF8e&C3KLW>ga#))E(gY!-oZ&Pj~cpNG1PIBJZZHiE4U6IFY;Rd-t868BV|V zOoZ z_obePue@1!`Nb`0U{Y5fd*SMi^o@O>q$spT4+$J)6J?G5WcE+LDPaENlxs4^^vTFu~x!|Ehzuo2nAa^c21VO-VpAi-Y zz(X?+#Y<}-5Edkp;68Gz1GR4->VFVN+FV(<4K>~<#M-GbNrW0-V0SmZs@PtYB%bWV>+buKRNLZM})+X_=avd&2;$RjcCe*sdFPgta!YL=GXGeZwqH zZqPQdFK1{q15f1E!Q)7(TmX3mXRCAya`1&6Ujl`>3*ZF+AeG9YQaV+F6ns&>D(Fc- zm9Q4vh+6$AYV{L{o?$%Rvx^Nb4tMJ8;l^D9H2uY#`<}V4=Y-ZMO5KoTb!v6o9i2VY zA8>d?h~V+-x z+TvyX$OYExV|^}biCit?M75=*yBcDR=O?g?ayjfXV|~_yMx$mKj~S_MndXBPwv4HL zk%+N4&0X>GHQ`W(w zfOeaGprUn|!)c@M9}6u2srf<&!*Nb(F}3=Ckzx~wHVxf$2QAl|tL(OvR-zv#m*uMpK|$JiRHET!gGl8X678`T+L)iqcS_P{r*PS2hX1w}LWvw-YHY z5~S(WMN3wmQ=}eT2N3lbj@PR-Ne{lMpaIq*^$h1IF!em1QU#`-O0CNH{mW}2?RHy4 zN%rXDfhMaXuJw5!xDf!kir2}Meq*Llqm|RnF&ff1!Z)*qeYJQa<9~jm7K|PHOT0ovn$f!$vajzc=v*T`|)A$ve>Lr z`t?$s)MraOvvcvKDq%DVlCz4X_Nwr4L_p&?<4JK1xb;GKF zKdaT4Ku~*&J1Q}$HKlH~SFJK7%-I2#vqTA=zvpe?%K4}fyg`K)0~->2kcK=&AfD5! zRb?)lTZF1Zw#)CqhtW+H6&uKrY&;y^SXsHfRB(pZS5$0_M#~{x77A^stlaq+_~}>w zzQJ5?v*Wl5@CYkS1cQSy<~O<9pegqweS_EAZo^?;LJoU}*Hfj0W%_!rx6NjAV%yki zP2o_LPK#^_L{P?Rvn^_F+ZYN}YIVkkAT8o~lTKF|@&?5s?Cy+6#EUQ_>0b7uj=a0n_;x{m&O+PeI*bk z{DH+KC7n71ip3WB5C|j#{zWCx&eB`JkEhTaAfhitL`RHItr^|PZ00iL27SRpz)RD3 zyZV1K=76F3WJ|hrxE22U|6&?j6vYP?;akDlo)hcJA$RlV}j&ZMgzUUJ(%}z;v-83M1Js~Aoo~y=EFDDJOvG8TgSMc2@ zXEKmySfvDgBM?FgK0s#YZr))wcc#>fu1=-uWqWAAvIezt!;IQx0jW;RDnz#V<$dRt z82t*FirvEimNRL+yJksBlQNdY-k*DD5r@#U6(L`^u>ZsWu{mkc$4o(KiMiBZNt#QS zq?^|`wMK?Mmu3_aWx}0U^ye;1TxWD~ip$iJBwZ!gEeeNH?N!=*5X4+^yF%+%!FOV4 zQHat*usWT-c3v*(s&}|+Ey+3nl3|%ep|Z(C5eO@imO784*#m#(X?6x$9OcdIjcnYb zbgA_*LoTEaXjLwSGYmiwZ(*sN3JY5=w}?d&aG^vbHpz`a0Af)~Q^*H2I*(j$3JFiw zC<6vdy>B&GR?XiSVow2D!wRH=Y3ETLI6HsRqYE#_F62-S<$USvdpO5S2LG{@BoE|15n zrIj?z=+yRAUBMQ-B`CIQtsRlxz2R^|T*>R4u1$B97{Xe6g{^Eb)3DNIu#f>%$y9M? zVo|9jYtuyx!Q4N4tO=dojz&@=Nisb*vPqA(*CQOVw>zB?0Q@$wPNENMfI|4II-rqT zWHv7{8eIy9LgSHx1CarbCq@s^Xo#<#BYewNVevNEll1`Tw3@Wb7E>F|_zFwnqBgL< zX5ejcb-AAXBN3V zi;Q45nn1-V_pj~8e*OL=_*e&6<2?qT(+IuYyTS&KT&iSV_`0oGo@JGVtyxH;IS8Kn z_KP%RS-q;bH!Cu$ZQVSx>Adqc{p0sY+?uQ1wt5${ZQ>Sfo|EwwtMYMDrlujk-@X=An+OUx4h*J^>tc()N4HNp~+ zjGcX1BPOVJOOQisW?Gl4j8&Kk%T4#;jku{Z76?ST!3Bo{` zGDF(#Z1X{ZZ2Q{%BqkkowQv!09s3%&C8_<|Rrjp)pyMhM4c9H)vv8{ejW`3ipa`w2 z*lD?@W0A$IVu$%?B6(uN-0Ny;mwA10X^=xJp3M-sesh~}5u^aKti#&qDOnUclh|CI zS?b5vzR}{nr*`F|O-(b=8XAl3Yim2+_4nkOL}F=l?g71U4Qlm0sMTqtu|>vPJ>7-W z$p>OItX;6RYmQEjfZ}vCvadJQV>TP%gG{_Ee(AuD@3yoK$XT(@?cTen6}JvDy_J=h zR7RSws;ull(!}kaTLxxblS$V>dSQ3ZE9;}PAL#7dY!I%-lx#u^{dd?poJFG%AUgu7 z*2w$?_$Q?`W??B%otZNVN*?~}$Usi`Phr+q!ml3x!^kXf3haJh`$OP1;pBt69uls2 zaK}T!M$q)Y4hn!cb1!3JM~D}S8;LqMs_Zlr2ky}1zKq<-dfx?`P6LFulQl4XT;5y2 z%V(352M>$S$;Q~-ep%cQ)d#x+RlBOKK8YCFjr(b+(OTwL)$OYCcLfYF_J)IiW5sr* zF#v%|Dfbz5AQ)}4_yPa~j7qzhEuizs73#5COx8SHcpBj=#^L$e+nGP>{c^dAKx3U|y_tM7_a4xpkLJO? z8k5V1DlsGYTNB`+W)nWe!f?cU&k8Hq7m+p1P-03!_RZ~-hh%T%Nyc@eqqA8*`pdJx z=nt|W$Qu3HEX`{HkN$(HOAfAnSb6dJs~&=NO3yEZAsiKA3K|k{Z1WSd-1p3O>#Rq?UWy_+2uw}*bJvWY6Ry^N( zBfVfLD618o$Tcq${=E*&L|Rxsk}>y@2xa-X4tU^aCxi}Fn6TUxfK3A_ouY!qbAfSSt6d)6;KQBhG( zgEM{bLs$XmnBTv$vU!s~5T@wSzYEJ48-rUE#IfsIQ9HC}`Qq^4Ya$|yFRhbi7eLU55Ac@<_uTo z>PehF@H^oN5~?qcc{96r5@y$|;fmZG;=2pp5ndwhyMUS@yw5y<#?w9K;X85rbn-3C zpq9Cs#01>+?2-!u0kcG08i|}YUwQubT3Y(#^78un7caPX7PFBi#g~APf~B~=d+?~E_9-U#I_KR%;k74!{2qArU19%%?Sje* zYJYQbCp?gWO;f|Mlka{7?)X%AZdV_!q56*DKH`a6 z3T4<6_r{T>;Dadn4ABjPx>)w#IF+kbgF-6$5jBGJp2!b9Lx-WeGD z2C&u9l68s9;$W;vcY|(zZSBzPdG|Cn%%X8lveA#2P3-H`Y-%TxgW2M#$h5n%glf}l zjf@+|Q#VMEOgwupc5Fk0)Iq;34Yd2pI<2;#w2GxU-f6WBRM)Nu1S@rVD_<@KGHJ}K z@o6f1O=c6#uv`f%$DV=4`iP=^TePInV04IMVp^%JjK$8MRkbPIaG8*yB_feoqe-}I z9+8N_m(wdzS)1~>@t&jeRv?zfH&)hM+zQr3HnqY8kwqk2sc%<>dy1IQ8 zG>7*oLTfUaH9=r;4wRNI^!rNb+ZptwUG?=BRtu+_uWN6=Fp;Q6+JVL8gg1i)`sRSY z+u=Y%ip4&=W1ymHX&_Lo*IPLSFV!kbou;^@yxVNHu^ePY zoWo)2F4wF$no8HocwVGd*OtZ(^tK(UZ$B!$E{BM|CXKqxY4b@WA{NT!&Gp_=xtx_F z&KLK;xP5)e>I4qN7KPC3bk2##*T&a19;}Yd39%wX8n0(TS=nHyHnAfSuBC6K2b!86 zm|xX=xUq3Zv?L9n*JZcDmMw-#r=!|vumIq(SQ}if3iamsw>7xCBawyV6hyd#IZ?P> zIKkUHg~O6Q`7yk^_RjTJ;oFk8fB#c!Zm9*&%&{wz%!NZksD_Qg^GsvG%X(@JJ$J&p zD(_l#-krmD3fErxo;7!s75i2fJ;!CJ23WjxNs|apT9S7BYwljcW&4lphi`xF1x%2E z&*WN|1K)5B6H<5MOeCnqySm(56)2K6Oh_pDtTH<4D`KVfbBx1Hw!=vNkPLfY+AX zQCrgnp~VIVQD1hVnQ%Az3bH-tp_!0Z1cOtzO7YR+SyLnbEI1akWK02@G6TrbBpeP6 zghDf%eowp4(crF{ZL>MC4AR3R4iPI7h5do;eX}pmR?KyoLsFUD&T~nEVS)E3sf&j*YF+R3ZT&I z*W+|)*?Dc*UD;|)#_4Qyg6iGLWViZg$JLFE+rp7JJx5!zF_T#t2t;WdF0MBm?ssp; zyFBa)m_59rEHvWusXgwyNBr2}2Cqzeh$dduc`>zvJAe}6PoXVlmv zDmjDzUZs&)!r?2|F1w|+c7fH7ql(ej(h7s2uMV=D&#R5wqgxsiD=n2X^m?g?5rUeO z-?vPnO8L$+hZG7W1SY*IYVyqvYrJY6oU{1hmgdOYOS$@imjz(&2rwF zwX|KFb!PNVKL85)S%{Re6$uMSY>LGy5!Wpce$JdJL_+X>vto%g5-3HA#I8>k>~uQS zVsR`SId{I~+~=B`X38a|kazd&By_(oFc)D5DR>j0TeB6{&Fno=QP~ELGIKgRzrT0c z)7?$0O)_{ehwtIHA%$u$nq%1e8&%J1&uYTNH5r}&zdkLrY{VK_-s@6w~3keJ3=t~uj{_|q7a>;8a zX9-T?F!omN7v2tJQH%NOMG}C%bm0u$ZWCeU!gOm&}qq&B`T zf(a5~Oxb{^N|wZ813pivFXZhE)-Q56P#p}f82On+!l;xr@iG#|xPDb2kdS%sWNuET zE)(9*_S>*xfP<-=EAyDlO_At&_9Y;Z$^y2-`S}b>eEy~B%%;TPy<#p0!hW}Crp4I?M5 ztVw9O9nkSo@ABHF^*+BJDKdWl@(M7BEno;MDzbO4UoupYYLYO$=?V+s#|P#m{1qXO3!HlR(dn2#24mQ-I}eaV*rkC0O(l2zow>jQ@|g@ z(MYJ!sK6{EzJ-+(wYs~A(&Du$1-Bvf*MzNCNI_gX%5t;tkR1$EadXha{TpHxlt-NNu^%By(`?ZAsnjK z=`6egD(+K=m4(=8S-;)Rur&PX@Jf|et1C4(t_}n%v|2Ox>k=9Qg+r|lnLH7hOw7`1 zMlO{&jmG-0+AdQXVf{ss)v5HdK%fi&twyAi%4|wUOsUrZkinh=bqCU`URwpwk8x(K zbkHA&K^U>ys#S$riiAZ!yb@iUFa^E*Z4C;JHWsl9;?D5p;FShqaBKo=VXlC;WaOWEE1G7YVkg%`285{hWa^St^>C<@7{2Q7{&}Y~fqhPs`hMIw{LJP5!;TZPqKx zGBOziyEinh_Xi>XB%;ynb#)h1u6lJ9B8MHDKVDx10;^6NH*UbeqkAmo#$d^&hWSS_ z=^7dw2Q&`O8BY$lk{JMo(Cp5~9KK}q6LQPDhui_0ka2Okz7<2(@Y4`0Sfl_U7Ca(i zfrx9I8R>O8f;3m1&RpK{6Wu4FPOH_*acO^GLG)YZlfF75nrmX(>2fWuu2~rjRvYvd zUZPSwpk-x@6fu=noAwx;$D}UZ%>HxjnyB4ABRP9_!0&_L2E-^jT|;TIQL9s-5>#t6 z*-%gILc7BOK+x@8m`ZL)_1)YHdT;GBHMl)ZW(#^Cry!6E_s~d^A&Jn2&lif05cs!L zcFd$ZYpf@`Z+emB9m^ktaDe>7iawJ`!)X~7LXGCzv_=DIhS6~nw7R7$R|NcVR$N(8 zdB@-=Wd)|1L6_6YiyITk^IMO>2kbAql&zU9cxT=R_W?TU^$w;lanw1TRc4DZX|-gn zm#5dnV(ms#LnOSearIC#nI`U-E~jfr-HbI(mlfnxk9~XIO>K>V#p&28Bs;zkj?izQ z@h!(OLuOCzXEr-MLw{o@zxZ3I-k{eqavJ?nsZK(tn3Xe9mAWDvo#}FhXs$M$xuQe( zhZVR&T{f$Y<1>N4qS#CD*0B!u+O0nDG=v5mT5!3s)L@KgfX>w&T@mSZyHhH4iQV3l z!ei_uV~nGIm!_KV80VfZbZ=3rbTx_igl6z%XdGLym3X#}f_H`|ZYGU;4otWzHYpkr zeB)6FX;z~&&#P}<7YbGBb!J{6;vQhtN=7UaS+u%rz-VBQQVw3ry|V{jP)GK`{2HA) zxcJgUq7m`0bRlc{>I-wiXipnLaU{NCCA;hD_NP{Se>GVB+A8bJl9G8oU!3M#I+0c^ zGfSB}bA6%xt*uvND_X$~a7KOoU32H&*9=W0iqapL1!x3YCr445a=&ewu1}U<<6Wn- zxnFdnu81uLLw$+PSkk>U6v}ASdU5)>jSw)5T5g)x)VL-Tti*knvx@tbXow}a@7lD_ zsHbt?nJOXeSeQ($2}jc4E?ARF9%^g5tOBHR7uYH-wv-`S4nS!rw7#-(S8DLPO9!7_ zYUv0Ddz{V)&HIfKokU@gVi`;m|BuIUgsH~y>-PUzf6}Bshlh6vALREd-Q_f78HL0+ zx0MW@4i6q9yH6oe;0~Cz+N|GXK&?lbLT(d0hIMe^F;9!z7}b^40GNrz&`2Ff<^`*D zX0&9!&mX7xsFhdn`hWtpSB%DE9vY9#gf(L_$4yW6Vk`luHqkW4Y82MRE%itylxwv{ zL}mVdULj{hJa1I16K*tbXc~Zvhi3`7{ATJ8A9mH+EOA{l1wcHE-4u7k2cKEG^w~jk z8=|Yr6=67!QEpR6^%B}5M8G?Rcnj1;qrYbsv#;TMeyxVHXgSTEVXEMt?Kx}b5c<{+ zx3w)+$awx?DNstQN@BZOs|Rd$7qaHLh{$a=H%FuE>N>8hZ|!|x(cJ6nu!5hIg~cL` zrZEw}NKe<-)I6|u!M`n7aB_arwoo`qbmFDy)S4I&XSSx(i#;A>IC?LRhe14AvZuB6 zc#m+V{YZ1mImo0TE7oa7itO*y*say<{j2X-1tTbLx@yL$ZH`dnnOE`wTpJPR$GLLuOMW8iXez-l-eRa0H3D{g$hwK2% z?dp1MTXfU+I=kl4FkBKnG{1a9dHJUDRF~02;)lP4quwIUj!uwG->hBW-E$s#?&QpF z_m;k{{fT&&)#4GO>36@9Q*&yCB4o37#lvM%DWvZN`>i88k&!Xd*mWqGtcI{G9Nto2 zcc?DUz25n;(s^!o5E0nr>U7dC96yd*bpdKs2J!FLv}(#SUThV3Z8>N5xVQB!zoFb- zrjlz}sZx2LhLJNeu}Cks4^)TaQYlTZ09&jh$1L>Sx#6yh6G=3ux*NQ+V*Z|B|80Gs z?~Z25OcIcHeLVKCMBs>InONs(U=61!>WwhUCY2ERn@TMfGd5SagWm z8yg-OTy?6WV^DTdRv##isc?JvN&6k$pa191x}}n{x(yc z%^sh>`g`3yD|i}J)*PwdjH7>Dz3%2zIs;*OdHL<@K>Zq@FNpL@w|iw%_d2)BMy^KK zZ42sJ*5Fu5c;9YeIaqWwovxzkWIA)_mc;x(u-;^-kCtr1_R@a}8|ahBCJIt(Mn4$E z=P_%rOavB&hdVg~iLVk&;m+jc2uPZqu&BDyOJm(Odyu{O$PIIkwRZXD#^W21bta7d ziGB@8P;JXbw~^d{%K*-n27wP&FcJ18N|HY-@&e+Vl*+n6mZpc+J)HYc37&J^=00M` zy$mYsGw7{wAb0)Rr=LC_EG`xHpcZw)D;Nd)9UNDsar{nEp7!IxFF79e?!V&R<*J}b z8#RYw$XKU)?;T*3X7jwJ-YsGFVKDL`Oj$~lQW@~u>@7~g3q~qQ0POxs%$?gu|HRzS zzDhFIlS`BCi55wAg84%7Dtq~CaXT$JCA$#aWe_emgWU$<5Y5rLx@hXk#pUZ$p6Wfd z7rrs0dCzM?12U7WWnWpg9%-8D z6LMsV%nJ3KX7BsuG*qFB0QCr&^6V>2(C95*}O%>~{OS zY{M#KFd)Hhuv+KURxa^)A{mY`TCMYI>sR@_VUEXzdAQ(YfUq4jaIAItkWgU=|Qg-nJXz|l~wkXZ-_+7u_^2s z%$@bq>MItkbpiT`_K}%Lr+sGhk4!oH z1F8h;w5{2R6rFlGgdAw`M2=ueO*!%^rrCN=(%7xm&|>AhyPBHjOIb#5wJvOkb-S%) z+Gs*DJH57CSH3n)D;*`#tF5h!S}nGy6fUjR$}$kLqJ-bSM1L!j3Q*uc_^X?|{S3KCjk=v=RW3IhfH#n)aqM3lQ(1 zSUfso9juZCbykqP2M5opXcL(z6D$vx>;#Fo%?vYzp zKZyQW1%6}#kfCKFRW=l^)62CS%R&7%b5*~WbJmd3AEIpj8<+oleo6+-cr+M`x`ls2!&CbKED z;a@$c45(EGlUnVUKPS?N#cGk-Xh#2tBx>QtrAzVN$G6Z}?_m0<2tI#boh>ptT9c-X z^n~;hg>7}DZ{;`DAEZkb$K$Kgt^4BD@QbbqGdt<5Gmnmn9&)2(Toh7DHYmmTCfv&`g=X<&bX&4QLHa9d})$VC^yBh4Z>x01< zgthedL3K*_5E#rcwMt8|)GMQ3Fc+|oBAH%J^-^o74Mg&?e3oXvX04j4vy7Q#<6FPQ zHIN7n?bpDO=?lQAJzC)f{i}m?AMJCwW<}$Re7;hE_)lV0<2;=f07LldPhv$dn1Dc~ zk~y`g=^Dd>v_+>aGZ}(Pr4lm8+$l5ZL+E!GG^$i#z0M<(Bjv-OQit_=uS_b<4GvoD$Z-MfhnlgS8x*n;O=@*!NQc~>d9nCHzc0aFscebq{c?pIGIqT#WrAN!8eWN1V%JVHyb6WPt^c15 z@3y>%zjPe{VyV<`wT9$!Igl%)Zex0;1$*C_E!J5T=%Z?jSms1x-<={OZ8Do@q@rP| zRO&X^f@lmu?(jt3FqLT4cInx?VN2^ZcIkhMH>6JCcjn|*?cQA?=Z)K!Q- zsM*G`aD9a#_7FXH%4lNoi4~6ji}63U%U0>Om&#>gL~FGszL#+oojWT4mm1(pF5G@0V zZj03hfY;?-Qk9%#x4Y%CoA!>ZoII2o&2&TQC^sst|E*~*MML>iekjpco?l*dHsj%(@ZJ9)WF`~b28u}}hGMDauHq9Cd{n>d7cjq4a)kNAF zBO0wkb~bJ88H399-<~D~5lZ}vP9qKVGb%%FD@xC=*bycDn_CxowtKLcNV_A~C1e;!~zJENt*=uN_ZlDz3><=L%;LOmU_ zj<9C%<6Opq-5PI!O&0jf@k?{1xzrG`zN-;ii_qH=;?=^Zv?+Xw4Sq2o{Mh!?g@hHGW+|%_ORXwyk?(3%R=8yKEZsQ@GLnpr95>Wjvb zQU>4n8F`3-5}s3v4Xw#Qy^-N*r5Z52+sMf|cVDD5DP=hTV1Lw-wYnSasTKfYKDk|K z$yzKKv(lmPL?PXnHkMm`oxZ3!ZSl1_G6YE*Gin1`T}W$)YP=-?HkCWt{kF>Xs3xd2 zmFfd!5M%4jX$fSjs-0OXQsJhwwKiQn}IG=b03w zpq4U>{+SXnk1{-^qWs9-ZAN@LlbS;(a*%+!8?#`DYuuZm1>%8Ew5<2?4pYK z+Mr5_Y<;BY7=ccu3jIt3&0c>*g#PpSBM^8J7CswGW?&gq*vzhx<@cz!m}}^!`(2gh z)j3DCZnfrqdcit%wexmib%(LR7-4C1@|fz_t4CEwg|;KABhI6!a7>8`N0mpw0!^vR zES0E`9nXt&Vu5zl*p2AtkiFVYe`>FC80}T|i_rhjTbpSDK&MuhSnASEp!GB;1H4%5 zK&+vVIE*H@L@M3W;EaQWyWWNVmHg=6qe%!8acH!=gg(#&wml9W+XiUIAo{%#4BiTI ze+J6{qqpd_;NP3@pAp!I|G?l}09cMyD`W}=S%ddpdF9(zf-Ax8=%2SI{Em1Fm){hIKLAm`Z+S(-8n4H1)M#P`shZ=sHwGDw;bx5_MiTVfU&WJJZOA7N znv5w+x*?uzTkUo^fy;zgAa~8%rKJ68HR#j7xM{I$Nd9oASER3 z0%kL9u+X##Mz^uhnQ_ycsr!#3!l@^Ib;q@ByjCu=Ypi8PW8503HW+PO535G2u@-?0 zWj23}L2qL|0i1B=vB$uuUW0Er0%%Ywj4rdK!L3!fakvIxR4B|Yv$-Dc=q+PDVVk(O zP`f<&c4ZO!PfF5WxaM3SBNKc7DdF|UKe+wG9tl#gbrwj+yuR69rJ_WyvqIXT)0e38 zZ2+g9I$Xo*)T+3vv|6o}!^Hq{oXKD`^E`v&yu6KQ(!pJizAY)z#7}#*Ovh)}3s1lP z!sWue#n0Z5uk4mv9tE_JLoMEdT6}HsE&NW3#+ORqDdE(c&tG=xGqC^Ekw3G4!0!O= zAt487^wtlV4;USHm@*Sjs7Y!@L4zm64hFqOMt6)istnaWcS@y@gCjV6z=~9QeKb<_ z>2-I##6AJd0fkPBqq8W&R#@3*HXD(-ZtCxS09TiHX5C*{NOqDn=`;KGSmkh3=w-5`S#A)CM1b}gO>q_K zoHe3A>!ebth}vL9ui0Wk3}ZI;b%J^Zkt2d*HYl|$OM`yE;LG$XsnNu8G@$->A;w{Xr77#I>rP9!D9D_I@p5n`NoY+DJGX>*h76!#YRGWKKDP zbq0f#osHBgWTV@YW>eY`L~_T>J_aozr3MWcdcDLBEBY-KGXN%wc@}6fXk0QZicCtS z#c8%Qd39<`6!ciBG&?QkMl_y%!i{i{x`~XZ)=NWX;qU?k0=ZGF?>-{5!$;7nucxTh zUVfrhQ;7KlA2}Jsu8Y-SQ`~69u8Zem*Ttbfdt0nlx0t`J;IG&{raf~7-Fsr(d8hzw zKN1eYmA}q?d@Z@oL+;D`7XAR=mpRi1k5Z$kIr%>vzT1JzZ^8uq7JMC**OKxoWD#A$ z$GHHGc1Q7G8MPB^L-74LPA>Zk1b5)q!7{fQL6?pGzJM(%V9zJmF<}-ni(q^5*k566 zJ&CbuK+rHbnc1Ank#Eixe9Tqss|c61NjvMS8XG7vCLgJ?blm zTaU2nPn1uPnSk9Q-ur2uaN3lV%R`o5n#A5rNNLZx$541)F{=uGZB1id^D)zJt_ za?caoEAmhqlczKN9=D-L=X0cgMo^OJmr(!uJoTSM)W;{c%;iiKYVAzY+LZ_^&h(>l zgp@g98IE|&abP1UKZ<+9RHNsK{Bu-3PTo%y$JoIBp!n_OYG&-)1e*W$^8aAQzJ*(l zzlGZ=DdLjW=W)+DjayH0(GuwKJXG`NG2S4w_yVILsyMbt|G`_0Wp zR7CTZ#AusnL3_{Me=3^R6K&|!+51;xf9bV+O)R#hqG7ey7p70aw)(pJmMuKl*}078 z>a*Evx?)QMT8Bg?p}ERvbVGUlBB#SiKSkG7RNgwc;PLj3#T?s^Ex)q8Y-Ld6kVqxq zoSH=rhaDgd*}t}a#hsN^jQ}Q7$)ObsugGM2tg47Z?$+s3&ZD3#{rqrN>>s*DZwkqZ=_Vs8=q0U0=*|IQ1>~| ziv5gnE;oJ#qWb*=zLeSqj{gfYyglzNRQ+}K@eRE|;;TTe8yFdFH+x}u_)o*d|Xc1PEn+oILG(yhC~*tK^;pm)@l zPlOKU86q9h(@G0MA@(E0Nv^zHFjx?j-F;5E-*MUspYrCSIYFewkqT2^PtLL+buczU~Ay)=u_I)Q)t1WI|1&qu_$k|K#o_ ztMDSS`Y)ollRALV$?RwUfa=&zuvaY^86AZthNrh9U4f%EkFPUW24U_bv*al-4}I&e z2)>(rAHhQf_E#dw{ zq<@9X<)}PF$|Qm!--O=!n0#X|vl9#;IEjGBSrGg;1-OYSLGV(c4Cm%V@O$uA;G7R` zK+u^&CC>PSpikwY|F|8`Oa#4z=vz!4`Zw2N1V4;wtta!UpVUgqWKQs+ou@>C3zqD3Iu(;fL#N&6J72!W5(ac39d1A&OEkya%YOG z=ODEXbQNXOJw@3x==!p_)_RKA%c-?wJo4CY7O|H**#dSQ-&Mq3NxfIZ{u}0Tf{o$V zQy8Dz!6mgnn6G^_NBH!%B8^|n*B&4;7U%UO*pC+45+c|nZxO+MHILoHU@p$zMnc~- z6WKKvj21M_cCt1E@Y+D&*Ae(0#E-Xg*#2{pS?~tJyB)ueLwpmwmk9jF2)+@&558M~ zKbN1O!aWn@Di2mOPv=)_1Rs~I7=ExgqZRxsMf^R?`(W1C>dqZ1;_qSZq*Qr)_67d) zF?`rf#leC+K6?rG@YtM&-Cr6DwQu6zD`L-}e4wLHdxASr#GY}QE7X0Ch%RDxQRN_0 zsJoVXv54LE)fa`j*N94s*qvw`$_sTzxzCE&ou7SKpi2$kQNRv@#nkg?Et*0fjw`%{ zpC3XaHknSn{QJeP^&xpOQ23gbySezazEMp9d%lP%V)sxjV1EJIHlZgyqKX1`wWugn z;Y_LobdHSyUzDnF=3n>%_C}Gbh&@0lL4N@|&b?p69{8!U(C=}H9n4GYDg7Ro+yN}P z$9qk62#*onbWG;1W*(&^SmvU)qJ*1V1^BZQWb`XV{5{N12{+|s^uo_H6HycGb84_YQrHE+4RQnXyqTqIP*I^o~Btpyzr!(SU6!T9KF z$H=Hj3Zru_`O0G9F``2TuntM!9})N(;TB>!jIA20nWskofmaRTW}>U-R}Bomcl7VY zRpysP{5{NX!P=sQd#H%NhdGXA2F7P!Ba~GYMlB1rSOFsXIkxS{}RWFJFwcT-02|?xf1VjAGrN6|p;i z^W_*__$38wJZi6kZByw(WJV-EYWvI+sDxHewuWfL?-n%Q*RV!REkWNpjWuGBDZnqo z8gT*NTf|>D`Z3XF^Y|YX@UhlvDq_D<#NNZaM|gr@<1r}Ij%S*xh~HntUqZb@W?CL! zS;WUP&57}ad)ONGt0F$;RLqM@P@hjT4;S%QGk25Tu0tF=OnA;vfZs*%uR`zvvd+Z| z@GS(s4voYx|8x<55A#pZhVc=6fZJBY-@_ao&E@ggzYuEvsX(<;gqqim{*m29ESye4 zokizUMQm>od*SGh2`%&3Zx*o^-bfd*UnyemVSY$xNwCTM>MX#Ik@=O!?=RvnL42{i zSo@hG{u1gcGQZXdx3GU7SVVYbF7HJn#tQzKSlHRFNBts0{nJd57J*m z#J(KUUskirMpus60Q}2E{5{MYctyx-M}(H?0{lKg%RGKx5q}Bw5?EH$roJlTFQIOy zqzKLNjCc`;szF_#R2>uAcf4%^}E^jv= z_(Y9s4)hc>t{W$5Tywxl0{;ZTZy_4igOk2{Td_SaPJ*9>PyKv)eCnP2eh-4*L+}se z;iC-%-ihE#3I1$-Q;;aZ66M&oZQHi)*tTukwr$(CZJT#&&+L7R*p1lNkssX|^^+&6 zE2{FG%CrZpozXIfphNiTg1(MJdeedU;SKbw1aM36bcI^sfPyOQE56$S7rP~CHDQef z4BTG?`qBc4RYOK!VCX@4sh2=!(#a${Q_V{5n9M67H|q{=(+J7K4ue(Gs_QV6I-FvM zy|1XCx44}LMTd#$W@mgSud!nYbJ#Vt1jyq+Qrx0^E7aL z`JgYVQCeJM_7Se@<9k{;LPlN>>VxJcJFEZwEy4A7-`Get60czC-r{n+oi?~kYRb!o z<--74zz)eI9DwB`NZ^g9E2bJQ$%?n3XLZd5)oX$BbA#i?Z{YiQxSI_l!?9LjxRmT2 zE4Uw`m5;L==DyX6e<;e5m`i5Ms!LcKM6dR1=C|-0`WThVt?q*k_M_7VJID*BO|#bT zWq1Dl7S>w{qD_M~YzOV8+;#=1CE@;8xf7DRWZ+Adazshm;Pae5LWDD#rm+Ec9AI~e zKu&913Eh)R5RTCO`c3P|u{<1Kg2cel2b?m6lFaYj_Z=MnX4SC!Y^51>gM$<^QUVk7Vixpz8hAXpiO1 z0-}r38ekRDNjLy03sE&7ZY++K2gTTfBQ6^PzzVNBfP>FpV&>}A_pu%&ckzoaFAWX> z89p>AzYGA7E(-`CFAWTW0ssL40nnofrv>o;Jb3@!-RvBV=}qlyot@|v?F{Xl?f%%= z+R+-?SsT+iJDXPbfO{*AEwXoai96ag*6h+sJ0{i8xoOSx1lU+F#W1!G^lV{Bz(WSa z%PUHd<0i%jKkZU?bWpMrc2pF%Wo^xn((o^sI@^61~eQbiW z^V^@rK#=B!$iGe2z9a~`=K`F`*^47=kV#$NVCQtZo!&np9O?wfulsp{b8XITo^3_TKe^uY*7-QbcYvG;?;Y7& zer$bm)v(j95{O{!S7YK}VD`9-%(g&C@(W7%ZtUBi>AS6inhEdO?Zfop&*k{|k2Q$9 z+ro_qN2N=p$8`?tyr~;eMv1D>l&|k(9F^jNA>Rc%=ToKn{M3 z(Ci)jmiB0Kr;KZz;aA9-{KvTd9U-9uq*!CnBD0IWu8uyeYQ1A4UzSKUK?ZhEZ4KB( zm+w~~AAgJz?D~{s-@zHqP^ga4{2kl#k3L%7ycO8S0-)y%Fx1usEB+IkY~4^iRLkNe z$FT_IfYtOp(!%9>5{n=_qkhu93y?NpGXiWr-*W7S0x4EVEBbRj+;SjS!L`uNT{O4& z0s)rbI|XmuzXk1(Lva)Gj;FZO&~b98lUUQeLi95}vK$Xe`u4Q4Ln7DCR=@a27G zs^X9?#B*M-MVP@Q!e-Q-5I%r8PdJq!7xYdDSOeC~P`54x&}eI5e4H@$wgRSRq$eJ* z#!pVafwLo+>MN}&Q?Hv!cE9VIDeU#H;XUEPOzTv zuKSob0={srdpCFT%?Oinh?4{KdKAAHy`j28rtFZNfKN8<@V23YepYv8KHR4kXj6OA z^9w3x%K1JZohVz;&w1eUy>l-bK`!M#!Eey@;}!%y)K~*K=Z?v6k4r&oJu$l=e<*$q z8Nj_GxY?$^p*gZWuSB@_Eu{Amz*)Y>h|Ayi4TA6niVlVwXzr38x54TsGXSSR;63_< z9>+Ea*O)xbFA%TzAJE0w)XCh72e9zIh8mz}32)N5`P$H}eIDGQXXAih_<8MnAzR__ zbjV{-$?FE#a|ago@du2EdA58GG2lB=mxg5H9B%r(?!@*Tu-s$t`eKOh;hwNQeAv+T zqS*J1?-Ii1eVsv$*TXCCQO}LO`tPO9z~kVjv0}fazS0TF;-$k<{Xt9jF#!4=gZ``q zk{1W~&H>Hj!i9UVS9b!}Z_b6fJ|_UYds%R+8s7m| zj1AVK475_hu!p1$$X+yN;EYvmjX&F$wehzcK6?oVHMn3%=h-^=`-iokV2gx7cHz<9ta3z=~z>^YCJDPtszm0Ww zc;Ub1RAzXy*zs*|otKrn1-^PDZv+0cuexzTUM~aJq&$F3yZ%Yz?#mwCjrC>6FR_Hy zei_J&EoK|?xgXgL@{s`0Q*-C-znBSR`7AI8`y>W5K6kK-v0easLkBX^u5u4}J_Z;5 z%IFI_ssfyn(2)s%Y8#9ni;)bfi3c|=1+D1=;ZrN12C};XI`2(o z&jz423*N2-EC*qq#a{=qr4kUL3>Xp3;FwEBK4Rt67P9+$GI0;fdA6I=b(w4?*AJ8D z@8PI8?{stDVJ37tFsAl(aeN5mmJ56N9#@7&lE=R#_-Yo^S|%_z1@yRoI-Ikgl}!iK z+ldN!rW49Cfpe;ImwHEcyff|<@e0cyU3Z)}_G_2UeU)9mHaIlM9=wP8qYz9th`oU2 zKyWBgOzP-#46bmXV5HC{-h=+E)J(#~?y2*Hxo|7)hi??u!FQUm9=x8g?sORJkmPVS zh8syA-ADOz7Q7j}1ac3Qwf{L>I9!*cnbb<^lR7PzE9on&PTH;dhM%C=tjR**sauU~ zhond9D?*eeBi$-(o4ifxA@fjq>|{}>Ogoc!Dmhg=v&eVRv1nBSFO`?nOE}ahks+{3 zu|?XY@sfX)-mSVzho54XqDSW^@DocUR3M*B(MoNr$W!UAcHhM$MX6*;@t6{(B3J%X zz*Wdqt6FtCPr;%)qdJq5N#9&nqVA$zw#w;j_Lpw?dSR!yOY1fLrewKYS)-D0B~vq7 zGo_QFg|~&?h3Z-V?@?ZfLPIE=PTwv0de*?*#BvZT1V zuM3;0muw}w$gd-sg)QvLd=g`qjFw6+KAfdJ6+BHoUY@8I?PmAQAefRdFEC?a+{A3e zw8YFtwT zbNdQ+L(S}ViZA)w^(Eoz*BF21;Ed#W+zEzrH9N|wcCupx$1XJk)-#f`y*JZA+eQ-xA_&J@+a{t>gBo`}%$K zk+@m2(rL9boqesNt$pv!*WyUK2wjy`)n&+b^0to0g2#mi`!V$+`NJ#ve&AJLMPSEZ z_8>D9Kcyq83+gp(EKMz)Z$WYXarffe;^yL|l!jYC*P2i4r@`xOuJRmet{0D-*2q+@0R#Zx2mnb$NBy)llQ!6zR#y3GNB=33{rYnjjSlDl2LZ zs+kIp`n^?2g`?7mmdd?~RV7||Y+Y^LuBML?tJadTlY@=+b?9bK%iP+JVp-K?l~+Aq zsjuj_94tD0xOTnsfCn_5y18C^A7ht;^wOlM%_Hc{9vu@smY(xYp%?l$_#(C76nxFk zDzg^9#di&D>C6(_imS`kl1&~RoL04#cBlL0p;=nBI#Zi+N3;IL@gjF>Z&$U&hR)Pa z7mwHb%>+xAX@- z4gqioFfH&9@ESZ12L`t~lRC5e!2XV~JB9B!<1$OLv-$J<{`^OQQy3jyr{(!-fmc{A zj;G1_-F%raKgUP z#cP>UlSh+HlfBd3dF6a_;b7rnfmv)0zsLRQVc}BD4!6hZDPh4(3_gZ(RB^0vRNE-G zp|T;wXlj&e3~X#Q&IWIbvDNIVw4rMZ57*1!YNjD>v={f&Cz~ISn+|6!Hf!{8^!o^U zG%dz0_BAFhCXdf|;BEHaYV#7E7;`NR?KUqDoc&JpZvt@6`Xh z_)p;jC&SD0{I!g&gfHvE`+Uig5u24Nds#NKRI>EEBwgB7DqhO|$1bDS*z@)YcM1Lv zKlk_Mlh=}->@P@#=ac9ANA&aT^UZV1<<_cOExu--!MDeyTTP$qx6LKK`tS6IU#*|r zH~OVtrXVvTb7ICa=A+Dk%!tg=^kl|v#zaPwY3rOeZfVk zA*1;;Ru-9_Qu)1w7;6^Gnw9P1)!IXgq-Fw}sMWlwRa#kma((h!@-T`)B#mfFVuoTu zBU6de?;*WhgOgKJfKQ(Kxc{^~ZWp1PO&H8RR{9X@8(jL30#SjJJKE_T+caQK`j7@g zn9VetDZLZjE@oZ8+5qC|SH@d(z5{4w36*NDKQ1wU z`zrJF;UtoZ5v^FTc&7&{C%75IdKkid%BBqH^;+}k}^W-A=v|kJ^!fxWo`DlL6@8fR1_xHiw2%i$3 ziND1=;Y0bge-x&}@O{;v2HwKZf_L%18LoxD!xmqmcjY|zPxda0Z1pE4UHY5w!jh6s znK}B7UMMF3ft=f!-@;)|_7cD+`u5M<2Fzg211f@?aAu_sy735g*|JCM>5e_^ z`8}e7dOV`sqda!Hclp!syG#63lJ6>iT6G8Zc`pfWwZrNBvCL_eMU3JrWco#)$l(Cw4K6tsq#=}^V0vO$wumzX^#qw(aNr-SV0n+v0sW0^R;1Pt zK_mWZfanR{HIKa>2xmmT%(`;!qwUW(EP4*C9nLp6a*li@CT>r;tVvoNR4tZgK>vYK zIf`$O`vIp`L|>2Z6KA#1)(%Cri1kElE6{gH_Jqw9sWtDg9U6O}$^+pN0PGV)y%3Wg zXFGauzQ+OocW%WUR5wEHfUXG0n(c*gGA{KhAC!l*ev1M7|b#{#u%A1CR=v4e`{Rh*xH+r6WMMI9nkQ)pZlJ! zJ1aYgejqI|Y#j6rsu5LBvNZvE!qpM67fLUtj*uH*%JtA{g3cRv;}6|{*F?#ir#EnK zg0>jlD0{-x1fC;kN20c9E!oNy7 zv2XIWi0x=xg4W&9vFZcFMwlMa=l#?%nhEZ^LFe7=8%0yLhF~s{95d`RkT(pz zS!V_wPn3o!;SvNR7@`b>0Yn^+aIQ&ax@kDu9P`jLL{qp0p*PZKGm{NTwn)5$DQX1K z!n9N=ZvB_&15yNG!!!Z2$e{$!($o`UR0gRGKeGVRc;9%|F>U|n&@t`<9b&wQDP>c% zx16uPC4I&h`e8o>vsmykxoP&7jISX7QOJ2;JKlFNdj7vs=*uyl>5ztkJ>~Gv$X5B5 z_(EF+v$rH{%LB{ESi2H{epDp2q%>EU+a-Fv*ZEeUO%)+5LD8 zs2lmaE(GL`1=``m@8tlfg+#}|G8Dkdyd36D(y5Q8MfV2R?hw`PEv_iDysDHOc z{I#V4QxXX}p%Wk?51_%1~lQp zwYjnDZ^YD5dG5Z&5#X;wKHj-d;y~mXs{o>Mh0cUp;}QCcD2Byf3qJwU;DE$+h(E~p zzb-jo%Yfl@KscPm_2H?o&+_E}@Tb=UYy5@S1omv7==&AGT@BIo&GGUr0O>$@KCtS~ z3AKSFo-hd%;R)us?($pKqkPKo8Oq_)2+@R200?YB^PdT7K}4{`i2W6W+rid=biZRS z9e{NKemJ1YdEgjLVb~8$yCK>D#99tU5O`C8Hfe{Z?xDhYl-x;;d6>dEIG;vtkg;WRG5k0x_b&?-B4uiQQ4+4jcq}AO-CE*`7Fa#dQBA z!D8Tw+z1B0uno7o&VlTI>>x%u^JeY^-HUuZ z_w4RJ;fOxGgJgh|r|{Wv zK!(3Z!oN>qQk12VAgu`GIdvRYvGwOUhI#_1AY&~~T~6>^6hMm)DNbNXFl`KPj#nK| zAY4o;G3VD1OHD#GCbb~1YB!hS3TlXbif=K-y&&}|=Erz!4<8%hW|Adqmk=-g#W)(z z(2gcPi+7qZb;RS$vnE83uX#j_(S}*DCf^ttVRWP%u2V8pV{lBkoPa$RqZ3NdBH+3v z{yaNE5-IK)-#I4e2-}vvA%0B)Cy4WgC_ExYs372TaEOTF*492Sgo?qWPZB;xeSm+U zdMEdY>6YE~m$tJ%}bb@KtGm#Kz+~j7Vah8OZWvb zgd9eEKt|^uuRCUc;O3NyO*k@6tv81I3p0&S&gu@62Wd2z0a4CXm~KuM8ewvn|0AIf zB14okOu{TAHXM!#No-;qovpwiCH8Me09$0Dm@g%1@)RAw$YdeIl{8??q!AtQFK`TI zBZKPbm6{bTh(HM+bI<62e%fqiGQ4 z2^q$v>5p_5ouQnZ@1E=LDle`#V%#0%>+ap$gO~b&*@W4Jm-^n^pN56m`h?lofS(nE z8efFJu;fi(fYvrdXvdpSQfFK}lVw@+Z3=C&fUcBATl49=NxdR-B& zr!X_mJRjC6{5-@XIG)(M8hmuCo3ryvTIGQTDx88q@ ztC_DqL2r+jVH;m-j~9#z1Ml)5oq-Ko2QP)F!@s!2w}?y95YHwk1uaa;3g)uvt|+04 zJWXFsS>Aq1P;?4VbgG2Gx^%$?UN&WSN`ttHlkTi89dA7)*_c5451lY>aZj;9&CbxR zG47%*A?0;6ca&BR1{%wI$f@8KaF;FFj25M)wmcRuFSB?xafpr;!3*x7mm8SPuE*jY z?us7nf!&}Iz&2!DA6Gd#;>c$as11-cv`pfi{x`kWA;f0~ z;aR55Kh@vV?J1ZcaP|}V=hrq?@K84Y^=C_IofWWR*RrrGv%$03X?~t>rCHacX)gJu zO^zKA-O}D%bWp{%vEZk^HY@qAPR>htXqt_CTwE2`;z1XDG;V!W%d)T7%0WZ1D zf5J_U4O(=N=YreZvnZv_X-k@2lN{s5Z7y--s>qh5Doa{)Q~Z#X+LJtSR^-f4mL)&A zEOhLo;730>EBw+Q~02h+7rF#qVPd4xh;Hhy6ATNXOw-~lk{m1Qzc)H7hjH) zd)kxiX^S%@&W{v3JW}j&ixWl859Qh(%5?14x24}Z&3#!fZc4qjm1^uKx20da&3$1n zuk)|D@2|@Ac#~_w@17StJ6r+uXFc%&$pm zrQ1ARWQ%LH-JD%|{$EH1dAh0tdDoaedRzSm^8bINr{UO#nj2i4GYpJdt?mjoHwzfU zR7mPU!tBZbpQ_Z7N!%4aCiWH14JO9v`&cMAP#kS?$%tW54RfQDF^b`h`Pp9y2!R}4 zot>f`#-g2gVX!*!!nLR9IlZxHfF@thAq9%ZG*B`--^}4gFW-B4UEh*k}QoSe}F}ky=~)3k&@8 zD+~A+UP5E%v1NNXJ3F~Cb2;(pFIMq1y_}t0ZY+kz4P2Jq5U#L)Hey*?L)zJw^VxZG z*RStpwx5v#22@4*A9xlUWT|az6m01bzyi&q`7s87*b#pg_Ls&d0XuJH6T z2`UxYqT9O2OPPY5d3+fC@K<~t@p1|t&$IKy=e~Fn$7FG_k{xl$L5dA{2d*HRjUL@4 ze=(K-vxUh~f5Q$KfeS1#p;e~(AzMK12W9Sq4uf(I19y1x;N`y<=f>{edHfI2bbei- zM~I1R(|U3tjkB07WeS1 z#OFIXCinhEiO+v>RObElh#3EHuhi>1IVbo2PRY-Ia#r?L-g9O0n2_{9U-UIa@yj&X z7yUq8^fgKG-S`fHQGAr2dkf*&J91m<3U7)quW7;kyDO^&Zj;mOvcQ(s>e1}7v?{Fi z*G`ZjH1#7V>mw)Z;Z^eg~_egu)zEARBMtyE_N=fj^W(f@$4l3 za#K3b>x|ifYgXE!pPL^(5UdKIT?$Rg@1?RwDkMdc@;2zLDopD5!Si1FMR!-F$Axd`T_tB6>$YU#w8 z>k6!BK;N0816yrhtZYOxL4pPeGHK`^d*#d((2wSb@5?2b>AihfBVU<3gZe=vnF^`) z`7QUS-jHU<05s~@u|l=T+5y*RWvv1!>O^s+Qn75w<4;@_HFXaM=2(ej<0y}ns}{}a zQJq1GkgnN8MS?VnG3{^$@WtRmYxQW!`5d`+y%To^Aw z+m6pzhZpSi4S~dzY^|*A}u|?FD zvJ@-4bfG0rZWtN5HSL|V6$(^~;!2{H^Ty#pm`^Y0o5!4Eic~^!_CLk_td&QrGeKAW zA0+g$6?3(Yuv=Qn`x0y!GnS89TOZH&855JD3k}ZQ!$V;GI@tVYh51edliYdEGS^Bs z*)4A_KzW80hO#Hvx9u076HzM|3k}YUkJ!XW;GC-t_1^8(#7reRDH$m#6jaQosOuin zB!h7+pL(apvw_V-7tf><0&(_nMA%Gcb5Kpshx84t ziSMzd40f|`s68pqr~8QhlpAfje^pA4MLUB zqv7+1#Kg~4c5C{^HggvN*)F0!eXF5GtL>60JJON5hQ5(VV&bBD)g)sD&AD>F-ePv@ zI?2@JYE^19E>By!ar)Uw7UwSN+Z*53+W{&&w@TT(!uU^pwo8N4-u&84&`o6UxiR07 zTGPH^LvPT3H%|B#VVd&NdEv!)0Er8Oh_OQE)i9QCk=4h2XOtWA^#2V>I2w%OH|^yc zyl@40QbAUa8mE=uyI6y>2}je0F;byMfju20({N<^#H_VX!@Iie9lNX&< zZE9oEIHpncM&AH-cfe-%Wq-9H!I%U0asVV>VtU)V(v>lMvGJe*Lw3DQ0fgxcvd-F(CNtAo2hDGPMObNIKi9e5W{8D4^$;X# z&HF}~x~EGwz;;?%05jdYH-&r05-__Q7<($ud>lu3O8r_~q0B^ik#Kg_mW}MDA)caFGZhmT6%iXbEtZgu z_9vxWeM>iAd=(oDpmM7tq-7pTXFIRk?t6$CS$nS{XIgBG?rffjjMS?C)|*|yoHY$m zCrTRE!ojS<`JL2B%Gd&_Cz48K=VshY-EFTl^K(eR|9YbEoylKm-E2fFU#aLX%g8z6 z1>BSocKHRiF-*JvjS`weicsG9Dcp%d)6w47t&Nv3Q5;Du9L%X1mBK~aeGF=lD3))` z6A>NJaE@%8hN)9d!$k&EE|LMupkGq1kT)G09zl4$->ey_*`mSR*udN{qqEmrb?-jx zE^NH0mT^)(#_4>)^~owR#;!G9`um(JDpjCNq}a;k!V0#!Tuy(z7+5;;u!*BYf5vYX zXbSIdnv_6SPldDo4t~NVyF!OK7_mOgr?y@zy`c6vm78lws{Rr8HDZ|~OQ+=49%1@2 zq`pX2*Qm+1{H%NHcoI;^nzw(3%4DL|+aX)96jatW<1^I-z@h`GEu7k^kmbFoCU>5v zRL+Y+aZO(1I7oDtmN8#Wz?brL4vQK5U0Txl^Do~YuH0gUc4AXYhs}Vsw4xnWNNSmq zxj&4RcbjnV6ZZYn8Tj?}S^C$r8H+QQv2(;QL#Raa2D7uH9i+Rz)#{|bresveKrvPO zRFd7Z1gS%{LepHs#m69keC}Yqr`f>C_QtVhzEJtS-310>w2L`D&R#(Xqkn=su4V+@ z0Q0s)j-U5*zXzm;ZE&+DNLLDuK3yK%uvw-Y&%MRJPQ4(0Wy_JO*pYMe>TF$4(b4R8 z-KT^U0Amb#(o4yOtA?$mFVW-Fec;K+wr%drfuCze64)x#jr%SFKskUW6cYU7jkbCa zzMlSvEbV8q7Xqb{OO^4}p~qzYlkYqSB4H!-7zsEWH1r(kh|jdFsEECRzR_CT{rCx* zIN{*>3MWZj#pR2e;K5RX(1`QL)BrCDHd$HVf)h(817H{ICvkxD#n&6N3uSGe0w;!g z|F7eV?x`3OYZh;o5RzFR@omzY{Qm0-!tHzhF^(a*MUws-#V6t?lP{DJY(Hr}zudNJrG$(I(LC!kF>UidkLOjy5~h+6&N3OydP0MKhP<+>w)a$Juhs)}WW7Xu zx^|{XO{x@$7a2YUCG}K`W*f_<=5s}eq3?Ef0|BQ-xja=`XWNJ|MG9)*(*fGo-v?+X z$LZSaY|Oqz8VMw+k@)Ro)6%R~8oI3UX%=!wq{d>YPh3ezpeRK>A~Z>Slu~jM5~oW~ z@M$Xxj6jv^Z)g%=zvd3v7^n~a!1R6iyB6g%D!OH}xReder^YMem#U%$pdgB#s$u>_ zn<_MD(JQqBLB^OxzHO6sI=mABxdMhc2 zQ7}@NH7?<5G)uxF)nQ)Zo?WyG8V!mhx`%YjV@J>dgJCsg@5{fiamlHvozl{HJMCAc ziHTB!c%Y>I$~4KUB(yrlPH421Ri3x&E#EpSD^G#Ce7uqh)JYQk zd%*?wI`Zup(-zorkLgdpqd(;g>dNzb+pV;l4|{kr0rhNSHK? z1m7J)3`Io;gfe7go(AvHsi?81q(TShuMV~gLnkNG+Ms=qOKG$cqG}w`w3?X45K@Y< zpOOQoA>IW+jv$k`n&Ce4nv+F*w6N>hJH968aI~h==%@8e=FLVDUU^ANUSnW+byZc> z;BnHp&?r!_*x0H5lvGRS*6!+PXIHK)cV*m1m`zSvqN}RlW=dXqRabixI(4cRR8Jvs zqE)PD+UnQ_yLgDDM|`FsYyw9-N}9C86ev1Kzc@;e&l!}JFr8E~y-EoiN=0a1ufpO4 zX9iATXY>k#o?>NaA|v0+s-wh>%}vep`05N0+WrV%5$Ss9i>~DvLZ;_3uq+0Lz4Zy_ zL&GNo_(?S*23JQG6n1x8aogB~Q>>MuOtGJVxeo`A?BMUNI@w^qfw+demq4X9V>~9)TyDek@EKTj{QJO!k$)C zmap&2Bfm*39fJ-b42_M5osqAXwb0bI*6!cNusP|)g!dgg5e+bAGhTr@U>n|br~gDn zBgG(XRP4c2^+$?&ux_=PdEd!^!gd1Ia71Bj7)(xY=ctfbP3Gqopv!ItH7_Yo!p&c6 z^H(DMh1jp;VaXeNgaTWGdhmeW+DOYVc+q)rX^>Zs*IZdtOwlAjiS&3EH*FJW-HQyt zLN9iUv2`n=pxhYIxCU;`#02^)l?=xW_}9;lYTrE&x78p(ii%n;N(w!K+2|1IS&}KN z`gS!i(C{TD6)M(6h53%RcjpEj3Yl@h`_xDm!ytUabZ2SGYItywOg2_Df9jfH=-c3Y z?pctk-on)BuH;JRD(g=++PzVAmdt+H`llMxw>V<$A=CvpFstOA3xJ~M#P24VGvPg z<>|Sv_HlCyp>8HFE?3pERTiyiybO7CbV}54C|DOCOWmIavy5nU1rcW%V`t~gk2eJ| zRAli&(1QcSgayXCeT*TkZo--L%xny^WQiCD$q494gy%-Fc(oao%U^VKX!gIYh7Q`1 z@~3}_=uR8e+39I;*{G|91{}bm6pfIPlSmRr7dKjtAMUYnT%9bX8dX}bz4M_Fd|B-i z95MVRCtZRMS1GHMFgi=S2u?h#J^w1uy*qf}<>dMfU*8)f$P}2<(pjjCn=o}0wv-pc zGEo|$$ac%CtgNf6JP(3Yk5pEclC^IWJw<29xOPpj+yt_ep6E*~lDmnmf>eno*GrgT~WaF|mfS;5W&Yb zOO9|-g2FmsqU=Iy8cgO$Xs@Vz7;!lGNTZ_u8zKpr@zBz=2ib#6VC}8#9SXx=Gaeol z(P9c#j0LB<4phs?{`Xjw5bc)+A@d}ZbhfrCr&gOLaZ*rSCqO+B z3q6hMK)*(TEC~S^+)5=zGLR!E_~d@?BF%&(oCFpXC-|MbvC-OJTa3~wtz>LuG{|yn zpo<|buQjMyNFA0SX~F$pD=|!%>6_k9UXsil(C?G7vSyBJ;#%ixE?u2D#R-$KT+%bM zPZ3GUh6Z&EQUJRgFn&ug&)=*~p|`dc(GF!Qt$h|&s}@X{&#JECg37DmJ;Fwa+XwA9q&Q{9e2&lD-j(Tm0C;9!z*JE=wVh+*3euQ$&-q6ee z?DEzAM4>E#<@Qm8N6vN(>DGF^?+>fm9ajadm&odBt`eS!0!1%Y4F+t^-HDfno~ydB z^<$SbjcU#WL`1~_qb~|Pei{v;TKfK9p5bdxfH6y5zP7Q=SyJY*MvjTx3jSGN%q*(Z zG&2ovAp@k(lqt)ee2WV_bb3EF#Z*LkiDZi7DBk1fjiuGSge)_?PJnVX|LZxhzh%p0 zd4_zuL%qK?-d}E4pA4CLO2V--Ybt7jxAB`IZiQ?MJ+DjQ5Vshx5Hm<^I=$uKb5Nm)r$SIPFiup_#?~y*pbtddaOLcumH0Em!c8TAS zrB3^dpYN>~8N6^GKf#ap|KQKDUH|%j?j+Udle7O~3e3SM_nQD0#NzxV#TcBbh~jfj z(5Db_x0O@45BTZjj*R5pJuC$F`38@S+-|BWVUqNa4ON2~X;P-D7;jLK3^oj$Bf@mQ zSZ$-CuB@b@+S{De?R&0?oUE*zjBI1jt6|jZ($}tAnn3Mr2(exWgcPo%qvbV;0k=wy z$1rrphPVy(q>bKsT)YqQ1U!n);{}I*fcO5`Yl^)-d4d%TKRe@xWfs1MyQb7a@lz-T zg~p^gem9dFi#RF5yeJ*){_+7Xiu3SMQLk2{%5-9$GEoeXr>SsgxWL~}o@|nqo~u@O zFtN3DXxZ}7@)}TVk*bNGu%g*)Y<^M+v0g9A#-S!``zPDCY{xlCwn6MvcsC1v&l|5C zV%JV=6RDC^ph}L)J_Re08uDE^f8Fb-ekIJSgZn$!O5_E+Omk9F0`8@@r>dzLA&M2! z%`~J+eeyG|1(gwEH+B3_8kmihp;(eEImNuHYtXdypgn7~dhBLq@*$$==lPMC&FY2Y zD&D)};Gm^R36KhuSTvL$dr2lxo^xp9TMV2p{j z6bO+hYYI(GlHwNd79ApWNHXsr+L2E(EZhLZncj>7%Rq9CtyZh9lxLjtIN?ZHo| zLPIA*uUQS$oGfwalol=8u*W#Vw}(4rc0)@uO+P);RZwQBUPHWlWS1md3o`C<2*ai0 z*J{T=YXtW6TE9o5)!My%H1O#qLUxqD&Q1 zIAEw-u4r+zSTf1e`hknE982u@JE{{Lmg5k{q zo>GK5|2TI~a}}3`QBXS>Jj*_;^n1f8cTG>#+fj5>I!KhKNLRzcnQ73tf;YFbqvPhW zy&~H*T_pD^#oD>I>?rzALl~o7p)hgMV(L^QRI4a8VkifuA1OkF7R8f+sT-j_%IuBhCmqg#Jg`J!| znF3qPR;5U$L}k(_rKCzqgK+lxI&q- ziBTkT<9j<5;bP_R_nLany{xy_P=9j!bjT`Z!ib#@3?A9+ZX%}_+VdpA7Y6nR{6hxh z?vZCRoW^fdQzrICwOCF-t7EJd2UCN0eND|#=mrOe45`!NhGCF>l;o2P`n)o#qM`@h)S>gg46ucmBcbt zlZgZf!^6WFES1^8?QiH#e>8wQOp;1zs?^humnWM*3?*GXKg=}@>^wV9Kn1L2j8!q)JsO(N9X#!V^&w;u9mFoNG-1Oy0JR zrQ$_IM21DjC=Nv{7!mRj2Y?*eow(hTa;A*7TlsDAB7fbo!i-;L+tXo!9CEt6Ie2+5 zTi4YEa|KgS(b3&>zn#TOC94$Zsi!HF#+Q!L&&gRf92yuWCMMoTXAnIjSkibBRxAhJ zf9P}~Wy@6Aw+<6q7=Z!^2noe)lqOSbJYL9Bq>?c3?NFqgJdKQsRwnej-iGM}rL407 zOi@K|4Do_AK>sql?yVXe_SFp8Cyy9&^%NYiD5Y*#Gv%z-@3SOLc!$Z8(9BFb3+ufp zWoDd&f_FDGOg?L9s9LG6en_>mIHZ+6$HkVs7b})1QazW%lzbM;4^9;G39w7*yM5T+ zdEe;iWWV};@w?bd(AOg#K>~WM`JRfu+_#)UMJN}poO^zkiid%4LDULn00&l1kRCWIY9S?7+~GgXQCxSr z;&ps@oxML_aKS<3j=?ej&~5X+B!9jG+IvX+Kgtrve*NfrNa9o2 zF{n4=!9$X3gf%>-iH>S$?gT3U+Pcgz#RK{Xs3_yj3t<}bUXv#&jUR(Tm2 z8!9FoePo=St*xyyuQK{+8t9B2r#ma$%OjCGuA|@D%gsH!6^dlwP=l*yGgT>~(Zxi< z4})j_)$@~~3hHA`#V~LeF_uwoW}%Zr#YOe;){y57o)UFW6Wsn+3kGZ)pRiy7G!e@t z@lQVqq>tZI`>(bWsAKT^AJw6XF4laRpI>bFeN8_o5&2c4B5? zUYl;VojS!+5;9XsSn2hq;ta=_trJq@&whA{cr`Ld_H!$%xokS+H<5G9J7P z3^Y7URMZ+-q~eIwuWswMo!qD+L*kPA`@`{e4kgbIchO=I^dtmyOw_EJ42too?DA?1 zIXQMxQW9gy;ZTl*b9o`}Y=uNc8boSmRgcQ0={UnTgSQc)0tEu;xQK9>aJg|+M};mN z%Pj1IR)xVzc=dQ+r6c;k*py(cEa~3_oQ;FCvtPXTdIJLwi-*lk35Mpbpy1G*GQX#s zX%Pw`euO*0pwENhGMI0xy=HrwDpb@;eR^*CH24Z0xBnh^NlSgN`0gDQrJS9r!IVuV zU#^D+l3K=~Jp_=Qb<$?8ue*1t9vu1fS(fi<(DLA95n*BTY&ACU5qAwbr3dOFsK`IZaqOab~NzWT5{|WF*MZ9Og8>r4LwU_X;8#$OXwhNcga9l z@AOtQ0rH2p))7i^V*MWgkU($07vXvNfnE5d&|UbYzv9*GI(!DZmp!~LunE79Z6?$B zarTBy_?=_VVs2;sI`Ek*!(?ayx0~>%*mYt<@9#een%@@;de14bP=N1~i^U~6sWmxS zsz{P%q^XnuooPvlf^4PEqflliIEAGK!$RYVT{fE|O{wxLRcTsblHTofZLeRmuc+A1 zGnaKj{w7Km7U*r2>a-Pp_bQ{&t=4$cQ(TFH#OR2Kcrs(Q7@U|5n@(yr5_Mb3JQiwf@^8-CE^si^Y#pIPawlS(D{=184fUd5{y z2@*|`g8~%xxCsWwKl2LI?lG6<}!Js zVV82B%(?%(Zz6_##d(Sm{(5uP=+FtnPBAA}pRSNf^Y+&XP8TT#7g9OT{v!M5$=6 znB13}TM+T|(~(6s+t${VTb+&t21$-gR%A4KfRjS5URk>O+QNdWn8R;HmfG!Go7=ZK z91W==lU(lR=DKYzn%B%XaNjEZ`_HRSPDOaC3g$nxKKm~|wRV^-n-@IavD<33*{s&x z9naUEYqjM5?dR4_7dRdM*bhERY%ecA*s1C~SYEy|@yjn_y*BGNVR5xVqIJO`+@5XhjZz?SGgzveI z51EHj(#BKIt^(hVjv|%sePyec$>d2QQMqjy*r}kvmAkj=tM_hFmB{7Bu#Z0$q$Vpp zdQOu<`YjOYiBFET4jqRJIwSnl3IhlJ084Q-dk?NYiZ`(@vA;-(l>LQ$5ue8Xh+EiO za0^!7Fmoe$arTwGTwb^VWu$P!5NUx>G)qp8q^Lu*p8}tl=j=hh*-2 z1?rNv!Yr>sVq0MwxTC1ZeeJapS)x5f(vci*UT$8#%WiWqeTV8zWfHkOA?|H~#N}{Y zxu*Wm@pE#UB!Wai!h6C57xy_3Gfn?z1Mb_UVFvD-LnxdqU|(msPbLT8`GsJefrM@JHZ-@I)2vP=HTUYEcN z+q}gRjY37K&H%Wy9#HroSj>b919}y}5zKJ7PdjO>4*BT9c=8hk{;6L#<6U$6^Gy+s ztgPwUx#wLqQ>H9OWRqSCh?BWUB#+KWPD+8$JiEY^o}ZW~5F{q%r!&{@#ys};!t<>b z*U<)Iby_T&7tU^OnKl@8;^Zy7s5pV3z(l5ABgK}q^lq24%a~^2B4y*;r@Rfkbfn|- z+$rY1-NzwOAo1XoYYZ0$F(;6KfZX`c#Zh1u%;v6bgDLuS!{oNn!V79^w-gR<9W`Vc zbiG?w7w=fGVCU?o=8TLXcj-_@hMBu6b#qsBJr@lXZmC;vaq;?#CNi>38DrZgigz~F zZ7b~Gz9!ph#qU?F4}LhgzM^8rlO<<2C zq%NwdYHh8mS%hbqyN}nhTS{A6NmsWj-!>lE_lz3SUZ&JvKHx9j4UQ#!czLv^%{J7e>iufH+hAPDUJ#ghTN}v!B0IsWjzUE`x%DrJ9gL|$=4YV*8ABGm=??@Vx!88Uw zZwuxBU2|o5OG|lWGkK(BQIp%<+`>t_6aU6^Gd~A*Oa6BE3GdXZR4qR4VSj-$6U)jJ(vqztV>M4y}-vdVKKk;lmt18A;?V zAwP0&xP5irlH-q&#E(9LF-4?}w}&Y_@n+Al>qy%X?z`T3@aB?`HZ^Yd5k#P=V%lfScfh;7H$_x7{P zf!f#1PfSW!W*{4e+`v9xNaC+Quo_N-R79%aU4P)t_Fe9J-BP=~kDJeH%qL7lm?SU; zXeZC-giOQ-7Q?2%82-B3ZfoBSW0u)%fibVL4>2(~mK)P~%9xlhO@^}#Ua3Use)&-Q z4o`qhFZe?lNcLJ-CRn|9j{6^O!ci|e!1)8t0{$ zHE@ysfsfu5azkdmFd4QOOC@3%uE1Z~;2Lr+Mall#+IPC^QU zf$ACV*Kz;iCvIb1%;{l`;G6S4#r<{t`FAm>emNDlW$N`EF4vgLX>3SMDG((<4k`1e zsY^9ZcoZA%Xxnc+Yj5{>mrHl678m92ZY_CZgKX2=ZA-7n%koJsl`ivoZ|_S$J(_&b24ma?_}!3 zE~np2hGa@7VCq>ne(YBMQ*Zqyek-hCzE=b71=$be5CXh?-#+|!*yV5i{>)q9UqT-T zdnxluSW)2f1y>kVBDaM|btyK^f6FjTC$x%ag3Ihrv6dtz#*WUcALGZzdx}!pFUYi; zXEtq`$uyfTVlTalxJ;%2=iZ5X&F1?j_BsblCKtJ~D&Kog^WJkupC3JYZ~YB^PXH%s zK!Q&}0w=6!@jOBV;*2BZggk&3;ZCaFfTHKq?cm2ZDIFJ?Oxf}AivGr`9;HaA&&s}d zT}qKBKAvw#lUJDwniUFpTw-F$i&r)KJvZ0w&8b${bDlS(s}|+%t=a3TY`KyO>|bw9 z$xW7)n@rvLL9sa*H>1;-7Ut@}CpG_vxc7i>qe%P5HM=Xx>SZOZdhcD9CAr&j?{@6O zY3@m!LPB~%5(1$lKnT5D=mByZ5K4fAqjxwsAXg{{FC~;f=o}p7z}EUdvy#_x3U|Nv z^L{@65QX*Q+0m3|o-*@1-yt194dU3M?+>CBlY^KHj`L=cMlsspEY6wu4E#o>oP)%n zP{5K0zx(bWFyJ@RtLW8W2MMLl0?y@7V?D^o4h0io#^j-3@6bQfmw}Z)08Yh&U?;tS zrWbN1!n#TTCL-I z@!x|%`sUB*i@}=D#^-;`ob%qm`3uobT*Tz|PynO=+Q8<68-5SsApU#$Wsvwi{VM(H z??D2r-3vhW zyRo4gV;?F${um=Fy1FXhXM8vFFryn;ayJ4q(S_f~!6zf|QTPPWHQs^WKi+}8dgKT_ zgOTF9IcE_q#0(CZJtKpw0UCR79N;GojXa`-Zd?J{{$8}XH}e?y^9uUbBZXUffcfKB zjtp1rIr7TK164P`Z@ZZD9nnP;?DMmX7Tb_=6t)^sjTmk+npu80UD z>uOtv%F?5qwVO+X(M`3Tqv^7t)|&MZVQf=P%WygTP0bp7&1(&9nBQjhv^Bg|-|jKn z{8%R~d#$#UA$HWgR@cE0J77Pr=UhrCpp936GM8MQluH5Bgd+29T^;5ezwlBZ`=eI( z2$0g3eTe4vX3iyqD_eRaoIeGZ;&X4t&mBJJN*#o~xjlK!J zxo_&*@FDo>C7|UM(DMDAO6A>|JzFf&k8@`(T#jSnE8-3&-X_jz=PX8g=HxMpzj0Rfzjz0o7CD?w$0uBh`dSio&SM=(O3 zQ0TVkTw;lsUWdib&-{hBs~u_urrrd3)bVv|Bw>8KvD+3a?keL=OW z+91`7Bvz%i)DEe3#}77}b)ceZ#BOug?XW;aztw63_woe-vqo(e2nvXT0<%tK76^s( zM2;#H6ch*qCbb4q3$Vp`W%&hWJySNb6i*C~zYKhCX3)jr0*yqhE|5r=;de8`FO%_A zA_-L>7Nd#4o1IgW>0~E!-0Ys3AU8Wf_;pS+$to3^WG6ex<5!%p^tV{=K;}-kS}-*| ziancMO-Pqu&)!3i@>~A>AhP;Cqrb;KVSb0CF*GMqumt!l1OL$9vRqV5{arUOb!0ENO)r7V6(=AwT&n5kEeCBDZsXlAQq0 zNn(uff%Q^}BH?l-m825>O*-vG3b}l}*=QT7Dj&Anold)bxV&n_W-w=Z>&we;?wh}- zyu2Ph?U~HVYwhiA zZF`kNaOO;WNo<4TLvbR|Q*MTG?j*gUPBIFvI2Fg4qRjqJ0+z`Add_6qr+U#eb3W?t z{P{O$`1!J3 z?ey~V&nJGSufxprF0d~15n?THaOqOI1EA{nu<^|8KW~2k9BNFqfeYnk#QWm zp!tF3%;BP+-)=q7@>0wFt@O`d7SZ$(NHxb_ii2zEQE=@Yz`hUcK}(Px+DE^CM~+6n z4_9O>J`pXdt+yb?&9{cuGsjJd`rgYq7h)Q|>B_M#~oo z{YD<(lOC0+yicJ}6geoDL?Y$!t(JZyge72Y@1;dWr7BWvQ}z6F;Oh%I&MyHKX-k9G zGcR7ZITB7LVzFJlMI$k5twZAO2t-f)60YDnuR5aFS5aL0PLYBy5aMTBQfjqUqf~~q z0t=}MsOr@|m7xgDj%(uI#MRteI0NVmIz5#Mhw*uNBj?H6$V%mH$no>oFhx$KJD*q= zbJ;g>eqM#dz54##yxZG|G&}oTO z#TN<87Gp0O<6b&NTn1P7GR}pQQI+|B|5FmdaR*k%tp5b}B;h!&>81J8zYxw0aamP` zYpB%O9ZYmvH4dpwXE2%ORhG>)o6Ue~s;PbIwDnKc)-{_=GB;%ilXh3S(lc67dPyQs zP1%j4(zvK0I_PqT=`Z@*+n!yt{_)z{X1!kS(`kJQk1z9dpvh#4C>_Q@ z+H5+pSY%S!n!r2r&yAU5YN=K%)rkcPp(g3J6sy%btHIb3SiC2dEKbG>FY2vX>{ojf zGMC!BupGW&jce3yQf8D=MK*m%X|O0Xn$|LK+Rf3JFBXklIInVnR~sND7NvJ-Mxqso zwGv&i(^Lq*M<7;<3<0gS#A}GE%R@7B0H0vWm%WdIP(cFl4igd$L&t!12ZhcdOO=57W=Qgxw2Xm^qU! z#Q~EY4K@>};l(HpCGE*q^!af<)bs!jc3O$k9)rs_YS08VR7B@&bh&4Q>Q;Mw!2^_v zEHvmMT1|*@H@RHx!MZg*ZwUJ*X(^*9BQ)l%YHLicR3@Xb^JZu)rIf}X77Hz;qYx_i z;=H8 zu^jYG(s|#r^nnQ))F4zIdJcoi0*uM)E` z06%Q2&u3dV!cl@BC+P*flXR?m;(M@%Ex(X0-_N-S_Gls-MaGP7Q*LxWWk#1l1md}5YlI|^lFyg2kV)lyIK11#CRUPmZcBDIb6unbu4|}#Cp&(N#}je z(g)x;m*h@+8z&JL6o5%I%S+drI@~21>7(>E1hb$6XQ|aPuTCG=NZr-$ITyyFMcn=4 z7vn4OU%T+tl7N1Do9ysPQdmIO40vc+`-@-F|%5b;{r9fk)=1W^ghmY3~$e-H3%Pxr7z)pKtBOj z9R*we7Snnvm+1gM=oCJSI22DXn@fr;?ocd-kcWWgPvhr->xpN+fq(XmeU1=_2x=dF z&0~)t8Ngr{F)b71T5t-(R}4ZCv!;bPeqO|^=`20X(g!C#U?gUi-ptbbVEKNQ9%1Rj z6MxU6x3To0iO<0bmTqV1^CnuE5n3dL;0?yNrpF~-H%4HV+7B}U=EP)QK zTXsSz3a}{vCRIRVJ&_Paz)Wmw7qYGD=PYL=;>wAyxYhg$NEc;C1H1`lK>As<7~w2I zx;QtlchLtRoxxAyV~{S%j`l(GTHHc0-5Z)47ehKG3`enBK6n%(u zappZZN^wZv2uDeh-5uwvQ_RXsCBUonr`xvS&t-Z)!#7~1nRTvbU74Fc27j%4c9J`4 z87`3JxL^zCCvOJ6wgH8ZPQXd^;tV(F+|&#~nfvh;q=CT5%%j3#~&q|0;luLGyD z^j?-eIPonwz|sd;dLJymhNaiB^x=sQ^XMs-K5t?kSPj=vKcs)aJq&%fNeqyzzvRd> zBu}uHF)e?2+WrS|zSZU_C6(keJRT1kXU)E%O?78HTZ^I+Yo9ygjF%c3TIi3>X3KD0 zeV@^&)f$a`b@js*iwRrt`oQm-G_^th;tEH(PV1I9O4WMf(5&9CcD=sq%UQjHgR^FR z1xDVSdv!8ZS(!>*JqJA|D=L!7t2wzoUc(<^`?!E}dS2i8EPY_&D=-^+kkN^oiEZ3( zI4({J6FtfVayU-VX9|y}*j=1yk+*;;oEH-b;0SDMtULRmI(@0xJu}4gTqcu+%s2dT ze%YnHO#jEfXL_v*t4N!S-i%=Y1K>MmOj2DYaAiRO9E+Vtdp|u*VGxSN*%7GOl1h&F z=`Z&9185v}W&18DD4=ASc8Oj>dcVw$jMs_1>_(D{=^wuz_WK={r+&wd$0l|>`Z-&` zT1aPbp7=wa4H#F}$qG)pG^I%USv$ zOJB&5F!M8)4k4VU935Iay+5<12iVemu$DD>xJj~X)R2wAPRdGt{LN3n(+EQ8lTUyi z`|$vj30sIm9=>Wp`Fyj*j&pLY zyqVF!n%wF+cdGTgZ&~`l#1EhfWtr30FvwKpOzTxAXgyU}82>FDl!4b1>k#@KFrelIp;wAGm%BRV&+eqGLLf7>&*#STXhMbMd(@fS$ZF&_p|f}OCQeZoGjhW z(&tT#GW9cPR}6m}a`m6h@OPHp$kG>1WSAMx(wkZO5QhtvK{|tj#eEObjk$V;ITTBu z$kBOV@ZJ7NDv!^W?t`TbZ0WDr(!+*tLw635jBv+|VU?s(;gLqMts??L{)Tz|ht-imits@`AOEey=Qpx3cAYMXs zRA;TVA8%J3i|%DhD5Y|fUR~;_cDq8C4osnY>BF~CDn&?_kM6~ee*-(BBNN|n9+;%_ zRg)u%b-y~mmbSB{`#DQEMo4G!nYiymdUI~hZ{TPlok7}Sc)^^bpT+P3L+2Ib=sd7+ z9L?@}=+BlzDKbgT`m@=xe7250SO+TYg>rE-PfNHtmWLQy4_m{@=H-4x{2e-LE(X;$ z;mBJ2>XX?h2v=)*o=iS21@ZSg=+A%nLE$33gT)M>76Y=C>i6g)D(P6JgMnJH6>AJ$ znbb*XD_ji57V+GH^UpusAxbW!kbROj5BdY@%EA0hvsJ zP?%t^7|bnZB(2OC%pcWGQh6MfI{4uLOBJxxg&!JOY5_~_8)d27Z&>Q^Yg1)KEOqFM zAY1ms92KpyHfF@L^!wP-1MedY;j5r0TntxP;qiz*CyI5RhH&GtT?I4}yUI}O^;c`u z6y#LDUSFhn_jKglg3aC6D(3be9XE zyNo@#@ehfjsM(}0afo*z{4#nagI`vOq6>Riyv^UzG;AydY}&NbfNZK1mBTh$)sU|K z<1#LR2i(Uk^^#EYDV7}WnLAbhu)|ZpXP5w?o|&;6>>2oZ^k99%93cSifxxkg+b1{7 z3^J%_ws~=G9x58>$j3v2^TObiF_P7u<&MMslT>EiWT|}%4J`G69F>oCK#%Jh4wx8+ z(tHtIHJ-dR^P3o8d z%xY4lY`_59KXEHU9^>B*+vLcu@CiG347Qa)!9o@vSdo(+w@=V4{gWIW_Sas^Qom+P z_i=8A{hFk|#+DvdO;KN9sq-%8u+-nN)B(#;gjWXj2*N9KBOd=Rz2^J?BnHL|1SpqO zb0W-Ggw(W=*yit@T`=`#JY=Fi8IhuE|;4 z!;ro@Hx^$`{0q`Ar6mZL434xrXNzA=ADpa*zleu!9L|pPUS^j9;T#|2aiNU$Ji^FW zaQDR5s66dN_+)JPC7e&_S90Y?d7R1e=nm}6+h|{$*+t`U6q7MF2%II0YUWDdg_&DH z9sMFG&cd4k9X^I}Kc+`^KD(24fAkU7yY*REH-j9;=n`L6GA^eksf@JCQWqXYTz(Ps zIeHjP;>)$~9>(X$mbSB{``02V$e@KWHT$zQZ=zW01WO(Kp?{Lftg0-vZ;D8*HaG=U=5{%XNmBK+Kv1BTRNc1t zzeX*abA64b%Htg_aaHP6Hc7JVUT$ZF(lfA_PaFz_9U&RaaOmRLwU z$)HH4bN%H{dCHSW?Tkx(TwlSlZZqut;^m7+Z)o(*jxc?;TD3L)B{wt%hKlmLs|%9! zcX|r^mFY6+RDuHJCvaiEul}y-ua`?C*`9Y_Q5l(Ged98@Jg>_Ig3KGiwX?IGhVK~3 zAY~|JdIfo5Pc^pR&VwPdNInxEOSe7250 zScf4G0W2_y0LB26p3tYflIVcIJT_UuDMaGvbfD zhoH2Ge4b&X%e@?QZo=S%abJY(jb_Jf3&v8vV5x&YHL=w1S!&-F9!q_Tr4D~KMSVF( zMeA{x!$s&=6JK%%iEA0%ms@s;lcSSS2xO5v_=19zxU}@=Vw=X$5Y`zy6lH1t zCWhLv&^-AHiYO*wyRB+tOXQe#%M1ZIr9ECpA>1`|mY_bi6T9Hbus1u8Q&f}f=f&85 zjldbck)=ymdOzoE4nMc=aw9YAh1pqOg0a-^S!&-B9!q_Tr4GL_MSVF(Mf2OiK^_Ey zvBuO~G`Z8nXvr-7dzRh@={%PHR*nv9&!fJ~mYz4UiK(5zR%2>UsXa^oSB?%> zsFuf4e`KjcHVp@W>xg^tGq^7>F>kmH;Ah-N9|8r$y?~-WM-ilFz~7%T`TID)N*;X+ zsJSnoTyAt50r4KbjQbUXZS8V!)p5w9_%ix`Zl>RV`V;Iug_0q{AyBqFhcbl2JJ4c=I%(P-Hvm58lMPo>q;7>#wBj27-ui`pTU z$_xs*A?R?-37RRFSRygV6$Zb0Q=3@F#?D&@%H&?uOFGBSpw&I7lw=fwx z)1u|_F-7o0FUjPJgxix)C}b~2LcudSJI)9NBivi`F(s+dkjj`oz1-~y1U&BL==rh zwniqFxYcTh1dg&)Y*(qB5{aDni@!08X4B~RH|h0evtHli*El7xj6~wrP%epBA{9$q z(Bk+z@d;t#ev^xvgdAjpA6)$7>!2{R?d3xN<9+Xg# z@*thWBT(8J5LOmHKW2r>k5j?+{>9=cRw(48TprNzXKf1xf_k+&Y2;pnqi`G*Wfckp zd+Zi-Zz52kR#8xXgRS%&T+JzGa3wvzA@{Jat_jrZ-N(CZ<>jhEqpvS~oESsAq?(w6 znK-{P*>P;15oUVAS5QSMhWymXM zOnlAk*y7B1qWD_YkDm_oqW}#r;sp}9BIPS@dNCFXZf=@=R>1E=0TtZ+W0xZ+HeK() z>}`I(FB}Y>*+ra+5QbXm4q`UjFlb;oR97eM(n>B>8i%zmKvHfqkthPCY z(x|}@S4g!Xjj7za=*Cp4WE_0*C3fY9ZT%Wr#yr$eFCaP5q*BtDyHLY#w*{Y)I0=$Mj+2rkw}(!`JSXTXIOK1YB1BXI->>7URC#iZ90 z-{W`k&YEmHc2(D|w|QsLtHCAE!vQ$)B2mj1u=z)@1UMP5?g(6QduBy@x}vMIvZf7l zbySznKu>%D{TN)0)rq#2RB>y2QE_W?X>m*2!~_=mZjlz^L7#8@b>yeb zpZJQ{!F>)sYS#%s{{Pd-E?!8Vj=j~=(D2fk|J`}+=;6cs*LQu@J8S5_Ji~=! zfZ{q1jNT@8(j)Ywa?hp1nha=8F#uA!#dh>&k{pH28*#&5uW z7=HlY{n1AsVJqKx2OB(c1lEtK4(KucRbm(R(G|Xc~43+{QPRrc_l>q37 z5ujRa_#FBw?9_1;c#5tj1esOX>k4r6$nMPZnMZ&30c;0Ca{Gpf9r90(bbd@HtRj!w zv&aA`MfM0e%kx>J9o$KOHhM>SMQv?G`5mJ`J9>LXd2MZZ#qF7wO$I9M@z!W{M(iB3 zk*aiAQ);`L`0BamM7<4-Ppnz>a9#aO(c_PcX4Tg}ylTzk4Gq1Suj`h%ZGK_qQK8@F zSd^|^>NI%-SY3gYa<8An41I@*!DC_~+|yhRYI3iTp)e;Q9{MwHwMM6>kEYAZ?^pt~ z3vMncsiZ&EsL5ii3dK7KgAUKCRxFwM^R{Q}>e_|$?O?9BtFHE`GZ3w9wc8$q--}@B z&dwoLC|H<~6L2PlHkRDSF=TGD1p7UBlm51BvD+2sXlQ(X95@2x^7eH4 zk<$|cm&D?6yFGIAs>GH@(&-Mk{+2-x=Mtg=+J6YE(!oDzd_+n!-AqAEpB_1&P^qZ= z;|Su(1g`W^p26agtK)I#lE<$aE*@|j!YY|ZXP;B#D6?t>YKcrI5Q#IVt0}5AVJXt6 zY!V>0s5Hg4WHXf7MCqw~txs++&1`G?+gA1ZXB!$j3|d9VV2&uXlu-UR3>SzbVaH?Y z#;uV^N+=ZS6|_Z6iR5~rNEGq;Rx_EA^r^%}+~+xN=7y^ruF-Tj`{SShamNYZ13ky1 zD`96WxF=oH2GqKQAuvBUdRu8}RWxkwikXYl{!mSM#a%0EM-$yfgVAC#^(LKZlOaM{ z42G6qxIs%%S_4(jeZIP+^p=rdhrlaxolq(*El%CKr1PAptxzHNQQ`G9{a3(NX0ASD zH(O>W!ky5}76=L`8BQQC$86Q>>s;|JJ*7pw@1+Nc2XiRjIj|TM?}uMWe=El%^ildf z@F>uL$Du(smQLf`vG?dEZ~&TNx!9R)JUgd^)5D%Z@Oj7a!qkn0p8ODS*0dmVwEP6` z?D&1H*J>MsSlwx%P@=J}?u9eAK37-U*w|Qh*QtpbrBbZbsLEW8r$>TaS9A{jt|*b( zZnj#6YD)TTR)@)A8A#VaIcz3A4tFB8E|GVXlwL7YwfdRH#u+`$O)sodt$wVzYN3mC zE0uPc)+3cj-Li*l!GO=dVf-^y_4-gSA*v3AmKCY$Ho+z&LZMA)%+7`VzMg33bRU!D zV>=H1mpMO8Oaa>cH}UW1b~HA=uyNpz%}sOZFKrfUe_6WUWHzcb@{mbeZ2k08V^pQ{ zN)41+ub*8L>#0M&q#C7pB1;?*0#c?z*(G@v^Sg&5=l2Y2lF)iCIYobV{G*R6|!NG!Uqm zX)?KFE`f=n(vi9qg|P)?;4ZXtKo1jbP*Pd{<82%s+gU)P@ac>V-dGD1k3gG@#xCfo zT^BXR)XdQwrL+hoQk`Dg6dn5`(Y)rScwyM>P#0MQS3;e)AIii=Cdbu_bYA`Or-3=- z#ndFASa!7V>7pFly7Z3nvNY5vcP@ob<>?yq6sm_q3{Igas_r9Lt}Ya+htKMU`no@F z2Ul%B)X>n>)X;EfJAKObKiAba9M)ScOFD15sdI_Ns>gP0L$|d-f7`aSV;dZk2VhI9 z;9A#bJ*8u|LnpV|9sq_|G_tGDT4^y?T0@4;kU6PRX`x9@ix*!K3VC@21!nC_3Nv3O zD^F(cAhS+c#Z$q4VWm-RzrZ;ih(pry#K*~MW?GaOs=5w;X@&)9=I zfQEKDou{@GF0KrzycVrPBo^Td-+XiYdVFE#(EQWUJt3Yagc8136!u_ts0+5!L&P9l zZw3Z&cseBDZ{R0Ri<}&+C@+6t!@5UnYMX!tu5#aK`RMhDM3Vl3(&@X)!p%mtU7|DS zyGu)F=ye(}q2Btpwziq=_4UuJAGcy+I9fVGXJf;&JJmI-ef|ikkT^9zGGaUxiEKp{ z7d?x)AFYbj>-pJ6YE3=|MmzBLb_Zo&1*WC_x`C<|f-bJs|cnaksiuStb_@>FeNN9Ng0k5{K_Yt!k+ zH*a{TswxfbfwVjGzRqBnU0L3(*HM%n4s_KVgF%bW`DjLC<1=fr=W1Q`^^Yu57mWmi z?H2kGb>&LGFBbFpS61fT1q3*0*h*pcMwIOBjwg{egm63s1`4CmopbCJW^=jK>S&DH zQYtlt_Z&S+2UlJjjRv@gi~c5~gi1w2Irs-BcfvCh*6(EYosLfnvuTu6zB&e1(qGh7 zSO0O%d5@Ns6e;DogG)cIhbu7paHe{_M)P2EM9cu zimFq+zHqQisgwhyLQ&{=EI!k0wuR#H+rTCK0-jQ=_e!NQAScO60UZFZsg}35J-T4Q z(`{`7D04ZTd0t%?3@$B=EQm(ud3O6&*4AD#bM(oMj#K}E)k4deUl8^C*VZN%1%kE6 z?}2@J7mlHa8N-vgJw@5;D6-NKm(yQ3O5yC#pH-k-P@vhiKbeds9Q2sU2S~N1p%7Y% zcPUDPfer28TUxdAugxuUl&G=fs_q#tF2C`Ixf^~uvuaHw+NehJh~lgE!8UYrChzG! zDLU}+b2}wRaxI@mOeB@yHu_&`k5s0#c|2zhM0@O%TQ2u#>@#EiXL?AzKp;>^WgZRv z16;E34}llxNTISoLJ9~j{jOBZlkf`^LZyz+=V5W8G`zApeP#FNH#@uL+ijY1r?X6B zx6ki#&xxfrRZnq@ugj^AstYR$1hSHlxh)Ll(tqe&VV6?{f`W>8;W-UE06@HSCG7iO zpngg*_YxycQJlc{o3Rdx` zerq@!F5te1&S%r;_Ma120gS`JT4=1I#_O(@N_HD-J>Ge72NX}ZMXaz&q*MWPQ7GW% zDTFeYT4Et6Lyf(7#P6si?x9yyRfFAaOKmojNc=AJ^#lcaMP`7OfTP$wQcZzaf@AN9 z#cr>C6lDNS!114eyca+bpNv+_%Rc=r2EQt)?1q2sB z4s}_np51t1Pi7OqXb*YB**V zm)Wiine;X8Lx=38I$MIYn_U*EMX8QxR~=oo>L|MZcH*DJwa~`*Ov-Dt{HJ-e)G-^Z z3ZiN3A0PsBV!bNSZLnAhl**=Ra5j_&;l}Fp!IhLi45fi3X62jM)N%YA{_F`5P>n3#40<}tUwPrI*)IEOw;K%Z}3NyUKG zW&>~0-bm2c8mbwzT5MdP6}H#aJ$=Tyr|Rljo9pYJ-@5Lxy1Fj#V$Go0Vh%*Ymo2h< zY*@P|WHMW=wgolJy*Ry{ogZCDf3oX?j?P(-$@ep8+c}i{FoT9TC2&xa(FQ<{O&A9t z{@ZxfxG1w1Cvb6rKrIn!#425KzROaiqRa&ZasGF6E-oxgBnk^Jo+FdFN=TAaC=@9d z#oa%Cd8pF{~l zT-#7pdH3k(zN*RwjF;JsEy-xTHv8;wbdKHbg>wtPkGZejG{skinw+aY>4|yVc87xS zjnTjdbUX00!VUte|%@yT%A* zE4QPG{#yYS00ZcvKcyF)cpNuQu}#g4rOR0jtI}u`L~ekz@dl%*4N8FA?61nn66p;a_H= zaT|%FTOHyGTyZ||fBz2sKWF-X3hki(=YyYs_mbkDu-42$oQK_+xdvOze0s-!MKr7x zY3vTTTCap!>)73o|Nbhk$<;DxcIPX&j=}b}r$#ot+S1$;4VyY53FzNj+Ugr#*tGP~ z#>O6?b6G9Dh3P?y#VnO7>Z5YE>bd7gr##XKU3aI$F!TWN!809IV8aGcQK3)y~oyQu+?a^SPX_HKPQJP zT$Q~mJB?Hovq6Tt=mkvT>kU8;7v%tc%dcJd&EtcxT$blM;gfkPujP0Fks@JLMCbU; zJSf+3u~1PHvo$Qdx)8d#1!4jx02hQ%-5Fk_$5}mOPbNQV>G3SAaCL`0y%9{q?9*e= z3Vwq@9N}za)f7T~o_5WiXVAW)an9MXXuTfe(TC`7%=15`{|d&9A_w#=qVCyxk${T& ze9Oy->oaZbG=`6TT4{|dl`3Tchgo4a6QAd;FvP=Xh2aYUp?Vyyu(iwzyBVt{{*ql` z2>Xsh3}*4D(>BGF{gP*^!|o5#pC;CNVoh2tMIWuLthjf%Ykh+0b-z?XnT$it;CZ@i z>%r2}luVj=1J*kO)_X+`|0uiAQDYon0sRe8Lw~!I{(0Br0T6L$tPs6H-@;Yp@}+ES z^VzrXdjL?KHT5Qa3syn=E%!FYAm}xVU0`59%X!UiO=3 zAjtVCX((rJNY4LW{xRQq1O4eqWg&hwrq36KALU6xv`d6;U7OVNd7@)_eu_KaX+^l@ z`B5b0^ijN}zV7jrTVHByXzOTbcy|41PuJBo105Hx*})2C@0UIcoawULN6O=~EmkWy zvhmS$x~{vu?Y&(fa^d0j_MRCH4Ua6XUFLGSgQ4)QA@(}TvaQ$ z&%+r%?v6+`lAus@PCGGFOtaAQcQjVi*96x!Hm?h$O6UIa%iLfvaQ4jZv%`rLJs}iJ z{8ocYBo+$ABA3DHmxzU63_Nn<;VQpB7E8Z%)i!JkoT|RzbN-aBsVyl^{|#G8<84b& z^o-TIqzzD(lYoUctIISWTF>A|mw>u(HC4Js?J!Zd5 zrV(j3EG#;^z2VmWiql?hX_?tkU;o4^_40@6YTG{yxjl=D)fLOV-f-CKU0$IsUgU9y z(0S`lbl%F`XzE8d7Oc%*CZ1`U?^sicf%BTue>*Y$(p!s*%gknTZ;9BKrYzQ~vhq8Y z(p5n7U8ssw%9Sdz(*NDQSfiR$k}6fD-{WzwYY%i-%@GME^-z|!K-(I(%ayr6sgU_} zM!!rd1Gl~-mrH#{om(Q2qWqOhV0)oEo_C&JINlG`_?(Z%Ucl!dJIF>qMtlHEC>Ram zAX)jC)mk7mX_#ELN)7nfMF3M>JN^w1c^AOC|sdV1hH-|6&cZ+{3>TZ_H}*U*cx zdhjE?7(KxcH}iD%32B%$P?`*!;1uTn#tvE2+faYs{FRT^)wO$E`dXj8RO9kOx8}i9 zNA9Ukw*s}*WNZ&5+jUxvl9YP&O277%SM(7T^ns-^gTdI7O7=p_1ys-7=JR`le*dQS z)I2-olt>*aTX(2^gV*B=`2$1kR%rGQVCQB}q!7R7Uii z+{t};HqI%}4sp{;>%pOb09nINK3QOYWAK>|O0y#f?=0Ggw9U zfQ#r`==UyV-oJ`I1&d(;U&dij^B=Yvl`YuE7vyM#=yyu2w4{! zzM8)6r|TcR`6qfWXvMyT-D%4lz~*Ou4-4l;p)7k|Ih<$h6J_-0^l}t63a*4-+X5bh zz1U0l<&9f@#6$Ub1uS_LbJ_bG*dV~^ho$b%mYVcai2KL(LHmxv=N~>i{(F2rlmIDu zh`5T!fqF88bVDw~VQQ}|$9$8KZ@F;)$q)y1evAWje-qa&1iFPcBooEOiRAT*=%Wj- zOF;8Ypd^(gUT>+A0D?e$zf@ptaP^mYy=5v=iFwqE?rUfmR@0;48r5)P!~KiYi|%i1 z7-pg|)WZ#p_is{1=c235GS{gpJf3;=>ezgbr;@~$pdZmm-X{7<;<4=L|jBG;?op53K*p+zE8PMK?@;PXy`jx6{9FM~xy%QG>?O zeI%W*7hl3RCM~*no<-MBe~E7G1q;CiZ_^tor81z_Mo1Dx zi!FfPbvpd6{}-EXIsG#z9Jw?a35O%mOGmJy^if*i3n!!!K3^hDgnih<;H18PpZ#Wx(N$ZSZ$6Pt$F=2urw#0(zrZ{z?kX#-tSl|NYX$u+P{isr z8kI_;sgKd$Vu!%;u@{oj$T{s@+oO@hVGT*fjfSX_WN^h+LP~ zddt8@e``Dx1~PjLug6)Y8&hR+PA8rmIq;)}mQYLQCaV*hUM|-03Vv z&Pl;@Po9zlX48j(tp~)Sk&6b0E{;Ybk!bXip}q?vkvI+tgc3=}ZVyW&BId~vf=}3b z@I0KJy9W1`SJb!F)jo8}hEtHC(NtA+_vn=yQj5LbXw>UnoZ3(fA0rX?h|U?{{LNtJ zZ_1iuG^Q;OiH8C)P@0v{&%oityUAI$!PSP zjs@5I>0Ypf-j2Pjhc>L9KB7~p3gH}19HLu^b|~3OPM#%6vQs*h^omc_n-`ip}H zfkqiYp$gf&NlZh^JlbsPt9$l^(P$hnnUu+4zqMFP+;-r$+YXG)!zEfbx|fp4q^yrN zs%3H>?;R%p^@<_vVJ5NCWKfql0J3aOfwNhd<+$vQBVw-OYf6T#x*qN3~Pb9cz(ib4k<98tMkhSY9swzGJKp3;2R(GlC$5m{Oa z)owBtJFlw~uHO>+YGXpB(gR?@v`R8IxkGppY%8-vm|Gvm`nom+_ZV5V25H@yY9ePCoZ8}Vv%@ynyy}_ zE_VSjqZO}ZEQBcy#QX;?g?*U~ZKGbO7*AnT$+ch<=^^+Ix^43hlQA*V9l+y%Jn?x# zg7^bHE*1%Oa)n7ms_1crOsJE|^+F{{XNn@>ZLQInHi=dwq$G~{iKfk=P$75!*wfJ( zQZ5sUl#NNEYV7GmgA#=pC>m4fr=iPZu|lg=Vo@qgV!ORC7Q1|iiExCiy(pVom3I7Q zYaJ(V?L`?ufk3a&*u+u^oe_(LRyAoBibNUaUgBtvO{Nz~t)#6h+_)hSh(L3+Gu{l} zSCUkF61y+cnP{cdq*_h26rrC+uPZ7_SZz|LTIZ7+42hzm>qc`izQh)uKF5iS-{Sa> z`!3ig^w0F?x7-50TCuOJw4$Q4Y~PAE-hes`T?`9#*c(LA0Z>REIxzN1Q6zG9NBdck za1mIWxks&l=CvWJP%@{H#S>o>cXOZP%w*TVvFAa^sbzQcatA#{*#yGr_s*im#q*>P z`m2WGW(;sg<)pGK7}(g+d_j>rB_i-&F)o1>aK&MdBP^9lG5n1;FbtPTr2(7XBUP#h z9RH=DERnppt!-T(SguqmFuWh@`LzpME^Xgk-*8$WSQsx2Z0|Bv+4XTsX_wl)E{mnp z@0($je&^K}8@=sjlS?jDmfE$&=8K*xD~rbh!3}lkoee6~?{=uc_YgA>#s!rA$8;p_ zp5BYB%^0Vq<94PT(+|Hq3H+P~ag5MvMS6wN4VNF50m(@8%+}HoZ@QNfNw7ZpMDGIJ_s69Ozt-v#wNFeqa)sW3dE`bB^{KE*OqD3VTs!3Ied&Tb}5x+s}J*U$% zGXNeRdmcP5bGJB}w)!0IP&l-+U+YpW z@Zw=$q~}13Z7whl&U)(gc_!mLAfvxyEHwCkAbTjYa%BebIrLkJCzu@@EvhLF9C&VX z2_Z+L8kyGZ?EHlO^Se(z^5KWOMvu%1-n6${P|yq>qMNw;$6v-1u!ZnB`*{{z9}3b7 zChLZ+JbB$rYkyaR>VE#fhaYa7aipdAjyr1A%5ros99+8>VQXQN;dA!$>=#XqU&5Nh zu;#~^bHX5Vk~F!iWK$d?r9J5O!7NXx0Xq2&107UOFCuBOEEj{&qS}Tm&u;mMImo%o|uhrhrR@J{4R(xHB9q{ELt1J%I8{0l;==mSa~!fzcy2NOVaP9;W}v=L0!xV>xUi^seC86~WPCzn^4VtA>qA9ot?< zw!K_F-{UF&U<0=R$8p{pJib6+)eB$8fgZM&$A6s{@Ee=L;KdAhfxh;cy`c z`n~I0yH#-wWfqI25nFNPs%X<{r_mG++2Apxai`$L(+ZpA1%h zZ6rHh-dk_bg-CyeQYPc`#ZkMq#Fl8?3{3$5otkCk-O7kcZ4`-RNpCFJ?V7jKAy-%} za1iVzY8zy6V{fW>M;jV4Ls(@DNaZp$C3R79mw0m2ur>GLIA2f7J(N@@(%6Lj0;|=w zur|Fa6sl3(kR3RsRV-KX1?t`^bAu<;ZZ-sDQm4i?t0>Z8btIwge1#x*DhaeZOfjWM z&P9xy9Xp&k+uQ{8zl&4K>}XH*d{XnUcE zR4UAi8%i&mHRIy4#^p9jJN`ZNAj5WDwbxf`@E41DJfT1qbsFmZfm*#YB;xb16|YyV zPi#C`WHftSk?V)bcQn7=cy{UV?x-&a3A^T2T@FkI$q|3qYy&iWRMu4ujy7Mx0e!sR zTh?dNXtk7OLA85USPy$U46VWe=tb!`Zst~|lim~K%6aunC&`?{#dL3Y3ZkPfUGv1| zEKmiV=rS5?Ji3HuGa9>6@F$~<4_@Hg491S>@EjZ9<4lB4@mG({-j_)9*=?RozYB#J zCFWXfE@+#Gq4vhP&mc^?Y(`Wr6gQQ(J6lLPuZR8DqkW(gL?H2T<{b4PAOMd~N@Pxz z*h*-rB2(33pSO}aO{IE~eh_M^^Y zPm=QOZ2Y7rNF>W=qyx3aL9%S+z^?Lny=$B6mpPm+r_;HtzGbb~<9iW`nt;XP6Nv;u zvDj-edL=T+W72YUX}8g66@0P3)~E>W->v3C2hC#=7K*@o;HT9OrPGa#>GVUZX(9WJ zU6y&MW~tK`2>6{#(^ymeDK3}CVRfzg)j)`oUhjN2@e#dv-#&27*puDL3X{ptMZGRU zy=J(I>Gl8WzNg>lb&<#CJ!AIltv;{Ee`7wAYXg*Z(=odw*U(^|({rad9$PRh3L$+@bEgIDsA$7mwe_6-{<{$-Vc2-BTSV zI9(H`L4U=^WZ{L-ZYH|hheX-M|DE(WLEPB!0tI{Fxfh@wmi7bfP|{ z0)M5W*pIJQtSj2|P>}%&li==wiVNFb@4B*T-o+t@+vkd$-v@<>>&?`nK)lf|QbDkrz6;?rW>&}|G{Dz`a=vhwi`(k|0FCHw+XA@gZbs+x?zaQX)f zBcuY6QK9ogE164(ye65QOs|i{d-NJ@St4KnBN8Q*Ms_(*(JWpNzz@6Gl#(9k&@87!rX*?Y7BHBC$nb?G9I;773>+;zj3W zUN~PQlmrdx0Ojb6I=dsGK)BQ4thQLI?4^AcgX!;+6GC)6t<-4ROX+Ju)uc=&k_n8Y z$Rz*a2c<=<& zd=Cupf#M*rKS7VnwV+1s7^)k6Zs8r_dhv|d@mB=}eV)n!M{8eY3 zxr)AH?CIi0rBEQ2i0l+(O|%uJcF8n$5%lLo%7*0B-k42nQOfipmn*k7hGqB0xc9+c zRp<5Uf4fTtaHc=EWP}2NPOfu_g+e;RFAzHQq)8|eXZOndZ5GllmANTPOMuxc`gq@bwWjv3%=rLQ1nK|90G$lc?O zi0P?@lkxrd$btH$(C;uB4Lzwun^vaqO^dQE-k%vxN%Ei&4|flju*zR9HB46N|K@A`l`H~7-sj~Y_u=0 zsko%wJbIw9aY#YmfX)Y?Qo4*=$=q2=a#Jp7M!5J~<`aiMV{=~t);9W`BX>Pazt;@x zf2QAQ1hxHt-dJU+$a~nc#@DR65{L0NRr^L2| zhqCdh%-fjlK9G4I+|RYX3zmO_ZonBI<5Cm9@YKwiU*2Z_q_T^rrf&>p{1Gft)bEeX z@>og?S}znC=L2A|n&*~!TU@R-uXi^0h8+sA)Gimvp@j74m9Em6dYv}6T4Bq6;*#{& zy!lM52bJ=qJei;Oc9()DxE~(sUAvhJOS}$Cypk)C^6)7>?fL_F9F%d%Lz}sq*K!Kz z8|mkGCERFVicJe3t*_Q%Wz(|`Qyv>)k5r@c#jH|@vY zeizQ)-{=KAIrjxSe)biI&_85t-pEXw}W)pDjl56vHW%u8cA1h!_VK2(Q5~I;4 zlLt(OB6mrr#cUFRS0=D!2->9^MbQ}z#0Q`wWh17@vR$m)vKYss*uBP zz^m4Dxm1=Lh6XE+$4t-zLI>7Csq-uY?AP%IH?vRDyJ2gjPQoL>3;79LH~O_p(j&{xdmjZtvDj<1O(@)au%e=9Qd`^K zHtxhH;mKLgKJV`g1RKm2=f`~=9UmkSsTe33K0W|FoUbX|DVgrLNr*n2iLAS>i(d>6Ds;IcWWbNLv z(z2IOY1a}2W56fx(K&4Hk^_FJ6OBbRE0?c7wridkKl6ougAL^m|;iNew!cMR~YTtmO88fNJ(}kjXy(VJ!XxC;&c@gGx=P6 zKUsa|TqW5?a1kK>1bG=FhsPfQE78~1lmLYVdxpK5#=xr z=CE@(3JmuLIrnX0e*`i(C}f}|{wOtr?0{nEkKakZa3;Q+;Cz<+9+rLKlPlQczz)Rl zR~r9>yb(MOt9>^+hiW{-PC!rQvJcU_V40B-@0YoE+#|OWxn3}G+c7|XAFl?|hk;b% z%u*;+3{3)xRwi~(*#lL-DV+CsmdWCB*c{|zpt^0oRj0Ao9sSMhV5rsO zC^B2iUH&d8vFgNE^hZ!{k0%z5lGw%fSW6gLBy&RHRkbtoCOVux`YX4?J-Z}(acNKMZDnP1Jl>$$Xtt2v?dEK)DP0PiLm~@X zjQO@r{#u7MTWcMxOkGYaQL!0C;NnLJ(Md@cdDp`v)X3&Si#1m}@@5D+aaL#sX5b+I5tq`N;ypq!MN^}1iO@79 z5yn48>$(-NhvP{?89U&`?cDua@YCJJHYrbd1d^{hw(8+0Yx)o z9AgB~QYPpb$@?zLM_irMxHNq4RJm3IPu@Ubev?736#%aQG*nhSy|`!~${rzqD^WV_ z_9?||C3s=g)8%F3WD?Rtkcp2IU(+`+uMkDZ7g067G-1$E>;NTE=Y;Zy|-?mV^4%D}aH@$}nbu^MI3HOITUdNZ8AO0+^z8Ys!hSzlv( zwd4NAhTmjm<~gkC*L4+KStFKt4TfURA+fL2kvG*Olk3!$t_(w#K7vk7CBC6I!I7Rp z6eqo@1V%(IC>U8iq>hskN!Ca+Dv|+t=Capo*F@%YXV#ldP9Y%20|3bnESR>fsHjEh z_cPCuZkMaK3%-2boq|kZDyM%ilhoiju#HKTb|S_d&d#%&qhM9niwESe%FF zbas4j>E*99)KAkQ+mQW~UJLuY8<$UcMx1lhjhtPRHWn2It?UE8u0%G=AB%dNP7kn} zjn(N(daetHLm(?XyoQ_#j;79pQ!cw>YH41V%NEh@cPtoJzM*95ZG{Enu?^Ww7xFP9 zT_d+kMg+(}XR02-x8~L;m5MBzDNir=SNbR4l#`vue!*UkuO>~8|0cacr_&Dyi)0SR zZ$Y;iU>P}_2a|tY#>4nT`zo#sox)#{Ja@>RVsF3)F&<*`(kt~ky-;w3i?Bh@W}9H& zYfYS@SHO8W55+I#?z0%qA2zPx`9q&FRruXqYQ&B3)HxwCI{u2RNVz=6SQ!e=EX-5(UYib{w4zw*dly%<{vf9oW6mo5K*i!18 z7U}j!nk{{63RCJCo z5JGZNVn2btZ)EGxxoY_RQ_cAMgf&ruzh9R)$DI#qt zsj05+&2`{&_RE7+y-swO&e>aaklIsMUcRe;9=gtrt}~{4+|zO*lhL(mSk81<&JVC0 zFM4y!onkM@Cy{Rq;qWo7k>wYRE}PVVl7YMO^72VCY-Yc=J4ql{D)R!cQK|k1ii*n0 zii#eXPX$XgTKJjIxP+%n5 zh-Je!B}VU=77X8q#SQDiR3U$3EH##(S)dv{ulZCdA5Is2Yc?%Sq^gNHn={huZ8C#c zte1wC)>W^KSi^FW7ywC{*d$~Bt}u#(LIAMcAW)=<6bvIINfNMMi9qFnN;qtFz3X^m6YsS^zOS^wJ-y% z);OVP*$zikqtStN3)+`?y)Lr4*56keSyVRg*6i%w?7Rhe>CH}Gncidp;xw^YzObl2 zJyfn%rJEw_#-nT6`Cpg}#@cXplf~)$+yUo9SnuY<34BVqo#3L&+Q*(n8g2A>x>w~RD(_K)Bi$v0NQ+BYyZp)O(of-$K@$cD7>DORO*TOO6O1&$^ zLn%6Xd0ODf%NwhSU4~J2Jv`q4s%VPMYNG@KlVOKaEOlu%hmrpy@Mn|NI=wp5Vhx2F zs%u`poPCc08RL5FcDu=JpIiSGS?_e%CdTHes{Q^tjXv1w2{n0J0&@xr*AyL*$mO-A zmu6;EYjsh3#**s(`w9w*k2+zqWk(v#cH~8wcoE&6g00v1Kh_1V-C%8a4_yDMKEDEx z-2hEubO%j(KrS7wPxX2+BhyMOYGuf1&(%1cm8GRSFJV6vfIwEA!C=s642{vB!F4dJ zB42Y_rqProHri)|M%0Ru(0PR}l^u?Gk zVH+WDp{mq|#`#^(GnQf-`K~NA0QtwDRY5{ykdgSzfyK2|Ya_5*K$`%FMFOShN3DSb zG)ajBX-1`3!B8|HL3}<`U2usaVpRD)ovUYKjxC~qU(z)F*3dLt%$QMQ@_XP&%vjM7 zoSs{}yf8c^Jm>8>u2QqN+~`k-BaxAb(zH_g#&~;PPY8J*&Cykrovf$~Evm_wQ;@r) z6ugDJhQb=}fi2lQ`d))jIEwvPbZlvG>PdTnG^kK~ISF8$Bp#EFj#dr?py<_Bu~;$_ zh!{!05?aXvS8ae3QfUk zlQ#hMG6Th;PD5PRKsy$iy7)$x?qY2)_B@-cBKU?f>U2duZ+C9xs!W4dE`yVRL&N@{ z)#1rfEP!*NOe=y5V#q3cY7@SCxocJFET1o?R?ES-an82v$kGZZ-5D>=jI=wQ*-Dul z)>a@FN^J^?Vkd$f&=lVVx$Q%Dv!K;on)04Gn!)oATZ}rQHF5)t+%j)}L&GGJ3~1T! z3^o!tZT9J)Y8=W z$&IrfEGw-el@j)hoB=AWw(6b2%*-W4=>D7hl3tw$&o`TQ7 zXU&d8W@ovO507Mj_?rGb?8P}3)lg&hhZv4746Y`nVtIxw=Z480+lp-wrBZ_j-*+|_ z2_RapPzFs(n^de62t{E0&~&J5c4V}=B2Cup4A^1alk=i$YvHsHduyo48K}@3O>hQH zGbuDVR%+rGUmy;vAcxoDyHY6*3v$OCSnd&w^)SWJ=&juowiFiDkldvF1Dcf83RRBF znyFAI!PKFZ(Ehi~-x`6;6ciRby42g`^EGdoV>Gfq^@cHrMn2XbNKkSJu z|D$JL{#eMr<i2kjMx%2lgY|lvTIlG*2*?dPhNBpS_gff_=c_n-7v3N z2^<-fm<3Q2QxeF?Y}yQED8}z6R32bJM=GK*m!?2PT|3B@(BSpQx5Nj3QBw=a?)Zkj zy?Zx+$zFB?vs2+h3cWT zrDS#u9fdl;DHe;hdVOOaTLaEcSmF11U?veOzC{kXpNc*2C2yOJbTc;WDOPtu;4pqG zDi))*uzvuP*&W_2?`2K7bHdJ&m1UQ|-_ksH*Nz=KdYYQwxvc8S5@%*#taeE-7$rqp z)@=s9Yx6>3wfv-9Ra0H{-;0^e>$cEq4p-LHDCH+q3YX7&O*2K%L=19w50qdOzaPM- zxGxryVAN~yQ94HR|8VY-0Rccx-3RAer{3U_;2)=6?~;fm`#f&XKuy(v+vD|mJOkC$ z{gB}Fdff2i05sR|*VX;-!*j`p-0(k9n%HgDI;Bz>dp$^8!vZ>}_R19+XnN&X##`X> zz@Szre41FV&l}DTg%*{MFIyB0Wruy`Qe^uPETe6lg=$zESudqYWj z`})ibs4*2`OYtM~*$0J!=Y>L9|Dz?P733MnsFnfk>r!G0$PAwkV#E3r0tTX5h7L&0$_(`zF1lN5=Q_VkK zR$3)$ZCaWnV0zi)hdMniP3mW#pFNxNZi!+AxX`(zx!lN6xz2BdREi1XB0F~Wwgszd=pdJ{j>Czu^j-{nIay`NZs^%A2iP%#(L*SZTg zop2YTE}RFFp+PP}2XH`v7gg+&JE_;^?G^hJ~10|(%eZG*{ zD06F7R=En2 zEj!Oeq&Mp3fAqpQVc>tEHBPpgI+MDNsP#LIEQS{*djV2D?CdR`N(VIFM})Dj}A}^{sUsZ7K@o_?*DE4;OGBQ%|{Z8 zar|EvS{04wd5$09$RUpmobTE=<=)J2{+V>n!&&39CrZo8t1Bz^UDm#_u&&>tQjc$J z`sn&)x5Yv=b6YEyWQ5BUrME_MTC7$t3NouxSSODwpKO5>vDGq#7PnN_JhM=@{N?)k z_RRF?gMDS!HC6zGM@)@RCj7!Z+f~g$F?ly7Mpl`{}o2 zGG%el)tTccHaQD*Dx1_$NN0s-`< z*q}GI=D5bUdJTS+)*%rHWfFCvQE3(^8J%30qme50TB$`TvqimHk5cEA2t@|9%BxbE z7$u`u=we2>lA%R*tttcchOgLW>L)=aTCdmUj1@0%jJLDo=PH%9B;d%v0R*RS%8ll$ zRPvzNRHl{q%98JB-Si<(A#6*A`6Nx6o1JsZ^mAF6_0U=s2#<(``FYW;$jZMOc?-dj z;$#HTNJaq=8Z_vpm`^6S3<~l5=S#-IL%k7J*@qU>7#ziEfV@O_m?%0t2+)!keuhh955U{L@KFjT z4ACS+Gx9U{y@!F18sM)6{*L?%PS+L{)z=jj)!lp9KtZ{|V6_&p=RzJ&DCG47NqKH@ zW_D@RVK&%@Ha)hmoVx0n#(+{`Sq(av^^ zTfBSsV#?W5QPK0e_?aG~PHzV9A%9L4L-aWGLk2qGI8#1+!wv6k+z9U7xbc1d6Kr2a z{A2oY(QI^63$BL?(3#yvis4;UBxfnq`S;PMC;zVeG`zgKX9Bf zVZjFODfCR#=R*N1BlwZS>@l$NzK4!6AH#=E??H|=&{JXhPt+%Zr8v?fituY-E*g26 zd}rqZ928x7%T#n2f;O zPM#H*u^&cVv>*@f3V~0LkU`6)@=p5G>#u0LGN&~i`HKgo^xM=|f}aT!-if~`FTRU6 zfspzNvZyHzAr@7L#r17%>mZBlqS-1-Osh2o0-k|tVS2sUWHXwS85U-bKA=#jV0#1* z<93(JZlBneMJZ*nfW=*)R;j84LLqD*oq(cI914&DrFIxf&4i_PaV~|?0_yPC0%H%a z{p~JT@`WP%$G&|?YMJEq)G?}*kCS~Y-a=kKI7m?7CAy1>3!aAGSg^+*Vbllyjfk$~ z&rd%Mgz;DLX^v361x1Or)Q3Wi7K`K3sNWxn`2A7A(+3Z-oxv)j(PB0ltAl|WXg67n zrkX%7H#g|d&4so92Yn6o8uKdDH9Fj)P@giXE18^A8*;Goz*FqWtA#?LM$)SED3n_I zJ_|_Ky}$GlM>%qYCl8s;c!W)-U#CgIaeVvvU&Z|nXood`E?KYSmo)jj5=*!k3iA0# zX2x$?TVZ=gvR4FcjzWvI$kj9zest!VO(lVbo@8sQ)u^@eCOMGI9g{$f+n1x0$#hHV zoyiZ2P#c_O@1~T*pKu!>-=RwO6ni(B8UGM|R|V(uD&i+3gSlg#tfH#eQ?OHIT1|O6 zxtH_g_7i&|3@1d5KyZ{hNQG>JZE$veld}{@`5pCv9#F@YfhXDL*=uUiNicF!{4w%J za({e1dDYo=a#A8ea6bY8%!x=OfSFX&)5srTdH|omLGh1P3!4Rgg2qwlXAvb}A*8Q_ z^iqKs((TFk^K=+eCnvt47h<%CL)$TWDLaX-$7pvF{S`zf`XT3?0v)7=@SgUf_?AQ* zqPtlIeG~I4q-$|5^N7RjUP!+T(kIfbke!AUlTuu=m~T)rLtqx&&lY~kn_e;bt92EkR3t`sNf%{c$d2*6|uu7-5; zJb>vj0zmo>n9ofJ5B`h8_hUYByg9*(0zbGJ*J|xYdsE!Qx(X2YFntwF--*){PH%?k zc{nY=>28?53a2eNeK}0m;B*>JzXa0~oEG!>oyKV?POpdQSvW1{pRdMg1x~la+FlOZ zR)9P@!8CU}38qyzjc!{!fzvvib|rf^Oq+2U_BQ$roHh;fBaFb-5#!eBO&kI}spl}= z%+bHabR1Jva1)f$1}vpDha`}SV@wKegw%~m>W^YnHx$(nV{c4Sk4tztui@pq=96Dg z??Dl=1P3AY_N4UpzXGZELN4~w#gN-J%po1Q@1#P?)yp{2vauAVRw)~-BMGt zf7zw`YHM3HDouf>YS&B@pV0!Y2viyjW~<#kqiXSEMOD?Yyy)$-rfx1S>auAvEHbN7 z<<|wOO-75$X79+E{ZMI1RZ%Rqb$aFmPoUaX&}!D@*z7f9jfIQ#MdY!y1>+<(_Cb4*sCrdbByB{8^SQm_mO12 ziBG`Bi;UfoWB>fI%SE?_jl>M_Uma#&t79xYa!UINqe zaN5b2U&{Op>+vk^wKG5M8e@!ccMxGZjN-v3XD+%Gji?LG5d1s7Ocz#9Hkq|LvuRS* zzvsnt%zM;hdNGCE=CRH6J9xzBji~{!44Cg=UvY9{-3qDL_dN3vl*Ch*I&GyK&6lvI z6LHP6@Uw>@s*yPX(_Wl@1E!}kAHt^=CG*n4`Gxo!v`v;`lnUr-5xam*WuM!yJXVEXDXabAN=^#v$q?B@!56 zS&N2e51|9*D(6PRGSCg_&G;?d5l9bm^lgLzjRbZx9tp|0Spb#+q_>u{cj12HNBss- z_rv);(SmxfpbJu!C=aqTK83iA*K#Ia%S}zJ1fBdSk@BNtYN8U<@hxzSYXL-WAuN1v zJk0e*M6V`Pkj}+BhrRq7Tt_YrAWSDEgFP+@m%!(aQ^3`bo`L)&3C2PC3635k zCO~>COQDEBkp3{P$Hc^u!~mo(V`a!gKcqjy)0d)A$g1%u?Z7|(9tQQgIT+7cS z(lF<^g`u)cjj@@>W+1tv+X{kT1%6V=m3;>IA^mQMUXF8}fOExZJVGZVd5K$jDfxLR z^(MZ=b7@jaCwVFL{!NX``i9;j%u2N}Mo&j=jG{0w-*9aV(I?EQo+|i^@2N8qAA$_N zNB*AIk2600mG9Rk9^IRG6V&tQlRUcjEp2nmzZd#o8ArL?zQSV-24Mq5yr#OF*Hkma-|%y*pGWr+YTO=4^rt+!mk{viDjwZO>>h#s z2Zu)VyD%QdW5T&V#&P~4#$)gPSjI0WbGINF<5)zfSA*RgdLQo9*q=SN_Fhk-jVNzB z+sw3MooB-1b`qJKt-B#F2{=x%cR54{`}rB8P=Ho=4xA3a=ljs};8E^*7pA)*eFAzO zJkQaS7Q2+RvuU5VF`OgZ#%9^G|6-ye959Y|{I^XtuPZa>o8BWk^wy$9Q(DV;l){)|BNTf%O^ zwq0sgolAc>LPsCq@vG=#cvL5K^tC*G75xla9dr0;Jidq63MTS+50CGG7Kbf~XMDo{ zPT^tiJImvT1P`R<0J7x+h)(=8|hIC|6`jJJ6>EB~|J9{Hu zDWqnNx%A5kv`QXeuf?``a@Iif{fQs=S>`hyzlwexOis-*SZAbj^tV$h5k@ThmABPMRC=T4NRLLo=B-AwP{tX)Y&uw3|myO0FdlKk;aAbGjo@YukMALF!n0r!FXQn&#ASpK;n^FRz0Bu4elGnU zmf9+I3p10xlgH1crzZE&*ypiTpV|+bOTR?~um$7B>&=t}Gne^1aZ73yfcZCbd>+F5 zV~Yn%GmoQxj`>gG=kWL*;yTQK5-;QNJ;a@u|6cY0eMmsie!_7E-|QsLkfrF1v}YUq zb{qRUMv1sZJ0xgrLK0ZJZ(#3c>adOS97oSj?o_aM)4$-_r6uX$%j6CLqGSC2QFIHW zkJvFLCnE1PxR2hA;!;8U3miRZL)jty=Mgs7MDPV?bKOlpJi_Lhh<4SG{RjCpVH@i) zj?d%{$`z1q!}-6=(Pb$-ir+bmN9Qn-coYq47>`!^kbX0ymtg$mNqQo=_P7<&b20uY zj&4b=(O|jd82=DgZWd?r-Oc1<{9cak$M}y~CGvv+h*VFH!_JF7TaduH^^)ap6!q)bSj+QRJq5tj8&WalkR~>vlPuiwD!Q#d`|z*I7H>GrF=lU;aX)Ia|L>x;Fbwr4MXc&sl1o2|T~A`E{PAl~RSEq~zCq zFHZ=5JI&1Qwy&5ewAuWgMa8?YBBA34FJCCRn8Yu~dXlI0u;e|?FRvX$d{UGXtbeQg zF1((2!~9+av&q^N?UPp@h<=+Hxum|}^fbpUaw*FV{p#$EC)_!&(sIOSlXW3mc4KDG z-23WZ7S}rcd7JX*?b8p@w>P|N_~Q8|cw6G#gO{&6S1BJmZTai!jC~@Px(({&-Q(L{ zGJ5p$tlzFsE4OU-&p-3!&&mI+e|Yct%7WVphKu84uPi9c^$YwCAlkW!d#|;FAjO}Wiyny(kJB@zq;UM&|N#L zSN%r%fitYDZ}u)=?Eub%Z@4~rJMSd!$M%yS{g`&}hft90|GquEd(}POWq$e@xblyQ z)QtPPiydbC{jodv&2fd=ucB|X6+Ta|Z{qou`r)8LMb}+ks~gW8Z)m4&{@%bpf$#A9 zycZvt80*TJJCrufzGwF5-Ryg1?-)1zKGON0Il!Bp!_KZSlH(u)gNP|3Lx49kiwFY; z2M5F6D86V0Bp?iAM?2@|m89mC#D`QCq!!2ORpjPuo#LH$$UvaY|AMv4y|B)O-K$n{ z==_S<7JGqNBAqD=cm&ddg5Q12E?P{TUT2SedNP0J|IZO0Q?`|EyW!v@T%&vJs)xvf z(u|(?YmbWmMcH*QdH!^}`Cy@#wS(d8dp^&0b3_zuJRY^Csh{ts3zx#R4ke*VI$txF$e{7!m z!e4F`dVZA+5)Qu5aH9NCPOHO_-OaDty}m4y**?`WSnld8gT;vg8R-v&9G3HD&DSqo zCnk1I_{*mS0(Ec2CREhREt<~W`a*Phk3IjT<$sjfKi1bJ{+PQZ{2_t5K=rqnC1CJDf)S(xk;%-nR)4; zh(OoxV!Jii0jS@dgMmR1MZY~W0|QupacW5kP4EA)t&}S z3?Ye0IjPw6e=Dp#cME9kb)XrtDAscWO$1vXUzD0ttdC-f9!Ln?C*2jkvB^L;Yl|>2 z@S_-IzzOq7No7tdR(~9@Ty7Kzw9(ohJs2+VKsBf2Czs{|Q#CekOki03`XkUz9iaU( zD0XLvqId(@5Ujq?%{Z^L5om%IFuu7_Oj-<#VMthD)oA_KX9MGP28KEQj0`F$8hgc| zP5^~rv3^i~QhrIkZ+>3BZc=_uif2h;PG+)RNl6-dfGS2UYSCe1V7Lv87@#kZz=L;C z6H78ub5r%fq#?F&IobM8?Zkcth7=P<21O(T7#RG&;&N0`YIx=t zVTK examples(BuildContext context) => [ 'Programmatically adds and removes annotations using a custom Widget.', onTap: () => annotationProcessingExample(context), ), + NutrientExampleItem( + title: 'Annotation Menu - Remove & Disable', + description: + 'Shows how to remove and disable items in the annotation contextual menu.', + onTap: () async { + await extractAsset(context, _documentPath).then((value) => + goTo(AnnotationMenuExample(documentPath: value.path), context)); + }, + ), NutrientExampleItem( title: 'Import Instant Document JSON', description: @@ -231,7 +242,14 @@ List examples(BuildContext context) => [ onTap: () async { await extractAsset(context, _documentPath).then((value) => goTo( NutrientAiAssistantExample(documentPath: value.path), context)); - }) + }), + if (kIsWeb) + NutrientExampleItem( + title: 'Office Document Conversion', + description: + 'Convert Excel, Word, and PowerPoint documents to PDF format.', + onTap: () => goTo(const OfficeToPdfExample(), context), + ) ]; List globalExamples(BuildContext context) => [ diff --git a/example/lib/main.dart b/example/lib/main.dart index 6637f0f5..2017f0ce 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -35,7 +35,7 @@ void main() { print('Analytics event: $eventName with attributes: $attributes'); } }; - runApp(const MyApp()); + runApp(const SafeArea(child: MyApp())); } class MyApp extends StatelessWidget { diff --git a/example/lib/nutrient_annotation_creation_mode_example.dart b/example/lib/nutrient_annotation_creation_mode_example.dart index 0184b83b..46bda6e7 100644 --- a/example/lib/nutrient_annotation_creation_mode_example.dart +++ b/example/lib/nutrient_annotation_creation_mode_example.dart @@ -61,6 +61,56 @@ class _AnnotationCreationModeExampleWidgetState } Widget _buildToolbar() { + // Top 20 essential annotation tools that work well across all platforms + final toolButtons = [ + // Drawing tools (3) + _buildToolButton(AnnotationTool.inkPen, 'Pen', Icons.brush), + _buildToolButton( + AnnotationTool.inkHighlighter, 'Highlighter', Icons.highlight), + _buildToolButton( + AnnotationTool.eraser, 'Eraser', Icons.auto_fix_normal), + + // Text markup tools (4) + _buildToolButton( + AnnotationTool.highlight, 'Highlight', Icons.format_color_fill), + _buildToolButton( + AnnotationTool.underline, 'Underline', Icons.format_underlined), + _buildToolButton( + AnnotationTool.strikeOut, 'Strike Out', Icons.format_strikethrough), + _buildToolButton( + AnnotationTool.squiggly, 'Squiggly', Icons.waves), + + // Text annotation tools (3) + _buildToolButton( + AnnotationTool.freeText, 'Text', Icons.text_fields), + _buildToolButton( + AnnotationTool.note, 'Note', Icons.note_add), + _buildToolButton( + AnnotationTool.freeTextCallOut, 'Callout', Icons.chat_bubble_outline), + + // Shape tools (4) + _buildToolButton( + AnnotationTool.square, 'Square', Icons.crop_square), + _buildToolButton( + AnnotationTool.circle, 'Circle', Icons.circle_outlined), + _buildToolButton(AnnotationTool.line, 'Line', Icons.show_chart), + _buildToolButton( + AnnotationTool.arrow, 'Arrow', Icons.arrow_forward), + + // Media & interactive tools (3) + _buildToolButton(AnnotationTool.stamp, 'Stamp', Icons.approval), + _buildToolButton(AnnotationTool.image, 'Image', Icons.image), + _buildToolButton(AnnotationTool.signature, 'Signature', Icons.draw), + + // Advanced tools (3) + _buildToolButton( + AnnotationTool.polygon, 'Polygon', Icons.pentagon_outlined), + _buildToolButton( + AnnotationTool.polyline, 'Polyline', Icons.polyline), + _buildToolButton( + AnnotationTool.measurementDistance, 'Measure', Icons.straighten), + ]; + return Container( color: Colors.grey[200], padding: const EdgeInsets.symmetric(vertical: 8.0), @@ -68,25 +118,7 @@ class _AnnotationCreationModeExampleWidgetState scrollDirection: Axis.horizontal, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _buildToolButton(AnnotationTool.inkPen, 'Ink Pen', Icons.brush), - _buildToolButton( - AnnotationTool.inkHighlighter, 'Highlighter', Icons.highlight), - _buildToolButton( - AnnotationTool.inkMagic, 'Magic Ink', Icons.auto_fix_high), - _buildToolButton( - AnnotationTool.freeText, 'Free Text', Icons.text_fields), - _buildToolButton( - AnnotationTool.square, 'Square', Icons.crop_square), - _buildToolButton( - AnnotationTool.circle, 'Circle', Icons.circle_outlined), - _buildToolButton(AnnotationTool.line, 'Line', Icons.show_chart), - _buildToolButton( - AnnotationTool.arrow, 'Arrow', Icons.arrow_forward), - _buildToolButton(AnnotationTool.signature, 'Signature', Icons.draw), - _buildToolButton( - AnnotationTool.eraser, 'Eraser', Icons.auto_fix_normal), - ], + children: toolButtons, ), ), ); diff --git a/example/lib/office_conversion_settings_example.dart b/example/lib/office_conversion_settings_example.dart new file mode 100644 index 00000000..bf3344df --- /dev/null +++ b/example/lib/office_conversion_settings_example.dart @@ -0,0 +1,99 @@ +/// +/// Copyright © 2024-2025 PSPDFKit GmbH. All rights reserved. +/// +/// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW +/// AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT. +/// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. +/// This notice may not be removed from this file. +/// + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:nutrient_flutter/nutrient_flutter.dart'; + +/// Example demonstrating how to configure Office document conversion settings +/// for Excel spreadsheets when opening them in Nutrient Web. +class OfficeConversionSettingsExample extends StatefulWidget { + final String documentPath; + + const OfficeConversionSettingsExample({ + super.key, + required this.documentPath, + }); + + @override + State createState() => + _OfficeConversionSettingsExampleState(); +} + +class _OfficeConversionSettingsExampleState + extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Office Conversion Settings'), + ), + body: Column( + children: [ + if (kIsWeb) + Container( + padding: const EdgeInsets.all(16), + color: Colors.blue.shade50, + child: const Text( + 'This example demonstrates Office document conversion settings for spreadsheets. ' + 'The settings control the maximum dimensions of content rendered per sheet.', + style: TextStyle(fontSize: 14), + ), + ), + Expanded( + child: kIsWeb + ? NutrientView( + documentPath: widget.documentPath, + configuration: PdfConfiguration( + webConfiguration: PdfWebConfiguration( + // Configure Office conversion settings for spreadsheets + officeConversionSettings: const OfficeConversionSettings( + // Maximum height in millimeters per sheet (A4 height is 297mm) + spreadsheetMaximumContentHeightPerSheet: 500, + // Maximum width in millimeters per sheet (A4 width is 210mm) + spreadsheetMaximumContentWidthPerSheet: 300, + ), + // Other web configuration options + allowPrinting: true, + showAnnotations: true, + interactionMode: NutrientWebInteractionMode.pan, + ), + ), + ) + : const Center( + child: Text( + 'Office conversion settings are only available on the web platform.', + textAlign: TextAlign.center, + ), + ), + ), + ], + ), + ); + } +} + +/// Example usage in a simple app +class OfficeConversionApp extends StatelessWidget { + const OfficeConversionApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Office Conversion Settings', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const OfficeConversionSettingsExample( + // This would be an Excel file (.xlsx) or other Office document + documentPath: 'assets/sample_spreadsheet.xlsx', + ), + ); + } +} diff --git a/example/lib/office_to_pdf_example.dart b/example/lib/office_to_pdf_example.dart new file mode 100644 index 00000000..190395fd --- /dev/null +++ b/example/lib/office_to_pdf_example.dart @@ -0,0 +1,135 @@ +/// +/// Copyright © 2023-2025 PSPDFKit GmbH. All rights reserved. +/// +/// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW +/// AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT. +/// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. +/// This notice may not be removed from this file. +/// + +import 'package:flutter/material.dart'; +import 'package:nutrient_flutter/nutrient_flutter.dart'; + +class OfficeToPdfExample extends StatefulWidget { + const OfficeToPdfExample({super.key}); + + @override + State createState() => _OfficeToPdfExampleState(); +} + +class _OfficeToPdfExampleState extends State { + static const String _excelDocumentPath = 'PDFs/test.docx'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Office to PDF Conversion'), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Card( + child: Padding( + padding: EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Office Document Support', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 8), + Text( + 'Nutrient Web SDK can load and display Office documents (Excel, Word, PowerPoint) directly. ' + 'The documents are converted to PDF format in the browser for viewing and annotation.', + ), + SizedBox(height: 16), + Text( + 'This example loads an Excel spreadsheet (test.xlsx) which will be ' + 'automatically displayed as a PDF in the viewer.', + style: TextStyle(fontStyle: FontStyle.italic), + ), + ], + ), + ), + ), + const SizedBox(height: 16), + ElevatedButton.icon( + onPressed: () => _openOfficeDocument(context), + icon: const Icon(Icons.table_chart), + label: const Text('Open Excel Document'), + ), + const SizedBox(height: 16), + const Card( + child: Padding( + padding: EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Features:', + style: TextStyle(fontWeight: FontWeight.bold), + ), + SizedBox(height: 8), + Text( + '• Supports Excel (.xlsx), Word (.docx), and PowerPoint (.pptx)\n' + '• Converts documents to PDF in the browser\n' + '• No server-side processing required\n' + '• Can export the converted document as PDF\n' + '• Supports annotations on converted documents', + ), + SizedBox(height: 16), + Text( + 'Note: Office document support is only available on Web platform for now', + style: TextStyle( + fontStyle: FontStyle.italic, + color: Colors.orange, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Future _openOfficeDocument(BuildContext context) async { + try { + // Configure the viewer + final configuration = PdfConfiguration( + documentLabelEnabled: false, + scrollDirection: ScrollDirection.vertical, + ); + + // Open the Office document + // On Web, Nutrient will load the Office file and display it as PDF + await Navigator.push( + context, + MaterialPageRoute( + builder: (_) => NutrientView( + documentPath: _excelDocumentPath, + configuration: configuration, + ), + ), + ); + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to open Office document: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + } +} diff --git a/example/lib/toolbar_customization.dart b/example/lib/toolbar_customization.dart index 1e037799..6b2f6d1e 100644 --- a/example/lib/toolbar_customization.dart +++ b/example/lib/toolbar_customization.dart @@ -59,6 +59,18 @@ class ToolbarCustomization extends StatelessWidget { AnnotationToolbarItem.underline ]), ], + // Configure annotation contextual menu on iOS and Android + annotationMenuConfiguration: + const AnnotationMenuConfiguration( + // Remove the delete action from default menu + itemsToRemove: [AnnotationMenuAction.delete], + // Show style picker for color selection + showStylePicker: true, + // Group markup items together + groupMarkupItems: true, + // Limit to 5 visible items before creating overflow menu + maxVisibleItems: 5, + ), webConfiguration: PdfWebConfiguration( toolbarItems: [ ...defaultWebToolbarItems?.reversed ?? [], diff --git a/ios/Classes/AnnotationMenuHelper.swift b/ios/Classes/AnnotationMenuHelper.swift new file mode 100644 index 00000000..6df67057 --- /dev/null +++ b/ios/Classes/AnnotationMenuHelper.swift @@ -0,0 +1,274 @@ +// +// Copyright © 2024-2025 PSPDFKit GmbH. All rights reserved. +// +// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW +// AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT. +// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. +// This notice may not be removed from this file. +// + +import Foundation +import PSPDFKit +import PSPDFKitUI + +/// Helper class for managing custom annotation contextual menus in PSPDFKit +@objc class AnnotationMenuHelper: NSObject { + + /// Configuration data for annotation menus + private static var menuConfiguration: AnnotationMenuConfigurationData? + + + /// Currently selected annotations for menu context + private static var selectedAnnotations: [Annotation] = [] + + /// Maps AnnotationMenuAction enum values to PSPDFKit action identifier patterns (static version for external access) + static func getActionIdentifiersStatic(for action: AnnotationMenuAction) -> [String] { + return getActionIdentifiers(for: action) + } + + /// Maps AnnotationMenuAction enum values to PSPDFKit action identifier patterns and title patterns + private static func getActionIdentifiers(for action: AnnotationMenuAction) -> [String] { + switch action { + case .delete: + // PSPDFKit and iOS system delete action identifiers and titles + return ["delete", "remove", "trash", "Delete", "Remove"] + case .copy: + return ["copy", "duplicate", "Copy", "Duplicate"] + case .cut: + return ["cut", "Cut"] + case .color: + return ["color", "style", "picker", "inspector", "Color", "Style", "Picker", "Inspector", "Appearance"] + case .note: + return ["note", "comment", "Note", "Comment"] + case .undo: + return ["undo", "Undo"] + case .redo: + return ["redo", "Redo"] + default: + return [] + } + } + + /// Sets up annotation menu configuration (used during initialization) + /// - Parameters: + /// - configuration: The annotation menu configuration from Flutter + static func setupAnnotationMenu(configuration: AnnotationMenuConfigurationData?) { + self.menuConfiguration = configuration + + // Configuration setup complete + } + + /// Updates the annotation menu configuration dynamically + /// - Parameter configuration: The new annotation menu configuration + static func updateConfiguration(configuration: AnnotationMenuConfigurationData?) { + self.menuConfiguration = configuration + + // Configuration updated + } + + /// Updates the currently selected annotations for menu context + /// - Parameter annotations: The currently selected annotations + static func updateSelectedAnnotations(_ annotations: [Annotation]) { + self.selectedAnnotations = annotations + } + + /// Creates a custom contextual menu for the selected annotation + /// - Parameters: + /// - annotation: The annotation to create a menu for + /// - defaultActions: The default PSPDFKit menu actions + /// - Returns: A configured UIMenu with custom and default items + @available(iOS 13.0, *) + static func createContextualMenu(for annotation: Annotation, defaultActions: [UIMenuElement]) -> UIMenu? { + // Check if we have a configuration + guard let config = menuConfiguration else { + return UIMenu(title: "", children: defaultActions) + } + + let filteredActions = filterMenuElements(defaultActions, config: config) + + return UIMenu(title: "", children: filteredActions) + } + + /// Recursively filters menu elements based on the configuration + /// - Parameters: + /// - elements: The menu elements to filter + /// - config: The annotation menu configuration + /// - Returns: Filtered array of menu elements + @available(iOS 13.0, *) + private static func filterMenuElements(_ elements: [UIMenuElement], config: AnnotationMenuConfigurationData) -> [UIMenuElement] { + return elements.compactMap { element -> UIMenuElement? in + if let action = element as? UIAction { + // Check if this action should be removed + if shouldRemoveAction(action, config: config) { + return nil + } + + // Check if this action should be disabled + if let disabledAction = getDisabledActionIfNeeded(action, config: config) { + return disabledAction + } + + return action + + } else if let menu = element as? UIMenu { + // Recursively filter submenu items + let filteredChildren = filterMenuElements(menu.children, config: config) + if !filteredChildren.isEmpty { + return UIMenu(title: menu.title, image: menu.image, identifier: menu.identifier, + options: menu.options, children: filteredChildren) + } else { + return nil + } + } + + return element + } + } + + /// Determines if an action should be removed based on configuration + /// - Parameters: + /// - action: The UIAction to check + /// - config: The annotation menu configuration + /// - Returns: True if the action should be removed + @available(iOS 13.0, *) + private static func shouldRemoveAction(_ action: UIAction, config: AnnotationMenuConfigurationData) -> Bool { + let title = action.title + let identifier = action.identifier.rawValue + + // Check against items to remove + for itemToRemove in config.itemsToRemove { + if matchesAction(title: title, identifier: identifier, action: itemToRemove) { + return true + } + } + + // Check style picker visibility + if !config.showStylePicker && isStylePickerAction(title: title, identifier: identifier) { + return true + } + + return false + } + + /// Creates a disabled version of an action if it should be disabled + /// - Parameters: + /// - action: The UIAction to check + /// - config: The annotation menu configuration + /// - Returns: A disabled UIAction if the action should be disabled, nil otherwise + @available(iOS 13.0, *) + private static func getDisabledActionIfNeeded(_ action: UIAction, config: AnnotationMenuConfigurationData) -> UIAction? { + let title = action.title + let identifier = action.identifier.rawValue + + // Check against items to disable + for itemToDisable in config.itemsToDisable { + if matchesAction(title: title, identifier: identifier, action: itemToDisable) { + let disabledAction = UIAction(title: action.title, image: action.image) { _ in + // No action for disabled items + } + disabledAction.attributes = .disabled + return disabledAction + } + } + + return nil + } + + /// Checks if a title/identifier matches a specific annotation menu action + /// - Parameters: + /// - title: The action title + /// - identifier: The action identifier + /// - action: The AnnotationMenuAction to match against + /// - Returns: True if the title or identifier matches the action + private static func matchesAction(title: String, identifier: String, action: AnnotationMenuAction) -> Bool { + let patterns = getActionIdentifiers(for: action) + let titleLower = title.lowercased() + let identifierLower = identifier.lowercased() + + for pattern in patterns { + let patternLower = pattern.lowercased() + + // Exact match + if titleLower == patternLower || identifierLower == patternLower { + return true + } + + // Word boundary match for titles (avoid partial matches) + if isWordBoundaryMatch(text: titleLower, pattern: patternLower) { + return true + } + + // Identifier suffix match (e.g., "com.example.delete" matches "delete") + if identifierLower.hasSuffix("." + patternLower) { + return true + } + } + + return false + } + + /// Checks if a pattern matches as a complete word within the text + /// - Parameters: + /// - text: The text to search in + /// - pattern: The pattern to search for + /// - Returns: True if the pattern matches as a complete word + private static func isWordBoundaryMatch(text: String, pattern: String) -> Bool { + // Use NSRegularExpression for proper word boundary matching + do { + let regex = try NSRegularExpression(pattern: "\\b" + NSRegularExpression.escapedPattern(for: pattern) + "\\b", options: .caseInsensitive) + let range = NSRange(location: 0, length: text.utf16.count) + return regex.firstMatch(in: text, options: [], range: range) != nil + } catch { + // Fallback to simple containment if regex fails + return text.contains(pattern) + } + } + + /// Checks if an action is related to the style picker + /// - Parameters: + /// - title: The action title + /// - identifier: The action identifier + /// - Returns: True if the action is style picker related + private static func isStylePickerAction(title: String, identifier: String) -> Bool { + return matchesAction(title: title, identifier: identifier, action: .color) + } + + + + /// Determines if an annotation should show custom contextual menu + /// - Parameter annotation: The annotation to check + /// - Returns: True if custom menu should be shown + static func shouldShowCustomMenu(for annotation: Annotation) -> Bool { + return menuConfiguration != nil + } + + /// Gets the current annotation menu configuration + /// - Returns: The current configuration, if any + static func getCurrentConfiguration() -> AnnotationMenuConfigurationData? { + return menuConfiguration + } + + /// Cleans up annotation menu resources + static func cleanup() { + menuConfiguration = nil + selectedAnnotations.removeAll() + } +} + +// MARK: - Menu Identifiers + +/// Common PSPDFKit menu item identifiers for reference +private enum PSPDFMenuIdentifier { + static let copy = "Copy" + static let delete = "Delete" + static let duplicate = "Duplicate" + static let style = "Style" + static let note = "Note" + static let highlight = "Highlight" + static let underline = "Underline" + static let strikeout = "Strikeout" + static let squiggly = "Squiggly" + static let edit = "Edit" + static let remove = "Remove" + static let inspector = "Inspector" +} \ No newline at end of file diff --git a/ios/Classes/PspdfPlatformView.m b/ios/Classes/PspdfPlatformView.m index 4903b871..0e1e9204 100644 --- a/ios/Classes/PspdfPlatformView.m +++ b/ios/Classes/PspdfPlatformView.m @@ -122,13 +122,23 @@ - (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId argum } if (_pdfViewController.configuration.userInterfaceViewMode == PSPDFUserInterfaceViewModeNever) { - // In this mode PDFViewController doesn’t hide the navigation bar on its own to avoid getting stuck. + // In this mode PDFViewController doesn't hide the navigation bar on its own to avoid getting stuck. _navigationController.navigationBarHidden = YES; } [_navigationController setViewControllers:@[_pdfViewController] animated:NO]; __weak id weakSelf = self; + // Handle annotation menu configuration if present (shared for both branches) + NSDictionary *configurationDictionary = [PspdfkitFlutterConverter processConfigurationOptionsDictionaryForPrefix:args[@"configuration"]]; + if (configurationDictionary && (id)configurationDictionary != NSNull.null && configurationDictionary[@"annotationMenuConfiguration"]) { + // Pass the raw dictionary to the Swift implementation to handle parsing + NSDictionary *annotationMenuDict = configurationDictionary[@"annotationMenuConfiguration"]; + if ([annotationMenuDict isKindOfClass:[NSDictionary class]]) { + [_platformViewImpl setAnnotationMenuConfigurationFromDictionary:annotationMenuDict]; + } + } + [_platformViewImpl setViewControllerWithController:_pdfViewController]; [_channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { @@ -185,6 +195,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [PspdfkitFlutterHelper processMethodCall:call result:result forViewController:self.pdfViewController]; } + # pragma mark - PSPDFViewControllerDelegate - (void)pdfViewControllerDidDismiss:(PSPDFViewController *)pdfController { diff --git a/ios/Classes/PspdfkitApiImpl.swift b/ios/Classes/PspdfkitApiImpl.swift index 82345eca..164ae27d 100644 --- a/ios/Classes/PspdfkitApiImpl.swift +++ b/ios/Classes/PspdfkitApiImpl.swift @@ -593,6 +593,17 @@ public class PspdfkitApiImpl: NSObject, NutrientApi, PDFViewControllerDelegate, } } + func setAnnotationMenuConfiguration(configuration: AnnotationMenuConfigurationData, completion: @escaping (Result) -> Void) { + NSLog("PspdfkitApiImpl: setAnnotationMenuConfiguration called") + + // Store the configuration globally for presentation-based PDFs (using PspdfkitApiImpl) + // Use updateConfiguration to ensure immediate effect + AnnotationMenuHelper.updateConfiguration(configuration: configuration) + + NSLog("PspdfkitApiImpl: Annotation menu configuration updated successfully") + completion(.success(true)) + } + private func setupAnalyticsClient(){ if let messenger { flutterAnalyticsClient = FlutterAnalyticsClient(analyticsEventsCallback: AnalyticsEventsCallback(binaryMessenger: messenger, messageChannelSuffix: PspdfkitApiImpl.messageChannelSuffix)) diff --git a/ios/Classes/PspdfkitPlatformViewImpl.swift b/ios/Classes/PspdfkitPlatformViewImpl.swift index 05c170ae..d2247ba8 100644 --- a/ios/Classes/PspdfkitPlatformViewImpl.swift +++ b/ios/Classes/PspdfkitPlatformViewImpl.swift @@ -8,6 +8,7 @@ // import Foundation +import UIKit import PSPDFKit @objc(PspdfkitPlatformViewImpl) @@ -19,8 +20,10 @@ public class PspdfkitPlatformViewImpl: NSObject, NutrientViewControllerApi, PDFV private var viewId: String? = nil; private var eventsHelper: FlutterEventsHelper? = nil; private var customToolbarItems: [[String: Any]] = []; + private var annotationMenuConfiguration: AnnotationMenuConfigurationData? = nil; private var lastReportedPageIndex: Int? = nil; + @objc public func setViewController(controller: PDFViewController){ self.pdfViewController = controller self.pdfViewController?.delegate = self @@ -28,6 +31,9 @@ public class PspdfkitPlatformViewImpl: NSObject, NutrientViewControllerApi, PDFV // Set the host view for the annotation toolbar controller controller.annotationToolbarController?.updateHostView(nil, container: nil, viewController: controller) CustomToolbarHelper.setupCustomToolbarItems(for: pdfViewController!, customToolbarItems:customToolbarItems, callbacks: customToolbarCallbacks) + + // Setup annotation menu helper with configuration + AnnotationMenuHelper.setupAnnotationMenu(configuration: annotationMenuConfiguration) } public func pdfViewController(_ pdfController: PDFViewController, didChange document: Document?) { @@ -42,11 +48,17 @@ public class PspdfkitPlatformViewImpl: NSObject, NutrientViewControllerApi, PDFV } public func pdfViewController(_ pdfController: PDFViewController, didSelect annotations: [Annotation], on pageView: PDFPageView) { + // Update annotation menu helper with selected annotations + AnnotationMenuHelper.updateSelectedAnnotations(annotations) + // Call the event helper to notify the listeners. eventsHelper?.annotationSelected(annotations: annotations) } public func pdfViewController(_ pdfController: PDFViewController, didDeselect annotations: [Annotation], on pageView: PDFPageView) { + // Clear selected annotations in menu helper + AnnotationMenuHelper.updateSelectedAnnotations([]) + // Call the event helper to notify the listeners. eventsHelper?.annotationDeselected(annotations: annotations) } @@ -360,10 +372,6 @@ public class PspdfkitPlatformViewImpl: NSObject, NutrientViewControllerApi, PDFV pdfViewController.annotationStateManager.toggleState(toolWithVariant.annotationTool, variant: toolWithVariant.variant) completion(.success(true)) } - - pdfViewController.annotationStateManager.toggleState(toolWithVariant.annotationTool, variant: toolWithVariant.variant) - // Ensure the annotation toolbar is visible - completion(.success(true)) } else { // Default to ink pen if the tool is not supported let defaultTool = AnnotationToolWithVariant(annotationTool: .ink, variant: nil) @@ -407,6 +415,34 @@ public class PspdfkitPlatformViewImpl: NSObject, NutrientViewControllerApi, PDFV } } + // MARK: - Annotation Menu Delegate Methods + + + /// Provides custom contextual menu for annotations (iOS 13+) + @available(iOS 13.0, *) + public func pdfViewController(_ pdfController: PDFViewController, menuForAnnotations annotations: [Annotation], onPageView pageView: PDFPageView, appearance: EditMenuAppearance, suggestedMenu: UIMenu) -> UIMenu { + + // If no annotations are selected, return the suggested menu + guard !annotations.isEmpty, let firstAnnotation = annotations.first else { + return suggestedMenu + } + + // Apply static configuration if available + + if let configuration = self.annotationMenuConfiguration { + AnnotationMenuHelper.updateConfiguration(configuration: configuration) + AnnotationMenuHelper.updateSelectedAnnotations(annotations) + + // Create custom menu with the static configuration + if let customMenu = AnnotationMenuHelper.createContextualMenu(for: firstAnnotation, defaultActions: suggestedMenu.children) { + return customMenu + } + } + + // Return the default suggested menu if no custom menu is configured + return suggestedMenu + } + public func pdfViewController(_ pdfController: PDFViewController, shouldShow controller: UIViewController, options: [String: Any]? = nil, animated: Bool) -> Bool { let stampController = PSPDFChildViewControllerForClass(controller, StampViewController.self) as? StampViewController // Check if custom default stamps are configured and disable date stamps only if they are @@ -429,6 +465,78 @@ public class PspdfkitPlatformViewImpl: NSObject, NutrientViewControllerApi, PDFV } } + /// Updates the annotation menu configuration (Pigeon API method) + /// - Parameters: + /// - configuration: The new annotation menu configuration + /// - completion: Completion callback with success/failure result + func setAnnotationMenuConfiguration(configuration: AnnotationMenuConfigurationData, completion: @escaping (Result) -> Void) { + do { + NSLog("PspdfkitPlatformViewImpl: setAnnotationMenuConfiguration called") + + // Update the stored configuration - this will be applied when the menu is actually shown + self.annotationMenuConfiguration = configuration + + // Immediately update the annotation menu helper with the new configuration + // This ensures that any currently visible menus or immediate menu requests use the new config + AnnotationMenuHelper.updateConfiguration(configuration: configuration) + + NSLog("PspdfkitPlatformViewImpl: Annotation menu configuration updated successfully") + + // Return success + completion(.success(true)) + } catch { + NSLog("PspdfkitPlatformViewImpl: Error updating annotation menu configuration: \(error)") + completion(.failure(error)) + } + } + + /// Updates the annotation menu configuration (internal method) + /// - Parameter configuration: The new annotation menu configuration + func setAnnotationMenuConfiguration(_ configuration: AnnotationMenuConfigurationData?) { + self.annotationMenuConfiguration = configuration + + // Update the annotation menu helper + AnnotationMenuHelper.setupAnnotationMenu(configuration: configuration) + } + + /// Updates the annotation menu configuration from a dictionary (called from Objective-C) + /// - Parameter dictionary: The dictionary containing annotation menu configuration + @objc public func setAnnotationMenuConfigurationFromDictionary(_ dictionary: [String: Any]) { + do { + // Convert dictionary to AnnotationMenuConfigurationData + let configuration = try parseAnnotationMenuConfiguration(from: dictionary) + setAnnotationMenuConfiguration(configuration) + } catch { + print("Warning: Failed to parse annotation menu configuration: \(error)") + } + } + + /// Parses annotation menu configuration from a dictionary + private func parseAnnotationMenuConfiguration(from dictionary: [String: Any]) throws -> AnnotationMenuConfigurationData { + let itemsToRemoveArray = dictionary["itemsToRemove"] as? [Int] ?? [] + let itemsToDisableArray = dictionary["itemsToDisable"] as? [Int] ?? [] + let showStylePicker = dictionary["showStylePicker"] as? Bool ?? true + let groupMarkupItems = dictionary["groupMarkupItems"] as? Bool ?? false + let maxVisibleItems = dictionary["maxVisibleItems"] as? Int64 + + // Convert enum indices to AnnotationMenuAction + let itemsToRemove: [AnnotationMenuAction] = itemsToRemoveArray.compactMap { index in + return AnnotationMenuAction(rawValue: index) + } + + let itemsToDisable: [AnnotationMenuAction] = itemsToDisableArray.compactMap { index in + return AnnotationMenuAction(rawValue: index) + } + + return AnnotationMenuConfigurationData( + itemsToRemove: itemsToRemove, + itemsToDisable: itemsToDisable, + showStylePicker: showStylePicker, + groupMarkupItems: groupMarkupItems, + maxVisibleItems: maxVisibleItems + ) + } + @objc public func register( binaryMessenger: FlutterBinaryMessenger, viewId: String, customToolbarItems: [[String: Any]]){ self.viewId = viewId pspdfkitWidgetCallbacks = NutrientViewCallbacks(binaryMessenger: binaryMessenger, messageChannelSuffix: "widget.callbacks.\(viewId)") @@ -442,13 +550,19 @@ public class PspdfkitPlatformViewImpl: NSObject, NutrientViewControllerApi, PDFV customToolbarCallbacks = CustomToolbarCallbacks(binaryMessenger: binaryMessenger, messageChannelSuffix: "customToolbar.callbacks.\(viewId)") self.customToolbarItems = customToolbarItems + } @objc public func unRegister(binaryMessenger: FlutterBinaryMessenger){ NotificationCenter.default.removeObserver(self) pspdfkitWidgetCallbacks = nil customToolbarCallbacks = nil + annotationMenuConfiguration = nil lastReportedPageIndex = nil + + // Clean up annotation menu helper + AnnotationMenuHelper.cleanup() + NutrientViewControllerApiSetup.setUp(binaryMessenger: binaryMessenger, api: nil, messageChannelSuffix: viewId ?? "") if eventsHelper != nil { eventsHelper = nil diff --git a/ios/Classes/api/NutrientApi.g.swift b/ios/Classes/api/NutrientApi.g.swift index 2231990a..78949f02 100644 --- a/ios/Classes/api/NutrientApi.g.swift +++ b/ios/Classes/api/NutrientApi.g.swift @@ -234,6 +234,42 @@ enum NutrientEvent: Int { case textSelectionChanged = 8 } +/// Enumeration of default annotation menu actions that can be removed or disabled. +/// +/// **Platform Support:** +/// - All actions can be removed or disabled on both iOS and Android +/// - Some system actions (copy/paste) may be harder to remove on iOS due to system restrictions +enum AnnotationMenuAction: Int { + /// Delete action - removes the annotation + /// - iOS: Part of UIMenu system actions + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_delete + case delete = 0 + /// Copy action - copies the annotation + /// - iOS: System copy action (may be harder to remove) + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_copy + case copy = 1 + /// Cut action - cuts the annotation to clipboard + /// - iOS: System cut action + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_cut + case cut = 2 + /// Color action - opens annotation color picker/inspector + /// - iOS: Style picker in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_picker + case color = 3 + /// Note action - opens annotation note editor + /// - iOS: Note action in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_annotation_note + case note = 4 + /// Undo action - undoes the last action + /// - iOS: Undo in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_undo + case undo = 5 + /// Redo action - redoes the previously undone action + /// - iOS: Redo in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_redo + case redo = 6 +} + /// Generated class from Pigeon that represents data sent in messages. struct PdfRect { var x: Double @@ -484,6 +520,102 @@ struct PointF { } } +/// Configuration data for annotation contextual menu +/// +/// This class defines how annotation menus should be configured +/// when displayed to users. It supports removing actions, disabling actions, +/// and controlling visual presentation options. +/// +/// **Usage Patterns**: +/// - **Static Configuration**: Set once via [NutrientViewController.setAnnotationMenuConfiguration] +/// +/// **Platform Compatibility**: +/// - [itemsToRemove]: Supported on Android, iOS, and Web +/// - [itemsToDisable]: Supported on Android, iOS, and Web +/// - [showStylePicker]: Supported on Android and iOS +/// - [groupMarkupItems]: iOS only (ignored on other platforms) +/// - [maxVisibleItems]: Platform-dependent behavior +/// +/// Generated class from Pigeon that represents data sent in messages. +struct AnnotationMenuConfigurationData { + /// List of default annotation menu actions to remove completely from the menu. + /// + /// These actions will not appear in the contextual menu at all. + /// Use this when you want to completely hide certain functionality. + /// + /// **Example**: Remove delete action for read-only annotations + /// ```dart + /// itemsToRemove: [AnnotationMenuAction.delete] + /// ``` + var itemsToRemove: [AnnotationMenuAction] + /// List of default annotation menu actions to disable (show as grayed out). + /// + /// These actions will appear in the menu but will be non-interactive. + /// Use this when you want to show functionality exists but is temporarily unavailable. + /// + /// **Example**: Disable copy action for certain annotation types + /// ```dart + /// itemsToDisable: [AnnotationMenuAction.copy] + /// ``` + var itemsToDisable: [AnnotationMenuAction] + /// Whether to show the platform's default style picker in the annotation menu. + /// + /// When true, users can access color, thickness, and other style options + /// directly from the annotation menu. + /// + /// **Platform Behavior**: + /// - **iOS**: Shows style picker as part of UIMenu + /// - **Android**: Shows annotation inspector/style picker + /// - **Web**: Shows color picker and basic style options + var showStylePicker: Bool + /// Whether to group markup annotation actions together in the menu. + /// + /// When true, related markup actions (highlight, underline, etc.) are + /// visually grouped in the menu for better organization. + /// + /// **Platform Support**: iOS only (ignored on Android and Web) + var groupMarkupItems: Bool + /// Maximum number of actions to show directly in the menu before creating overflow. + /// + /// When the number of available actions exceeds this limit, the platform + /// may create a submenu or overflow menu to accommodate additional actions. + /// + /// **Platform Behavior**: + /// - **iOS**: Respects platform UI guidelines for menu length + /// - **Android**: Limited by toolbar space and screen size + /// - **Web**: Creates scrollable or paginated menu as needed + /// + /// **Note**: If null, the platform default behavior is used. + var maxVisibleItems: Int64? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> AnnotationMenuConfigurationData? { + let itemsToRemove = pigeonVar_list[0] as! [AnnotationMenuAction] + let itemsToDisable = pigeonVar_list[1] as! [AnnotationMenuAction] + let showStylePicker = pigeonVar_list[2] as! Bool + let groupMarkupItems = pigeonVar_list[3] as! Bool + let maxVisibleItems: Int64? = nilOrValue(pigeonVar_list[4]) + + return AnnotationMenuConfigurationData( + itemsToRemove: itemsToRemove, + itemsToDisable: itemsToDisable, + showStylePicker: showStylePicker, + groupMarkupItems: groupMarkupItems, + maxVisibleItems: maxVisibleItems + ) + } + func toList() -> [Any?] { + return [ + itemsToRemove, + itemsToDisable, + showStylePicker, + groupMarkupItems, + maxVisibleItems, + ] + } +} + private class NutrientApiPigeonCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { @@ -542,17 +674,25 @@ private class NutrientApiPigeonCodecReader: FlutterStandardReader { } return nil case 138: - return PdfRect.fromList(self.readValue() as! [Any?]) + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return AnnotationMenuAction(rawValue: enumResultAsInt) + } + return nil case 139: - return PageInfo.fromList(self.readValue() as! [Any?]) + return PdfRect.fromList(self.readValue() as! [Any?]) case 140: - return DocumentSaveOptions.fromList(self.readValue() as! [Any?]) + return PageInfo.fromList(self.readValue() as! [Any?]) case 141: - return PdfFormOption.fromList(self.readValue() as! [Any?]) + return DocumentSaveOptions.fromList(self.readValue() as! [Any?]) case 142: - return FormFieldData.fromList(self.readValue() as! [Any?]) + return PdfFormOption.fromList(self.readValue() as! [Any?]) case 143: + return FormFieldData.fromList(self.readValue() as! [Any?]) + case 144: return PointF.fromList(self.readValue() as! [Any?]) + case 145: + return AnnotationMenuConfigurationData.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) } @@ -588,23 +728,29 @@ private class NutrientApiPigeonCodecWriter: FlutterStandardWriter { } else if let value = value as? NutrientEvent { super.writeByte(137) super.writeValue(value.rawValue) - } else if let value = value as? PdfRect { + } else if let value = value as? AnnotationMenuAction { super.writeByte(138) + super.writeValue(value.rawValue) + } else if let value = value as? PdfRect { + super.writeByte(139) super.writeValue(value.toList()) } else if let value = value as? PageInfo { - super.writeByte(139) + super.writeByte(140) super.writeValue(value.toList()) } else if let value = value as? DocumentSaveOptions { - super.writeByte(140) + super.writeByte(141) super.writeValue(value.toList()) } else if let value = value as? PdfFormOption { - super.writeByte(141) + super.writeByte(142) super.writeValue(value.toList()) } else if let value = value as? FormFieldData { - super.writeByte(142) + super.writeByte(143) super.writeValue(value.toList()) } else if let value = value as? PointF { - super.writeByte(143) + super.writeByte(144) + super.writeValue(value.toList()) + } else if let value = value as? AnnotationMenuConfigurationData { + super.writeByte(145) super.writeValue(value.toList()) } else { super.writeValue(value) @@ -673,6 +819,12 @@ protocol NutrientApi { func generatePdfFromHtmlUri(htmlUri: String, outPutFile: String, options: [String: Any]?, completion: @escaping (Result) -> Void) /// Configure Nutrient Analytics events. func enableAnalyticsEvents(enable: Bool) throws + /// Sets the annotation menu configuration for the global presenter. + /// This configuration applies to all annotation menus in presented documents. + /// + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + func setAnnotationMenuConfiguration(configuration: AnnotationMenuConfigurationData, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -1228,6 +1380,28 @@ class NutrientApiSetup { } else { enableAnalyticsEventsChannel.setMessageHandler(nil) } + /// Sets the annotation menu configuration for the global presenter. + /// This configuration applies to all annotation menus in presented documents. + /// + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + let setAnnotationMenuConfigurationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.nutrient_flutter.NutrientApi.setAnnotationMenuConfiguration\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setAnnotationMenuConfigurationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let configurationArg = args[0] as! AnnotationMenuConfigurationData + api.setAnnotationMenuConfiguration(configuration: configurationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setAnnotationMenuConfigurationChannel.setMessageHandler(nil) + } } } /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. @@ -1560,6 +1734,12 @@ protocol NutrientViewControllerApi { /// Returns a [Future] that completes with a boolean indicating whether /// exiting annotation creation mode was successful. func exitAnnotationCreationMode(completion: @escaping (Result) -> Void) + /// Sets the annotation menu configuration for the current view controller. + /// This configuration applies only to annotation menus in the current document view. + /// + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + func setAnnotationMenuConfiguration(configuration: AnnotationMenuConfigurationData, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -1945,6 +2125,28 @@ class NutrientViewControllerApiSetup { } else { exitAnnotationCreationModeChannel.setMessageHandler(nil) } + /// Sets the annotation menu configuration for the current view controller. + /// This configuration applies only to annotation menus in the current document view. + /// + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + let setAnnotationMenuConfigurationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.setAnnotationMenuConfiguration\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setAnnotationMenuConfigurationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let configurationArg = args[0] as! AnnotationMenuConfigurationData + api.setAnnotationMenuConfiguration(configuration: configurationArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setAnnotationMenuConfigurationChannel.setMessageHandler(nil) + } } } /// Generated protocol from Pigeon that represents a handler of messages from Flutter. diff --git a/ios/Classes/helpers/AnnotationHelper.swift b/ios/Classes/helpers/AnnotationHelper.swift index a22cc612..1ae785e7 100644 --- a/ios/Classes/helpers/AnnotationHelper.swift +++ b/ios/Classes/helpers/AnnotationHelper.swift @@ -106,9 +106,21 @@ class AnnotationHelper { return AnnotationToolWithVariant(annotationTool: .polyLine, variant: PSPDFKit.Annotation.Variant.perimeterMeasurement) case AnnotationTool.measurementDistance: return AnnotationToolWithVariant(annotationTool: .line, variant: PSPDFKit.Annotation.Variant.distanceMeasurement) - // Some Flutter tools don't have direct iOS equivalents - case AnnotationTool.caret, AnnotationTool.richMedia, AnnotationTool.screen,AnnotationTool.file, AnnotationTool.widget, AnnotationTool.stampImage,AnnotationTool.link: - return nil + // Additional supported tools + case AnnotationTool.caret: + return AnnotationToolWithVariant(annotationTool: .caret) + case AnnotationTool.richMedia: + return AnnotationToolWithVariant(annotationTool: .richMedia) + case AnnotationTool.screen: + return AnnotationToolWithVariant(annotationTool: .screen) + case AnnotationTool.file: + return AnnotationToolWithVariant(annotationTool: .file) + case AnnotationTool.widget: + return AnnotationToolWithVariant(annotationTool: .widget) + case AnnotationTool.stampImage: + return AnnotationToolWithVariant(annotationTool: .stamp) + case AnnotationTool.link: + return AnnotationToolWithVariant(annotationTool: .link) } } diff --git a/ios/nutrient_flutter.podspec b/ios/nutrient_flutter.podspec index 0785f64f..4989cc4d 100644 --- a/ios/nutrient_flutter.podspec +++ b/ios/nutrient_flutter.podspec @@ -18,8 +18,8 @@ Pod::Spec.new do |s| s.source_files = "Classes/**/*.{h,m,swift}" s.public_header_files = "Classes/**/*.h" s.dependency("Flutter") - s.dependency("PSPDFKit", "14.10.0") - s.dependency("Instant", "14.10.0") + s.dependency("PSPDFKit") + s.dependency("Instant") s.swift_version = "5.0" s.platform = :ios, "16.0" s.version = "5.0.1" diff --git a/lib/nutrient_flutter.dart b/lib/nutrient_flutter.dart index 8d4f3223..e30ad37a 100644 --- a/lib/nutrient_flutter.dart +++ b/lib/nutrient_flutter.dart @@ -18,6 +18,7 @@ export 'src/widgets/nutrient_view.dart' // All other exports. export 'src/pdf_configuration.dart'; export 'src/web/nutrient_web_configuration.dart'; +export 'src/web/office_conversion_settings.dart'; export 'src/types.dart'; export 'src/web/models/models.dart'; export 'src/configuration_options.dart'; @@ -32,6 +33,7 @@ export 'src/api/nutrient_api.g.dart'; export 'src/annotation_preset_configurations.dart'; export 'src/annotations/annotations.dart'; +export 'src/annotations/annotation_menu_configuration.dart'; export 'src/web/models/nutrient_web_events.dart'; export 'src/nutrient.dart'; diff --git a/lib/src/annotations/annotation_extensions.dart b/lib/src/annotations/annotation_extensions.dart index 36421481..d3d85d59 100644 --- a/lib/src/annotations/annotation_extensions.dart +++ b/lib/src/annotations/annotation_extensions.dart @@ -75,6 +75,26 @@ extension AnnotationToolWebExtension on AnnotationTool { case AnnotationTool.link: return 'link'; + // Widget annotation tools + case AnnotationTool.widget: + return 'widget'; + case AnnotationTool.file: + return 'file'; + + // Other annotation tools + case AnnotationTool.caret: + return 'caret'; + case AnnotationTool.redaction: + return 'redaction'; + case AnnotationTool.sound: + return 'sound'; + case AnnotationTool.richMedia: + return 'richMedia'; + case AnnotationTool.screen: + return 'screen'; + case AnnotationTool.cloudy: + return 'cloudy'; + // Measurement tools case AnnotationTool.measurementDistance: return 'measurementDistance'; @@ -150,6 +170,26 @@ extension AnnotationToolWebExtension on AnnotationTool { case AnnotationTool.link: return 'LINK'; + // Widget annotation tools + case AnnotationTool.widget: + return 'FORM_CREATOR'; + case AnnotationTool.file: + return 'DOCUMENT_EDITOR'; + + // Other annotation tools + case AnnotationTool.caret: + return 'COMMENT_MARKER'; + case AnnotationTool.redaction: + return 'REDACT_TEXT_HIGHLIGHTER'; + case AnnotationTool.sound: + return 'NOTE'; // Sound annotations use note interaction mode + case AnnotationTool.richMedia: + return 'NOTE'; // Rich media annotations use note interaction mode + case AnnotationTool.screen: + return 'NOTE'; // Screen annotations use note interaction mode + case AnnotationTool.cloudy: + return 'SHAPE_RECTANGLE'; // Cloudy is a border style, not a separate interaction mode + // Measurement tools case AnnotationTool.measurementDistance: return 'DISTANCE'; diff --git a/lib/src/annotations/annotation_menu_configuration.dart b/lib/src/annotations/annotation_menu_configuration.dart new file mode 100644 index 00000000..94c8c22a --- /dev/null +++ b/lib/src/annotations/annotation_menu_configuration.dart @@ -0,0 +1,65 @@ +/// +/// Copyright © 2024-2025 PSPDFKit GmbH. All rights reserved. +/// +/// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW +/// AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT. +/// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. +/// This notice may not be removed from this file. +/// + +import 'package:nutrient_flutter/src/api/nutrient_api.g.dart'; + +/// Configuration for annotation contextual menu customization. +class AnnotationMenuConfiguration { + + /// Default menu actions to remove from the contextual menu. + final List itemsToRemove; + + /// Default menu actions to disable (show as grayed out). + final List itemsToDisable; + + /// Whether to show the default style picker. Defaults to true. + final bool showStylePicker; + + /// Whether to group markup annotations (highlight, underline, etc.) together. + /// + /// **Platform Support:** iOS only + final bool groupMarkupItems; + + /// Maximum number of items to show before creating an overflow menu. + /// + /// **Platform Support:** + /// - iOS: ✅ Respects platform UI guidelines + /// - Android: ⚠️ Limited by toolbar constraints + final int? maxVisibleItems; + + const AnnotationMenuConfiguration({ + this.itemsToRemove = const [], + this.itemsToDisable = const [], + this.showStylePicker = true, + this.groupMarkupItems = true, + this.maxVisibleItems, + }); + + + Map toMap() { + return { + 'itemsToRemove': itemsToRemove.map((action) => action.index).toList(), + 'itemsToDisable': itemsToDisable.map((action) => action.index).toList(), + 'showStylePicker': showStylePicker, + 'groupMarkupItems': groupMarkupItems, + 'maxVisibleItems': maxVisibleItems, + }; + } + + /// Converts to Pigeon data object. + AnnotationMenuConfigurationData toPigeonData() { + return AnnotationMenuConfigurationData( + itemsToRemove: itemsToRemove, + itemsToDisable: itemsToDisable, + showStylePicker: showStylePicker, + groupMarkupItems: groupMarkupItems, + maxVisibleItems: maxVisibleItems, + ); + } +} diff --git a/lib/src/api/nutrient_api.g.dart b/lib/src/api/nutrient_api.g.dart index be7ebc4a..8be0b590 100644 --- a/lib/src/api/nutrient_api.g.dart +++ b/lib/src/api/nutrient_api.g.dart @@ -21,8 +21,7 @@ PlatformException _createConnectionError(String channelName) { ); } -List wrapResponse( - {Object? result, PlatformException? error, bool empty = false}) { +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -132,25 +131,18 @@ enum AnnotationProcessingMode { enum DocumentPermissions { /// Allow printing of document. printing, - /// Modify the contents of the document. modification, - /// Copy text and images from the document. extract, - /// Add or modify text annotations, fill in interactive form fields. annotationsAndForms, - /// Fill in existing interactive form fields (including signature fields). fillForms, - /// Extract text and images from the document. extractAccessibility, - /// Assemble the document (insert, rotate, or delete pages and create document outline items or thumbnail images). assemble, - /// Print high quality. printHighQuality, } @@ -181,32 +173,60 @@ enum PdfFormFieldTypes { enum NutrientEvent { /// Event triggered when annotations are created. annotationsCreated, - /// Event triggered when annotations are pressed. annotationsDeselected, - /// Event triggered when annotations are updated. annotationsUpdated, - /// Event triggered when annotations are deleted. annotationsDeleted, - /// Event triggered when annotations are focused. annotationsSelected, - /// Event triggered when form field values are updated. formFieldValuesUpdated, - /// Event triggered when form fields are loaded. formFieldSelected, - /// Event triggered when form fields are about to be saved. formFieldDeselected, - /// Event triggered when text selection changes. textSelectionChanged, } +/// Enumeration of default annotation menu actions that can be removed or disabled. +/// +/// **Platform Support:** +/// - All actions can be removed or disabled on both iOS and Android +/// - Some system actions (copy/paste) may be harder to remove on iOS due to system restrictions +enum AnnotationMenuAction { + /// Delete action - removes the annotation + /// - iOS: Part of UIMenu system actions + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_delete + delete, + /// Copy action - copies the annotation + /// - iOS: System copy action (may be harder to remove) + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_copy + copy, + /// Cut action - cuts the annotation to clipboard + /// - iOS: System cut action + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_cut + cut, + /// Color action - opens annotation color picker/inspector + /// - iOS: Style picker in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_picker + color, + /// Note action - opens annotation note editor + /// - iOS: Note action in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_annotation_note + note, + /// Undo action - undoes the last action + /// - iOS: Undo in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_undo + undo, + /// Redo action - redoes the previously undone action + /// - iOS: Redo in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_redo + redo, +} + class PdfRect { PdfRect({ required this.x, @@ -491,6 +511,107 @@ class PointF { } } +/// Configuration data for annotation contextual menu +/// +/// This class defines how annotation menus should be configured +/// when displayed to users. It supports removing actions, disabling actions, +/// and controlling visual presentation options. +/// +/// **Usage Patterns**: +/// - **Static Configuration**: Set once via [NutrientViewController.setAnnotationMenuConfiguration] +/// +/// **Platform Compatibility**: +/// - [itemsToRemove]: Supported on Android, iOS, and Web +/// - [itemsToDisable]: Supported on Android, iOS, and Web +/// - [showStylePicker]: Supported on Android and iOS +/// - [groupMarkupItems]: iOS only (ignored on other platforms) +/// - [maxVisibleItems]: Platform-dependent behavior +class AnnotationMenuConfigurationData { + AnnotationMenuConfigurationData({ + required this.itemsToRemove, + required this.itemsToDisable, + required this.showStylePicker, + required this.groupMarkupItems, + this.maxVisibleItems, + }); + + /// List of default annotation menu actions to remove completely from the menu. + /// + /// These actions will not appear in the contextual menu at all. + /// Use this when you want to completely hide certain functionality. + /// + /// **Example**: Remove delete action for read-only annotations + /// ```dart + /// itemsToRemove: [AnnotationMenuAction.delete] + /// ``` + List itemsToRemove; + + /// List of default annotation menu actions to disable (show as grayed out). + /// + /// These actions will appear in the menu but will be non-interactive. + /// Use this when you want to show functionality exists but is temporarily unavailable. + /// + /// **Example**: Disable copy action for certain annotation types + /// ```dart + /// itemsToDisable: [AnnotationMenuAction.copy] + /// ``` + List itemsToDisable; + + /// Whether to show the platform's default style picker in the annotation menu. + /// + /// When true, users can access color, thickness, and other style options + /// directly from the annotation menu. + /// + /// **Platform Behavior**: + /// - **iOS**: Shows style picker as part of UIMenu + /// - **Android**: Shows annotation inspector/style picker + /// - **Web**: Shows color picker and basic style options + bool showStylePicker; + + /// Whether to group markup annotation actions together in the menu. + /// + /// When true, related markup actions (highlight, underline, etc.) are + /// visually grouped in the menu for better organization. + /// + /// **Platform Support**: iOS only (ignored on Android and Web) + bool groupMarkupItems; + + /// Maximum number of actions to show directly in the menu before creating overflow. + /// + /// When the number of available actions exceeds this limit, the platform + /// may create a submenu or overflow menu to accommodate additional actions. + /// + /// **Platform Behavior**: + /// - **iOS**: Respects platform UI guidelines for menu length + /// - **Android**: Limited by toolbar space and screen size + /// - **Web**: Creates scrollable or paginated menu as needed + /// + /// **Note**: If null, the platform default behavior is used. + int? maxVisibleItems; + + Object encode() { + return [ + itemsToRemove, + itemsToDisable, + showStylePicker, + groupMarkupItems, + maxVisibleItems, + ]; + } + + static AnnotationMenuConfigurationData decode(Object result) { + result as List; + return AnnotationMenuConfigurationData( + itemsToRemove: (result[0] as List?)!.cast(), + itemsToDisable: (result[1] as List?)!.cast(), + showStylePicker: result[2]! as bool, + groupMarkupItems: result[3]! as bool, + maxVisibleItems: result[4] as int?, + ); + } +} + + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -498,51 +619,57 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is AndroidPermissionStatus) { + } else if (value is AndroidPermissionStatus) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is AnnotationType) { + } else if (value is AnnotationType) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is AnnotationTool) { + } else if (value is AnnotationTool) { buffer.putUint8(131); writeValue(buffer, value.index); - } else if (value is AnnotationToolVariant) { + } else if (value is AnnotationToolVariant) { buffer.putUint8(132); writeValue(buffer, value.index); - } else if (value is AnnotationProcessingMode) { + } else if (value is AnnotationProcessingMode) { buffer.putUint8(133); writeValue(buffer, value.index); - } else if (value is DocumentPermissions) { + } else if (value is DocumentPermissions) { buffer.putUint8(134); writeValue(buffer, value.index); - } else if (value is PdfVersion) { + } else if (value is PdfVersion) { buffer.putUint8(135); writeValue(buffer, value.index); - } else if (value is PdfFormFieldTypes) { + } else if (value is PdfFormFieldTypes) { buffer.putUint8(136); writeValue(buffer, value.index); - } else if (value is NutrientEvent) { + } else if (value is NutrientEvent) { buffer.putUint8(137); writeValue(buffer, value.index); - } else if (value is PdfRect) { + } else if (value is AnnotationMenuAction) { buffer.putUint8(138); - writeValue(buffer, value.encode()); - } else if (value is PageInfo) { + writeValue(buffer, value.index); + } else if (value is PdfRect) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is DocumentSaveOptions) { + } else if (value is PageInfo) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is PdfFormOption) { + } else if (value is DocumentSaveOptions) { buffer.putUint8(141); writeValue(buffer, value.encode()); - } else if (value is FormFieldData) { + } else if (value is PdfFormOption) { buffer.putUint8(142); writeValue(buffer, value.encode()); - } else if (value is PointF) { + } else if (value is FormFieldData) { buffer.putUint8(143); writeValue(buffer, value.encode()); + } else if (value is PointF) { + buffer.putUint8(144); + writeValue(buffer, value.encode()); + } else if (value is AnnotationMenuConfigurationData) { + buffer.putUint8(145); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -551,45 +678,50 @@ class _PigeonCodec extends StandardMessageCodec { @override Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { - case 129: + case 129: final int? value = readValue(buffer) as int?; return value == null ? null : AndroidPermissionStatus.values[value]; - case 130: + case 130: final int? value = readValue(buffer) as int?; return value == null ? null : AnnotationType.values[value]; - case 131: + case 131: final int? value = readValue(buffer) as int?; return value == null ? null : AnnotationTool.values[value]; - case 132: + case 132: final int? value = readValue(buffer) as int?; return value == null ? null : AnnotationToolVariant.values[value]; - case 133: + case 133: final int? value = readValue(buffer) as int?; return value == null ? null : AnnotationProcessingMode.values[value]; - case 134: + case 134: final int? value = readValue(buffer) as int?; return value == null ? null : DocumentPermissions.values[value]; - case 135: + case 135: final int? value = readValue(buffer) as int?; return value == null ? null : PdfVersion.values[value]; - case 136: + case 136: final int? value = readValue(buffer) as int?; return value == null ? null : PdfFormFieldTypes.values[value]; - case 137: + case 137: final int? value = readValue(buffer) as int?; return value == null ? null : NutrientEvent.values[value]; - case 138: + case 138: + final int? value = readValue(buffer) as int?; + return value == null ? null : AnnotationMenuAction.values[value]; + case 139: return PdfRect.decode(readValue(buffer)!); - case 139: + case 140: return PageInfo.decode(readValue(buffer)!); - case 140: + case 141: return DocumentSaveOptions.decode(readValue(buffer)!); - case 141: + case 142: return PdfFormOption.decode(readValue(buffer)!); - case 142: + case 143: return FormFieldData.decode(readValue(buffer)!); - case 143: + case 144: return PointF.decode(readValue(buffer)!); + case 145: + return AnnotationMenuConfigurationData.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); } @@ -601,11 +733,9 @@ class NutrientApi { /// Constructor for [NutrientApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - NutrientApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + NutrientApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -613,10 +743,8 @@ class NutrientApi { final String pigeonVar_messageChannelSuffix; Future getFrameworkVersion() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getFrameworkVersion$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getFrameworkVersion$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -638,16 +766,13 @@ class NutrientApi { } Future setLicenseKey(String? licenseKey) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setLicenseKey$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setLicenseKey$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([licenseKey]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([licenseKey]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -663,18 +788,14 @@ class NutrientApi { } } - Future setLicenseKeys(String? androidLicenseKey, String? iOSLicenseKey, - String? webLicenseKey) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setLicenseKeys$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future setLicenseKeys(String? androidLicenseKey, String? iOSLicenseKey, String? webLicenseKey) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setLicenseKeys$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel - .send([androidLicenseKey, iOSLicenseKey, webLicenseKey]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([androidLicenseKey, iOSLicenseKey, webLicenseKey]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -690,18 +811,14 @@ class NutrientApi { } } - Future present(String document, - {Map? configuration}) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.present$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future present(String document, {Map? configuration}) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.present$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([document, configuration]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([document, configuration]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -717,21 +834,14 @@ class NutrientApi { } } - Future presentInstant( - String serverUrl, - String jwt, { - Map? configuration, - }) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.presentInstant$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future presentInstant(String serverUrl, String jwt, {Map? configuration, }) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.presentInstant$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([serverUrl, jwt, configuration]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([serverUrl, jwt, configuration]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -747,18 +857,14 @@ class NutrientApi { } } - Future setFormFieldValue( - String value, String fullyQualifiedName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future setFormFieldValue(String value, String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([value, fullyQualifiedName]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([value, fullyQualifiedName]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -775,16 +881,13 @@ class NutrientApi { } Future getFormFieldValue(String fullyQualifiedName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([fullyQualifiedName]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([fullyQualifiedName]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -801,16 +904,13 @@ class NutrientApi { } Future applyInstantJson(String annotationsJson) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.applyInstantJson$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.applyInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotationsJson]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotationsJson]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -827,10 +927,8 @@ class NutrientApi { } Future exportInstantJson() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.exportInstantJson$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.exportInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -852,16 +950,13 @@ class NutrientApi { } Future addAnnotation(String annotation, String? attachment) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.addAnnotation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.addAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotation, attachment]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotation, attachment]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -878,16 +973,13 @@ class NutrientApi { } Future removeAnnotation(String annotation) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.removeAnnotation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.removeAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotation]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotation]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -904,16 +996,13 @@ class NutrientApi { } Future getAnnotations(int pageIndex, String type) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([pageIndex, type]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([pageIndex, type]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -930,10 +1019,8 @@ class NutrientApi { } Future getAllUnsavedAnnotations() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -955,16 +1042,13 @@ class NutrientApi { } Future updateAnnotation(String annotation) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.updateAnnotation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.updateAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotation]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotation]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -980,18 +1064,14 @@ class NutrientApi { } } - Future processAnnotations(AnnotationType type, - AnnotationProcessingMode processingMode, String destinationPath) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.processAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future processAnnotations(AnnotationType type, AnnotationProcessingMode processingMode, String destinationPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.processAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel - .send([type, processingMode, destinationPath]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([type, processingMode, destinationPath]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1008,16 +1088,13 @@ class NutrientApi { } Future importXfdf(String xfdfString) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.importXfdf$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.importXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([xfdfString]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([xfdfString]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1034,16 +1111,13 @@ class NutrientApi { } Future exportXfdf(String xfdfPath) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.exportXfdf$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.exportXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([xfdfPath]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([xfdfPath]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1060,10 +1134,8 @@ class NutrientApi { } Future save() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.save$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.save$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1085,16 +1157,13 @@ class NutrientApi { } Future setDelayForSyncingLocalChanges(double delay) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setDelayForSyncingLocalChanges$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setDelayForSyncingLocalChanges$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([delay]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([delay]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1111,16 +1180,13 @@ class NutrientApi { } Future setListenToServerChanges(bool listen) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setListenToServerChanges$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setListenToServerChanges$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([listen]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([listen]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1137,10 +1203,8 @@ class NutrientApi { } Future syncAnnotations() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.syncAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.syncAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1162,10 +1226,8 @@ class NutrientApi { } Future checkAndroidWriteExternalStoragePermission() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.checkAndroidWriteExternalStoragePermission$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.checkAndroidWriteExternalStoragePermission$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1186,12 +1248,9 @@ class NutrientApi { } } - Future - requestAndroidWriteExternalStoragePermission() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.requestAndroidWriteExternalStoragePermission$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future requestAndroidWriteExternalStoragePermission() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.requestAndroidWriteExternalStoragePermission$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1218,10 +1277,8 @@ class NutrientApi { } Future openAndroidSettings() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.openAndroidSettings$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.openAndroidSettings$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1242,18 +1299,14 @@ class NutrientApi { } } - Future setAnnotationPresetConfigurations( - Map configurations) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setAnnotationPresetConfigurations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future setAnnotationPresetConfigurations(Map configurations) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setAnnotationPresetConfigurations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([configurations]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([configurations]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1270,10 +1323,8 @@ class NutrientApi { } Future getTemporaryDirectory() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getTemporaryDirectory$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getTemporaryDirectory$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1300,16 +1351,13 @@ class NutrientApi { } Future setAuthorName(String name) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setAuthorName$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setAuthorName$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([name]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([name]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1326,10 +1374,8 @@ class NutrientApi { } Future getAuthorName() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getAuthorName$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.getAuthorName$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1359,18 +1405,14 @@ class NutrientApi { /// [pages]: [NewPage]s to be added to the PDF. /// [outputPath]: The path to the output file. /// Returns the path to the generated PDF path or null if the input is invalid or if the PDF generation fails. - Future generatePdf( - List> pages, String outputPath) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.generatePdf$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future generatePdf(List> pages, String outputPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.generatePdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([pages, outputPath]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([pages, outputPath]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1391,18 +1433,14 @@ class NutrientApi { /// [html]: The HTML string to be converted to PDF. /// [outPutFile]: The path to the output file. /// Returns the path to the generated PDF file or null if the input is invalid or if the PDF generation fails. - Future generatePdfFromHtmlString( - String html, String outPutFile, Map? options) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.generatePdfFromHtmlString$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future generatePdfFromHtmlString(String html, String outPutFile, Map? options) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.generatePdfFromHtmlString$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([html, outPutFile, options]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([html, outPutFile, options]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1418,18 +1456,14 @@ class NutrientApi { } } - Future generatePdfFromHtmlUri( - String htmlUri, String outPutFile, Map? options) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.generatePdfFromHtmlUri$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future generatePdfFromHtmlUri(String htmlUri, String outPutFile, Map? options) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.generatePdfFromHtmlUri$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([htmlUri, outPutFile, options]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([htmlUri, outPutFile, options]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1447,16 +1481,13 @@ class NutrientApi { /// Configure Nutrient Analytics events. Future enableAnalyticsEvents(bool enable) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.enableAnalyticsEvents$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.enableAnalyticsEvents$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([enable]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([enable]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1471,6 +1502,34 @@ class NutrientApi { return; } } + + /// Sets the annotation menu configuration for the global presenter. + /// This configuration applies to all annotation menus in presented documents. + /// + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + Future setAnnotationMenuConfiguration(AnnotationMenuConfigurationData configuration) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientApi.setAnnotationMenuConfiguration$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([configuration]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } } abstract class NutrientApiCallbacks { @@ -1512,19 +1571,11 @@ abstract class NutrientApiCallbacks { /// Called when instant document download fails. void onInstantDownloadFailed(String documentId, String error); - static void setUp( - NutrientApiCallbacks? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(NutrientApiCallbacks? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onPdfActivityOnPause$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onPdfActivityOnPause$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1535,19 +1586,15 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onPdfFragmentAdded$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onPdfFragmentAdded$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1558,26 +1605,22 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onDocumentLoaded$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onDocumentLoaded$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onDocumentLoaded was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onDocumentLoaded was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -1587,19 +1630,15 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onPdfViewControllerWillDismiss$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onPdfViewControllerWillDismiss$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1610,19 +1649,15 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onPdfViewControllerDidDismiss$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onPdfViewControllerDidDismiss$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1633,26 +1668,22 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncStarted$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncStarted$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncStarted was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncStarted was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -1662,26 +1693,22 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncFinished$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncFinished$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncFinished was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncFinished was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -1691,26 +1718,22 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncFailed$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncFailed$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncFailed was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantSyncFailed was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -1723,26 +1746,22 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantAuthenticationFinished$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantAuthenticationFinished$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantAuthenticationFinished was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantAuthenticationFinished was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -1755,26 +1774,22 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantAuthenticationFailed$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantAuthenticationFailed$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantAuthenticationFailed was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantAuthenticationFailed was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -1787,26 +1802,22 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantDownloadFinished$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantDownloadFinished$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantDownloadFinished was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantDownloadFinished was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -1816,26 +1827,22 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantDownloadFailed$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantDownloadFailed$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantDownloadFailed was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientApiCallbacks.onInstantDownloadFailed was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -1848,9 +1855,8 @@ abstract class NutrientApiCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } @@ -1862,11 +1868,9 @@ class NutrientViewControllerApi { /// Constructor for [NutrientViewControllerApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - NutrientViewControllerApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + NutrientViewControllerApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -1875,18 +1879,14 @@ class NutrientViewControllerApi { /// Sets the value of a form field by specifying its fully qualified field name. /// This method is deprecated. Use [PdfDocument.setFormFieldValue] instead. - Future setFormFieldValue( - String value, String fullyQualifiedName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future setFormFieldValue(String value, String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([value, fullyQualifiedName]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([value, fullyQualifiedName]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1904,16 +1904,13 @@ class NutrientViewControllerApi { /// Gets the form field value by specifying its fully qualified name. Future getFormFieldValue(String fullyQualifiedName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([fullyQualifiedName]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([fullyQualifiedName]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1931,16 +1928,13 @@ class NutrientViewControllerApi { /// Applies Instant document JSON to the presented document. Future applyInstantJson(String annotationsJson) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.applyInstantJson$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.applyInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotationsJson]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotationsJson]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -1958,10 +1952,8 @@ class NutrientViewControllerApi { /// Exports Instant document JSON from the presented document. Future exportInstantJson() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.exportInstantJson$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.exportInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1985,16 +1977,13 @@ class NutrientViewControllerApi { /// Adds the given annotation to the presented document. /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). Future addAnnotation(String annotation) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.addAnnotation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.addAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotation]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotation]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2013,16 +2002,13 @@ class NutrientViewControllerApi { /// Removes the given annotation from the presented document. /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). Future removeAnnotation(String annotation) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.removeAnnotation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.removeAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotation]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotation]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2040,16 +2026,13 @@ class NutrientViewControllerApi { /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. Future getAnnotations(int pageIndex, String type) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([pageIndex, type]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([pageIndex, type]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2072,10 +2055,8 @@ class NutrientViewControllerApi { /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. Future getAllUnsavedAnnotations() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -2103,18 +2084,14 @@ class NutrientViewControllerApi { /// Processes annotations of the given type with the provided processing /// mode and stores the PDF at the given destination path. - Future processAnnotations(AnnotationType type, - AnnotationProcessingMode processingMode, String destinationPath) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.processAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future processAnnotations(AnnotationType type, AnnotationProcessingMode processingMode, String destinationPath) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.processAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel - .send([type, processingMode, destinationPath]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([type, processingMode, destinationPath]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2137,16 +2114,13 @@ class NutrientViewControllerApi { /// Imports annotations from the XFDF file at the given path. Future importXfdf(String xfdfString) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.importXfdf$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.importXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([xfdfString]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([xfdfString]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2169,16 +2143,13 @@ class NutrientViewControllerApi { /// Exports annotations to the XFDF file at the given path. Future exportXfdf(String xfdfPath) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.exportXfdf$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.exportXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([xfdfPath]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([xfdfPath]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2202,10 +2173,8 @@ class NutrientViewControllerApi { /// Saves the document back to its original location if it has been changed. /// If there were no changes to the document, the document file will not be modified. Future save() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.save$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.save$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -2235,18 +2204,14 @@ class NutrientViewControllerApi { /// @param configurations A map of annotation tools and their corresponding configurations. /// @param modifyAssociatedAnnotations Whether to modify the annotations associated with the old configuration. Only used for Android. /// @return True if the configurations were set successfully, false otherwise. - Future setAnnotationConfigurations( - Map> configurations) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.setAnnotationConfigurations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future setAnnotationConfigurations(Map> configurations) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.setAnnotationConfigurations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([configurations]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([configurations]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2266,16 +2231,13 @@ class NutrientViewControllerApi { /// pageIndex The index of the page. This is a zero-based index. /// Returns a [Future] that completes with the visible rect of the given page. Future getVisibleRect(int pageIndex) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getVisibleRect$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getVisibleRect$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([pageIndex]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([pageIndex]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2300,18 +2262,14 @@ class NutrientViewControllerApi { /// pageIndex The index of the page. This is a zero-based index. /// rect The rect to zoom to. /// Returns a [Future] that completes when the zoom operation is done. - Future zoomToRect( - int pageIndex, PdfRect rect, bool? animated, double? duration) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.zoomToRect$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future zoomToRect(int pageIndex, PdfRect rect, bool? animated, double? duration) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.zoomToRect$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([pageIndex, rect, animated, duration]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([pageIndex, rect, animated, duration]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2336,16 +2294,13 @@ class NutrientViewControllerApi { /// pageIndex The index of the page. This is a zero-based index. /// Returns a [Future] that completes with the zoom scale of the given page. Future getZoomScale(int pageIndex) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getZoomScale$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.getZoomScale$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([pageIndex]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([pageIndex]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2367,16 +2322,13 @@ class NutrientViewControllerApi { } Future addEventListener(NutrientEvent event) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.addEventListener$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.addEventListener$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([event]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([event]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2393,16 +2345,13 @@ class NutrientViewControllerApi { } Future removeEventListener(NutrientEvent event) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.removeEventListener$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.removeEventListener$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([event]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([event]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2425,18 +2374,14 @@ class NutrientViewControllerApi { /// /// Returns a [Future] that completes with a boolean indicating whether /// entering annotation creation mode was successful. - Future enterAnnotationCreationMode( - AnnotationTool? annotationTool) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.enterAnnotationCreationMode$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future enterAnnotationCreationMode(AnnotationTool? annotationTool) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.enterAnnotationCreationMode$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotationTool]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotationTool]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2457,10 +2402,8 @@ class NutrientViewControllerApi { /// Returns a [Future] that completes with a boolean indicating whether /// exiting annotation creation mode was successful. Future exitAnnotationCreationMode() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.exitAnnotationCreationMode$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.exitAnnotationCreationMode$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -2480,17 +2423,43 @@ class NutrientViewControllerApi { return (pigeonVar_replyList[0] as bool?); } } + + /// Sets the annotation menu configuration for the current view controller. + /// This configuration applies only to annotation menus in the current document view. + /// + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + Future setAnnotationMenuConfiguration(AnnotationMenuConfigurationData configuration) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.NutrientViewControllerApi.setAnnotationMenuConfiguration$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([configuration]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as bool?); + } + } } class PdfDocumentApi { /// Constructor for [PdfDocumentApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - PdfDocumentApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + PdfDocumentApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -2500,16 +2469,13 @@ class PdfDocumentApi { /// Returns the page info for the given page index. /// pageIndex The index of the page. This is a zero-based index. Future getPageInfo(int pageIndex) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getPageInfo$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getPageInfo$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([pageIndex]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([pageIndex]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2534,16 +2500,13 @@ class PdfDocumentApi { /// options:[DocumentSaveOptions] The options to use when exporting the document. /// Returns a [Uint8List] containing the exported PDF data. Future exportPdf(DocumentSaveOptions? options) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.exportPdf$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.exportPdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([options]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([options]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2565,16 +2528,13 @@ class PdfDocumentApi { } Future> getFormField(String fieldName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getFormField$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getFormField$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([fieldName]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([fieldName]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2591,17 +2551,14 @@ class PdfDocumentApi { message: 'Host platform returned null value for non-null return value.', ); } else { - return (pigeonVar_replyList[0] as Map?)! - .cast(); + return (pigeonVar_replyList[0] as Map?)!.cast(); } } /// Returns a list of all form fields in the document. Future>> getFormFields() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getFormFields$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getFormFields$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -2623,24 +2580,19 @@ class PdfDocumentApi { message: 'Host platform returned null value for non-null return value.', ); } else { - return (pigeonVar_replyList[0] as List?)! - .cast>(); + return (pigeonVar_replyList[0] as List?)!.cast>(); } } /// Sets the value of a form field by specifying its fully qualified field name. - Future setFormFieldValue( - String value, String fullyQualifiedName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future setFormFieldValue(String value, String fullyQualifiedName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.setFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([value, fullyQualifiedName]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([value, fullyQualifiedName]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2658,16 +2610,13 @@ class PdfDocumentApi { /// Gets the form field value by specifying its fully qualified name. Future getFormFieldValue(String fullyQualifiedName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getFormFieldValue$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([fullyQualifiedName]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([fullyQualifiedName]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2685,16 +2634,13 @@ class PdfDocumentApi { /// Applies Instant document JSON to the presented document. Future applyInstantJson(String annotationsJson) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.applyInstantJson$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.applyInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([annotationsJson]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([annotationsJson]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2712,10 +2658,8 @@ class PdfDocumentApi { /// Exports Instant document JSON from the presented document. Future exportInstantJson() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.exportInstantJson$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.exportInstantJson$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -2739,16 +2683,13 @@ class PdfDocumentApi { /// Adds the given annotation to the presented document. /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). Future addAnnotation(String jsonAnnotation, Object? attachment) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.addAnnotation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.addAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([jsonAnnotation, attachment]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([jsonAnnotation, attachment]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2767,16 +2708,13 @@ class PdfDocumentApi { /// Updates the given annotation in the presented document. /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). Future updateAnnotation(String jsonAnnotation) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.updateAnnotation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.updateAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([jsonAnnotation]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([jsonAnnotation]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2795,16 +2733,13 @@ class PdfDocumentApi { /// Removes the given annotation from the presented document. /// `jsonAnnotation` can either be a JSON string or a valid JSON Dictionary (iOS) / HashMap (Android). Future removeAnnotation(String jsonAnnotation) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.removeAnnotation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.removeAnnotation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([jsonAnnotation]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([jsonAnnotation]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2822,16 +2757,13 @@ class PdfDocumentApi { /// Returns a list of JSON dictionaries for all the annotations of the given `type` on the given `pageIndex`. Future getAnnotations(int pageIndex, String type) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([pageIndex, type]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([pageIndex, type]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2854,10 +2786,8 @@ class PdfDocumentApi { /// Returns a list of JSON dictionaries for all the unsaved annotations in the presented document. Future getAllUnsavedAnnotations() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getAllUnsavedAnnotations$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -2885,16 +2815,13 @@ class PdfDocumentApi { /// Imports annotations from the XFDF file at the given path. Future importXfdf(String xfdfString) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.importXfdf$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.importXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([xfdfString]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([xfdfString]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2917,16 +2844,13 @@ class PdfDocumentApi { /// Exports annotations to the XFDF file at the given path. Future exportXfdf(String xfdfPath) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.exportXfdf$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.exportXfdf$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([xfdfPath]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([xfdfPath]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2950,16 +2874,13 @@ class PdfDocumentApi { /// Saves the document back to its original location if it has been changed. /// If there were no changes to the document, the document file will not be modified. Future save(String? outputPath, DocumentSaveOptions? options) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.save$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.save$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([outputPath, options]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([outputPath, options]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -2982,10 +2903,8 @@ class PdfDocumentApi { /// Get the total number of pages in the document. Future getPageCount() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getPageCount$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.nutrient_flutter.PdfDocumentApi.getPageCount$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -3021,31 +2940,22 @@ abstract class NutrientViewCallbacks { void onPageChanged(String documentId, int pageIndex); - void onPageClick( - String documentId, int pageIndex, PointF? point, Object? annotation); + void onPageClick(String documentId, int pageIndex, PointF? point, Object? annotation); void onDocumentSaved(String documentId, String? path); - static void setUp( - NutrientViewCallbacks? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(NutrientViewCallbacks? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentLoaded$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentLoaded$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentLoaded was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentLoaded was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -3055,26 +2965,22 @@ abstract class NutrientViewCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentError$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentError$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentError was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentError was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -3087,26 +2993,22 @@ abstract class NutrientViewCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageChanged$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageChanged$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageChanged was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageChanged was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -3119,26 +3021,22 @@ abstract class NutrientViewCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageClick$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageClick$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageClick was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageClick was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -3147,33 +3045,28 @@ abstract class NutrientViewCallbacks { assert(arg_pageIndex != null, 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onPageClick was null, expected non-null int.'); final PointF? arg_point = (args[2] as PointF?); - final Object? arg_annotation = args[3]; + final Object? arg_annotation = (args[3] as Object?); try { - api.onPageClick( - arg_documentId!, arg_pageIndex!, arg_point, arg_annotation); + api.onPageClick(arg_documentId!, arg_pageIndex!, arg_point, arg_annotation); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentSaved$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentSaved$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentSaved was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientViewCallbacks.onDocumentSaved was null.'); final List args = (message as List?)!; final String? arg_documentId = (args[0] as String?); assert(arg_documentId != null, @@ -3184,9 +3077,8 @@ abstract class NutrientViewCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } @@ -3199,39 +3091,30 @@ abstract class NutrientEventsCallbacks { void onEvent(NutrientEvent event, Object? data); - static void setUp( - NutrientEventsCallbacks? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(NutrientEventsCallbacks? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.NutrientEventsCallbacks.onEvent$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.NutrientEventsCallbacks.onEvent$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientEventsCallbacks.onEvent was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientEventsCallbacks.onEvent was null.'); final List args = (message as List?)!; final NutrientEvent? arg_event = (args[0] as NutrientEvent?); assert(arg_event != null, 'Argument for dev.flutter.pigeon.nutrient_flutter.NutrientEventsCallbacks.onEvent was null, expected non-null NutrientEvent.'); - final Object? arg_data = args[1]; + final Object? arg_data = (args[1] as Object?); try { api.onEvent(arg_event!, arg_data); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } @@ -3244,40 +3127,30 @@ abstract class AnalyticsEventsCallback { void onEvent(String event, Map? attributes); - static void setUp( - AnalyticsEventsCallback? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(AnalyticsEventsCallback? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.AnalyticsEventsCallback.onEvent$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.AnalyticsEventsCallback.onEvent$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.AnalyticsEventsCallback.onEvent was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.AnalyticsEventsCallback.onEvent was null.'); final List args = (message as List?)!; final String? arg_event = (args[0] as String?); assert(arg_event != null, 'Argument for dev.flutter.pigeon.nutrient_flutter.AnalyticsEventsCallback.onEvent was null, expected non-null String.'); - final Map? arg_attributes = - (args[1] as Map?)?.cast(); + final Map? arg_attributes = (args[1] as Map?)?.cast(); try { api.onEvent(arg_event!, arg_attributes); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } @@ -3292,26 +3165,18 @@ abstract class CustomToolbarCallbacks { /// Called when a custom toolbar item is tapped void onCustomToolbarItemTapped(String identifier); - static void setUp( - CustomToolbarCallbacks? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(CustomToolbarCallbacks? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.nutrient_flutter.CustomToolbarCallbacks.onCustomToolbarItemTapped$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.nutrient_flutter.CustomToolbarCallbacks.onCustomToolbarItemTapped$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.nutrient_flutter.CustomToolbarCallbacks.onCustomToolbarItemTapped was null.'); + 'Argument for dev.flutter.pigeon.nutrient_flutter.CustomToolbarCallbacks.onCustomToolbarItemTapped was null.'); final List args = (message as List?)!; final String? arg_identifier = (args[0] as String?); assert(arg_identifier != null, @@ -3321,9 +3186,8 @@ abstract class CustomToolbarCallbacks { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/lib/src/pdf_configuration.dart b/lib/src/pdf_configuration.dart index 12daf978..f1890f50 100644 --- a/lib/src/pdf_configuration.dart +++ b/lib/src/pdf_configuration.dart @@ -186,6 +186,9 @@ class PdfConfiguration { final bool? androidEnableAiAssistant; + /// Configuration for annotation contextual menu customization. + final AnnotationMenuConfiguration? annotationMenuConfiguration; + PdfConfiguration({ this.scrollDirection, this.pageTransition, @@ -240,6 +243,7 @@ class PdfConfiguration { this.signatureCreationConfiguration, this.aiAssistantConfiguration, this.androidEnableAiAssistant, + this.annotationMenuConfiguration, }); /// Returns a [Map] representation of the [PdfConfiguration] object. @@ -297,6 +301,7 @@ class PdfConfiguration { 'signatureCreationConfiguration': signatureCreationConfiguration?.toMap(), 'aiAssistant': aiAssistantConfiguration?.toMap(), 'enableAiAssistant': androidEnableAiAssistant, + 'annotationMenuConfiguration': annotationMenuConfiguration?.toMap(), }..removeWhere((key, value) => value == null); } diff --git a/lib/src/types.dart b/lib/src/types.dart index b6bb88c0..19eded8d 100644 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -387,6 +387,9 @@ typedef OnCustomToolbarItemTappedCallback = void Function(String identifier); typedef NutrientViewCreatedCallback = void Function( NutrientViewController controller); +typedef OnBuildAnnotationMenuCallback = AnnotationMenuConfigurationData? Function( + String documentId, Object annotation); + extension WebShowSignatureValidationStatusMode on ShowSignatureValidationStatusMode { String? get webName { diff --git a/lib/src/web/nutrient_web_configuration.dart b/lib/src/web/nutrient_web_configuration.dart index 6fcc8df5..795835ae 100644 --- a/lib/src/web/nutrient_web_configuration.dart +++ b/lib/src/web/nutrient_web_configuration.dart @@ -205,6 +205,24 @@ class PdfWebConfiguration { /// Main toolbar items. If not set, the default toolbar items will be used. final List? toolbarItems; + /// Office conversion settings for documents like .docx, .xlsx, .pptx. + /// + /// These settings control how Office documents are converted to PDF for viewing. + /// Currently supports configuration for spreadsheet dimensions: + /// - `spreadsheetMaximumContentHeightPerSheet`: Maximum height in millimeters per sheet + /// - `spreadsheetMaximumContentWidthPerSheet`: Maximum width in millimeters per sheet + /// + /// Example: + /// ```dart + /// PdfWebConfiguration( + /// officeConversionSettings: OfficeConversionSettings( + /// spreadsheetMaximumContentHeightPerSheet: 500, + /// spreadsheetMaximumContentWidthPerSheet: 300, + /// ), + /// ) + /// ``` + final OfficeConversionSettings? officeConversionSettings; + /// Annotation toolbar items callback. If not set, the default annotation toolbar items will be used. final NutrientWebAnnotationToolbarItemsCallback? annotationToolbarItems; @@ -274,7 +292,8 @@ class PdfWebConfiguration { this.disableForms, this.disableTextSelection, this.toolbarItems, - this.annotationToolbarItems}); + this.annotationToolbarItems, + this.officeConversionSettings}); Map toMap() { return { @@ -336,7 +355,8 @@ class PdfWebConfiguration { 'disableTextSelection': disableTextSelection, 'toolbarItems': toolbarItems, 'annotationToolbarItems': annotationToolbarItems, - 'authPayload': authPayload + 'authPayload': authPayload, + ...?officeConversionSettings?.toMap() }..removeWhere((key, value) => value == null); } } diff --git a/lib/src/web/office_conversion_settings.dart b/lib/src/web/office_conversion_settings.dart new file mode 100644 index 00000000..9d6902fd --- /dev/null +++ b/lib/src/web/office_conversion_settings.dart @@ -0,0 +1,46 @@ +/// +/// Copyright © 2024-2025 PSPDFKit GmbH. All rights reserved. +/// +/// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW +/// AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT. +/// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. +/// This notice may not be removed from this file. +/// + +/// Configuration options for Office document conversion in Nutrient Web. +/// +/// These settings control how Office documents (.docx, .xlsx, .pptx) are +/// converted to PDF for viewing in the web viewer. +class OfficeConversionSettings { + /// Maximum height (in millimeters) for spreadsheet content per sheet. + /// + /// This setting controls the maximum height of content that will be rendered + /// for each sheet in Excel spreadsheets. Content exceeding this height will + /// be truncated. The default value is platform-specific. + final num? spreadsheetMaximumContentHeightPerSheet; + + /// Maximum width (in millimeters) for spreadsheet content per sheet. + /// + /// This setting controls the maximum width of content that will be rendered + /// for each sheet in Excel spreadsheets. Content exceeding this width will + /// be truncated. The default value is platform-specific. + final num? spreadsheetMaximumContentWidthPerSheet; + + /// Creates an instance of [OfficeConversionSettings]. + /// + /// All parameters are optional and will use platform defaults if not specified. + const OfficeConversionSettings({ + this.spreadsheetMaximumContentHeightPerSheet, + this.spreadsheetMaximumContentWidthPerSheet, + }); + + /// Converts this configuration to a Map for JavaScript interop. + Map toMap() { + return { + 'spreadsheetMaximumContentHeightPerSheet': + spreadsheetMaximumContentHeightPerSheet, + 'spreadsheetMaximumContentWidthPerSheet': + spreadsheetMaximumContentWidthPerSheet, + }..removeWhere((key, value) => value == null); + } +} \ No newline at end of file diff --git a/lib/src/widgets/nutrient_view.dart b/lib/src/widgets/nutrient_view.dart index 111e3a78..91d1671d 100644 --- a/lib/src/widgets/nutrient_view.dart +++ b/lib/src/widgets/nutrient_view.dart @@ -50,6 +50,7 @@ class NutrientView extends StatefulWidget { /// Called when a custom toolbar item is tapped. final OnCustomToolbarItemTappedCallback? onCustomToolbarItemTapped; + /// Creates a new [NutrientView] widget. const NutrientView({ Key? key, diff --git a/lib/src/widgets/nutrient_view_controller.dart b/lib/src/widgets/nutrient_view_controller.dart index c8c83c3c..96839610 100644 --- a/lib/src/widgets/nutrient_view_controller.dart +++ b/lib/src/widgets/nutrient_view_controller.dart @@ -38,6 +38,14 @@ abstract class NutrientViewController { Map configurations, ); + /// Sets the annotation menu configuration dynamically. + /// This allows you to update the annotation contextual menu configuration at runtime. + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + Future setAnnotationMenuConfiguration( + AnnotationMenuConfiguration configuration, + ); + /// Adds an event listener for the given event. /// @param event. The event to listen for. Future addEventListener( @@ -75,18 +83,10 @@ abstract class NutrientViewController { /// Returns a [Future] that completes with the zoom scale of the given page. Future getZoomScale(int pageIndex); - /// Enters annotation creation mode. - /// - /// If [annotationTool] is provided, that specific tool will be activated. - /// If no tool is provided, the default annotation tool will be used. - /// - /// Returns a [Future] that completes with a boolean indicating whether - /// entering annotation creation mode was successful. + /// Enters annotation creation mode for the specified annotation tool. + /// If no tool is specified, defaults to [AnnotationTool.inkPen]. Future enterAnnotationCreationMode([AnnotationTool? annotationTool]); - /// Exits annotation creation mode. - /// - /// Returns a [Future] that completes with a boolean indicating whether - /// exiting annotation creation mode was successful. + /// Exits annotation creation mode and returns to normal viewer interaction. Future exitAnnotationCreationMode(); } diff --git a/lib/src/widgets/nutrient_view_controller_native.dart b/lib/src/widgets/nutrient_view_controller_native.dart index 160a0d7c..b9abc1e2 100644 --- a/lib/src/widgets/nutrient_view_controller_native.dart +++ b/lib/src/widgets/nutrient_view_controller_native.dart @@ -85,6 +85,23 @@ class NutrientViewControllerNative return _pspdfkitWidgetControllerApi.save(); } + @override + Future setAnnotationMenuConfiguration( + AnnotationMenuConfiguration configuration, + ) { + // Convert AnnotationMenuConfiguration to AnnotationMenuConfigurationData for Pigeon API + final configData = AnnotationMenuConfigurationData( + itemsToRemove: configuration.itemsToRemove.toList(), + itemsToDisable: configuration.itemsToDisable.toList(), + showStylePicker: configuration.showStylePicker, + groupMarkupItems: configuration.groupMarkupItems, + maxVisibleItems: configuration.maxVisibleItems, + ); + + return _pspdfkitWidgetControllerApi + .setAnnotationMenuConfiguration(configData); + } + @override Future setAnnotationConfigurations( Map configurations) { @@ -267,6 +284,7 @@ class NutrientViewControllerNative onCustomToolbarItemTappedListener?.call(identifier); } + @override void addWebEventListener( NutrientWebEvent event, Function(dynamic p1) callback) { diff --git a/lib/src/widgets/nutrient_view_controller_web.dart b/lib/src/widgets/nutrient_view_controller_web.dart index c54568ed..b19feb0b 100644 --- a/lib/src/widgets/nutrient_view_controller_web.dart +++ b/lib/src/widgets/nutrient_view_controller_web.dart @@ -50,6 +50,19 @@ class NutrientViewControllerWeb extends NutrientViewController return Future.value(true); } + @override + Future setAnnotationMenuConfiguration( + AnnotationMenuConfiguration configuration, + ) { + // Web implementation: annotation menu configuration is handled differently on web + // This would need to be implemented using the web-specific API + // For now, we'll return true to indicate the API is available + if (kDebugMode) { + print('setAnnotationMenuConfiguration called on web - not yet implemented'); + } + return Future.value(true); + } + @override Future setAnnotationConfigurations( Map configurations) async { diff --git a/lib/src/widgets/pspdfkit_flutter_widget_controller_impl.dart b/lib/src/widgets/pspdfkit_flutter_widget_controller_impl.dart index 98fd42b1..f4de0cc0 100644 --- a/lib/src/widgets/pspdfkit_flutter_widget_controller_impl.dart +++ b/lib/src/widgets/pspdfkit_flutter_widget_controller_impl.dart @@ -324,4 +324,5 @@ class PspdfkitFlutterWidgetControllerImpl throw UnimplementedError( 'removeWebEventListener is only supported on web.'); } + } diff --git a/pigeons/nutrient.dart b/pigeons/nutrient.dart index 1e835428..4705cdea 100644 --- a/pigeons/nutrient.dart +++ b/pigeons/nutrient.dart @@ -417,6 +417,15 @@ abstract class NutrientApi { /// Configure Nutrient Analytics events. void enableAnalyticsEvents(bool enable); + + /// Sets the annotation menu configuration for the global presenter. + /// This configuration applies to all annotation menus in presented documents. + /// + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + @async + bool? setAnnotationMenuConfiguration( + AnnotationMenuConfigurationData configuration); } @FlutterApi() @@ -566,6 +575,15 @@ abstract class NutrientViewControllerApi { /// exiting annotation creation mode was successful. @async bool? exitAnnotationCreationMode(); + + /// Sets the annotation menu configuration for the current view controller. + /// This configuration applies only to annotation menus in the current document view. + /// + /// @param configuration The annotation menu configuration to apply. + /// @return True if the configuration was set successfully, false otherwise. + @async + bool? setAnnotationMenuConfiguration( + AnnotationMenuConfigurationData configuration); } @HostApi() @@ -661,6 +679,7 @@ abstract class NutrientViewCallbacks { String documentId, int pageIndex, PointF? point, Object? annotation); void onDocumentSaved(String documentId, String? path); + } @FlutterApi() @@ -715,3 +734,125 @@ abstract class CustomToolbarCallbacks { /// Called when a custom toolbar item is tapped void onCustomToolbarItemTapped(String identifier); } + +/// Enumeration of default annotation menu actions that can be removed or disabled. +/// +/// **Platform Support:** +/// - All actions can be removed or disabled on both iOS and Android +/// - Some system actions (copy/paste) may be harder to remove on iOS due to system restrictions +enum AnnotationMenuAction { + /// Delete action - removes the annotation + /// - iOS: Part of UIMenu system actions + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_delete + delete, + + /// Copy action - copies the annotation + /// - iOS: System copy action (may be harder to remove) + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_copy + copy, + + /// Cut action - cuts the annotation to clipboard + /// - iOS: System cut action + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_cut + cut, + + /// Color action - opens annotation color picker/inspector + /// - iOS: Style picker in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_picker + color, + + /// Note action - opens annotation note editor + /// - iOS: Note action in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_annotation_note + note, + + /// Undo action - undoes the last action + /// - iOS: Undo in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_undo + undo, + + /// Redo action - redoes the previously undone action + /// - iOS: Redo in UIMenu + /// - Android: R.id.pspdf__annotation_editing_toolbar_item_redo + redo, +} + +/// Configuration data for annotation contextual menu +/// +/// This class defines how annotation menus should be configured +/// when displayed to users. It supports removing actions, disabling actions, +/// and controlling visual presentation options. +/// +/// **Usage Patterns**: +/// - **Static Configuration**: Set once via [NutrientViewController.setAnnotationMenuConfiguration] +/// +/// **Platform Compatibility**: +/// - [itemsToRemove]: Supported on Android, iOS, and Web +/// - [itemsToDisable]: Supported on Android, iOS, and Web +/// - [showStylePicker]: Supported on Android and iOS +/// - [groupMarkupItems]: iOS only (ignored on other platforms) +/// - [maxVisibleItems]: Platform-dependent behavior +class AnnotationMenuConfigurationData { + /// List of default annotation menu actions to remove completely from the menu. + /// + /// These actions will not appear in the contextual menu at all. + /// Use this when you want to completely hide certain functionality. + /// + /// **Example**: Remove delete action for read-only annotations + /// ```dart + /// itemsToRemove: [AnnotationMenuAction.delete] + /// ``` + final List itemsToRemove; + + /// List of default annotation menu actions to disable (show as grayed out). + /// + /// These actions will appear in the menu but will be non-interactive. + /// Use this when you want to show functionality exists but is temporarily unavailable. + /// + /// **Example**: Disable copy action for certain annotation types + /// ```dart + /// itemsToDisable: [AnnotationMenuAction.copy] + /// ``` + final List itemsToDisable; + + /// Whether to show the platform's default style picker in the annotation menu. + /// + /// When true, users can access color, thickness, and other style options + /// directly from the annotation menu. + /// + /// **Platform Behavior**: + /// - **iOS**: Shows style picker as part of UIMenu + /// - **Android**: Shows annotation inspector/style picker + /// - **Web**: Shows color picker and basic style options + final bool showStylePicker; + + /// Whether to group markup annotation actions together in the menu. + /// + /// When true, related markup actions (highlight, underline, etc.) are + /// visually grouped in the menu for better organization. + /// + /// **Platform Support**: iOS only (ignored on Android and Web) + final bool groupMarkupItems; + + /// Maximum number of actions to show directly in the menu before creating overflow. + /// + /// When the number of available actions exceeds this limit, the platform + /// may create a submenu or overflow menu to accommodate additional actions. + /// + /// **Platform Behavior**: + /// - **iOS**: Respects platform UI guidelines for menu length + /// - **Android**: Limited by toolbar space and screen size + /// - **Web**: Creates scrollable or paginated menu as needed + /// + /// **Note**: If null, the platform default behavior is used. + final int? maxVisibleItems; + + AnnotationMenuConfigurationData({ + required this.itemsToRemove, + required this.itemsToDisable, + required this.showStylePicker, + required this.groupMarkupItems, + this.maxVisibleItems, + }); +} + diff --git a/pubspec.yaml b/pubspec.yaml index 80922381..c1111da0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,7 +39,6 @@ dev_dependencies: sdk: flutter pigeon: ^24.2.1 build_runner: ^2.2.1 - pigeon_build_runner: ^1.1.1 mockito: ^5.3.1 # Ignore false positives for security scanning diff --git a/test/html_pdf_converter_test.mocks.dart b/test/html_pdf_converter_test.mocks.dart index 20ab5c4a..4b52a6f8 100644 --- a/test/html_pdf_converter_test.mocks.dart +++ b/test/html_pdf_converter_test.mocks.dart @@ -1,5 +1,5 @@ -// Mocks generated by Mockito 5.4.5 from annotations -// in pspdfkit_flutter/test/html_pdf_converter_test.dart. +// Mocks generated by Mockito 5.4.6 from annotations +// in nutrient_flutter/test/html_pdf_converter_test.dart. // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes diff --git a/test/office_conversion_settings_test.dart b/test/office_conversion_settings_test.dart new file mode 100644 index 00000000..5886a4f4 --- /dev/null +++ b/test/office_conversion_settings_test.dart @@ -0,0 +1,81 @@ +/// +/// Copyright © 2024-2025 PSPDFKit GmbH. All rights reserved. +/// +/// THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW +/// AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE PSPDFKIT LICENSE AGREEMENT. +/// UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES. +/// This notice may not be removed from this file. +/// + +import 'package:flutter_test/flutter_test.dart'; +import 'package:nutrient_flutter/nutrient_flutter.dart'; + +void main() { + group('OfficeConversionSettings', () { + test('should serialize to Map correctly', () { + const settings = OfficeConversionSettings( + spreadsheetMaximumContentHeightPerSheet: 500, + spreadsheetMaximumContentWidthPerSheet: 300, + ); + + final map = settings.toMap(); + + expect(map['spreadsheetMaximumContentHeightPerSheet'], equals(500)); + expect(map['spreadsheetMaximumContentWidthPerSheet'], equals(300)); + }); + + test('should omit null values from Map', () { + const settings = OfficeConversionSettings( + spreadsheetMaximumContentHeightPerSheet: 500, + // spreadsheetMaximumContentWidthPerSheet is null + ); + + final map = settings.toMap(); + + expect(map['spreadsheetMaximumContentHeightPerSheet'], equals(500)); + expect(map.containsKey('spreadsheetMaximumContentWidthPerSheet'), isFalse); + }); + + test('should handle all null values', () { + const settings = OfficeConversionSettings(); + + final map = settings.toMap(); + + expect(map.isEmpty, isTrue); + }); + }); + + group('PdfWebConfiguration with OfficeConversionSettings', () { + test('should include office conversion settings in configuration map', () { + final webConfig = PdfWebConfiguration( + officeConversionSettings: const OfficeConversionSettings( + spreadsheetMaximumContentHeightPerSheet: 800, + spreadsheetMaximumContentWidthPerSheet: 600, + ), + allowPrinting: true, + showAnnotations: true, + ); + + final map = webConfig.toMap(); + + expect(map['spreadsheetMaximumContentHeightPerSheet'], equals(800)); + expect(map['spreadsheetMaximumContentWidthPerSheet'], equals(600)); + expect(map['allowPrinting'], equals(true)); + expect(map['showAnnotations'], equals(true)); + }); + + test('should flatten office conversion settings in map', () { + final webConfig = PdfWebConfiguration( + officeConversionSettings: const OfficeConversionSettings( + spreadsheetMaximumContentHeightPerSheet: 1000, + ), + ); + + final map = webConfig.toMap(); + + // Settings should be flattened, not nested + expect(map['spreadsheetMaximumContentHeightPerSheet'], equals(1000)); + expect(map.containsKey('officeConversionSettings'), isFalse); + }); + }); +} \ No newline at end of file