From 2c08ab2b315cccb7577e4024a59bb8ee9bb31ad2 Mon Sep 17 00:00:00 2001 From: catch <catch@35733.no-reply.drupal.org> Date: Thu, 7 Nov 2019 19:46:18 +0000 Subject: [PATCH] Issue #3084983 by plach, amateescu, catch, Berdir, xjm: Move all the code related to path aliases to a new (required) "path_alias" module --- core/MAINTAINERS.txt | 3 + core/composer.json | 1 + core/core.api.php | 4 +- core/core.services.yml | 63 +++--- .../Core/EventSubscriber/PathSubscriber.php | 12 ++ core/lib/Drupal/Core/Path/AliasManager.php | 33 +++- .../Core/Path/AliasManagerInterface.php | 5 + core/lib/Drupal/Core/Path/AliasRepository.php | 12 ++ .../Core/Path/AliasRepositoryInterface.php | 11 +- core/lib/Drupal/Core/Path/AliasStorage.php | 12 +- .../Core/Path/AliasStorageInterface.php | 2 +- core/lib/Drupal/Core/Path/AliasWhitelist.php | 14 +- .../Core/Path/AliasWhitelistInterface.php | 8 +- .../UniquePathAliasConstraintValidator.php | 2 +- .../Core/PathProcessor/PathProcessorAlias.php | 12 ++ .../lib/Drupal/Core/Routing/RouteProvider.php | 4 +- .../Core/Update/UpdateServiceProvider.php | 4 +- .../d6/MigrateBlockContentTranslationTest.php | 1 + .../Kernel/Migrate/d6/MigrateBlockTest.php | 1 + .../d7/MigrateBlockContentTranslationTest.php | 1 + .../Kernel/Migrate/d7/MigrateBlockTest.php | 1 + .../src/Functional/ConfigImportAllTest.php | 2 +- .../tests/src/Functional/PathAliasTest.php | 2 +- .../menu_link_content.module | 2 +- .../Kernel/PathAliasMenuLinkContentTest.php | 4 +- ...content_settings.path_alias.path_alias.yml | 4 +- core/modules/path/path.info.yml | 2 + core/modules/path/path.module | 20 +- core/modules/path/src/PathAliasForm.php | 2 +- .../Field/FieldType/PathFieldItemList.php | 2 +- .../Plugin/Field/FieldWidget/PathWidget.php | 2 +- .../tests/src/Functional/PathAliasTest.php | 2 +- .../Kernel/Migrate/d6/MigrateUrlAliasTest.php | 5 +- .../Kernel/Migrate/d7/MigrateUrlAliasTest.php | 1 + .../Migrate/d7/MigrateUrlAliasTestBase.php | 1 + .../path/tests/src/Kernel/PathItemTest.php | 4 +- .../src/Kernel/PathLegacyRoutesKernelTest.php | 2 +- core/modules/path_alias/path_alias.info.yml | 7 + core/modules/path_alias/src/AliasManager.php | 10 + .../path_alias/src/AliasManagerInterface.php | 12 ++ .../path_alias/src/AliasRepository.php | 10 + .../src/AliasRepositoryInterface.php | 20 ++ .../modules/path_alias/src/AliasWhitelist.php | 10 + .../src/AliasWhitelistInterface.php | 15 ++ .../path_alias/src}/Entity/PathAlias.php | 8 +- .../EventSubscriber/PathAliasSubscriber.php | 10 + .../path_alias/src}/PathAliasInterface.php | 2 +- .../src/PathAliasServiceProvider.php | 79 ++++++++ .../path_alias/src}/PathAliasStorage.php | 2 +- .../src}/PathAliasStorageSchema.php | 2 +- .../src/PathProcessor/AliasPathProcessor.php | 10 + .../path_alias_deprecated_test.info.yml | 5 + .../path_alias_deprecated_test.services.yml | 5 + .../src/AliasManagerDecorator.php | 50 +++++ .../src/NewAliasManager.php | 30 +++ .../src/OverriddenAliasManager.php | 10 + ...PathAliasDeprecatedTestServiceProvider.php | 44 +++++ .../Hal/PathAliasHalJsonAnonTest.php | 3 +- .../Hal/PathAliasHalJsonBasicAuthTest.php | 3 +- .../Hal/PathAliasHalJsonCookieTest.php | 3 +- .../Hal/PathAliasHalJsonTestBase.php | 4 +- .../Rest/PathAliasJsonAnonTest.php | 4 +- .../Rest/PathAliasJsonBasicAuthTest.php | 4 +- .../Rest/PathAliasJsonCookieTest.php | 4 +- .../Rest/PathAliasResourceTestBase.php | 9 +- .../Functional}/Rest/PathAliasXmlAnonTest.php | 4 +- .../Rest/PathAliasXmlBasicAuthTest.php | 4 +- .../Rest/PathAliasXmlCookieTest.php | 4 +- .../Functional}/UrlAlterFunctionalTest.php | 4 +- .../tests/src/Kernel}/AliasTest.php | 29 +-- .../src/Kernel/DeprecatedServicesTest.php | 186 ++++++++++++++++++ .../tests/src/Kernel/PathHooksTest.php | 12 +- .../tests/src/Unit}/AliasManagerTest.php | 14 +- .../tests/src/Unit/DeprecatedClassesTest.php | 170 ++++++++++++++++ .../PathProcessor/AliasPathProcessorTest.php} | 19 +- .../modules/simpletest/src/KernelTestBase.php | 4 +- core/modules/system/system.install | 111 ++++------- .../Update/PathAliasToEntityUpdateTest.php | 18 ++ .../src/Kernel/DeprecatedPathHooksTest.php | 2 +- .../src/Kernel/Views/ArgumentValidateTest.php | 1 + .../tests/src/Kernel/ViewsKernelTestBase.php | 2 +- .../src/WorkspacesAliasRepository.php | 2 +- .../src/WorkspacesServiceProvider.php | 4 +- ...solvedLibraryDefinitionsFilesMatchTest.php | 3 +- .../KernelTests/Core/Command/DbDumpTest.php | 2 +- ...CacheabilityMetadataConfigOverrideTest.php | 1 + .../Core/Entity/CreateSampleEntityTest.php | 2 +- .../Core/Path/LegacyAliasStorageTest.php | 20 +- .../Routing/ContentNegotiationRoutingTest.php | 6 +- .../Core/Routing/RouteProviderTest.php | 6 +- .../Core/Theme/StableLibraryOverrideTest.php | 3 +- .../Drupal/KernelTests/KernelTestBase.php | 4 +- .../Listeners/DeprecationListenerTrait.php | 9 + .../Tests/Traits/Core/PathAliasTestTrait.php | 6 +- .../config_install/multilingual.tar.gz | 87 ++++---- .../testing_config_install.tar.gz | 90 ++++----- 96 files changed, 1132 insertions(+), 335 deletions(-) create mode 100644 core/modules/path_alias/path_alias.info.yml create mode 100644 core/modules/path_alias/src/AliasManager.php create mode 100644 core/modules/path_alias/src/AliasManagerInterface.php create mode 100644 core/modules/path_alias/src/AliasRepository.php create mode 100644 core/modules/path_alias/src/AliasRepositoryInterface.php create mode 100644 core/modules/path_alias/src/AliasWhitelist.php create mode 100644 core/modules/path_alias/src/AliasWhitelistInterface.php rename core/{lib/Drupal/Core/Path => modules/path_alias/src}/Entity/PathAlias.php (95%) create mode 100644 core/modules/path_alias/src/EventSubscriber/PathAliasSubscriber.php rename core/{lib/Drupal/Core/Path => modules/path_alias/src}/PathAliasInterface.php (96%) create mode 100644 core/modules/path_alias/src/PathAliasServiceProvider.php rename core/{lib/Drupal/Core/Path => modules/path_alias/src}/PathAliasStorage.php (98%) rename core/{lib/Drupal/Core/Path => modules/path_alias/src}/PathAliasStorageSchema.php (95%) create mode 100644 core/modules/path_alias/src/PathProcessor/AliasPathProcessor.php create mode 100644 core/modules/path_alias/tests/modules/path_alias_deprecated_test/path_alias_deprecated_test.info.yml create mode 100644 core/modules/path_alias/tests/modules/path_alias_deprecated_test/path_alias_deprecated_test.services.yml create mode 100644 core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/AliasManagerDecorator.php create mode 100644 core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/NewAliasManager.php create mode 100644 core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/OverriddenAliasManager.php create mode 100644 core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/PathAliasDeprecatedTestServiceProvider.php rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Hal/PathAliasHalJsonAnonTest.php (85%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Hal/PathAliasHalJsonBasicAuthTest.php (87%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Hal/PathAliasHalJsonCookieTest.php (87%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Hal/PathAliasHalJsonTestBase.php (90%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Rest/PathAliasJsonAnonTest.php (84%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Rest/PathAliasJsonBasicAuthTest.php (88%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Rest/PathAliasJsonCookieTest.php (86%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Rest/PathAliasResourceTestBase.php (92%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Rest/PathAliasXmlAnonTest.php (87%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Rest/PathAliasXmlBasicAuthTest.php (90%) rename core/{tests/Drupal/FunctionalTests => modules/path_alias/tests/src/Functional}/Rest/PathAliasXmlCookieTest.php (88%) rename core/modules/{system/tests/src/Functional/Path => path_alias/tests/src/Functional}/UrlAlterFunctionalTest.php (98%) rename core/{tests/Drupal/KernelTests/Core/Path => modules/path_alias/tests/src/Kernel}/AliasTest.php (93%) create mode 100644 core/modules/path_alias/tests/src/Kernel/DeprecatedServicesTest.php rename core/modules/{system => path_alias}/tests/src/Kernel/PathHooksTest.php (88%) rename core/{tests/Drupal/Tests/Core/Path => modules/path_alias/tests/src/Unit}/AliasManagerTest.php (97%) create mode 100644 core/modules/path_alias/tests/src/Unit/DeprecatedClassesTest.php rename core/{tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php => modules/path_alias/tests/src/Unit/PathProcessor/AliasPathProcessorTest.php} (75%) diff --git a/core/MAINTAINERS.txt b/core/MAINTAINERS.txt index e93c71b10e85..55020fc2e3de 100644 --- a/core/MAINTAINERS.txt +++ b/core/MAINTAINERS.txt @@ -322,6 +322,9 @@ Page Cache Path - Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch +Path Alias +- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch + Plugin - Kris Vanderwater 'EclipseGc' https://www.drupal.org/u/eclipseGc - Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia diff --git a/core/composer.json b/core/composer.json index 2573c591d23b..970d15ebfcd0 100644 --- a/core/composer.json +++ b/core/composer.json @@ -138,6 +138,7 @@ "drupal/options": "self.version", "drupal/page_cache": "self.version", "drupal/path": "self.version", + "drupal/path_alias": "self.version", "drupal/quickedit": "self.version", "drupal/rdf": "self.version", "drupal/responsive_image": "self.version", diff --git a/core/core.api.php b/core/core.api.php index cfb8800728e7..f54be27586bb 100644 --- a/core/core.api.php +++ b/core/core.api.php @@ -762,8 +762,8 @@ * A typical service definition in a *.services.yml file looks like this: * @code * path.alias_manager: - * class: Drupal\Core\Path\AliasManager - * arguments: ['@path.crud', '@path.alias_whitelist', '@language_manager'] + * class: Drupal\path_alias\AliasManager + * arguments: ['@path.crud', '@path_alias.whitelist', '@language_manager'] * @endcode * Some services use other services as factories; a typical service definition * is: diff --git a/core/core.services.yml b/core/core.services.yml index 5cdcc3efe5a5..9da94f629861 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -461,14 +461,18 @@ services: queue.database: class: Drupal\Core\Queue\QueueDatabaseFactory arguments: ['@database'] + # @deprecated in Drupal 8.8.x and will be removed before 9.0.0. Use the + # "path_alias.whitelist" service instead. + # See https://www.drupal.org/node/3092086 path.alias_whitelist: - class: Drupal\Core\Path\AliasWhitelist - tags: - - { name: needs_destruction } - arguments: [path_alias_whitelist, '@cache.bootstrap', '@lock', '@state', '@path.alias_repository'] + alias: path_alias.whitelist + deprecated: 'The "%alias_id%" service alias is deprecated. Use "path_alias.whitelist" instead. See https://drupal.org/node/3092086' + # @deprecated in Drupal 8.8.x and will be removed before 9.0.0. Use the + # "path_alias.manager" service instead. + # See https://www.drupal.org/node/3092086 path.alias_manager: class: Drupal\Core\Path\AliasManager - arguments: ['@path.alias_repository', '@path.alias_whitelist', '@language_manager', '@cache.data'] + arguments: ['@path_alias.repository', '@path_alias.whitelist', '@language_manager', '@cache.data'] path.current: class: Drupal\Core\Path\CurrentPathStack arguments: ['@request_stack'] @@ -960,17 +964,12 @@ services: arguments: ['@lock', '@plugin.manager.menu.link', '@database', '@database.replica_kill_switch'] tags: - { name: event_subscriber } - path.alias_repository: - class: Drupal\Core\Path\AliasRepository - arguments: ['@database'] - tags: - - { name: backend_overridable } path.alias_storage: class: Drupal\Core\Path\AliasStorage arguments: ['@database', '@module_handler', '@entity_type.manager'] tags: - { name: backend_overridable } - deprecated: The "%service_id%" service is deprecated. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865 + deprecated: The "%service_id%" service is deprecated. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865 path.matcher: class: Drupal\Core\Path\PathMatcher arguments: ['@config.factory', '@current_route_match'] @@ -1222,11 +1221,6 @@ services: arguments: ['@maintenance_mode', '@config.factory', '@string_translation', '@url_generator', '@current_user', '@bare_html_page_renderer', '@messenger'] tags: - { name: event_subscriber } - path_subscriber: - class: Drupal\Core\EventSubscriber\PathSubscriber - tags: - - { name: event_subscriber } - arguments: ['@path.alias_manager', '@path.current'] route_access_response_subscriber: class: Drupal\Core\EventSubscriber\RouteAccessResponseSubscriber tags: @@ -1357,12 +1351,6 @@ services: arguments: ['@current_route_match'] tags: - { name: route_processor_outbound, priority: 200 } - path_processor_alias: - class: Drupal\Core\PathProcessor\PathProcessorAlias - tags: - - { name: path_processor_inbound, priority: 100 } - - { name: path_processor_outbound, priority: 300 } - arguments: ['@path.alias_manager'] route_processor_csrf: class: Drupal\Core\Access\RouteProcessorCsrf tags: @@ -1755,3 +1743,34 @@ services: pager.parameters: class: Drupal\Core\Pager\PagerParameters arguments: ['@request_stack'] + + # Path Alias services, defined here to be available even when "path_alias" is + # not enabled yet. These will replace the legacy core services, which are now + # deprecated and will be removed in Drupal 9. + # See https://www.drupal.org/node/3092086 + # @todo Move these to "path_alias" once core fully supports it as an optional + # module. See https://www.drupal.org/node/3092090. + path_alias.subscriber: + class: Drupal\Core\EventSubscriber\PathSubscriber + tags: + - { name: event_subscriber } + arguments: ['@path.alias_manager', '@path.current'] + path_alias.path_processor: + class: Drupal\Core\PathProcessor\PathProcessorAlias + tags: + - { name: path_processor_inbound, priority: 100 } + - { name: path_processor_outbound, priority: 300 } + arguments: ['@path.alias_manager'] + path_alias.manager: + class: Drupal\Core\Path\AliasManager + arguments: ['@path_alias.repository', '@path_alias.whitelist', '@language_manager', '@cache.data'] + path_alias.repository: + class: Drupal\Core\Path\AliasRepository + arguments: ['@database'] + tags: + - { name: backend_overridable } + path_alias.whitelist: + class: Drupal\Core\Path\AliasWhitelist + tags: + - { name: needs_destruction } + arguments: [path_alias_whitelist, '@cache.bootstrap', '@lock', '@state', '@path_alias.repository'] diff --git a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php index 819fdf94b726..f25bc49b4ac5 100644 --- a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php @@ -11,6 +11,11 @@ /** * Provides a path subscriber that converts path aliases. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. + * Use \Drupal\path_alias\EventSubscriber\PathAliasSubscriber. + * + * @see https://www.drupal.org/node/3092086 */ class PathSubscriber implements EventSubscriberInterface { @@ -39,6 +44,13 @@ class PathSubscriber implements EventSubscriberInterface { public function __construct(AliasManagerInterface $alias_manager, CurrentPathStack $current_path) { $this->aliasManager = $alias_manager; $this->currentPath = $current_path; + + // This is used as base class by the new class, so we do not trigger + // deprecation notices when that or any child class is instantiated. + $new_class = 'Drupal\path_alias\EventSubscriber\PathAliasSubscriber'; + if (!is_a($this, $new_class) && class_exists($new_class)) { + @trigger_error('The \\' . __CLASS__ . ' class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \\' . $new_class . '. See https://drupal.org/node/3092086', E_USER_DEPRECATED); + } } /** diff --git a/core/lib/Drupal/Core/Path/AliasManager.php b/core/lib/Drupal/Core/Path/AliasManager.php index 59694bb2f852..77aaf8274bac 100644 --- a/core/lib/Drupal/Core/Path/AliasManager.php +++ b/core/lib/Drupal/Core/Path/AliasManager.php @@ -7,9 +7,15 @@ use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageManagerInterface; +use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; /** * The default alias manager implementation. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. + * Use \Drupal\path_alias\AliasManager. + * + * @see https://www.drupal.org/node/3092086 */ class AliasManager implements AliasManagerInterface, CacheDecoratorInterface { @@ -115,12 +121,37 @@ class AliasManager implements AliasManagerInterface, CacheDecoratorInterface { public function __construct($alias_repository, AliasWhitelistInterface $whitelist, LanguageManagerInterface $language_manager, CacheBackendInterface $cache) { if (!$alias_repository instanceof AliasRepositoryInterface) { @trigger_error('Passing the path.alias_storage service to AliasManager::__construct() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Pass the new dependencies instead. See https://www.drupal.org/node/3013865.', E_USER_DEPRECATED); - $alias_repository = \Drupal::service('path.alias_repository'); + $alias_repository = \Drupal::service('path_alias.repository'); } $this->pathAliasRepository = $alias_repository; $this->languageManager = $language_manager; $this->whitelist = $whitelist; $this->cache = $cache; + + // This is used as base class by the new class, so we do not trigger + // deprecation notices when that or any child class is instantiated. + $new_class = 'Drupal\path_alias\AliasManager'; + if (!is_a($this, $new_class) && class_exists($new_class)) { + @trigger_error('The \\' . __CLASS__ . ' class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \\' . $new_class . '. See https://drupal.org/node/3092086', E_USER_DEPRECATED); + + // Despite being two different services, hence two different class + // instances, both the new and the legacy alias managers need to share the + // same internal state to keep the path/alias lookup optimizations + // working. + try { + $alias_manager = \Drupal::service('path_alias.manager'); + if ($alias_manager instanceof $new_class) { + $synced_properties = ['cacheKey', 'langcodePreloaded', 'lookupMap', 'noAlias', 'noPath', 'preloadedPathLookups']; + foreach ($synced_properties as $property) { + $this->{$property} = &$alias_manager->{$property}; + } + } + } + catch (ServiceCircularReferenceException $e) { + // This may happen during installation when "path_alias" has not swapped + // the alias manager class yet. Nothing to do in this case. + } + } } /** diff --git a/core/lib/Drupal/Core/Path/AliasManagerInterface.php b/core/lib/Drupal/Core/Path/AliasManagerInterface.php index 6ede000e4196..0684223176d7 100644 --- a/core/lib/Drupal/Core/Path/AliasManagerInterface.php +++ b/core/lib/Drupal/Core/Path/AliasManagerInterface.php @@ -4,6 +4,11 @@ /** * Find an alias for a path and vice versa. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. + * Use \Drupal\path_alias\AliasManagerInterface. + * + * @see https://www.drupal.org/node/3092086 */ interface AliasManagerInterface { diff --git a/core/lib/Drupal/Core/Path/AliasRepository.php b/core/lib/Drupal/Core/Path/AliasRepository.php index dbb14d800ca2..7c28161fdfc0 100644 --- a/core/lib/Drupal/Core/Path/AliasRepository.php +++ b/core/lib/Drupal/Core/Path/AliasRepository.php @@ -9,6 +9,11 @@ /** * Provides the default path alias lookup operations. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. + * Use \Drupal\path_alias\AliasRepository. + * + * @see https://www.drupal.org/node/3092086 */ class AliasRepository implements AliasRepositoryInterface { @@ -27,6 +32,13 @@ class AliasRepository implements AliasRepositoryInterface { */ public function __construct(Connection $connection) { $this->connection = $connection; + + // This is used as base class by the new class, so we do not trigger + // deprecation notices when that or any child class is instantiated. + $new_class = 'Drupal\path_alias\AliasRepository'; + if (!is_a($this, $new_class) && class_exists($new_class)) { + @trigger_error('The \\' . __CLASS__ . ' class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \\' . $new_class . '. See https://drupal.org/node/3092086', E_USER_DEPRECATED); + } } /** diff --git a/core/lib/Drupal/Core/Path/AliasRepositoryInterface.php b/core/lib/Drupal/Core/Path/AliasRepositoryInterface.php index 15febd495b14..2c8947d6c361 100644 --- a/core/lib/Drupal/Core/Path/AliasRepositoryInterface.php +++ b/core/lib/Drupal/Core/Path/AliasRepositoryInterface.php @@ -5,15 +5,10 @@ /** * Provides an interface for path alias lookup operations. * - * The path alias repository service is only used internally in order to - * optimize alias lookup queries needed in the critical path of each request. - * However, it is not marked as an internal service because alternative storage - * backends still need to override it if they provide a different storage class - * for the PathAlias entity type. + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. + * Use \Drupal\path_alias\AliasRepositoryInterface. * - * Whenever you need to determine whether an alias exists for a system path, or - * whether a system path has an alias, the 'path.alias_manager' service should - * be used instead. + * @see https://www.drupal.org/node/3092086 */ interface AliasRepositoryInterface { diff --git a/core/lib/Drupal/Core/Path/AliasStorage.php b/core/lib/Drupal/Core/Path/AliasStorage.php index b0dfb5bc9b66..d61860e9b97e 100644 --- a/core/lib/Drupal/Core/Path/AliasStorage.php +++ b/core/lib/Drupal/Core/Path/AliasStorage.php @@ -9,7 +9,7 @@ use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageInterface; -@trigger_error('\Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.', E_USER_DEPRECATED); +@trigger_error('\Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.', E_USER_DEPRECATED); /** * Provides a class for CRUD operations on path aliases. @@ -19,7 +19,7 @@ * the same, and will both refer to the same internal system path. * * @deprecated \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and - * is removed from drupal:9.0.0. Use the "path.alias_repository" service + * is removed from drupal:9.0.0. Use the "path_alias.repository" service * instead, or the entity storage handler for the "path_alias" entity type * for CRUD methods. * @@ -82,7 +82,7 @@ public function save($source, $alias, $langcode = LanguageInterface::LANGCODE_NO } if ($pid) { - /** @var \Drupal\Core\Path\PathAliasInterface $path_alias */ + /** @var \Drupal\path_alias\PathAliasInterface $path_alias */ $path_alias = $this->getPathAliasEntityStorage()->load($pid); $original_values = [ 'source' => $path_alias->getPath(), @@ -142,7 +142,7 @@ public function load($conditions) { ->execute(); $entities = $this->getPathAliasEntityStorage()->loadMultiple($result); - /** @var \Drupal\Core\Path\PathAliasInterface $path_alias */ + /** @var \Drupal\path_alias\PathAliasInterface $path_alias */ $path_alias = reset($entities); if ($path_alias) { return [ @@ -326,6 +326,10 @@ public function getAliasesForAdminListing($header, $keys = NULL) { * {@inheritdoc} */ public function pathHasMatchingAlias($initial_substring) { + if (!$this->moduleHandler->moduleExists('path_alias')) { + return FALSE; + } + $query = $this->getBaseQuery(); $query->addExpression(1); diff --git a/core/lib/Drupal/Core/Path/AliasStorageInterface.php b/core/lib/Drupal/Core/Path/AliasStorageInterface.php index 24a7c627b14a..3191faef4d73 100644 --- a/core/lib/Drupal/Core/Path/AliasStorageInterface.php +++ b/core/lib/Drupal/Core/Path/AliasStorageInterface.php @@ -8,7 +8,7 @@ * Provides a class for CRUD operations on path aliases. * * @deprecated \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and - * is removed from drupal:9.0.0. Use the "path.alias_repository" service + * is removed from drupal:9.0.0. Use the "path_alias.repository" service * instead, or the entity storage handler for the "path_alias" entity type * for CRUD methods. * diff --git a/core/lib/Drupal/Core/Path/AliasWhitelist.php b/core/lib/Drupal/Core/Path/AliasWhitelist.php index 48b736280c50..ff6c193f67de 100644 --- a/core/lib/Drupal/Core/Path/AliasWhitelist.php +++ b/core/lib/Drupal/Core/Path/AliasWhitelist.php @@ -10,6 +10,11 @@ /** * Extends CacheCollector to build the path alias whitelist over time. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. + * Use \Drupal\path_alias\AliasWhitelist. + * + * @see https://www.drupal.org/node/3092086 */ class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface { @@ -54,9 +59,16 @@ public function __construct($cid, CacheBackendInterface $cache, LockBackendInter if (!$alias_repository instanceof AliasRepositoryInterface) { @trigger_error('Passing the path.alias_storage service to AliasWhitelist::__construct() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Pass the new dependencies instead. See https://www.drupal.org/node/3013865.', E_USER_DEPRECATED); - $alias_repository = \Drupal::service('path.alias_repository'); + $alias_repository = \Drupal::service('path_alias.repository'); } $this->pathAliasRepository = $alias_repository; + + // This is used as base class by the new class, so we do not trigger + // deprecation notices when that or any child class is instantiated. + $new_class = 'Drupal\path_alias\AliasWhitelist'; + if (!is_a($this, $new_class) && class_exists($new_class)) { + @trigger_error('The \\' . __CLASS__ . ' class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \\' . $new_class . '. See https://drupal.org/node/3092086', E_USER_DEPRECATED); + } } /** diff --git a/core/lib/Drupal/Core/Path/AliasWhitelistInterface.php b/core/lib/Drupal/Core/Path/AliasWhitelistInterface.php index ca2cf6300e0b..76ed7c36ce47 100644 --- a/core/lib/Drupal/Core/Path/AliasWhitelistInterface.php +++ b/core/lib/Drupal/Core/Path/AliasWhitelistInterface.php @@ -7,9 +7,9 @@ /** * Cache the alias whitelist. * - * The whitelist contains the first element of the router paths of all - * aliases. For example, if /node/12345 has an alias then "node" is added to - * the whitelist. This optimization allows skipping the lookup for every - * /user/{user} path if "user" is not in the whitelist. + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. + * Use \Drupal\path_alias\AliasWhitelistInterface. + * + * @see https://www.drupal.org/node/3092086 */ interface AliasWhitelistInterface extends CacheCollectorInterface {} diff --git a/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/UniquePathAliasConstraintValidator.php b/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/UniquePathAliasConstraintValidator.php index 2e95cc8653bf..ba4a785eeb10 100644 --- a/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/UniquePathAliasConstraintValidator.php +++ b/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/UniquePathAliasConstraintValidator.php @@ -43,7 +43,7 @@ public static function create(ContainerInterface $container) { * {@inheritdoc} */ public function validate($entity, Constraint $constraint) { - /** @var \Drupal\Core\Path\PathAliasInterface $entity */ + /** @var \Drupal\path_alias\PathAliasInterface $entity */ $path = $entity->getPath(); $alias = $entity->getAlias(); $langcode = $entity->language()->getId(); diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php index d0690fee203d..de7f29c6a70f 100644 --- a/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php +++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php @@ -8,6 +8,11 @@ /** * Processes the inbound path using path alias lookups. + * + * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. + * Use \Drupal\path_alias\PathProcessor\AliasPathProcessor. + * + * @see https://www.drupal.org/node/3092086 */ class PathProcessorAlias implements InboundPathProcessorInterface, OutboundPathProcessorInterface { @@ -26,6 +31,13 @@ class PathProcessorAlias implements InboundPathProcessorInterface, OutboundPathP */ public function __construct(AliasManagerInterface $alias_manager) { $this->aliasManager = $alias_manager; + + // This is used as base class by the new class, so we do not trigger + // deprecation notices when that or any child class is instantiated. + $new_class = 'Drupal\path_alias\PathProcessor\AliasPathProcessor'; + if (!is_a($this, $new_class) && class_exists($new_class)) { + @trigger_error('The \\' . __CLASS__ . ' class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \\' . $new_class . '. See https://drupal.org/node/3092086', E_USER_DEPRECATED); + } } /** diff --git a/core/lib/Drupal/Core/Routing/RouteProvider.php b/core/lib/Drupal/Core/Routing/RouteProvider.php index c6355508124e..627aa506cdf1 100644 --- a/core/lib/Drupal/Core/Routing/RouteProvider.php +++ b/core/lib/Drupal/Core/Routing/RouteProvider.php @@ -490,8 +490,8 @@ protected function getRouteCollectionCacheId(Request $request) { */ protected function getCurrentLanguageCacheIdPart() { // This must be in sync with the language logic in - // \Drupal\Core\PathProcessor\PathProcessorAlias::processInbound() and - // \Drupal\Core\Path\AliasManager::getPathByAlias(). + // \Drupal\path_alias\PathProcessor\AliasPathProcessor::processInbound() and + // \Drupal\path_alias\AliasManager::getPathByAlias(). // @todo Update this if necessary in https://www.drupal.org/node/1125428. return $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId(); } diff --git a/core/lib/Drupal/Core/Update/UpdateServiceProvider.php b/core/lib/Drupal/Core/Update/UpdateServiceProvider.php index e26b019470a5..c663e9ae64a3 100644 --- a/core/lib/Drupal/Core/Update/UpdateServiceProvider.php +++ b/core/lib/Drupal/Core/Update/UpdateServiceProvider.php @@ -41,8 +41,8 @@ public function alter(ContainerBuilder $container) { // manager. We do this by removing the tags that the compiler pass looks // for. This means that the URL generator can safely be used during the // database update process. - if ($container->hasDefinition('path_processor_alias')) { - $container->getDefinition('path_processor_alias') + if ($container->hasDefinition('path_alias.path_processor')) { + $container->getDefinition('path_alias.path_processor') ->clearTag('path_processor_inbound') ->clearTag('path_processor_outbound'); } diff --git a/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockContentTranslationTest.php b/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockContentTranslationTest.php index db255d79f8a8..be66745fdbf4 100644 --- a/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockContentTranslationTest.php +++ b/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockContentTranslationTest.php @@ -24,6 +24,7 @@ class MigrateBlockContentTranslationTest extends MigrateDrupal6TestBase { 'block_content', 'content_translation', 'language', + 'path_alias', 'statistics', 'taxonomy', // Required for translation migrations. diff --git a/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockTest.php b/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockTest.php index 6ea998b0c9ea..2e3e55ee37b5 100644 --- a/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockTest.php +++ b/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockTest.php @@ -26,6 +26,7 @@ class MigrateBlockTest extends MigrateDrupal6TestBase { 'aggregator', 'book', 'forum', + 'path_alias', 'statistics', ]; diff --git a/core/modules/block/tests/src/Kernel/Migrate/d7/MigrateBlockContentTranslationTest.php b/core/modules/block/tests/src/Kernel/Migrate/d7/MigrateBlockContentTranslationTest.php index 3201d02b1642..cb24a69ab395 100644 --- a/core/modules/block/tests/src/Kernel/Migrate/d7/MigrateBlockContentTranslationTest.php +++ b/core/modules/block/tests/src/Kernel/Migrate/d7/MigrateBlockContentTranslationTest.php @@ -28,6 +28,7 @@ class MigrateBlockContentTranslationTest extends MigrateDrupal7TestBase { 'config_translation', 'content_translation', 'language', + 'path_alias', 'statistics', 'taxonomy', // Required for translation migrations. diff --git a/core/modules/block/tests/src/Kernel/Migrate/d7/MigrateBlockTest.php b/core/modules/block/tests/src/Kernel/Migrate/d7/MigrateBlockTest.php index 929854165a3c..fca92af331e4 100644 --- a/core/modules/block/tests/src/Kernel/Migrate/d7/MigrateBlockTest.php +++ b/core/modules/block/tests/src/Kernel/Migrate/d7/MigrateBlockTest.php @@ -25,6 +25,7 @@ class MigrateBlockTest extends MigrateDrupal7TestBase { 'node', 'text', 'filter', + 'path_alias', 'user', ]; diff --git a/core/modules/config/tests/src/Functional/ConfigImportAllTest.php b/core/modules/config/tests/src/Functional/ConfigImportAllTest.php index 07d00def17db..548a27c4c057 100644 --- a/core/modules/config/tests/src/Functional/ConfigImportAllTest.php +++ b/core/modules/config/tests/src/Functional/ConfigImportAllTest.php @@ -90,7 +90,7 @@ public function testInstallUninstall() { // Ensure that only core required modules and the install profile can not be uninstalled. $validation_reasons = \Drupal::service('module_installer')->validateUninstall(array_keys($all_modules)); - $this->assertEquals(['system', 'user', 'standard'], array_keys($validation_reasons)); + $this->assertEquals(['path_alias', 'system', 'user', 'standard'], array_keys($validation_reasons)); $modules_to_uninstall = array_filter($all_modules, function ($module) use ($validation_reasons) { // Filter required and not enabled modules. diff --git a/core/modules/jsonapi/tests/src/Functional/PathAliasTest.php b/core/modules/jsonapi/tests/src/Functional/PathAliasTest.php index 745f85f84084..3b80c5f06956 100644 --- a/core/modules/jsonapi/tests/src/Functional/PathAliasTest.php +++ b/core/modules/jsonapi/tests/src/Functional/PathAliasTest.php @@ -2,7 +2,7 @@ namespace Drupal\Tests\jsonapi\Functional; -use Drupal\Core\Path\Entity\PathAlias; +use Drupal\path_alias\Entity\PathAlias; use Drupal\Core\Url; /** diff --git a/core/modules/menu_link_content/menu_link_content.module b/core/modules/menu_link_content/menu_link_content.module index 48dafd76d38f..def0ed9db0e7 100644 --- a/core/modules/menu_link_content/menu_link_content.module +++ b/core/modules/menu_link_content/menu_link_content.module @@ -7,7 +7,7 @@ use Drupal\Core\Url; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Path\PathAliasInterface; +use Drupal\path_alias\PathAliasInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\system\MenuInterface; diff --git a/core/modules/menu_link_content/tests/src/Kernel/PathAliasMenuLinkContentTest.php b/core/modules/menu_link_content/tests/src/Kernel/PathAliasMenuLinkContentTest.php index a00bbd183811..7980de976591 100644 --- a/core/modules/menu_link_content/tests/src/Kernel/PathAliasMenuLinkContentTest.php +++ b/core/modules/menu_link_content/tests/src/Kernel/PathAliasMenuLinkContentTest.php @@ -21,7 +21,7 @@ class PathAliasMenuLinkContentTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['menu_link_content', 'system', 'link', 'test_page_test', 'user']; + public static $modules = ['menu_link_content', 'system', 'link', 'path_alias', 'test_page_test', 'user']; /** * {@inheritdoc} @@ -44,7 +44,7 @@ protected function setUp() { public function register(ContainerBuilder $container) { parent::register($container); - $definition = $container->getDefinition('path_processor_alias'); + $definition = $container->getDefinition('path_alias.path_processor'); $definition ->addTag('path_processor_inbound', ['priority' => 100]); } diff --git a/core/modules/path/config/optional/language.content_settings.path_alias.path_alias.yml b/core/modules/path/config/optional/language.content_settings.path_alias.path_alias.yml index e7c75a72a8e3..daacf92e0783 100644 --- a/core/modules/path/config/optional/language.content_settings.path_alias.path_alias.yml +++ b/core/modules/path/config/optional/language.content_settings.path_alias.path_alias.yml @@ -1,6 +1,8 @@ langcode: en status: true -dependencies: { } +dependencies: + module: + - path_alias id: path_alias.path_alias target_entity_type_id: path_alias target_bundle: path_alias diff --git a/core/modules/path/path.info.yml b/core/modules/path/path.info.yml index 2c3f23fcb508..f0b3aec706ab 100644 --- a/core/modules/path/path.info.yml +++ b/core/modules/path/path.info.yml @@ -4,3 +4,5 @@ description: 'Allows users to rename URLs.' package: Core version: VERSION configure: entity.path_alias.collection +dependencies: + - drupal:path_alias diff --git a/core/modules/path/path.module b/core/modules/path/path.module index 0e7ce166a3a8..40323b0d21d9 100644 --- a/core/modules/path/path.module +++ b/core/modules/path/path.module @@ -47,15 +47,19 @@ function path_help($route_name, RouteMatchInterface $route_match) { * Implements hook_entity_type_alter(). */ function path_entity_type_alter(array &$entity_types) { + // @todo Remove the conditional once core fully supports "path_alias" as an + // optional module. See https://drupal.org/node/3092090. /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ - $entity_types['path_alias']->setFormClass('default', PathAliasForm::class); - $entity_types['path_alias']->setFormClass('delete', ContentEntityDeleteForm::class); - $entity_types['path_alias']->setHandlerClass('route_provider', ['html' => AdminHtmlRouteProvider::class]); - $entity_types['path_alias']->setListBuilderClass(PathAliasListBuilder::class); - $entity_types['path_alias']->setLinkTemplate('collection', '/admin/config/search/path'); - $entity_types['path_alias']->setLinkTemplate('add-form', '/admin/config/search/path/add'); - $entity_types['path_alias']->setLinkTemplate('edit-form', '/admin/config/search/path/edit/{path_alias}'); - $entity_types['path_alias']->setLinkTemplate('delete-form', '/admin/config/search/path/delete/{path_alias}'); + if (isset($entity_types['path_alias'])) { + $entity_types['path_alias']->setFormClass('default', PathAliasForm::class); + $entity_types['path_alias']->setFormClass('delete', ContentEntityDeleteForm::class); + $entity_types['path_alias']->setHandlerClass('route_provider', ['html' => AdminHtmlRouteProvider::class]); + $entity_types['path_alias']->setListBuilderClass(PathAliasListBuilder::class); + $entity_types['path_alias']->setLinkTemplate('collection', '/admin/config/search/path'); + $entity_types['path_alias']->setLinkTemplate('add-form', '/admin/config/search/path/add'); + $entity_types['path_alias']->setLinkTemplate('edit-form', '/admin/config/search/path/edit/{path_alias}'); + $entity_types['path_alias']->setLinkTemplate('delete-form', '/admin/config/search/path/delete/{path_alias}'); + } } /** diff --git a/core/modules/path/src/PathAliasForm.php b/core/modules/path/src/PathAliasForm.php index 6a4430911070..3ce2da6307ad 100644 --- a/core/modules/path/src/PathAliasForm.php +++ b/core/modules/path/src/PathAliasForm.php @@ -15,7 +15,7 @@ class PathAliasForm extends ContentEntityForm { /** * The path_alias entity. * - * @var \Drupal\Core\Path\PathAliasInterface + * @var \Drupal\path_alias\PathAliasInterface */ protected $entity; diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php index bdc20e60aa49..a791d7afeb0a 100644 --- a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php +++ b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php @@ -27,7 +27,7 @@ protected function computeValue() { $entity = $this->getEntity(); if (!$entity->isNew()) { /** @var \Drupal\Core\Path\AliasRepositoryInterface $path_alias_repository */ - $path_alias_repository = \Drupal::service('path.alias_repository'); + $path_alias_repository = \Drupal::service('path_alias.repository'); if ($path_alias = $path_alias_repository->lookupBySystemPath('/' . $entity->toUrl()->getInternalPath(), $this->getLangcode())) { $value = [ diff --git a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php index 3962175b261a..5ddc00902d38 100644 --- a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php +++ b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php @@ -87,7 +87,7 @@ public static function validateFormElement(array &$element, FormStateInterface $ if (!empty($alias)) { $form_state->setValueForElement($element['alias'], $alias); - /** @var \Drupal\Core\Path\PathAliasInterface $path_alias */ + /** @var \Drupal\path_alias\PathAliasInterface $path_alias */ $path_alias = \Drupal::entityTypeManager()->getStorage('path_alias')->create([ 'path' => $element['source']['#value'], 'alias' => $alias, diff --git a/core/modules/path/tests/src/Functional/PathAliasTest.php b/core/modules/path/tests/src/Functional/PathAliasTest.php index 71e5783b9a4f..295430480cd5 100644 --- a/core/modules/path/tests/src/Functional/PathAliasTest.php +++ b/core/modules/path/tests/src/Functional/PathAliasTest.php @@ -326,7 +326,7 @@ public function testNodeAlias() { // Delete the node and check that the path alias is also deleted. $node5->delete(); - $path_alias = \Drupal::service('path.alias_repository')->lookUpBySystemPath('/node/' . $node5->id(), $node5->language()->getId()); + $path_alias = \Drupal::service('path_alias.repository')->lookUpBySystemPath('/node/' . $node5->id(), $node5->language()->getId()); $this->assertFalse($path_alias, 'Alias was successfully deleted when the referenced node was deleted.'); // Create sixth test node. diff --git a/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php b/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php index c38f3d1f89ac..617fe73f0e0a 100644 --- a/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php +++ b/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php @@ -2,7 +2,7 @@ namespace Drupal\Tests\path\Kernel\Migrate\d6; -use Drupal\Core\Path\PathAliasInterface; +use Drupal\path_alias\PathAliasInterface; use Drupal\migrate\Plugin\MigrateIdMapInterface; use Drupal\Core\Database\Database; use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase; @@ -24,6 +24,7 @@ class MigrateUrlAliasTest extends MigrateDrupal6TestBase { 'language', 'content_translation', 'path', + 'path_alias', 'menu_ui', // Required for translation migrations. 'migrate_drupal_multilingual', @@ -57,7 +58,7 @@ protected function setUp() { * The path alias ID. * @param array $conditions * The path conditions. - * @param \Drupal\Core\Path\PathAliasInterface $path_alias + * @param \Drupal\path_alias\PathAliasInterface $path_alias * The path alias. */ private function assertPath($pid, $conditions, PathAliasInterface $path_alias) { diff --git a/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTest.php b/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTest.php index 307e5172f6c8..e776a31f2d4d 100644 --- a/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTest.php +++ b/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTest.php @@ -13,6 +13,7 @@ class MigrateUrlAliasTest extends MigrateUrlAliasTestBase { * {@inheritdoc} */ public static $modules = [ + 'path_alias', 'content_translation', 'migrate_drupal_multilingual', ]; diff --git a/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTestBase.php b/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTestBase.php index 5d9ca426b56a..86a11fe71dfc 100644 --- a/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTestBase.php +++ b/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTestBase.php @@ -22,6 +22,7 @@ abstract class MigrateUrlAliasTestBase extends MigrateDrupal7TestBase { 'menu_ui', 'node', 'path', + 'path_alias', 'text', ]; diff --git a/core/modules/path/tests/src/Kernel/PathItemTest.php b/core/modules/path/tests/src/Kernel/PathItemTest.php index 5a39d698b3f1..3398116d454c 100644 --- a/core/modules/path/tests/src/Kernel/PathItemTest.php +++ b/core/modules/path/tests/src/Kernel/PathItemTest.php @@ -19,7 +19,7 @@ class PathItemTest extends KernelTestBase { * * @var array */ - public static $modules = ['path', 'node', 'user', 'system', 'language', 'content_translation']; + public static $modules = ['path', 'path_alias', 'node', 'user', 'system', 'language', 'content_translation']; /** * {@inheritdoc} @@ -45,7 +45,7 @@ protected function setUp() { */ public function testPathItem() { /** @var \Drupal\Core\Path\AliasRepositoryInterface $alias_repository */ - $alias_repository = \Drupal::service('path.alias_repository'); + $alias_repository = \Drupal::service('path_alias.repository'); $node_storage = \Drupal::entityTypeManager()->getStorage('node'); diff --git a/core/modules/path/tests/src/Kernel/PathLegacyRoutesKernelTest.php b/core/modules/path/tests/src/Kernel/PathLegacyRoutesKernelTest.php index f83ad0bcb49a..3cd8832b7241 100644 --- a/core/modules/path/tests/src/Kernel/PathLegacyRoutesKernelTest.php +++ b/core/modules/path/tests/src/Kernel/PathLegacyRoutesKernelTest.php @@ -16,7 +16,7 @@ class PathLegacyRoutesKernelTest extends KernelTestBase { /** * {@inheritdoc} */ - protected static $modules = ['path']; + protected static $modules = ['path', 'path_alias']; /** * @expectedDeprecation The 'path.admin_add' route is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the 'entity.path_alias.add_form' route instead. See https://www.drupal.org/node/3013865 diff --git a/core/modules/path_alias/path_alias.info.yml b/core/modules/path_alias/path_alias.info.yml new file mode 100644 index 000000000000..76bdd35a48e8 --- /dev/null +++ b/core/modules/path_alias/path_alias.info.yml @@ -0,0 +1,7 @@ +name: Path alias +type: module +description: 'Provides the API allowing to rename URLs.' +package: Core +version: VERSION +required: true +hidden: true diff --git a/core/modules/path_alias/src/AliasManager.php b/core/modules/path_alias/src/AliasManager.php new file mode 100644 index 000000000000..a169b402babb --- /dev/null +++ b/core/modules/path_alias/src/AliasManager.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\path_alias; + +use Drupal\Core\Path\AliasManager as CoreAliasManager; + +/** + * The default alias manager implementation. + */ +class AliasManager extends CoreAliasManager implements AliasManagerInterface {} diff --git a/core/modules/path_alias/src/AliasManagerInterface.php b/core/modules/path_alias/src/AliasManagerInterface.php new file mode 100644 index 000000000000..6d6e1f4be1f0 --- /dev/null +++ b/core/modules/path_alias/src/AliasManagerInterface.php @@ -0,0 +1,12 @@ +<?php + +namespace Drupal\path_alias; + +use Drupal\Core\Path\AliasManagerInterface as CoreAliasManagerInterface; + +/** + * Find an alias for a path and vice versa. + * + * @see \Drupal\Core\Path\AliasStorageInterface + */ +interface AliasManagerInterface extends CoreAliasManagerInterface {} diff --git a/core/modules/path_alias/src/AliasRepository.php b/core/modules/path_alias/src/AliasRepository.php new file mode 100644 index 000000000000..d99d375847fd --- /dev/null +++ b/core/modules/path_alias/src/AliasRepository.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\path_alias; + +use Drupal\Core\Path\AliasRepository as CoreAliasRepository; + +/** + * Provides the default path alias lookup operations. + */ +class AliasRepository extends CoreAliasRepository implements AliasRepositoryInterface {} diff --git a/core/modules/path_alias/src/AliasRepositoryInterface.php b/core/modules/path_alias/src/AliasRepositoryInterface.php new file mode 100644 index 000000000000..ed92c597ebcc --- /dev/null +++ b/core/modules/path_alias/src/AliasRepositoryInterface.php @@ -0,0 +1,20 @@ +<?php + +namespace Drupal\path_alias; + +use Drupal\Core\Path\AliasRepositoryInterface as CoreAliasRepositoryInterface; + +/** + * Provides an interface for path alias lookup operations. + * + * The path alias repository service is only used internally in order to + * optimize alias lookup queries needed in the critical path of each request. + * However, it is not marked as an internal service because alternative storage + * backends still need to override it if they provide a different storage class + * for the PathAlias entity type. + * + * Whenever you need to determine whether an alias exists for a system path, or + * whether a system path has an alias, the 'path_alias.manager' service should + * be used instead. + */ +interface AliasRepositoryInterface extends CoreAliasRepositoryInterface {} diff --git a/core/modules/path_alias/src/AliasWhitelist.php b/core/modules/path_alias/src/AliasWhitelist.php new file mode 100644 index 000000000000..574492a04221 --- /dev/null +++ b/core/modules/path_alias/src/AliasWhitelist.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\path_alias; + +use Drupal\Core\Path\AliasWhitelist as CoreAliasWhitelist; + +/** + * Extends CacheCollector to build the path alias whitelist over time. + */ +class AliasWhitelist extends CoreAliasWhitelist implements AliasWhitelistInterface {} diff --git a/core/modules/path_alias/src/AliasWhitelistInterface.php b/core/modules/path_alias/src/AliasWhitelistInterface.php new file mode 100644 index 000000000000..841f1cec02da --- /dev/null +++ b/core/modules/path_alias/src/AliasWhitelistInterface.php @@ -0,0 +1,15 @@ +<?php + +namespace Drupal\path_alias; + +use Drupal\Core\Path\AliasWhitelistInterface as CoreAliasWhitelistInterface; + +/** + * Cache the alias whitelist. + * + * The whitelist contains the first element of the router paths of all + * aliases. For example, if /node/12345 has an alias then "node" is added to + * the whitelist. This optimization allows skipping the lookup for every + * /user/{user} path if "user" is not in the whitelist. + */ +interface AliasWhitelistInterface extends CoreAliasWhitelistInterface {} diff --git a/core/lib/Drupal/Core/Path/Entity/PathAlias.php b/core/modules/path_alias/src/Entity/PathAlias.php similarity index 95% rename from core/lib/Drupal/Core/Path/Entity/PathAlias.php rename to core/modules/path_alias/src/Entity/PathAlias.php index 4e29120f7a44..209d160d5460 100644 --- a/core/lib/Drupal/Core/Path/Entity/PathAlias.php +++ b/core/modules/path_alias/src/Entity/PathAlias.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\Core\Path\Entity; +namespace Drupal\path_alias\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityPublishedTrait; @@ -9,7 +9,7 @@ use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; -use Drupal\Core\Path\PathAliasInterface; +use Drupal\path_alias\PathAliasInterface; /** * Defines the path_alias entity class. @@ -25,8 +25,8 @@ * plural = "@count URL aliases" * ), * handlers = { - * "storage" = "Drupal\Core\Path\PathAliasStorage", - * "storage_schema" = "Drupal\Core\Path\PathAliasStorageSchema", + * "storage" = "Drupal\path_alias\PathAliasStorage", + * "storage_schema" = "Drupal\path_alias\PathAliasStorageSchema", * }, * base_table = "path_alias", * revision_table = "path_alias_revision", diff --git a/core/modules/path_alias/src/EventSubscriber/PathAliasSubscriber.php b/core/modules/path_alias/src/EventSubscriber/PathAliasSubscriber.php new file mode 100644 index 000000000000..986448cb00bc --- /dev/null +++ b/core/modules/path_alias/src/EventSubscriber/PathAliasSubscriber.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\path_alias\EventSubscriber; + +use Drupal\Core\EventSubscriber\PathSubscriber; + +/** + * Provides a path subscriber that converts path aliases. + */ +class PathAliasSubscriber extends PathSubscriber {} diff --git a/core/lib/Drupal/Core/Path/PathAliasInterface.php b/core/modules/path_alias/src/PathAliasInterface.php similarity index 96% rename from core/lib/Drupal/Core/Path/PathAliasInterface.php rename to core/modules/path_alias/src/PathAliasInterface.php index b6f5c3b0f776..8c3371c313ab 100644 --- a/core/lib/Drupal/Core/Path/PathAliasInterface.php +++ b/core/modules/path_alias/src/PathAliasInterface.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\Core\Path; +namespace Drupal\path_alias; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityPublishedInterface; diff --git a/core/modules/path_alias/src/PathAliasServiceProvider.php b/core/modules/path_alias/src/PathAliasServiceProvider.php new file mode 100644 index 000000000000..f35853220a99 --- /dev/null +++ b/core/modules/path_alias/src/PathAliasServiceProvider.php @@ -0,0 +1,79 @@ +<?php + +namespace Drupal\path_alias; + +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\DependencyInjection\ServiceModifierInterface; +use Drupal\Core\EventSubscriber\PathSubscriber; +use Drupal\Core\Path\AliasManager as CoreAliasManager; +use Drupal\Core\Path\AliasRepository as CoreAliasRepository; +use Drupal\Core\Path\AliasWhitelist as CoreAliasWhitelist; +use Drupal\Core\PathProcessor\PathProcessorAlias; +use Drupal\path_alias\EventSubscriber\PathAliasSubscriber; +use Drupal\path_alias\PathProcessor\AliasPathProcessor; + +/** + * Path Alias service provider. + * + * Updates core path alias service definitions to use the new classes provided + * by "path_alias" and marks the old ones as deprecated. The "path_alias.*" + * services defined in "core.services.yml" will bridge the gap. + * + * @see https://www.drupal.org/node/3092086 + * + * @todo Remove this once core fully supports "path_alias" as an optional + * module. See https://www.drupal.org/node/3092090. + */ +class PathAliasServiceProvider implements ServiceModifierInterface { + + /** + * {@inheritdoc} + */ + public function alter(ContainerBuilder $container) { + $service_map = [ + 'path_subscriber' => [ + 'class' => PathAliasSubscriber::class, + 'core_class' => PathSubscriber::class, + 'new_service' => 'path_alias.subscriber', + ], + 'path_processor_alias' => [ + 'class' => AliasPathProcessor::class, + 'core_class' => PathProcessorAlias::class, + 'new_service' => 'path_alias.path_processor', + ], + 'path.alias_manager' => [ + 'class' => AliasManager::class, + 'core_class' => CoreAliasManager::class, + 'new_service' => 'path_alias.manager', + ], + 'path.alias_whitelist' => [ + 'class' => AliasWhitelist::class, + 'core_class' => CoreAliasWhitelist::class, + 'new_service' => 'path_alias.whitelist', + ], + 'path_alias.repository' => [ + 'class' => AliasRepository::class, + 'core_class' => CoreAliasRepository::class, + 'new_service' => 'path_alias.repository', + ], + ]; + + // Replace services only if core classes are implementing them to avoid + // overriding customizations not relying on decoration. + foreach ($service_map as $id => $info) { + // Mark legacy services as "deprecated". + $definition = $id !== $info['new_service'] && $container->hasDefinition($id) ? $container->getDefinition($id) : NULL; + if ($definition && $definition->getClass() === $info['core_class']) { + $definition->setDeprecated(TRUE, 'The "%service_id%" service is deprecated. Use "' . $info['new_service'] . '" instead. See https://drupal.org/node/3092086'); + } + // Also the new service's class is initially set to the legacy one, to + // avoid errors when the "path_alias" module is not enabled yet. Here we + // need to replace that as well. + $definition = $container->getDefinition($info['new_service']); + if ($definition && $definition->getClass() === $info['core_class']) { + $definition->setClass($info['class']); + } + } + } + +} diff --git a/core/lib/Drupal/Core/Path/PathAliasStorage.php b/core/modules/path_alias/src/PathAliasStorage.php similarity index 98% rename from core/lib/Drupal/Core/Path/PathAliasStorage.php rename to core/modules/path_alias/src/PathAliasStorage.php index ed765accbcd4..e3a936ed79cf 100644 --- a/core/lib/Drupal/Core/Path/PathAliasStorage.php +++ b/core/modules/path_alias/src/PathAliasStorage.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\Core\Path; +namespace Drupal\path_alias; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; diff --git a/core/lib/Drupal/Core/Path/PathAliasStorageSchema.php b/core/modules/path_alias/src/PathAliasStorageSchema.php similarity index 95% rename from core/lib/Drupal/Core/Path/PathAliasStorageSchema.php rename to core/modules/path_alias/src/PathAliasStorageSchema.php index c79e2c77f0f1..53acc85c7238 100644 --- a/core/lib/Drupal/Core/Path/PathAliasStorageSchema.php +++ b/core/modules/path_alias/src/PathAliasStorageSchema.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\Core\Path; +namespace Drupal\path_alias; use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; diff --git a/core/modules/path_alias/src/PathProcessor/AliasPathProcessor.php b/core/modules/path_alias/src/PathProcessor/AliasPathProcessor.php new file mode 100644 index 000000000000..db43ce619129 --- /dev/null +++ b/core/modules/path_alias/src/PathProcessor/AliasPathProcessor.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\path_alias\PathProcessor; + +use Drupal\Core\PathProcessor\PathProcessorAlias; + +/** + * Processes the inbound path using path alias lookups. + */ +class AliasPathProcessor extends PathProcessorAlias {} diff --git a/core/modules/path_alias/tests/modules/path_alias_deprecated_test/path_alias_deprecated_test.info.yml b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/path_alias_deprecated_test.info.yml new file mode 100644 index 000000000000..ca5d78e4daee --- /dev/null +++ b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/path_alias_deprecated_test.info.yml @@ -0,0 +1,5 @@ +name: 'Path Alias deprecated test' +type: module +description: 'Support module for testing deprecated functionality for path aliases.' +package: Testing +version: VERSION diff --git a/core/modules/path_alias/tests/modules/path_alias_deprecated_test/path_alias_deprecated_test.services.yml b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/path_alias_deprecated_test.services.yml new file mode 100644 index 000000000000..58112439e44d --- /dev/null +++ b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/path_alias_deprecated_test.services.yml @@ -0,0 +1,5 @@ +services: + path_alias_deprecated_test.path.alias_manager: + class: Drupal\path_alias_deprecated_test\AliasManagerDecorator + decorates: path.alias_manager + arguments: ['@path_alias_deprecated_test.path.alias_manager.inner'] diff --git a/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/AliasManagerDecorator.php b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/AliasManagerDecorator.php new file mode 100644 index 000000000000..c6469a53cd5b --- /dev/null +++ b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/AliasManagerDecorator.php @@ -0,0 +1,50 @@ +<?php + +namespace Drupal\path_alias_deprecated_test; + +use Drupal\Core\Path\AliasManagerInterface; + +/** + * Test alias manager decorator. + */ +class AliasManagerDecorator implements AliasManagerInterface { + + /** + * The decorated alias manager. + * + * @var \Drupal\Core\Path\AliasManagerInterface + */ + protected $aliasManager; + + /** + * AliasManagerDecorator constructor. + * + * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager + * The decorated alias manager. + */ + public function __construct(AliasManagerInterface $alias_manager) { + $this->aliasManager = $alias_manager; + } + + /** + * {@inheritdoc} + */ + public function getPathByAlias($alias, $langcode = NULL) { + $this->aliasManager->getPathByAlias($alias, $langcode); + } + + /** + * {@inheritdoc} + */ + public function getAliasByPath($path, $langcode = NULL) { + return $this->aliasManager->getAliasByPath($path, $langcode); + } + + /** + * {@inheritdoc} + */ + public function cacheClear($source = NULL) { + $this->aliasManager->cacheClear($source); + } + +} diff --git a/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/NewAliasManager.php b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/NewAliasManager.php new file mode 100644 index 000000000000..3adcb0ee9ecc --- /dev/null +++ b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/NewAliasManager.php @@ -0,0 +1,30 @@ +<?php + +namespace Drupal\path_alias_deprecated_test; + +use Drupal\Core\Path\AliasManagerInterface; + +/** + * New test implementation for the alias manager. + */ +class NewAliasManager implements AliasManagerInterface { + + /** + * {@inheritdoc} + */ + public function getPathByAlias($alias, $langcode = NULL) { + } + + /** + * {@inheritdoc} + */ + public function getAliasByPath($path, $langcode = NULL) { + } + + /** + * {@inheritdoc} + */ + public function cacheClear($source = NULL) { + } + +} diff --git a/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/OverriddenAliasManager.php b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/OverriddenAliasManager.php new file mode 100644 index 000000000000..2b37ac729d96 --- /dev/null +++ b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/OverriddenAliasManager.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\path_alias_deprecated_test; + +use Drupal\Core\Path\AliasManager; + +/** + * Overridden test implementation for the alias manager. + */ +class OverriddenAliasManager extends AliasManager {} diff --git a/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/PathAliasDeprecatedTestServiceProvider.php b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/PathAliasDeprecatedTestServiceProvider.php new file mode 100644 index 000000000000..a2477635e90b --- /dev/null +++ b/core/modules/path_alias/tests/modules/path_alias_deprecated_test/src/PathAliasDeprecatedTestServiceProvider.php @@ -0,0 +1,44 @@ +<?php + +namespace Drupal\path_alias_deprecated_test; + +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\DependencyInjection\ServiceModifierInterface; + +/** + * Test service provider to test path alias deprecated services BC logic. + */ +class PathAliasDeprecatedTestServiceProvider implements ServiceModifierInterface { + + /** + * The name of the new implementation class for the alias manager. + * + * @var string + */ + public static $newClass; + + /** + * Whether to use a decorator to wrap the alias manager implementation. + * + * @var bool + */ + public static $useDecorator = FALSE; + + /** + * {@inheritdoc} + */ + public function alter(ContainerBuilder $container) { + if (isset(static::$newClass)) { + $definition = $container->getDefinition('path.alias_manager'); + $definition->setClass(static::$newClass); + } + + if (!static::$useDecorator) { + $decorator_id = 'path_alias_deprecated_test.path.alias_manager'; + if ($container->hasDefinition($decorator_id)) { + $container->removeDefinition($decorator_id); + } + } + } + +} diff --git a/core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonAnonTest.php b/core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonAnonTest.php similarity index 85% rename from core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonAnonTest.php rename to core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonAnonTest.php index 5c8c16c6a896..22e3f441af25 100644 --- a/core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonAnonTest.php +++ b/core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonAnonTest.php @@ -1,11 +1,12 @@ <?php -namespace Drupal\FunctionalTests\Hal; +namespace Drupal\Tests\path_alias\Functional\Hal; use Drupal\Tests\rest\Functional\AnonResourceTestTrait; /** * @group hal + * @group path_alias */ class PathAliasHalJsonAnonTest extends PathAliasHalJsonTestBase { diff --git a/core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonBasicAuthTest.php b/core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonBasicAuthTest.php similarity index 87% rename from core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonBasicAuthTest.php rename to core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonBasicAuthTest.php index 4ab304a91109..634c78970bf0 100644 --- a/core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonBasicAuthTest.php +++ b/core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonBasicAuthTest.php @@ -1,11 +1,12 @@ <?php -namespace Drupal\FunctionalTests\Hal; +namespace Drupal\Tests\path_alias\Functional\Hal; use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait; /** * @group hal + * @group path_alias */ class PathAliasHalJsonBasicAuthTest extends PathAliasHalJsonTestBase { diff --git a/core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonCookieTest.php b/core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonCookieTest.php similarity index 87% rename from core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonCookieTest.php rename to core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonCookieTest.php index df8e3f3972db..746daaeb4b40 100644 --- a/core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonCookieTest.php +++ b/core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonCookieTest.php @@ -1,11 +1,12 @@ <?php -namespace Drupal\FunctionalTests\Hal; +namespace Drupal\Tests\path_alias\Functional\Hal; use Drupal\Tests\rest\Functional\CookieResourceTestTrait; /** * @group hal + * @group path_alias */ class PathAliasHalJsonCookieTest extends PathAliasHalJsonTestBase { diff --git a/core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonTestBase.php b/core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonTestBase.php similarity index 90% rename from core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonTestBase.php rename to core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonTestBase.php index be9ac829558e..1e28291e02b5 100644 --- a/core/tests/Drupal/FunctionalTests/Hal/PathAliasHalJsonTestBase.php +++ b/core/modules/path_alias/tests/src/Functional/Hal/PathAliasHalJsonTestBase.php @@ -1,9 +1,9 @@ <?php -namespace Drupal\FunctionalTests\Hal; +namespace Drupal\Tests\path_alias\Functional\Hal; -use Drupal\FunctionalTests\Rest\PathAliasResourceTestBase; use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait; +use Drupal\Tests\path_alias\Functional\Rest\PathAliasResourceTestBase; /** * Base hal_json test class for the path_alias entity type. diff --git a/core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonAnonTest.php b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonAnonTest.php similarity index 84% rename from core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonAnonTest.php rename to core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonAnonTest.php index 9febf9eadedd..8a5c3a79f91a 100644 --- a/core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonAnonTest.php +++ b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonAnonTest.php @@ -1,13 +1,13 @@ <?php -namespace Drupal\FunctionalTests\Rest; +namespace Drupal\Tests\path_alias\Functional\Rest; use Drupal\Tests\rest\Functional\AnonResourceTestTrait; /** * Test path_alias entities for unauthenticated JSON requests. * - * @group path + * @group path_alias */ class PathAliasJsonAnonTest extends PathAliasResourceTestBase { diff --git a/core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonBasicAuthTest.php b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonBasicAuthTest.php similarity index 88% rename from core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonBasicAuthTest.php rename to core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonBasicAuthTest.php index 9615f42b87a0..b00359e0cd8f 100644 --- a/core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonBasicAuthTest.php +++ b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonBasicAuthTest.php @@ -1,13 +1,13 @@ <?php -namespace Drupal\FunctionalTests\Rest; +namespace Drupal\Tests\path_alias\Functional\Rest; use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait; /** * Test path_alias entities for JSON requests via basic auth. * - * @group path + * @group path_alias */ class PathAliasJsonBasicAuthTest extends PathAliasResourceTestBase { diff --git a/core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonCookieTest.php b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonCookieTest.php similarity index 86% rename from core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonCookieTest.php rename to core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonCookieTest.php index ebf456420a7d..a93723d72f30 100644 --- a/core/tests/Drupal/FunctionalTests/Rest/PathAliasJsonCookieTest.php +++ b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasJsonCookieTest.php @@ -1,13 +1,13 @@ <?php -namespace Drupal\FunctionalTests\Rest; +namespace Drupal\Tests\path_alias\Functional\Rest; use Drupal\Tests\rest\Functional\CookieResourceTestTrait; /** * Test path_alias entities for JSON requests with cookie authentication. * - * @group path + * @group path_alias */ class PathAliasJsonCookieTest extends PathAliasResourceTestBase { diff --git a/core/tests/Drupal/FunctionalTests/Rest/PathAliasResourceTestBase.php b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasResourceTestBase.php similarity index 92% rename from core/tests/Drupal/FunctionalTests/Rest/PathAliasResourceTestBase.php rename to core/modules/path_alias/tests/src/Functional/Rest/PathAliasResourceTestBase.php index 784a0230ea93..78a2399d8135 100644 --- a/core/tests/Drupal/FunctionalTests/Rest/PathAliasResourceTestBase.php +++ b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasResourceTestBase.php @@ -1,9 +1,9 @@ <?php -namespace Drupal\FunctionalTests\Rest; +namespace Drupal\Tests\path_alias\Functional\Rest; use Drupal\Core\Language\LanguageInterface; -use Drupal\Core\Path\Entity\PathAlias; +use Drupal\path_alias\Entity\PathAlias; use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait; use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase; @@ -14,6 +14,11 @@ abstract class PathAliasResourceTestBase extends EntityResourceTestBase { use BcTimestampNormalizerUnixTestTrait; + /** + * {@inheritdoc} + */ + public static $modules = ['path_alias']; + /** * {@inheritdoc} */ diff --git a/core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlAnonTest.php b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlAnonTest.php similarity index 87% rename from core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlAnonTest.php rename to core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlAnonTest.php index e0575a913ea5..0ab6712f1d65 100644 --- a/core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlAnonTest.php +++ b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlAnonTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\FunctionalTests\Rest; +namespace Drupal\Tests\path_alias\Functional\Rest; use Drupal\Tests\rest\Functional\AnonResourceTestTrait; use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait; @@ -8,7 +8,7 @@ /** * Test path_alias entities for unauthenticated XML requests. * - * @group path + * @group path_alias */ class PathAliasXmlAnonTest extends PathAliasResourceTestBase { diff --git a/core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlBasicAuthTest.php b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlBasicAuthTest.php similarity index 90% rename from core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlBasicAuthTest.php rename to core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlBasicAuthTest.php index 8830a9ad6d32..677b5f4d2541 100644 --- a/core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlBasicAuthTest.php +++ b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlBasicAuthTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\FunctionalTests\Rest; +namespace Drupal\Tests\path_alias\Functional\Rest; use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait; use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait; @@ -8,7 +8,7 @@ /** * Test path_alias entities for XML requests with cookie authentication. * - * @group path + * @group path_alias */ class PathAliasXmlBasicAuthTest extends PathAliasResourceTestBase { diff --git a/core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlCookieTest.php b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlCookieTest.php similarity index 88% rename from core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlCookieTest.php rename to core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlCookieTest.php index 11a9b7d3921e..c5fea144785e 100644 --- a/core/tests/Drupal/FunctionalTests/Rest/PathAliasXmlCookieTest.php +++ b/core/modules/path_alias/tests/src/Functional/Rest/PathAliasXmlCookieTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\FunctionalTests\Rest; +namespace Drupal\Tests\path_alias\Functional\Rest; use Drupal\Tests\rest\Functional\CookieResourceTestTrait; use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait; @@ -8,7 +8,7 @@ /** * Test path_alias entities for XML requests. * - * @group path + * @group path_alias */ class PathAliasXmlCookieTest extends PathAliasResourceTestBase { diff --git a/core/modules/system/tests/src/Functional/Path/UrlAlterFunctionalTest.php b/core/modules/path_alias/tests/src/Functional/UrlAlterFunctionalTest.php similarity index 98% rename from core/modules/system/tests/src/Functional/Path/UrlAlterFunctionalTest.php rename to core/modules/path_alias/tests/src/Functional/UrlAlterFunctionalTest.php index 6dc35713362e..58d7079987ae 100644 --- a/core/modules/system/tests/src/Functional/Path/UrlAlterFunctionalTest.php +++ b/core/modules/path_alias/tests/src/Functional/UrlAlterFunctionalTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\Tests\system\Functional\Path; +namespace Drupal\Tests\path_alias\Functional; use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Database\Database; @@ -12,7 +12,7 @@ /** * Tests altering the inbound path and the outbound path. * - * @group path + * @group path_alias */ class UrlAlterFunctionalTest extends BrowserTestBase { diff --git a/core/tests/Drupal/KernelTests/Core/Path/AliasTest.php b/core/modules/path_alias/tests/src/Kernel/AliasTest.php similarity index 93% rename from core/tests/Drupal/KernelTests/Core/Path/AliasTest.php rename to core/modules/path_alias/tests/src/Kernel/AliasTest.php index f37ba98b1eb3..b9c3cc358e01 100644 --- a/core/tests/Drupal/KernelTests/Core/Path/AliasTest.php +++ b/core/modules/path_alias/tests/src/Kernel/AliasTest.php @@ -1,12 +1,12 @@ <?php -namespace Drupal\KernelTests\Core\Path; +namespace Drupal\Tests\path_alias\Kernel; use Drupal\Core\Cache\MemoryCounterBackend; use Drupal\Core\Language\LanguageInterface; -use Drupal\Core\Path\AliasManager; -use Drupal\Core\Path\AliasWhitelist; use Drupal\KernelTests\KernelTestBase; +use Drupal\path_alias\AliasManager; +use Drupal\path_alias\AliasWhitelist; use Drupal\Tests\Traits\Core\PathAliasTestTrait; /** @@ -14,12 +14,17 @@ * * @coversDefaultClass \Drupal\Core\Path\AliasRepository * - * @group path + * @group path_alias */ class AliasTest extends KernelTestBase { use PathAliasTestTrait; + /** + * {@inheritdoc} + */ + protected static $modules = ['path_alias']; + /** * {@inheritdoc} */ @@ -39,7 +44,7 @@ protected function setUp() { public function testLookupBySystemPath() { $this->createPathAlias('/test-source-Case', '/test-alias'); - $path_alias_repository = $this->container->get('path.alias_repository'); + $path_alias_repository = $this->container->get('path_alias.repository'); $this->assertEquals('/test-alias', $path_alias_repository->lookupBySystemPath('/test-source-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['alias']); $this->assertEquals('/test-alias', $path_alias_repository->lookupBySystemPath('/test-source-case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['alias']); } @@ -50,7 +55,7 @@ public function testLookupBySystemPath() { public function testLookupByAlias() { $this->createPathAlias('/test-source', '/test-alias-Case'); - $path_alias_repository = $this->container->get('path.alias_repository'); + $path_alias_repository = $this->container->get('path_alias.repository'); $this->assertEquals('/test-source', $path_alias_repository->lookupByAlias('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['path']); $this->assertEquals('/test-source', $path_alias_repository->lookupByAlias('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['path']); } @@ -112,8 +117,8 @@ public function testWhitelist() { $memoryCounterBackend = new MemoryCounterBackend(); // Create AliasManager and Path object. - $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path.alias_repository')); - $aliasManager = new AliasManager($this->container->get('path.alias_repository'), $whitelist, $this->container->get('language_manager'), $memoryCounterBackend); + $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository')); + $aliasManager = new AliasManager($this->container->get('path_alias.repository'), $whitelist, $this->container->get('language_manager'), $memoryCounterBackend); // No alias for user and admin yet, so should be NULL. $this->assertNull($whitelist->get('user')); @@ -153,7 +158,7 @@ public function testWhitelist() { // Re-initialize the whitelist using the same cache backend, should load // from cache. - $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path.alias_repository')); + $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository')); $this->assertNull($whitelist->get('user')); $this->assertTrue($whitelist->get('admin')); $this->assertNull($whitelist->get($this->randomMachineName())); @@ -173,8 +178,8 @@ public function testWhitelistCacheDeletionMidRequest() { $memoryCounterBackend = new MemoryCounterBackend(); // Create AliasManager and Path object. - $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path.alias_repository')); - $aliasManager = new AliasManager($this->container->get('path.alias_repository'), $whitelist, $this->container->get('language_manager'), $memoryCounterBackend); + $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository')); + $aliasManager = new AliasManager($this->container->get('path_alias.repository'), $whitelist, $this->container->get('language_manager'), $memoryCounterBackend); // Whitelist cache should not exist at all yet. $this->assertFalse($memoryCounterBackend->get('path_alias_whitelist')); @@ -201,7 +206,7 @@ public function testWhitelistCacheDeletionMidRequest() { // Whitelist should load data from its cache, see that it hasn't done a // check for 'user' yet, perform the check, then mark the result to be // persisted to cache. - $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path.alias_repository')); + $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository')); $this->assertTrue($whitelist->get('user')); // Delete the whitelist cache. This could happen from an outside process, diff --git a/core/modules/path_alias/tests/src/Kernel/DeprecatedServicesTest.php b/core/modules/path_alias/tests/src/Kernel/DeprecatedServicesTest.php new file mode 100644 index 000000000000..9e88d8d6a79a --- /dev/null +++ b/core/modules/path_alias/tests/src/Kernel/DeprecatedServicesTest.php @@ -0,0 +1,186 @@ +<?php + +namespace Drupal\Tests\path_alias\Kernel; + +use Drupal\KernelTests\KernelTestBase; +use Drupal\Core\Path\AliasManager as CoreAliasManager; +use Drupal\path_alias\AliasManager; +use Drupal\path_alias\Entity\PathAlias; +use Drupal\path_alias_deprecated_test\AliasManagerDecorator; +use Drupal\path_alias_deprecated_test\NewAliasManager; +use Drupal\path_alias_deprecated_test\OverriddenAliasManager; +use Drupal\path_alias_deprecated_test\PathAliasDeprecatedTestServiceProvider; + +/** + * Tests deprecation of path alias core services and the related BC logic. + * + * @group path_alias + * @group legacy + */ +class DeprecatedServicesTest extends KernelTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = ['path_alias', 'path_alias_deprecated_test']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->installEntitySchema('path_alias'); + } + + /** + * @expectedDeprecation The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086 + */ + public function testAliasManagerDeprecation() { + $this->container->get('path.alias_manager'); + } + + /** + * @expectedDeprecation The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086 + * @expectedDeprecation The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086 + */ + public function testOverriddenServiceImplementation() { + $class = $this->setServiceClass(OverriddenAliasManager::class); + $this->assertServiceClass('path.alias_manager', $class); + $this->assertServiceClass('path_alias.manager', AliasManager::class); + } + + /** + * @expectedDeprecation The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086 + */ + public function testNewServiceImplementation() { + $class = $this->setServiceClass(NewAliasManager::class); + $this->assertServiceClass('path.alias_manager', $class); + $this->assertServiceClass('path_alias.manager', AliasManager::class); + } + + /** + * @expectedDeprecation The "path_alias_deprecated_test.path.alias_manager.inner" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086 + * @expectedDeprecation The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086 + */ + public function testDecoratorForOverriddenServiceImplementation() { + $this->setServiceClass(OverriddenAliasManager::class, TRUE); + $this->assertServiceClass('path.alias_manager', AliasManagerDecorator::class); + $this->assertServiceClass('path_alias.manager', AliasManager::class); + } + + /** + * @expectedDeprecation The "path_alias_deprecated_test.path.alias_manager.inner" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086 + */ + public function testDecoratorForNewServiceImplementation() { + $this->setServiceClass(NewAliasManager::class, TRUE); + $this->assertServiceClass('path.alias_manager', AliasManagerDecorator::class); + $this->assertServiceClass('path_alias.manager', AliasManager::class); + } + + /** + * @expectedDeprecation The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086 + */ + public function testDefaultImplementations() { + $this->assertServiceClass('path.alias_manager', CoreAliasManager::class); + $this->assertServiceClass('path_alias.manager', AliasManager::class); + } + + /** + * No deprecation message expected. + */ + public function testRegularImplementation() { + $this->assertServiceClass('path_alias.manager', AliasManager::class); + } + + /** + * Test that the new alias manager and the legacy ones share the same state. + * + * @expectedDeprecation The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086 + */ + public function testAliasManagerSharedState() { + /** @var \Drupal\Core\Path\AliasManager $legacy_alias_manager */ + $legacy_alias_manager = $this->container->get('path.alias_manager'); + /** @var \Drupal\path_alias\AliasManager $alias_manager */ + $alias_manager = $this->container->get('path_alias.manager'); + + $cache_key = $this->randomMachineName(); + $alias_manager->setCacheKey($cache_key); + $this->assertSharedProperty('preload-paths:' . $cache_key, $legacy_alias_manager, 'cacheKey'); + + $invalid_alias = '/' . $this->randomMachineName(); + $alias_manager->getPathByAlias($invalid_alias); + $this->assertSharedProperty(['en' => [$invalid_alias => TRUE]], $legacy_alias_manager, 'noPath'); + + $this->assertSharedProperty(FALSE, $legacy_alias_manager, 'preloadedPathLookups'); + + /** @var \Drupal\path_alias\Entity\PathAlias $alias */ + $alias = PathAlias::create([ + 'path' => '/' . $this->randomMachineName(), + 'alias' => $invalid_alias . '2', + ]); + $alias->save(); + + $this->assertSharedProperty([], $legacy_alias_manager, 'preloadedPathLookups'); + + /** @var \Drupal\Core\State\StateInterface $state */ + $state = $this->container->get('state'); + $state->set('router.path_roots', [ltrim($alias->getPath(), '/')]); + + $alias_manager->getAliasByPath($alias->getPath()); + $this->assertSharedProperty(['en' => [$alias->getPath() => $alias->getAlias()]], $legacy_alias_manager, 'lookupMap'); + + $invalid_path = $alias->getPath() . '/' . $this->randomMachineName(); + $alias_manager->getAliasByPath($invalid_path); + $this->assertSharedProperty(['en' => [$invalid_path => TRUE]], $legacy_alias_manager, 'noAlias'); + } + + /** + * Asserts that a shared property has the expected value. + * + * @param mixed $expected + * The property expected value. + * @param \Drupal\Core\Path\AliasManager $legacy_alias_manager + * An instance of the legacy alias manager. + * @param string $property + * The property name. + */ + protected function assertSharedProperty($expected, CoreAliasManager $legacy_alias_manager, $property) { + $reflector = new \ReflectionProperty(get_class($legacy_alias_manager), $property); + $reflector->setAccessible(TRUE); + $this->assertSame($expected, $reflector->getValue($legacy_alias_manager)); + } + + /** + * Asserts that the specified service is implemented by the expected class. + * + * @param string $service_id + * A service ID. + * @param string $expected_class + * The name of the expected class. + */ + protected function assertServiceClass($service_id, $expected_class) { + $service = $this->container->get($service_id); + $this->assertSame(get_class($service), $expected_class); + } + + /** + * Sets the specified implementation for the service being tested. + * + * @param string $class + * The name of the implementation class. + * @param bool $use_decorator + * (optional) Whether using a decorator service to wrap the specified class. + * Defaults to no decorator. + * + * @return string + * The specified class name. + */ + protected function setServiceClass($class, $use_decorator = FALSE) { + PathAliasDeprecatedTestServiceProvider::$newClass = $class; + PathAliasDeprecatedTestServiceProvider::$useDecorator = $use_decorator; + $this->container->get('kernel')->rebuildContainer(); + return $class; + } + +} diff --git a/core/modules/system/tests/src/Kernel/PathHooksTest.php b/core/modules/path_alias/tests/src/Kernel/PathHooksTest.php similarity index 88% rename from core/modules/system/tests/src/Kernel/PathHooksTest.php rename to core/modules/path_alias/tests/src/Kernel/PathHooksTest.php index cef1211928de..2a7b86743174 100644 --- a/core/modules/system/tests/src/Kernel/PathHooksTest.php +++ b/core/modules/path_alias/tests/src/Kernel/PathHooksTest.php @@ -1,23 +1,23 @@ <?php -namespace Drupal\Tests\system\Kernel; +namespace Drupal\Tests\path_alias\Kernel; -use Drupal\Core\Path\AliasManagerInterface; -use Drupal\Core\Path\Entity\PathAlias; use Drupal\KernelTests\KernelTestBase; +use Drupal\path_alias\AliasManagerInterface; +use Drupal\path_alias\Entity\PathAlias; use Prophecy\Argument; /** - * @coversDefaultClass \Drupal\Core\Path\Entity\PathAlias + * @coversDefaultClass \Drupal\path_alias\Entity\PathAlias * - * @group path + * @group path_alias */ class PathHooksTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['system']; + public static $modules = ['path_alias']; /** * {@inheritdoc} diff --git a/core/tests/Drupal/Tests/Core/Path/AliasManagerTest.php b/core/modules/path_alias/tests/src/Unit/AliasManagerTest.php similarity index 97% rename from core/tests/Drupal/Tests/Core/Path/AliasManagerTest.php rename to core/modules/path_alias/tests/src/Unit/AliasManagerTest.php index 40d982c7291a..c0b767480eb2 100644 --- a/core/tests/Drupal/Tests/Core/Path/AliasManagerTest.php +++ b/core/modules/path_alias/tests/src/Unit/AliasManagerTest.php @@ -1,23 +1,23 @@ <?php -namespace Drupal\Tests\Core\Path; +namespace Drupal\Tests\path_alias\Unit; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageInterface; -use Drupal\Core\Path\AliasManager; use Drupal\Core\Path\AliasRepositoryInterface; +use Drupal\path_alias\AliasManager; use Drupal\Tests\UnitTestCase; /** - * @coversDefaultClass \Drupal\Core\Path\AliasManager - * @group path + * @coversDefaultClass \Drupal\path_alias\AliasManager + * @group path_alias */ class AliasManagerTest extends UnitTestCase { /** * The alias manager. * - * @var \Drupal\Core\Path\AliasManager + * @var \Drupal\path_alias\AliasManager */ protected $aliasManager; @@ -38,7 +38,7 @@ class AliasManagerTest extends UnitTestCase { /** * Alias whitelist. * - * @var \Drupal\Core\Path\AliasWhitelistInterface|\PHPUnit\Framework\MockObject\MockObject + * @var \Drupal\path_alias\AliasWhitelistInterface|\PHPUnit\Framework\MockObject\MockObject */ protected $aliasWhitelist; @@ -77,7 +77,7 @@ protected function setUp() { parent::setUp(); $this->aliasRepository = $this->createMock(AliasRepositoryInterface::class); - $this->aliasWhitelist = $this->createMock('Drupal\Core\Path\AliasWhitelistInterface'); + $this->aliasWhitelist = $this->createMock('Drupal\path_alias\AliasWhitelistInterface'); $this->languageManager = $this->createMock('Drupal\Core\Language\LanguageManagerInterface'); $this->cache = $this->createMock('Drupal\Core\Cache\CacheBackendInterface'); diff --git a/core/modules/path_alias/tests/src/Unit/DeprecatedClassesTest.php b/core/modules/path_alias/tests/src/Unit/DeprecatedClassesTest.php new file mode 100644 index 000000000000..8ac7df49d366 --- /dev/null +++ b/core/modules/path_alias/tests/src/Unit/DeprecatedClassesTest.php @@ -0,0 +1,170 @@ +<?php + +namespace Drupal\Tests\path_alias\Unit; + +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\EventSubscriber\PathSubscriber; +use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Lock\LockBackendInterface; +use Drupal\Core\Path\AliasManager as CoreAliasManager; +use Drupal\Core\Path\AliasWhitelist as CoreAliasWhitelist; +use Drupal\Core\Path\CurrentPathStack; +use Drupal\Core\PathProcessor\PathProcessorAlias; +use Drupal\Core\State\StateInterface; +use Drupal\path_alias\AliasManager; +use Drupal\path_alias\AliasManagerInterface; +use Drupal\path_alias\AliasRepositoryInterface; +use Drupal\path_alias\AliasWhitelist; +use Drupal\path_alias\AliasWhitelistInterface; +use Drupal\path_alias\EventSubscriber\PathAliasSubscriber; +use Drupal\path_alias\PathProcessor\AliasPathProcessor; +use Drupal\Tests\UnitTestCase; + +/** + * Tests deprecation of path alias core service classes. + * + * @group path_alias + * @group legacy + */ +class DeprecatedClassesTest extends UnitTestCase { + + /** + * @var \Drupal\path_alias\AliasManagerInterface + */ + protected $aliasManager; + + /** + * @var \Drupal\path_alias\AliasRepositoryInterface + */ + protected $aliasRepository; + + /** + * @var \Drupal\path_alias\AliasWhitelistInterface + */ + protected $aliasWhitelist; + + /** + * @var \Drupal\Core\Cache\CacheBackendInterface + */ + protected $cache; + + /** + * @var \Drupal\Core\Path\CurrentPathStack + */ + protected $currentPathStack; + + /** + * @var \Drupal\Core\Language\LanguageManagerInterface + */ + protected $languageManager; + + /** + * @var \Drupal\Core\Lock\LockBackendInterface + */ + protected $lock; + + /** + * @var \Drupal\Core\State\StateInterface + */ + protected $state; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->aliasManager = $this->prophesize(AliasManagerInterface::class) + ->reveal(); + $this->aliasRepository = $this->prophesize(AliasRepositoryInterface::class) + ->reveal(); + $this->aliasWhitelist = $this->prophesize(AliasWhitelistInterface::class) + ->reveal(); + $this->cache = $this->prophesize(CacheBackendInterface::class) + ->reveal(); + $this->currentPathStack = $this->prophesize(CurrentPathStack::class) + ->reveal(); + $this->languageManager = $this->prophesize(LanguageManagerInterface::class) + ->reveal(); + $this->lock = $this->prophesize(LockBackendInterface::class) + ->reveal(); + $this->state = $this->prophesize(StateInterface::class) + ->reveal(); + + /** @var \Prophecy\Prophecy\ObjectProphecy $container */ + $container = $this->prophesize(ContainerBuilder::class); + $container->get('path_alias.manager') + ->willReturn($this->aliasManager); + \Drupal::setContainer($container->reveal()); + } + + /** + * @covers \Drupal\Core\EventSubscriber\PathSubscriber::__construct + * + * @expectedDeprecation The \Drupal\Core\EventSubscriber\PathSubscriber class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\EventSubscriber\PathAliasSubscriber. See https://drupal.org/node/3092086 + */ + public function testPathSubscriber() { + new PathSubscriber($this->aliasManager, $this->currentPathStack); + } + + /** + * @covers \Drupal\path_alias\EventSubscriber\PathAliasSubscriber::__construct + */ + public function testPathAliasSubscriber() { + $object = new PathAliasSubscriber($this->aliasManager, $this->currentPathStack); + $this->assertInstanceOf(PathSubscriber::class, $object); + } + + /** + * @covers \Drupal\Core\PathProcessor\PathProcessorAlias::__construct + * + * @expectedDeprecation The \Drupal\Core\PathProcessor\PathProcessorAlias class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\PathProcessor\AliasPathProcessor. See https://drupal.org/node/3092086 + */ + public function testPathProcessorAlias() { + new PathProcessorAlias($this->aliasManager); + } + + /** + * @covers \Drupal\path_alias\PathProcessor\AliasPathProcessor::__construct + */ + public function testAliasPathProcessor() { + $object = new AliasPathProcessor($this->aliasManager); + $this->assertInstanceOf(PathProcessorAlias::class, $object); + } + + /** + * @covers \Drupal\Core\Path\AliasManager::__construct + * + * @expectedDeprecation The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086 + */ + public function testCoreAliasManager() { + new CoreAliasManager($this->aliasRepository, $this->aliasWhitelist, $this->languageManager, $this->cache); + } + + /** + * @covers \Drupal\path_alias\AliasManager::__construct + */ + public function testAliasManager() { + $object = new AliasManager($this->aliasRepository, $this->aliasWhitelist, $this->languageManager, $this->cache); + $this->assertInstanceOf(CoreAliasManager::class, $object); + } + + /** + * @covers \Drupal\Core\Path\AliasWhitelist::__construct + * + * @expectedDeprecation The \Drupal\Core\Path\AliasWhitelist class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasWhitelist. See https://drupal.org/node/3092086 + */ + public function testCoreAliasWhitelist() { + new CoreAliasWhitelist('path_alias_whitelist', $this->cache, $this->lock, $this->state, $this->aliasRepository); + } + + /** + * @covers \Drupal\path_alias\AliasWhitelist::__construct + */ + public function testAliasWhitelist() { + $object = new AliasWhitelist('path_alias_whitelist', $this->cache, $this->lock, $this->state, $this->aliasRepository); + $this->assertInstanceOf(CoreAliasWhitelist::class, $object); + } + +} diff --git a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php b/core/modules/path_alias/tests/src/Unit/PathProcessor/AliasPathProcessorTest.php similarity index 75% rename from core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php rename to core/modules/path_alias/tests/src/Unit/PathProcessor/AliasPathProcessorTest.php index 8a2a17ecd65e..4f28f64953c9 100644 --- a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php +++ b/core/modules/path_alias/tests/src/Unit/PathProcessor/AliasPathProcessorTest.php @@ -1,42 +1,43 @@ <?php -namespace Drupal\Tests\Core\PathProcessor; +namespace Drupal\Tests\path_alias\Unit\PathProcessor; use Drupal\Core\Cache\Cache; -use Drupal\Core\PathProcessor\PathProcessorAlias; +use Drupal\path_alias\PathProcessor\AliasPathProcessor; use Drupal\Core\Render\BubbleableMetadata; use Drupal\Tests\UnitTestCase; use Symfony\Component\HttpFoundation\Request; /** - * @coversDefaultClass \Drupal\Core\PathProcessor\PathProcessorAlias + * @coversDefaultClass \Drupal\path_alias\PathProcessor\AliasPathProcessor * @group PathProcessor + * @group path_alias */ -class PathProcessorAliasTest extends UnitTestCase { +class AliasPathProcessorTest extends UnitTestCase { /** * The mocked alias manager. * - * @var \Drupal\Core\Path\AliasManagerInterface|\PHPUnit\Framework\MockObject\MockObject + * @var \Drupal\path_alias\AliasManagerInterface|\PHPUnit\Framework\MockObject\MockObject */ protected $aliasManager; /** * The tested path processor. * - * @var \Drupal\Core\PathProcessor\PathProcessorAlias + * @var \Drupal\path_alias\PathProcessor\AliasPathProcessor */ protected $pathProcessor; protected function setUp() { - $this->aliasManager = $this->createMock('Drupal\Core\Path\AliasManagerInterface'); - $this->pathProcessor = new PathProcessorAlias($this->aliasManager); + $this->aliasManager = $this->createMock('Drupal\path_alias\AliasManagerInterface'); + $this->pathProcessor = new AliasPathProcessor($this->aliasManager); } /** * Tests the processInbound method. * - * @see \Drupal\Core\PathProcessor\PathProcessorAlias::processInbound + * @see \Drupal\path_alias\PathProcessor\AliasPathProcessor::processInbound */ public function testProcessInbound() { $this->aliasManager->expects($this->exactly(2)) diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php index b212bc5961e3..1464c023050d 100644 --- a/core/modules/simpletest/src/KernelTestBase.php +++ b/core/modules/simpletest/src/KernelTestBase.php @@ -385,12 +385,12 @@ public function containerBuild(ContainerBuilder $container) { ->addArgument(new Reference('keyvalue')); } - if ($container->hasDefinition('path_processor_alias')) { + if ($container->hasDefinition('path_alias.path_processor')) { // The alias-based processor requires the path_alias entity schema to be // installed, so we prevent it from being registered to the path processor // manager. We do this by removing the tags that the compiler pass looks // for. This means that the URL generator can safely be used within tests. - $definition = $container->getDefinition('path_processor_alias'); + $definition = $container->getDefinition('path_alias.path_processor'); $definition->clearTag('path_processor_inbound')->clearTag('path_processor_outbound'); } diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 82fb06aef937..e0f57178a312 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -13,17 +13,14 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Database\Database; use Drupal\Core\DrupalKernel; -use Drupal\Core\Entity\ContentEntityType; use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Extension\Extension; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\File\FileSystemInterface; -use Drupal\Core\Language\LanguageInterface; -use Drupal\Core\Path\Entity\PathAlias; -use Drupal\Core\Path\PathAliasStorage; -use Drupal\Core\Path\PathAliasStorageSchema; +use Drupal\path_alias\Entity\PathAlias; +use Drupal\path_alias\PathAliasStorage; use Drupal\Core\Site\Settings; use Drupal\Core\StreamWrapper\PrivateStream; use Drupal\Core\StreamWrapper\PublicStream; @@ -2395,71 +2392,9 @@ function system_update_8802() { * Install the 'path_alias' entity type. */ function system_update_8803() { - $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); - if (!$entity_definition_update_manager->getEntityType('path_alias')) { - $entity_type = new ContentEntityType([ - 'id' => 'path_alias', - 'class' => PathAlias::class, - 'label' => new TranslatableMarkup('Path alias'), - 'handlers' => [ - 'storage' => PathAliasStorage::class, - 'storage_schema' => PathAliasStorageSchema::class, - ], - 'base_table' => 'path_alias', - 'revision_table' => 'path_alias_revision', - 'entity_keys' => [ - 'id' => 'id', - 'revision' => 'revision_id', - 'langcode' => 'langcode', - 'uuid' => 'uuid', - 'published' => 'status', - ], - ]); - - $field_storage_definitions['id'] = BaseFieldDefinition::create('integer') - ->setLabel(new TranslatableMarkup('ID')) - ->setReadOnly(TRUE) - ->setSetting('unsigned', TRUE); - - $field_storage_definitions['uuid'] = BaseFieldDefinition::create('uuid') - ->setLabel(new TranslatableMarkup('UUID')) - ->setReadOnly(TRUE); - - $field_storage_definitions['revision_id'] = BaseFieldDefinition::create('integer') - ->setLabel(new TranslatableMarkup('Revision ID')) - ->setReadOnly(TRUE) - ->setSetting('unsigned', TRUE); - - $field_storage_definitions['langcode'] = BaseFieldDefinition::create('language') - ->setLabel(new TranslatableMarkup('Language')) - ->setRevisionable(TRUE) - ->setDefaultValue(LanguageInterface::LANGCODE_NOT_SPECIFIED); - - $field_storage_definitions['revision_default'] = BaseFieldDefinition::create('boolean') - ->setLabel(new TranslatableMarkup('Default revision')) - ->setStorageRequired(TRUE) - ->setInternal(TRUE) - ->setRevisionable(TRUE); - - $field_storage_definitions['status'] = BaseFieldDefinition::create('boolean') - ->setLabel(new TranslatableMarkup('Published')) - ->setRevisionable(TRUE) - ->setDefaultValue(TRUE); - - $field_storage_definitions['path'] = BaseFieldDefinition::create('string') - ->setLabel(new TranslatableMarkup('System path')) - ->setDescription(new TranslatableMarkup('The path that this alias belongs to.')) - ->setRequired(TRUE) - ->setRevisionable(TRUE); - - $field_storage_definitions['alias'] = BaseFieldDefinition::create('string') - ->setLabel(new TranslatableMarkup('Path alias')) - ->setDescription(new TranslatableMarkup('An alias used with this path.')) - ->setRequired(TRUE) - ->setRevisionable(TRUE); - - $entity_definition_update_manager->installFieldableEntityType($entity_type, $field_storage_definitions); - + // Enable the Path Alias module if needed. + if (!\Drupal::moduleHandler()->moduleExists('path_alias')) { + \Drupal::service('module_installer')->install(['path_alias'], FALSE); return t('The "path_alias" entity type has been installed.'); } } @@ -2550,3 +2485,39 @@ function system_update_8804(&$sandbox = NULL) { return t('Path aliases have been converted to entities.'); } } + +/** + * Change the provider of the 'path_alias' entity type and its base fields. + */ +function system_update_8805() { + // If the path alias module is not installed, it means that + // system_update_8803() ran as part of Drupal 8.8.0-alpha1, in which case we + // need to enable the module and change the provider of the 'path_alias' + // entity type. + if (!\Drupal::moduleHandler()->moduleExists('path_alias')) { + \Drupal::service('module_installer')->install(['path_alias'], FALSE); + + /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */ + $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository'); + $entity_type = $last_installed_schema_repository->getLastInstalledDefinition('path_alias'); + + // Set the new class for the entity type. + $entity_type->setClass(PathAlias::class); + + // Set the new provider for the entity type. + $reflection = new ReflectionClass($entity_type); + $property = $reflection->getProperty('provider'); + $property->setAccessible(TRUE); + $property->setValue($entity_type, 'path_alias'); + + $last_installed_schema_repository->setLastInstalledDefinition($entity_type); + + $field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('path_alias'); + foreach ($field_storage_definitions as $field_storage_definition) { + if ($field_storage_definition->isBaseField()) { + $field_storage_definition->setProvider('path_alias'); + $last_installed_schema_repository->setLastInstalledFieldStorageDefinition($field_storage_definition); + } + } + } +} diff --git a/core/modules/system/tests/src/Functional/Update/PathAliasToEntityUpdateTest.php b/core/modules/system/tests/src/Functional/Update/PathAliasToEntityUpdateTest.php index e688faab80d3..0d0a1401b9e7 100644 --- a/core/modules/system/tests/src/Functional/Update/PathAliasToEntityUpdateTest.php +++ b/core/modules/system/tests/src/Functional/Update/PathAliasToEntityUpdateTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\system\Functional\Update; use Drupal\FunctionalTests\Update\UpdatePathTestBase; +use Drupal\path_alias\Entity\PathAlias; /** * Tests the conversion of path aliases to entities. @@ -52,6 +53,23 @@ public function testConversionToEntities() { $this->runUpdates(); + /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */ + $module_handler = $this->container->get('module_handler'); + $this->assertTrue($module_handler->moduleExists('path_alias')); + + $entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('path_alias'); + $this->assertEquals('path_alias', $entity_type->getProvider()); + $this->assertEquals(PathAlias::class, $entity_type->getClass()); + + $field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('path_alias'); + $this->assertEquals('path_alias', $field_storage_definitions['id']->getProvider()); + $this->assertEquals('path_alias', $field_storage_definitions['revision_id']->getProvider()); + $this->assertEquals('path_alias', $field_storage_definitions['langcode']->getProvider()); + $this->assertEquals('path_alias', $field_storage_definitions['uuid']->getProvider()); + $this->assertEquals('path_alias', $field_storage_definitions['status']->getProvider()); + $this->assertEquals('path_alias', $field_storage_definitions['path']->getProvider()); + $this->assertEquals('path_alias', $field_storage_definitions['alias']->getProvider()); + // Check that the 'path_alias' entity tables have been created and the // 'url_alias' table has been deleted. $this->assertTrue($schema->tableExists('path_alias')); diff --git a/core/modules/system/tests/src/Kernel/DeprecatedPathHooksTest.php b/core/modules/system/tests/src/Kernel/DeprecatedPathHooksTest.php index 75f3ae4a7fef..b8969137858e 100644 --- a/core/modules/system/tests/src/Kernel/DeprecatedPathHooksTest.php +++ b/core/modules/system/tests/src/Kernel/DeprecatedPathHooksTest.php @@ -16,7 +16,7 @@ class DeprecatedPathHooksTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['system', 'path_deprecated_test']; + public static $modules = ['system', 'path_alias', 'path_deprecated_test']; /** * {@inheritdoc} diff --git a/core/modules/user/tests/src/Kernel/Views/ArgumentValidateTest.php b/core/modules/user/tests/src/Kernel/Views/ArgumentValidateTest.php index 76bfad7ce4f2..62b49e6ec6aa 100644 --- a/core/modules/user/tests/src/Kernel/Views/ArgumentValidateTest.php +++ b/core/modules/user/tests/src/Kernel/Views/ArgumentValidateTest.php @@ -23,6 +23,7 @@ class ArgumentValidateTest extends ViewsKernelTestBase { */ public static $modules = [ 'node', + 'path_alias', 'user_test_views', ]; diff --git a/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php b/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php index 6d1ee400dd57..3f2cf3bae674 100644 --- a/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php +++ b/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php @@ -28,7 +28,7 @@ abstract class ViewsKernelTestBase extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['system', 'views', 'views_test_config', 'views_test_data', 'user']; + public static $modules = ['path_alias', 'system', 'views', 'views_test_config', 'views_test_data', 'user']; /** * {@inheritdoc} diff --git a/core/modules/workspaces/src/WorkspacesAliasRepository.php b/core/modules/workspaces/src/WorkspacesAliasRepository.php index e1a1e828341f..6230f04f4dee 100644 --- a/core/modules/workspaces/src/WorkspacesAliasRepository.php +++ b/core/modules/workspaces/src/WorkspacesAliasRepository.php @@ -2,7 +2,7 @@ namespace Drupal\workspaces; -use Drupal\Core\Path\AliasRepository; +use Drupal\path_alias\AliasRepository; /** * Provides workspace-specific path alias lookup queries. diff --git a/core/modules/workspaces/src/WorkspacesServiceProvider.php b/core/modules/workspaces/src/WorkspacesServiceProvider.php index 1ed61747aaab..712af5f36858 100644 --- a/core/modules/workspaces/src/WorkspacesServiceProvider.php +++ b/core/modules/workspaces/src/WorkspacesServiceProvider.php @@ -20,8 +20,8 @@ public function alter(ContainerBuilder $container) { $renderer_config['required_cache_contexts'][] = 'workspace'; $container->setParameter('renderer.config', $renderer_config); - // Replace the class of the 'path.alias_repository' service. - $container->getDefinition('path.alias_repository') + // Replace the class of the 'path_alias.repository' service. + $container->getDefinition('path_alias.repository') ->setClass(WorkspacesAliasRepository::class) ->addMethodCall('setWorkspacesManager', [new Reference('workspaces.manager')]); } diff --git a/core/tests/Drupal/KernelTests/Core/Asset/ResolvedLibraryDefinitionsFilesMatchTest.php b/core/tests/Drupal/KernelTests/Core/Asset/ResolvedLibraryDefinitionsFilesMatchTest.php index af0ffd89ed74..ad2c6eaede63 100644 --- a/core/tests/Drupal/KernelTests/Core/Asset/ResolvedLibraryDefinitionsFilesMatchTest.php +++ b/core/tests/Drupal/KernelTests/Core/Asset/ResolvedLibraryDefinitionsFilesMatchTest.php @@ -86,7 +86,7 @@ class ResolvedLibraryDefinitionsFilesMatchTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['system', 'user']; + public static $modules = ['system', 'user', 'path_alias']; /** * {@inheritdoc} @@ -124,6 +124,7 @@ protected function setUp() { $this->allModules = array_keys($all_modules); $this->allModules[] = 'system'; $this->allModules[] = 'user'; + $this->allModules[] = 'path_alias'; sort($this->allModules); $this->container->get('module_installer')->install($this->allModules); diff --git a/core/tests/Drupal/KernelTests/Core/Command/DbDumpTest.php b/core/tests/Drupal/KernelTests/Core/Command/DbDumpTest.php index f0f430e2c8cc..f5f8456848fc 100644 --- a/core/tests/Drupal/KernelTests/Core/Command/DbDumpTest.php +++ b/core/tests/Drupal/KernelTests/Core/Command/DbDumpTest.php @@ -25,7 +25,7 @@ class DbDumpTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['system', 'config', 'dblog', 'menu_link_content', 'link', 'block_content', 'file', 'user']; + public static $modules = ['system', 'config', 'dblog', 'menu_link_content', 'link', 'block_content', 'file', 'path_alias', 'user']; /** * Test data to write into config. diff --git a/core/tests/Drupal/KernelTests/Core/Config/CacheabilityMetadataConfigOverrideTest.php b/core/tests/Drupal/KernelTests/Core/Config/CacheabilityMetadataConfigOverrideTest.php index 7f3e44bb4045..ed9147f09fc0 100644 --- a/core/tests/Drupal/KernelTests/Core/Config/CacheabilityMetadataConfigOverrideTest.php +++ b/core/tests/Drupal/KernelTests/Core/Config/CacheabilityMetadataConfigOverrideTest.php @@ -20,6 +20,7 @@ class CacheabilityMetadataConfigOverrideTest extends KernelTestBase { 'block_content', 'config', 'config_override_test', + 'path_alias', 'system', 'user', ]; diff --git a/core/tests/Drupal/KernelTests/Core/Entity/CreateSampleEntityTest.php b/core/tests/Drupal/KernelTests/Core/Entity/CreateSampleEntityTest.php index 0efc69ef14b7..f4eeec9c0579 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/CreateSampleEntityTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/CreateSampleEntityTest.php @@ -25,7 +25,7 @@ class CreateSampleEntityTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['system', 'field', 'filter', 'text', 'file', 'user', 'node', 'comment', 'taxonomy']; + public static $modules = ['path_alias', 'system', 'field', 'filter', 'text', 'file', 'user', 'node', 'comment', 'taxonomy']; /** * {@inheritdoc} diff --git a/core/tests/Drupal/KernelTests/Core/Path/LegacyAliasStorageTest.php b/core/tests/Drupal/KernelTests/Core/Path/LegacyAliasStorageTest.php index dc15422796f6..aff96fa38305 100644 --- a/core/tests/Drupal/KernelTests/Core/Path/LegacyAliasStorageTest.php +++ b/core/tests/Drupal/KernelTests/Core/Path/LegacyAliasStorageTest.php @@ -15,7 +15,7 @@ class LegacyAliasStorageTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['system']; + public static $modules = ['system', 'path_alias']; /** * @var \Drupal\Core\Path\AliasStorage @@ -34,7 +34,7 @@ protected function setUp() { /** * @covers ::load - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testLoad() { $this->storage->save('/test-source-Case', '/test-alias-Case'); @@ -56,7 +56,7 @@ public function testLoad() { * @covers ::load * @covers ::save * @covers ::delete - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testCRUD() { $entity_storage = \Drupal::entityTypeManager()->getStorage('path_alias'); @@ -148,7 +148,7 @@ protected function sampleUrlAliases() { /** * @covers ::preloadPathAlias - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testPreLoadPathAlias() { $this->storage->save('/test-source-Case', '/test-alias'); @@ -158,7 +158,7 @@ public function testPreLoadPathAlias() { /** * @covers ::lookupPathAlias - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testLookupPathAlias() { $this->storage->save('/test-source-Case', '/test-alias'); @@ -169,7 +169,7 @@ public function testLookupPathAlias() { /** * @covers ::lookupPathSource - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testLookupPathSource() { $this->storage->save('/test-source', '/test-alias-Case'); @@ -180,7 +180,7 @@ public function testLookupPathSource() { /** * @covers ::aliasExists - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testAliasExists() { $this->storage->save('/test-source-Case', '/test-alias-Case'); @@ -191,7 +191,7 @@ public function testAliasExists() { /** * @covers ::languageAliasExists - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testLanguageAliasExists() { $this->assertFalse($this->storage->languageAliasExists()); @@ -202,7 +202,7 @@ public function testLanguageAliasExists() { /** * @covers ::getAliasesForAdminListing - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testGetAliasesForAdminListing() { $this->storage->save('/test-source-Case', '/test-alias-Case'); @@ -226,7 +226,7 @@ public function testGetAliasesForAdminListing() { /** * @covers ::pathHasMatchingAlias - * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. + * @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path_alias.repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865. */ public function testPathHasMatchingAlias() { $this->storage->save('/test-source-Case', '/test-alias-Case'); diff --git a/core/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php b/core/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php index a393a1ceeb20..d05170deb98f 100644 --- a/core/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php +++ b/core/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php @@ -20,7 +20,7 @@ class ContentNegotiationRoutingTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['conneg_test']; + public static $modules = ['conneg_test', 'path_alias']; /** * {@inheritdoc} @@ -39,8 +39,8 @@ public function register(ContainerBuilder $container) { // \Drupal\KernelTests\KernelTestBase::register() removes the alias path // processor. - if ($container->hasDefinition('path_processor_alias')) { - $definition = $container->getDefinition('path_processor_alias'); + if ($container->hasDefinition('path_alias.path_processor')) { + $definition = $container->getDefinition('path_alias.path_processor'); $definition->addTag('path_processor_inbound', ['priority' => 100])->addTag('path_processor_outbound', ['priority' => 300]); } } diff --git a/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php b/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php index bb1380faa733..57a8aa06dc29 100644 --- a/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php +++ b/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php @@ -38,7 +38,7 @@ class RouteProviderTest extends KernelTestBase { /** * Modules to enable. */ - public static $modules = ['url_alter_test', 'system', 'language']; + public static $modules = ['url_alter_test', 'system', 'language', 'path_alias']; /** * A collection of shared fixture data for tests. @@ -100,8 +100,8 @@ public function register(ContainerBuilder $container) { parent::register($container); // Read the incoming path alias for these tests. - if ($container->hasDefinition('path_processor_alias')) { - $definition = $container->getDefinition('path_processor_alias'); + if ($container->hasDefinition('path_alias.path_processor')) { + $definition = $container->getDefinition('path_alias.path_processor'); $definition->addTag('path_processor_inbound'); } } diff --git a/core/tests/Drupal/KernelTests/Core/Theme/StableLibraryOverrideTest.php b/core/tests/Drupal/KernelTests/Core/Theme/StableLibraryOverrideTest.php index 795ea334664b..ec11d3dab69c 100644 --- a/core/tests/Drupal/KernelTests/Core/Theme/StableLibraryOverrideTest.php +++ b/core/tests/Drupal/KernelTests/Core/Theme/StableLibraryOverrideTest.php @@ -49,7 +49,7 @@ class StableLibraryOverrideTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = ['system', 'user']; + public static $modules = ['system', 'user', 'path_alias']; /** * {@inheritdoc} @@ -72,6 +72,7 @@ protected function setUp() { $this->allModules = array_keys($all_modules); $this->allModules[] = 'system'; $this->allModules[] = 'user'; + $this->allModules[] = 'path_alias'; sort($this->allModules); $this->container->get('module_installer')->install($this->allModules); diff --git a/core/tests/Drupal/KernelTests/KernelTestBase.php b/core/tests/Drupal/KernelTests/KernelTestBase.php index dfda4a9fc060..0d13d9d2d366 100644 --- a/core/tests/Drupal/KernelTests/KernelTestBase.php +++ b/core/tests/Drupal/KernelTests/KernelTestBase.php @@ -538,12 +538,12 @@ public function register(ContainerBuilder $container) { ->addTag('event_subscriber'); } - if ($container->hasDefinition('path_processor_alias')) { + if ($container->hasDefinition('path_alias.path_processor')) { // The alias-based processor requires the path_alias entity schema to be // installed, so we prevent it from being registered to the path processor // manager. We do this by removing the tags that the compiler pass looks // for. This means that the URL generator can safely be used within tests. - $container->getDefinition('path_processor_alias') + $container->getDefinition('path_alias.path_processor') ->clearTag('path_processor_inbound') ->clearTag('path_processor_outbound'); } diff --git a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php index b669a36258e1..de82e6583974 100644 --- a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php +++ b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php @@ -192,6 +192,15 @@ public static function getSkippedDeprecations() { // The following deprecation is listed for Twig 2 compatibility when unit // testing using \Symfony\Component\ErrorHandler\DebugClassLoader. 'The "Twig\Environment::getTemplateClass()" method is considered internal. It may change without further notice. You should not extend it from "Drupal\Core\Template\TwigEnvironment".', + // These deprecations are triggered when instantiating path alias + // services. The new versions live in the "path_alias" module. + // @todo Remove in https://www.drupal.org/node/3092090. + 'The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086', + 'The \Drupal\Core\EventSubscriber\PathSubscriber class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\EventSubscriber\PathAliasSubscriber. See https://drupal.org/node/3092086', + 'The \Drupal\Core\PathProcessor\PathProcessorAlias class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\PathProcessor\AliasPathProcessor. See https://drupal.org/node/3092086', + 'The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086', + 'The \Drupal\Core\Path\AliasRepository class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasRepository. See https://drupal.org/node/3092086', + 'The \Drupal\Core\Path\AliasWhitelist class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasWhitelist. See https://drupal.org/node/3092086', ]; } diff --git a/core/tests/Drupal/Tests/Traits/Core/PathAliasTestTrait.php b/core/tests/Drupal/Tests/Traits/Core/PathAliasTestTrait.php index 2f12e4c399ce..24153b3ba247 100644 --- a/core/tests/Drupal/Tests/Traits/Core/PathAliasTestTrait.php +++ b/core/tests/Drupal/Tests/Traits/Core/PathAliasTestTrait.php @@ -22,11 +22,11 @@ trait PathAliasTestTrait { * (optional) A language code for the path alias. Defaults to * \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED. * - * @return \Drupal\Core\Path\PathAliasInterface + * @return \Drupal\path_alias\PathAliasInterface * A path alias entity. */ protected function createPathAlias($path, $alias, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED) { - /** @var \Drupal\Core\Path\PathAliasInterface $path_alias */ + /** @var \Drupal\path_alias\PathAliasInterface $path_alias */ $path_alias = \Drupal::entityTypeManager()->getStorage('path_alias')->create([ 'path' => $path, 'alias' => $alias, @@ -43,7 +43,7 @@ protected function createPathAlias($path, $alias, $langcode = LanguageInterface: * @param array $conditions * An array of query conditions. * - * @return \Drupal\Core\Path\PathAliasInterface|null + * @return \Drupal\path_alias\PathAliasInterface|null * A path alias entity or NULL. */ protected function loadPathAliasByConditions($conditions) { diff --git a/core/tests/fixtures/config_install/multilingual.tar.gz b/core/tests/fixtures/config_install/multilingual.tar.gz index e4961cc7de8c..e60ae04ec242 100644 --- a/core/tests/fixtures/config_install/multilingual.tar.gz +++ b/core/tests/fixtures/config_install/multilingual.tar.gz @@ -1,47 +1,40 @@ -‹�Jú,]�ìmsª<·Ç÷ë~ -ßí7Wöæ!!ÐwZµµ¶>µÕ¹g˜E-àSÏœï~hmµv_–î{«3-†Ö –;¦Ã_Vü;‰?4 9Þ¯åÈýq,“„iFeŒ¤—#“ÅÏYU1–5 Ë¢žŒ¦ýÈIG;‚l}ë\î‡Å}æøï×Û·þ¿Ô¦S‡æTqÛÐ €,¨Ù›1€æ*±©Á-~â¯GÇŒŸæ¸w"ÎZ8 Ns¡?å'ŒO¸Ç¸GœžärtìÙN/ZÊå@.X!ýqoú+v.Q>³©Ë_×Â>mJ#w<1éØ‹·ÉÔ ÍdãfŸýÓ\ñ>_À$oç/¹Ÿ-[zA¹Úã¡SÓnéÕݤèPƒô$ú¢/\ü$ÙÙj7>ï9cO|r·ˆoÚŽ„'sîôúáiN>™øã™XåŸæ¼©ëžLÜiÏÕ&‡nF_ÎŒ):7þó$àaèx½ø|D{~¿f.ç‹»§¹|ôÙ BŸ„âXDùf§Ïg(®j2'˜¸dyš›9c¹<ZÁgÑ6äøLMBqn$±Èâ1“¸®éˆ ˆf7à'ñÿ9®ŠmüO.÷¿'ß퇙}Y;úoùÂc„ç¯ Ø£ÿFªÐIH¿"i*ú¯)šœé–è?…† •A @ÛÖQ -ˆ%‹!M¡Èþ„þKÝíÆÕC`ÈíEqVªŸÎz·¹}¦•WzáØâŽÚ›Âê¾v෾ωPÔge—ÞSö•\¯7–HöŽª¿]ëYÑ6…êæÖk$é?¥¨Þ4àf þÙtǽñê4¿(õHôͶKQ™x«òÃ$~—±H\“Ш -Ž"ûø×Te‹¬JjÆ–ð¯CÅ`"ʈª€:¡À Ü�”2®aÕb6ÇŸàÿÓ ßÚö¨ò…æ -˃ûÑ]ÐÀ5L½¢Wrf³ñÄ»ô -W¿ª•^€þÊSߦ]ì%äÞ&ò»À¿ÚÚ;¸¿Ugû¿ÌÅq]nUë5ôÑYxùoŠÈÞã?$Áð8ôÀ?Üiÿ1V2þÓ°„Eª®Ú6 ˜#Ñþ3èÐÒ•‘*AÉ"6R¾’ -$ͲJn£ƒ‚«QÏb8™ôZ÷†Z -!(]–—5§ÝZúeg‡ÿØS¤_ÙC¼ÙYã™ü±‚1jÅ*ñÜz\&Û”¤+oñßK7ÿ#˜×¶øGš„2þÓ°„L©¤Ù¢Õç´T¡PR�³Kµ)’!ÿÿ¯ãžú" -°î6½û],®ª•r£ªÖÔ¬šC:QkƒóžwçSà.½úEå•(ô>—ÛyW¢ãN6÷Ž"ìTØ„m±*¯zÝþ¯ÎÅ;Yœoˆvùñ =~¬ÆÿÇü£mþ5UÊò¿©ØŠ¢pCgÝe�b]#D„X‚†ŠeIEßÐÿGÕªö¤zµ0‹B‹>)-Y.^ÇR[¾@ÍÞ…«‚+ù -°vàwúÿ‚z7"Ÿ³ƒ“�ë-~œØªõ" Ÿ«Üzýái€ô`—ÿ‰8F3tB—Köò/íð¯I8ã? Kø—˜¢AY×Ò™ˆÿ©Ì…X†"+H²8fŸáÿÓ ëËIX´µ{ÿaÁ—|Ö~‚Þ-šÙ>.„‹úãY¡ê9^ÿN©\ʽ o<õÀð_}ôͦÞa|§Â‹n¿X•‹Wýå}ý·l—ÿp<vØøÿ8 ÿñ‹û¿8Žÿ5˜ñŸ†%üs‚˜Ìt$ª�Bƒ(TD”3KRU IG¹ÿ;×#„ÅÙ3¸f´{‹ºA¤¢lN˜>[ÔJ}»ê-ºTtúƒà…p$GqŒ>ÂwuãtÿwUs“FXœ4oûFg÷#!7í±?"á/QѵˆPƒã)À>þUûVû/¡¬ýOÅþm*IÌV£ü?²õX–Pe‰È™PæCùOëclñÐm¢Êýƒ?º#·“N·œ´9]èm¥\–°zcûa+˜MgI¾í”'ë6·¼*ÈE®›K\÷çIDg«ƒš0ä~ÄhñŸÜè7ûÝšrqêüÌžuxa;ü÷ÑQ:£#õ�öó/oßÿ“Õ,ÿ—Šîÿ[Š¥HH\b\´ÿ*„ˆž�²ÑeB±¦Ócò?XØgî¼[i<TUý�÷CÚ]ÏÛwã›JImŽ”Z£ë–§ ÿ¯œòY.ZÕë\qUú.ý0ì?-Aþip“Á¿eïóŸ^þO„þÙó?ßd«ö_4ö„@ Ø*üc®B ×t2E#<&ÿ¥›º¶ë·£ÕÚuŧ—ðÁ1]~Vº ©#µ@VØ´ ZÃ×üï²ÿ÷1öíûìmþGc/ìM�þ€ˆ3þS±„H™e"c@ÄÑÿg`’Æ%¶Îäƒó‡ðßÅWÓ³ö¼jÞ³VmvMÇn8}PM�èåî°UÓ®zµyYâÕ ÿ±S¾€jTôdüï³·ù?^ìÙ^þávü¯)8‹ÿS±Õó†eA‹è@Öe @…2@¦¬+\±lhäàñ‡ð_ÅËG‡v†mUë7–hb0?OΧßoå›åtPuCí¾ˆÿwcÿÖGqðgñþ{›ÿ9çGL�þIü³ü_*¶¾ÿOmê]’�$º,ÉRDü¯ë†A£æÿæWExŒïÌy¹7Sf½ -Ñ|¾Ü¬<ùK.ãåð‰Í}/?Ú ÿ‘S¾æÿ^”¼ßúÿçþ>£Ÿ½Íÿ’ßåApœDÀ^þÑÿŠXŸ=ÿ›Š%ü[œ ŒT è–Eü ëÄ62¨¥*X‡9&ÿènBæUÿê¶t{6ßÀÎä–HbùFa=§ra·žœËpîŽÚºáÿ•S¾‚ÎjU|;à=EÈòoØûü§Ùþ£Ýçÿ2þS±„Dd kŠ$-�%.é:`@Mf -´0;&ÿ7>têÓ£aÝÕSÜ\® Øèu®ùíãžOìÚyÖŸüákþw±?ïŸÅþØÿîø˜Ccûtû/£,ÿŸ’%üËX#Ó(°Ið¯CÿÛÑܔ۪£æÿÆ==¸è¦Öuu®žB©;è=6—ýr¡<¢VûÞœ_S»fO’±7^ïýb²Å¸p«ÁOžrÙh€ûO®œü“Ëný¿g;ü8s¦£TŸÿSµíñ¿áìùÿTluÿOç#D€EðÏu@l]„XâB‹ h0ã˜ü{O׈I -¬ *¦Þr[Ú´œŸXuGöpt1t/Ï€â~>Éÿ%N¹£�Iñ ÈžþùÈvøúc?<n�°¿ýߎÿÌžÿKÇÖó?‰•*€JDôÿ1€A*¦Ô6Ueš~Lþóî_.ü^ñ -½EåܸPÚÅËN žzw -AñjäZÝùj`Oä”;øÇ¥{èÏÐÿØbþ¹:á2V�s$®ð¯h˜â¯è‘è@œÆ¯Ïÿi;ù?%ëÿ§c+þ¹%‹S/Í0$ ¢}UÇ€Q©[¢sðçãÿâ1¯{&úqú-:AhyM—Kܽ¾éßž_wÇV·~ɆùòÝýzpgšõ}åŸk]h¬?‹Úãa)vêÖrÂWÃn)¡ýõ¤9ß}Úÿ{ÉÿÌáó„/úeO]7•ùT¼3ÿ’åÿÓ±„B5©¢ë4Yð/Gãÿ¨à_£˜BKבßá?io?€È›ö=èúaÅ[œºŸ2¹D7†¦=GéŸ+•EÙ™…=O -/n‚$!øì ›âÃzÄßÏ7$ >ˆL¶íþýàHÃ�÷ÇÿÛãÅb–ÿKÅVãmY%ª¤ÝŠæÿ³T,›jÀ’ Í2TI‘ß›ÿïHüÏÜΓü‰bµêÔ]åûØx†4¢cˆ}];ŸŸùí ÿÂAŸÛþf3cþOìþN|Ú7qaÿJöñ%e;þÇ(Ëÿ¥b«ö_œx ê*Pl¨+ŠàMÓ�cªÍˆTl}-ÿö]Ù¾œ™çO…F Ì'Ë."¢Þ ¼¾Uºy8×ÜYƒ©SBigÃÿK}Žšqa..Ì‽¶ŸŸârýØË¿²Ýÿ—eœÿOÅV÷ÿQ¾J•t@nc ëq$�1ÂL6dýkãíü즷JÃbÖEuîëšÕÒÏìsëÑ/t®nšgæC–Ônu‡ÿÄA· )ÝL÷ãx=! -“iÖ9xeðr!ûwHþo{þO¬ÉÙü¿©ØjþO[Ò0äˆ:^�Úš[¶Fˆˆ4>øþߟà_}2ï}yØî\I£A#^|ôÐÔngaWÜ3±ÇB0YÞs¸Á?ñÏ5÷äSÆöçìmþãü*&„á^à~þÑvü/ÉYÿ?[Ïÿ©ê2‘ PÅ�ª6 Ìæ@'ŠmQ±F>3ÿϧóÿX>kæ}óºvK{S¨ *°Rså«|kHú#¾l—¥Vþ~IôÞ&ÿ¿òϵ�œ>fÙÿÏØügþ_U²ö?Kø7x4ÜW³…˜ˆÿu KÕE8`QªrÆlÉÿ �£z¥lÚãÎ`äÝ5}£:¡ExÖ"—%³<¹‘óË"3‹Áð)<ïW7ð*ÿϸK(OßÎÿg"ð¦%ü/BîÎø¸Ó~?Û>þ”^ð¯ þ¡³ñ¿©Ø†ÔdNºxú8&–{«Å¥GFMæÚ\á•ÛwÙzÑ}.tÃhÚ:)ž±ÎëMÅ?>E“篖½XC¢¥í&ÓÝ%Ë¡pÊd)"w]Dýøµt8ž¸v®kŽ„œ8®í/š -OxÔÉóD‚ñì~« ü’=`#ûÄJ9¿{”åvþænZë ô…"»zs;Lfõºù´¸w)ª¥ö_¯21ÿñÔŒ‘¢‹ÏO(ÎÃÐϸï;ìßϾY…Ûñ¿€Œÿ4L8¸ã9ñ›j›¹‹up¾-…mP#çf®Þë³ù¤Sµ@a €Ym–{ÖãU»Õ©þõ¾Ÿ™¸þ‘ÔÿZOVú=í¿¼óþ/()ÿ©˜?žµ9áªáü˜~®ë*9üPž—ý`ÉÜNéð¶{S;kÚ¥T‡]ãêéÂBzFÿ…ÅqÜ·ó¿=þOðŸÅÿ©Ød*:ʦEBÚ7çIÄÇhŸx—C©•¯žÜÚ)¼ï\T°U)Ý^Ÿ;R¡óØݲ’‡ÏúöTÊDào·ÿáØ}±ä¾Ÿ5fËtßÿ¥lßÿC(Ëÿ§c«çÿu®hQ jÑølÀà¶dc•)ÔÐôƒçÿ|ûþ_²uê÷= \hñãÍý#qº¤n6Ό຃*ãâÕ¤ßTáã»ÊE36º{ñ$Pä²'±+¯ÞŒ¬ÒÚáæ6`²…9wB¡xÓQô.¾ÍdýIhuüÉá¾YD‰p$SèË'¡O¼À%!±Üu^1~òèyÔ„û¬vçÍø ×ç -çÌ}ë]¤zý£œÈ7ÿ{ùWàvü¯jÙóéãõI”�ˆßÜóHì¨ñ&¼^ôZ YÑOšÔ'‚Sá´Ëä%7¿^‚ß‘3ýŽ*ûÞ÷s]òCo~ýNÃLLu¹©© -Ó.ûìñá*€³bŸ“s”…_jIÊö×jðïÄ%ŽgF—ÿ˜R°‡Y–væÿ!@ƶzþ_¢Yš8D@3 † ,…[¶F)ÖÈQçÿªU® -¡6œ›ÓÛ~"=† ¥è5l<jÞôòu¶Àu6¯ªƒ«~’4è?o#׌•éçI⧹»>¿©G–N—Ž‘dÑŒ§BG&« $žó`g]¼jóò¤B\øêÛF/ß'Wx@<ïyê»;{e°§ýÄŸ^îÆ\5V6»'Óp<Ù9€¸ôßÂw¿º,³#ØJÿ¿4ÜÿÉÛúEÊô? [¿YÉ|CS‰;'ËÀúã¹ù\öÇ}î«|,óeçvPUïYÁ4ýi9Zëzî9f›v¢sh)lQ¯„‹|¦#ßcëÛô¿¿pã¡wù¶Å¿"äÐÓ³ý?çÿùú‹îÛWíã°ë¯Šf@…âwtýQ4þ7»þ_o/¯ÿzyõ<诩ÇRyþSRwßÿ†²üo*ö<jJt®x0áԱͪúÝ–Y*ö’ÿ¯zô^þ¡´;þ#{þ#{™PXiÁÅÿ±wmˉ#Ùö½¾B31žŽ8YÖýRQÑÓ¾qƒ+&B‘’R ’¬ Â?30'Î'ôL 07wµ-w—µªAˆ4 ¹vî¹÷^È÷áÄ‹�r3ðƒc“ÿK¡n¨“Ó€ä,X à©ËßmŽ¯ÿÜný7i —ó?¬ÖÿJ}i%ËpsàC`“ÿoUöüèœÿ™`ÅÿbDÖ{Ê@T`S`åüÿxÞÿO -t°=°ÿÔQþ{þ¿”÷Ìüÿ“Îoÿ #Û%ÆÀûí?˹1øQñÜþz¥zУügöô¥\ÿ9,9îl+æ4ÿh8ÿO Eb@è诤}ŒÿÌžþ‹ÄÐùù&˜ HrO~ ¬Q(ûE²B]é!4\Ês} -GÄ#˜Àdƒ Ùt?S·®=E7 CM¢˜Ò|4EŸ©Šu¿¼7ˆ(?#éaðsîIü¹°Éÿ$ÒƒL £ë?Ëï®ÿçfè¸N<qI¾_Áùíÿ0±Ýœ¡ÏÇÿИX<8~þ·×ÿQâóý¿Lp þ/Ý -B²„c‹›ƒÏóßv™ð7þ—$)ïÿ– íÿ]:–n%Û -ˆ Èö‡âÒ êuVþÇýÿ½ý?1ÏÿËùšÿ±ñìþFúO4»›ÿ/JR¾ÿ— Vûÿû_×ΉÿÁp`ý'ûÀ™ö!ÅÞ»ý_rýçlVW—üȃ9ù? žòÿM×} éçÇóÿv׉Îýÿl°ŠùÊó}> žóÿó?¦û¸ÂwðŸÍõŸ²ÁŠÿ57¤ çÙ–NZ™åüÿ(Øäÿ[õ‚:Îÿ=ýW6ïÿ˜ –Ý•:øgv©Àr¨ô×ÏÓÿ?žòÿ_§ò7ÅwäÿHLÞÿ1ä5¿o•ó¿‰cüçöû¿‹¹þK6Xö–– LÄH€Wx@‘e"K¢@‹4+Úkö´Ïú%Ï(5úÍÐ7;WÍ¡/VG««óóø®í¶®h¨Ó‹› ‡ -I“güw -Ò´¤k-e‡þ§Ç…ÛíšßûëýÓãÎü6qŒÿ,»»ÿùŸçÿf‚¥þ3¯4À#…Ãÿ hD@Q ‰d5xdü>þ'¬ V¬m{Ðy†µLÎÚ÷Â[õüÚÄÑõ/ÿÏëÿ2BÊ]EZ4À2xV�„´XJ,ÓÍ'ô_¿oýGµ¾h߯KðNæœbuÈÒÕ�Óܵf•í©L³¥ëbÑ›.õžãÓæNå²Q2Nž2)ìÚ¤äb¯Ïáöü7q”ÿ»õÿŒ@³yüŸ –ë¿¢<ö��+êð¬ÌÅ$�%Z£uQƒÌëöç„"2{š³€Vêêh>_¨•Î4š]Žîõ[GŸLZ ì§þ?ž•Ÿž:©xÂ�p¹x ÖüŸàïô:€çÿžÿ/äþ6À?;aé‰ãž|¡ˆ2“&à!ðBüx¹º‚!t‚äg«éË`8Þ¹0qw.è„ÛWœQƒÁÎ}<^9¢Uí!é.â›*Z׬EÍB¯r6½ëÖ¾5.-gž‡õZ{”ôÜìcÍ ÜЂ¬Óßaü~ÿ_`™<ÿ7(–ÚOôá%î«Yñi©_¸‘Ošþ{0ªžLkNÞ<@K1„Y}r’>’à3Ö%Í$߀ÈÆK72ÔGׂ$ŸªK¢a~tŽ—K%¼{÷‹IÐѤªÙ(ZBÜèõÛóB™£ý®ÜÔr)ê'±æ?Qþz'ýWzîé¿ryÿ¯L�í„à`My•4ñMì‘o_Nƒ†Û‰”QÊÉÈO$ŸjcuI+ ·G]2†±Ò6ZÝÖäD›ýù7’–ªEÛWÁJ΄ì=R>ð‹Æ}Þ<÷nT¾¿ Píª6=îÝõ\³œrý²çwC‹Ùz§Öl¨ï©•ƒ$øÖ -GøÏÐôæú/þ3RžÿŸ t¨‘„~*é•ÄÊ+QS¤¢ô´mµ/?‚S˜ÊEî¨@®˜¬ß»$zàÁ—΃&.:x½'³nƒ8D8r™‰ô“ç»#<.øiJ¤S±7úÓzòÜ“7ÈÇ·¨Ø'Á¤%¾Å0½/§§fè}6’‚†Ï®?HD)ƒÓÏœþ”¨V®þÒéñ?éâf>qMRÉVkñxX±ùªã†[w,%Ô"Ï ßfb]¦ÐV ©a"Uêô§Ëÿ¯ßhM<×Õ•EJG~Þ�ÝÜÏd¯Ð¼4}>hµÃ€mµzEBµŠ8mu¤òð¾¬jB±Þ¨Œsÿè£"‘O~gý_lîwì?'Šyþw& :©õWÃ!š¼P×WûŶÞïÖoÚw—%xÃQ¿çDÇq`µWëÚ¥ùùý·E…éæ–åÏšŽÊÃ?®úðˆcüçy~¥ÿÅ%:aøÕ<ÿ;¤ç?<¯1’iò@Ódð¦ÀÅD< uÁø7zéù6©x6ŠLª#åÛœ•˜k{(„ß`å*–£:j©lµ)åR•Ÿ¤ì^uϵñer´?O×ÇC¥äêRÇ"<ù”*š'ŸÁ³£EÅô¬óËÖ�_È-'Ñlz¢ôÃKÜàÿŽID`éãøuŒÀQþìöúÏÒ‚ïÿf‚”ÿ2'1ŽÃfòàe‘øÄ4C“WDˆÄ·äP×XñªsfÅë§-ºwWÕaõ~¤ŠãOµ©?^xLCú‘ÿûótmªø¥• Ò[Z‚§Æù8Và)þGÎëY€£üéþ3“ïÿf‚”ÿšÁȈƒ %Ö�¼ É@ÆÜþM ˆxE“Ñ[òß.U•Éô²RˆäöLöCë|Û—â¾pÛðKùgcíÚÇ;üß™§‡-Àê¦#6`w¬`ðßóÝt£îµ€ãë?¿ÿK—×d‚”ÿ´Æ*#š@6‘ xV€b˜:Ð ‚8ü«H´"½%ÿkt«tÖ¹·®yãÚñïöØÝ®ôbݸˆ7]¤TAÝôd¥ûÈÿíyºf~#½¼&èR¦SDÌèi°3ÚGà>Á!þGÙôÏÿIþGªÿMc_€ðŸÎó?3Aʉ7LYç`Šæ¿ Ó@¬t‘LY”iCSþÛAs¬¹¼3úšª[¹.6*ýJ¯<ê•™K©é -â„Š¯·ÜÂÿ·æé#ÿÓË/ÚØâ#n¼•æë&ŽòŸ×üg.ÑÉϳAÊA -SŸç9h"ÇILÈr‚ü›ò¿«\^°¸™ë3Ñû6iA½Å¸¤iCWk ‡x³¡ù½ÞEeðÈÿyº&_{ó7Þüi¿ÆþGÎ+G�Çãfwÿ•òüïL°¬ÿV8i’Yb°ÿoè@fð’¨A‰“½¸þû{øuæ…#ÇŒêÕ00®ãÁØîÏÝú�Õ‹jØœÛãx2rœÐ‹û»ótmZhâ>šâýO^ì øLÂaþ¿np<þ×)忘ïÿg‚”ÿŠÄ"…3À@‘°žg±ÿÏh@dEC †ö-ù?¨4ûV;ðf›¶ãz[œ©Å†7%ݺ/Õnʳ^=6nÃË-þŽ�º«^ä ìó±Ümþ85€Q“‡¯c�Žó_Ú]ÿy.ÏÿÉËúOF1CcH×ÿ3ŠdÞd�£‰¬©ñ¯@ý»ùOfÒþ—âØ[tÌΰÏÐårs8E¹o˜çÚÍMìûƒ¦Ý¸ &÷ŠOëÁÎÓµ8#¯Páؤ&É;þü¼²ÉgZY‚'Fûà�ÿu¢üj¿¢8Êiÿü?ÏÿË)ÿ!¤MV2L @žƒ4ÀWLÀØ8‹m@åÅõßßÃgêß(ZÙ²gÓ «êŠßtÊ%ï¬ ggÝQ{Øn‡b JÝGþïÏÓµ(&/í[� -êº9á³–àÀ¸?®)8ÀÿÈyeàxü/ìò_Êãÿl°ÌÿÑ51¢t¤È€ 9ú@˜OP—,1ßþÿþ·A·´¸–.LÌ Ðl×=È`&B5žõûœ)ÝtiL?òÿÀ<Ý´ïðøãR?ÁŠÿQ8t}kñºÂ/KÏÿvë¿x>ÿ3)6JJL<å—ÜÄëqdÛG(»9#«ü¢áÇöù Ü·ôºmêA¿73/;‹Q‰×G̸e˜ƒ‰/?–ü×ý×oû°Æ1þ³,»[ÿÃåþ6‡> -†®9ûè>²|4AN¨3è;–3øB1+ÓôîËÈ÷]¿ÈÒŠH«…¦….í0ª¼¸¸[ÌÏËíÞ(¾(ö¢«xh Åo*ì\ö-‡æÏsc‘)–ü'õ©ïÆŽÙÿæ8>ÏÿËI8ìÇÌM:³˜–„¤N™”)‡Ö-\mÝtù®‡N¿E¾¥ÓJo?õø·B¬J )ŠØ“Çšé‘Ž[¥ù}¶ÒèÐBw]QL¶ÒkÞ—+l§U‘§úÂ2f#/–z®›ß‹ÿ-Ó|7þ3»û˜ÿ\žÿ— ’²yÒÏÁ¶¨6‚F²ì³ëK8>°ìåµç©Êô 3çÃyOVeU¸Ã GrÖ•îÙE@Û5‘æA/oÉôçÀ’ÿ$|?ÿŸ#ùÿMš?á•?_ÿ3´mw¦ZN€ôÈGjäÙ.4‚Õ:½nµ¢§Í’“rýž1žëC?V'pnM¢‰ -ˆœ"B^»JiqgŽ4N+Ô/ï/nú8<³ûCQ΄Fì*¡œod%ÿ iv3xýÞïG׎ÛÝÿ£¥|ýÏ# ÔûÚ$†’„ãÛá…9¾ºêv†¨L;Ó±Û7-ÿú®2\´Fõִ׿™Ó÷¯€-þ¿‘p”ÿ¬¸ëÿtžÿŸ ˆÎßØÂQøÀ8ÖÏ0ò{ðÁ{ÞPzžÅ·îg…Òˆ©Gf yºs oo&×5–Ï©ÿ—Á’ÿ¶;àï}ú¿2Üný/Oyý&H¶ñqÐ?%ÇæCëh¦nÄg,l…-ÃùÈ/V{:.飂©s‰1‹SWŒ¹¹ø`¥ù --ûýöÿ„½þŸçÿd‚ŽÇë-yoè©dJ1þÝ ”¢aš ÖÀšúÛ(Gñ%mœÓ‹®,Ê‹›ZÛ^\»ù±ÞŸü'•$óñô_izwý—è¼ÿ_&˜ H6ïN~%]ˆ)+ ôÈ÷‘Ú1‘]C>µ97¨¢‚¡Ù¥!ŠtP'O}|ógª3„ΘŠÝˆhÈ“ÿú¤½±…ÈûN¶³tª}ËôË’T9/æt¥)Z½Ž<k‡£rt'Ÿ•”º¹f¯sõžÓlj¾/“£3×ã™Ýø?×Ë -Ëú$r¼ #F<”!d�E:˼.rÊkê¿UÕ³¡Ì¸A)î6ùÙ-]tÕšqV»/ª²ÜÌG°h”GÊÄ™%ù¾Ë™ù˜Þ»‘ËO‘¹{‚?CÚ™>ÉÒ=¹±œq@ùˆt±7H ’L2z§h«à䣫ÄmñŸô~ý7ioý'-rþg€eý/4„4 (2¤oÐ2€²L*A¢V@Œüšü wn±w¥Š{©ÄÍËŽÚ\Þ²Ó®ÑKmý‚¾åÌBÜFá&Í÷OfæŠýòÄ -Â4%‡ø›/b®‡0“,†qðá™~›ü7]ƒïàÿ»ë?/Jyþo&Xöÿ€2N´"aÖ -dN& !]6$VxMþK±o÷„…²0,:‹ô3¶Ò¸ï_·«MóB±Ûv/i½²T(ë ÿÓ™¹2�åôÙ6ñÛIôâàÐc’Ø…œõ/Â&ÿI ÷õ?$Ù‡ÿ$%8çX®ÿš¢(ºd�™eÈúÏÊØM ˆç¡.š´òâúÿ—ð¿É¶ 72ÝËÛ1mríÑüª/2ZÜj–oÏ -š·¸+5ëÖ;®œðŸÌÌÖ¾–C9pj ¢ïºþ‰!RIèÜÃ&ÿÉYð»è?K{õBžÿ› Rþ‹²&@Ú ÍਟWhVfÄ(º(±†‰-òkòÿ¬XÓ[f±hÁ›‹#÷…–ZŒ*õ‘\(_M;séìÚVåŠ>O×ÿdf®@'y²MúdC€Ü•2þ(בƒãì×PZ¼¬HÎ-Á–ü÷ŸxNï±ÿÏÐ{ù?¼”ïÿeƒDÿ1U,+ö'pžæóÒŸô ©ç÷|äù®Ž‚`]Ï3XXÞò‰ ƒPåižÜ¹O˜êçÓþ翾„óðÁsË|yè_ƒüFÁƒ¥»ÁÌ|0íéƒ>°4ˆo´Û~@sô�ïçœZD‰Íu;"Íןâƒ0Æì~H²Ø’ÿ£Ÿÿ}zJn†â2|ý[©^ìÜ5Γ¿|]þ‹ ñË×Ð -môþüTÍ ql9Æ×Óôâ×ÓôÍ5b|;óËÆøÙWï—Î%e‘( ûŒÝÖ õ÷_ÉGû;5ƒåàÛMr;…]‘phTªYùù멇O‡=M>ÌɧѾj<Wm”¨eª…›Ôÿ·wdËi#Á}öW¨ö%IUDð´€ÇÄ€1¶c¼IQ:F £\_¿Ó3’¸œ�[6Îz§\–õ}ÌôLwO¡X.;=¯µìà‘·ÛNõæ¯ì†f}lÖ?î®…qݘ; §cµðµvÇ\7ÿ?èÿ |©ËÿØ'þ{Ëÿ³ 2ÿ£€>T]ÙTk¬®¨Þ`;Ê i`˜¢yˆŸXhÚwÈ*óÌ!§º7ö¥ÕI²?4gqÞéÞšÓA¾.ôÆêyx[G§’]ntÜŽ}Ê.<$ògÿ¯æÿEó¿®û±øã�µÿL9oÈÈ”yÉEü鼪—ó¼ —KrÁT˦®œÐº›X°I4h¬Ú'à#–œÎü…fªãÛ(§{ÎIh{•j‘t]) "y†ÿ¤ä?’”¹Â}‚ÙOøË=¡wÑb¾ªG‰¢¡±hSd †pë7ds‚À3ÐHºJÏj©:¿)‡¥ö®Ûfõòú¬o9µy»9ˆòeÔ¶ÇÆgyq!úÊ|ü&£Ëù'—ÿ涧©ÏïºKþ‹Â–ÿ·"3ù? -˜ê_.ÉÚf9ˆfF#vÔ§‰käK¼Ð3£ü*»°žHoØé!Z探6!R£8 Ùà°0CÊšUÍ·t(ÈŒ›µBlY¦¥'©Ö’_¤-LŸiîç5\TA`âUöoâ¯ÕB9¨ÞJW£XAÍZg¦Æquð¸°uKÿüP¨†òâL•“»^ûoû ÉÿkÅI›ç?b‘íÿÈ|Kd$“ÑñíN±Øºo–çá\kväÖ¢ñ(‘ÕÉÕQ»73NaçƒþhôŸ7ü#¢(Â+º—ÚØ-ÿ[ö¿R`ç¿G,ÃCì8ÐÁFî�¦ÏÝ™j#4ÕåºÖþ*öÕûæUè—ü’2ÐtAlMœzqP»\\ÙÊðŽE‚ý¾�©œi{Þˤ~ °sÿOÜôÿóE6ÿ°ùß÷\{ž.¢-¿Ÿl÷x˜Z®áM+œ -¬ºÓbú”–ï“ûå¶g6è*ß-=~uÊWÝÉÌTÜN•NÃV—5½ðÛjÝ×:ßB¦1ŽDþ_4ús§ü+Oìÿ y¶ÿH.; r8 ºp*Yáþü›$t4¬Ð·Õ9{?>~w¿»Õô¼¢*è×4Ö+ ÇÀ²Îi¹œ£ˆS#îoØ\®9ÀÐób\6džüôIž›|‚w^,dþ�ݶô^¥ÒƒTpóༀÓ=/U×À†ËXΊ8ËÅ#XµÀ›BO fÚ'Z'±ÿ€—öÍY…ƒƒ\Z`S÷QÏ\o•Es4AAhi6"}¹ÉÚ‚f¾ ׌;€8wÚ„¿B›¦–mã¡ñ}<0–IšHâ&Ïs«CÅEHuþÄôcíé–³š4e)5 æî šm�öcÃpêF7E‡œ|D‚iR<Ë`¿Å�¶7€!{Núâáç!e)Ov”3:/I…ǃ9BaøñƒŽ wIc .B/È…Hq™J<$¸éˆ¼,0I #we¬ š -öã†w3Ã5ÂtÒI2fŽttÍùy_nÐÀ -#¸í€î»¦öâ -.ª.Ã-pëØ #$qï3þH&ǽe> cDèŸ×ëåɧ9®|fVëM‡qÙpx RgÆ°ã‰[é8¡è)=˜¡&#ÿÝMë©À /«ÝSϸtý9ÎP®×ÇüxÕî'‰Ã÷á«õ â¡üº"aÜó»rOÂ!Šð²2<\/)n`Æ>ÏÍ5XOù¾3Vøz-þ=i —¶$ǵÆÖÊG‹Ð*I¤#ˆ=SAÛc"X^“«(UË%œ·¢¨UÍ‹1:ÌÃ?n3ÄGÂM]2®„G^ŽÜû¬ó -²!øðBÑIä×ä"#GÆcŸ[ -2¬ˆpîw…z1“«~&{N|½Õ¥ÎåŠá›_ï¼–¦J(À¿žÆâÞ§²¿d$-q/?2‹gƒtš‡v#©eÙj_<_7R|/Ü´š%q¤†xÝö&b¡}6Ž¯{ç—ÚLìúÆéy<ž•íþ¢µ&ÖplÔßdBb²ÿxØœÅÓ•;w¼øùOvúmù‰íÿ¨ÿ—TÐäbA”ø² ¼¤)^U‘/뺮!IEõYó<—ͶѨë‚ÖœthX¼EÚÈµÒ _ø|ÿe<4ýÆÂKò¤¼™VÓ7$Ç»Ä;b¬0Y‡$;Ú> -+ñb‹x£ðÜ;¬¯P./m¼&¬ÈŒ'^7‚u1zÞà òŸß’Ybù?ŽIþR^7x£¨J¼$—d¾T0u>/+&RÊeÍе産!\N[ÝÇâX¾¿{¨ž‡ñݩ߸-Ð]\M¿·í¶”zTþWys©Vßnè<Ó{‘ÿWöÿPÄ'ü?ØüÈfÖ -—M©'ÄsÞ§ÞÝDÂ]/Âoˆ7çúÑ2ÐoíX!}½e`o¤Sv/ئ ’üd§:Å÷ë}Ç_mí1Ñ_¤ånbaÓÂ’ýî$龃¢¡·q9éËÆùJs/ÆR’%AX–†QxÚŠ0Xi4¶›ÂÅ·û»æíÃéB‘¤žž—ÏÚCQyö´jitÞvKæzÇ€0`À€0`À€ÿ_øüØê«�¸� \ No newline at end of file +‹�üÓ¸]�í}érë8²fÿöSp:¦ÃÝî‹£¢oK–%o’¬Í²|ë$A‰EÒ\´MÍÃܘóýbÔn[>§dºªÌïDø nù%@fB³]}t¦Åƒú#cË9›í¿4M‹<O‘ÿ%Qˆÿ§ÙdŸ€Áÿ(†ã$‰E‰á)š–þEíÞ@DžßŠgC}ðÆyø4Ó|ãxò,Ôêÿ?¢È2Î)Ž©È +4Ù�¼h�š†$AB4uièĆN_w tN!ç¿Ž0 +ΩÐЉ<äÈÑ-œŸP”î:¦Õ'[¨`„h|6FNt.»Fd£í3ðN8@ãu)ÇUwý¸È@&ŒìPM*W0œS¥n¡(]Á‚Y¸A~a<oËEöˆÏ3K‡¾×o¼’@×OȃnˆøIr±ô2>ê[®ƒ÷,iÐWMË“)²úƒðœbN<ßàCþ9åD¶}âÙQߧŸ&·®’‡ScÇ•Ÿž(-§¿rå×Ϥ(jÈ>§ +dß +B†ø^pùú¢«7ŸªV€åu~NM¬ÀÒlD ©ƒ‰ß”âwCãM4ó c¨Ð¶UW€?˜ í�Ä¿³l+Äuü/Šúß'Ÿ-‡9>Úžþ×|,1Xr×Ðÿ´$pXÿÓXõ³´È XÿK,Ãåú?$ú_ç“DpOÞ4e�YV,/Ñš!ˆ¬.˜ß¡ÿ¥ÝÍæíc¨0YirY-.šòS1€SóB,?kcÄöCWC×ø í¾à—ü�A¬QWš~M³§êzYY¢²÷´úËg4úik]jyôô]*ý”&çERücÕvûnúš7JHžl·4À'C'-ŸŠßç?Þ„¶ +uÒGQ‡ø/rì6ÿYšå„œÿY á¿Ì³Š< èœxê@Ñ‘tÝ@¢Äi†‰¤ïàÿwýÞ4Ç P(¶BXvÇASª¡ rJÎ¥5™¸žsㇶ|[»Ü ú–¤¾Ìv|•9kC0¯~«¶WèþÒ9k²ßûÖús*¶ë¨ô¬mÒ“·ð2å?É"{ÿ!FÇaÿ;øÏïµÿËçüÏ ÿY–çdÎ4”€Ûƒ2¯É@gŽæi šû‘ü×-jÚ¥Ýì Áí¸o$Þóúí®Â]†<¸¼)ÏkV穪É7½=þÇ’úNö³Ø×õ&÷7ÏX1¿ µà4'gÅZbÕzߦ±.ÉV¼Äÿ~¶ã?˜óâÿE“rþg„ÿ’®Ó¢‰[}Dó&à9kžf¡±gêãïáÿ¶ýÍSÿG”ß°[N·¨Ïf·Õër³*Z¤V‡‘îqµa¥ï<ø:°çNãêzK)ô¿olçU•@î;©î°wÂÚèàCT|h»ýOßÅ+£8Ÿ`ìóŒ‚�öѱÿ¿¼ƒÿÂ.ÿqóŸÿf‚”ÿEŠl@¤ðøõY„›Í+œÄÐœð ý¡Z3FœéUogêlVlë¶Í0¥;þñ²Ã\ þ•-ƒžQ +`)À¯ôÿ1ëmÂ|d¼{`YãÛƒ�;gmÄïŠZÿ0@ú`Ÿÿ¾G5´BKä?½Çgrþg„ÿ´ÁŠ<#Ë@ lÿ늄զ°+Ð’Œïáÿw]ž{aÉ»þãÍѤ³à{abúR1œ5ž/ŠUÇrìõ Óß úZRßiþs¯}]Õ+ß;a£ÛQñ¡ßy_ÿ%ìó?t]ûˆÿ_Þ1þ/Ió¿±ÿEFÌùŸþ#(Œ!€–yð<+�²:¶tdh4lj}”ùßX¸Žh!Ì.êÖðÎ(2 Óœ5H—Õ3äɬv90«ÎìñI—‡½ÁÕ0ØPÉ]£ð¬n\ù»æÓ3×ÃéËÉrÚ—¼Ý3†H5]Ã3|¢A¬ Ž§ñŸùÝöŸfòö?$ü7uš6LŽŒÿf½$M¢ À14R…1°F~/ÿÁz›¶ÒÈn ×ÝGºx€÷^ï©\Ä©>“;l¹Ì<J\ÝôÃv0‰&ÉxÿR(O–mn9- ˆèR‰èžžV!#½)†!ò GK?QãoÆ·Ö)WçÖiîë°=þÂ1V4¸ »þ?núóùÿOBÊLvy˜D˜ÿHP‡:Ð(+<î@?&ÿ/ë ;ì4îÇ}]ì4X_¿á-ÕF—7C!²èv0¬µ@{ó%”+pÕ®ÞQ%\òë{`Œœê‡ð:ÿCk|$p¸ýgvçÿi1ÿÏ©ÿÆj,-°�Ñæ?Ï �BC�‚&@™º$Êú1ù?œ™öôéºùxm蓪 @w¤?ÍJ•Îƒ[¿¾äZc¶Ö|²ËÑå6ÿ‰Pîë�Rújë+‚_Ú¸å?êy㿃—ù?vpp4àÚžÍÛÿLðŸ× Eb 8I’/,îÿ +0hÑ0thÊóîñ¿÷ðÿIº.:ÓªÚ5ÚµÉîÚaôÈ©² —ŸFíšxÛ¯MË4ª®ùå6ù«¤è gû!¼ÌÿãµýùÏ3{ö?›·ÿ™ õÿS4× ™ÏꀂÈIf«™"á»ã?ÞÃÿª4¶ôިɃæ\ðÃ/ÀJ±h SŸGÃ2.h(ÜÓFû¿ßö·ßj÷ã?oïàeþO:â�àôÿ¹|ü/,çÿu““0ëY™¦eh´Æâþ¿,+ +h^9êøßô¶Äw÷A–ûvÒ¿æÇz¡Pn]/ü9b¤ùhaL}§àÌÞšÿD(·ùßÅ%¯·þ¿t»9ûáeþÏô³ä¿°ÏÿÜÿ7$ü ƒ? Ë�Úà5ÀÓˆ² ËÀà!/2Ëk’qLþׇhd5¢G¥©=4XUÖ¯Šw +ßì÷îÐýó£4õÌZ¥¯7þÆøÊmþ÷pÉëýþ¼í^ç¿‚à8ù/ì´ÿ,Ãäþÿ٠ῆ œdM‘pÿ_P€,C˜‚¢k+É< ÉáÁƒÓª{y1rë|Ï»‡t»T®³Fߺ¾2Ûë&œÚãÎLßæÿJ(÷9O¾¦òù€°ÇÛ=fèoŒïæ?#æó!á?#‰P1Dh +Û™Çö¿©I€äæБÉa#à¨ãn_ºƒbt¥ÝU§Ü…k/Ÿ†ýçÖ|P.–ǺÖéªÓ;ݬiîI{ãôWŒ/%5Æ…;„O¼\Ö6€ýU¦†?QùÔÿkØãÿV4ÎÔÿÙýøŸÜÿ?¤óÿ2â‘ @ +‹ùd�Mw$ ¬¨ðŠ¡“ÿÎâN0°Ô†×ªÜ¶ÛbT.DŠÄÙcs4¾Ù7€µ¿Œÿ%B¹§’â: ÷þy{ü®×�8ÜþïöÿE>÷ÿËËüOø§³@§!¶ÿ ¨�Bp’®› +Ëq†(“ÿ{æó° _;Åþ캢\±ÒM/à.*Šü4çÍ t;¶µ§iØC„rþqéöçÔ1ÿ‘Zá<Ö�êá3¦xF\¢ü?¾ÿ/î÷ÿóñ¿lòi~õ…ØÚ—€ÂÉ0tNàxIÃÿ‹c^$ú±mÝ„ù>ŸKOwõÁ}å¶òäjOcT(?t¸»�YQê»%ŸK½Ð\îãÚGáe,Ôí¹‡Ò°[àeÒœÏ~í¿lòb¡i‡ü1#ÛÎ$ÿ'íçÿÉÇÿ²A¨‹,îri@̆Äÿé˜ÿ¢.é¼&Ë‚)½Âÿ¤½}[i:älûáµ3«Ÿ©¡w#ÔD}‹TØëYÙš„}‡¯êA2!°ÐuD�ÞYFü¾ â›ÈUÀ.Þà¿)ð°ý/îùÿJùø_&HãM†ƒÍY#ùÿ4N�š©‹@cQS8l½–ÿïHüŸØ½…|5•ZÕ ÛçƒòÐ~n>…ë®� yW«L/üΚÿX@Wm«•sþGðÿ}} ZøÃÎ~“"8ÄžÞmÿ‰ÉÇÿ2AÚþã/ò2XS�/³,æ›(ÃàLÄò'iËó¡lÞLÔʢؼS¯y¥™%rCg ]Ö+¢=i\u½·æÿ¦€®ì€V\HÅ…¹p‡ùï£�®ß¢�òŸÝíÿ³›Çÿg‚tþÏб•Ïé@§eðÈ”€,Ç–�/ ’Á(Œü±ö¿X¹¨7Àðžmj†vUz݆¨µå³¢=ûÅÞm½u¡>öøKÇÿD@w@RºN÷c9}¬¼(ïlá þ‡Gý{Ïø·kÿ|žÿ7¤ù?MZ”x$ü À›¢“1!¶ ¯Ò»çÿ~„þÕ…òÜõ™Q§wK‡ÍB¥øÂcK¼Ÿ„O,UrŒxó.â×ôOäsÉûv²—sûûð2ÿãñUÝ{P?Â\àaþ»ü—ø¼ÿŸ –ù?9™þ€×9@ÃD@†¬©éI"üžü?ß=þ/1‚¯ÞÕîõ~$–Äá5]³™ÛB{c4—íBwåþzü?•Ï¥¸HwóÑÿïÁüÿÔñ!oÿ3A‘p_Ñš``û_y q264]çaŒÆü¸ýÿ0n\—UÓí ÇÎCËWªž^â/ÚðæR-{u¦0/j)-ÂÊ ºV�[ãÿqÆ]¨ënôòø®^DÂÿYˆœÀr›ö{…CüD²þ› ˆŒÀHCÑŒ@çãÙ`ÍÔ$']œ>ÎÀÛýtsîÀ±¥'¹6SúrÓB¶±Ü´W…vHÒÖÑqÆ:§á¥{$y~ºíÄ:„líVêÁp BÛ‚A²Ÿ¤¿K¶C,¤Éaò², ýú¥*±ü‘l[cõbÙ¹>I‡?ÇÉ*±`œí/Mè—Üø;*9¤¼ØÊÃ3Ãt +õ‡¨ÖÊ3:Ìjý>z“FC]Ìî\hÏ™bõ²ó»Ó:1ÿãÔŒD£ãç'ÄÏ=RÝ ò}Ëøí™ÀñŸáøÝñŽËÇÿ2h˱â•jÞ—¹ÇèI…v@#Žú”ëÊ“©×«j 8@¶Ê}íù¶ÓîUw²žc±ª?[&+ýœöŸÙ]ÿ‹á%!ç&ðÝ)Ööc+LÊ·Ùd™ƒ•À™iÙæ†Ýë2ÿT¯]´Ìæœ.…£'åvq¥ rÎþ?b;îÓù¿ÿGfrþg/ÂeUƒ¡>PkíaápnFt»Ð(.ìš+°h`]]KÚõåý]Å¢‹½ç§É½qéH3¢s%ð{GÊÿÐõq_,™÷Ó\cžíú_ìîúøô|ü?¤þÿ2bEIÐ'’øIS€‚L0Œ$q«+¢üîü¿/Ïÿ%›¤È¸Øq¥çz÷ZO°¡6/”à®'\»¥[oÐâø‰$=\_µ +㇠O "²'±(§+ãÆé°v¸žL6É]¨S+Ä/“µøÖÉú“.PzÿÉínGéÐ7,&)ô™“ЇN`Ãjör\1ö<ZÅAyȬ ½œãªñM.ß›Ž…Ï«)û–—Èôû“1nþòŸå÷ì1ÿË +tßòÈ�@¼rÏŠ ± ÆL8}²¬ÃÊ'–žœeX>Ò±ÐΓEn¾%| ¾aúFN +÷sw ˜Çþô.T½¦¨’.3-‘c ñf`<?Þü¤4@°"^æ&ć"²=Kƒ1 ,G%Ÿÿ˜ªà�ÿ†ÞÍÿ)J|nÿg‚ÔÿŸÖ Ai€xA�¼ˆ +Š 4i¦¨ë’šÿ§v}[ÅÑTîµkú9l²%§iJãV½_h3©¡ðÛêðQkœ$ úé=ÍX3ž$ÒzNÅuµRCŸ$""ɦ§ÂŠz©Qç<Ø;Z/¾“œn=-)Ø\O<>aÛ€X]9òí½+ⲸÒÎuâ½Í˨KE-±ëËÃ(t½½ˆKû-|öÒe9Ž€Tÿ¨xÐþcvõ¿Àl®ÿ³Àre%õ +í)œj0p§êê<}àZúª¯ò¶š/[÷Ã*×5ŠªêGå‚TÛwSÇR;ú“6F#¡Âk¬1k\‡³B®G>Ëiúox Â{Axÿ„/ÛüÇ;ü_(áïi…/ÎÿÕ÷ÇÝ·ºÆû¾?gýÀÉ÷çIüoþý?›ß?vªû�KàPûOvv×äòþ_&€ŽëÌÇ.±÷οÿŸcݼ)þBØäÿr;õ?ûíž_ ó·ý—$6·ÿ3Aê>}xðßÿ×µsî1¼ÅÿÅì·å}Xâ ÿ9z7þƒÉã?³Á2|¢æ†ô<ÛÒÉTfž*ñ«`“ÿ‰»}â ±u¬pÃíÿÞúO"ûd‚”ÿò¹ ô¡ná^@Nÿ¯‚×øoºî1R¿ÆøöŸÎùŸ –íÿ½…(QÞ¿ÿ»o90oÿ¿ +6ùG�ž%ã8¹$ê÷ìß´ÔAþ»üg¤<ÿk6Øt(Xê‚ö¿ÿOÙn®¾�6ùÿQ¾`‡Ûÿ½üLîÿ Rïª6þÌ.X•|}7gü×ÀÛíÿqFòŸßËÿ&Ñùú/™à…ö?øBx›ÿ¶ÛÏ„ÿ»ù_i‰ÍÇÿ3ÁKöÿµcéVlþ( * 7þ´xmü/t]ûX>@‡Çÿ÷üD!ÿÊ)ç¯ïñ…œ9Ù¿6ùÿQ¹ ÷ÿwí–çsû?,Ûü‹ˆpŸ´ùQAßÊ�¾^hÿ¡N¢ã\j�'HM~ØøþslÎÿL°ä“Þ€~º‚šeäüÿxÉþ‡‘èè¿iÖoCügv×gÉ”@Îÿ,0FAç9ýW`…ˆBAøïÿ¦HV×Az —ò\ŸÂïÁ€˜c+ˆ¸¯àžQ®=Ac7 C£9¥ùh‚Ψ +<Ä? ¿ "ÊÃ{$<žåjå÷…·ü#ÇÈÈÿ—ÙóÿÍý²ÁjÕ$ËÁÜ÷n™–ýœ¦_/´ÿ¤È4ÿÍ»ù_&·ÿ3A2ÿ_ò#æÁ?_oÆÿ)�à0ÿ÷üÿ%6oÿ3Á2þÏéÛV0È5ÀWÃÛóÿÇ™<È~Ïÿ_âóüï™à…ùÿ|.ðá£ÚüMâ?·—ÿ]òõ_²AšÿYZ‚0#^á�E–ŠL<1DšÖí˜ùíâcÉ3J÷Ð7Û7/V‡Í››ËËy¯å6oh¨“«» ‹ +q’g|ÁC%IAK²ÖRv蟬Sn§kþì×û»ÇGåüØÄ!þ³ìnÿó?Ïÿ“ ÒõŸyE iÄ�)þƒt E&’Öà‘ñ}üY,YÛò ók™œµŸ…óßÄÁö×ÿ—òþFHø¯‹¢H‹†�xAf¯Ñ +€–+@‰exâ¡ýÊú¯?Öþ£Ú£hß]Ü–`O朋ꀥ«s�Àœæn5«lOdš-Ý^\x“t½gÇ8ÙÌT’NT ãô5•Â®TJ¾Øë[ø¨œ?›8ÈÿÝø_Ì1÷ÿÍiû¯h-�ÀŠ:<+ó@1 @‰Öh]Ô sÜüïœpÌ®æ, 5õ>u4›-ÔJ{M¯‡=C}jëãq„‰ý¥òäµLE¯(�.W�ïÁŠÿcüN?(øaþïÙÿ|nÿgüÙ KO÷ôœr4²3I/ÄÛÌÕÅ� Ä{ œ.’Ã`0Ú)»;:aãv‰³SkÐß)ÐÁºäÀzQÕ.’zßP Ô:f-jº•â¤×©=Ý_[Î"¼ëµÖ8(é¹ØÇŠÿ껡›§ïËø~û_Ä›9ÿ³@€‚ ]ûɃ>£x÷¥Tœ¤ë—n䓤ÿñížLkF~o t1„Y}zšlqç3Ö%Τ/Ÿ€7dã¦êÚ´ Î'jJôÌ.ÑýuûZ Äîób´5©jÞ_XÂü¾ûØšjÌÝé½rCË—¢~+þ“•¿>iýWÜõÜ[ÿUÌóÿdhÇ+Ê«ÄùÛ7±E¾]œ„Û…d)£„“‘/øZUK2Ó¸]ëRA:ŒåÚFË“Àªšd ¢Í«¿ýCrBºjÑv)X.gBÆ©nø]õ¾žŒg7*??¨vS›\·w;Ó,§\¿nG³ÞÀâçl½]kÜ«Ÿ¹V6î$Á^ò�ÿ\¼Á1^ÿ‡Ëýÿ2ŽŸ©Aè'KzÅ}å墦HEÉlÛr\~'0Y.rgÈ%3‚ÕoS¢G®<5|4vqÐÁí=‘º â…#ÓLDó|wˆë›¥S±5ú·U幧? +OQ±M‚IKl‹Azçß¾™¡wfÄg®ß¥¾mÜWðíoñª•Ë+};|I˜úÄ4I–lµëÉŠÍ£Žn‘.¡yy›±v™@[5à<H1¨£'ø–>×7ŒO´Æžë‡êR#%5¿€îž§²Wh\›>4[aÀ6›ÝŠ"¡ZEœ4ÛRyð\V5á¢~_åöÑWE¼|ò'¯ÿËðÌŽþçE&Ïÿ’ ˆ‚Ž³|©á�ß¹®[¯>^´ôÇNý®Õ».)Àëü3':Ž«ÝZÇ.Í.ŸŸ¦“k–ß7^ˆù6p¯<üíQßkâ?ÏóËõ¿ˆ#ñÿäóüÙ ™ÿáy‘L“š&€7(&↠pÈÀä½ó?Xi$ë'Ý&@¡: Pžfô°ÄÜÚ!|‚•›¹ÕQSe«‘R.UùY_jÃÎMçR]ÇóAûrºš*Å¥i{xz’¬h߃gG}‹ŠÉ\çùVçä”Óuo6™QúÓ/qûÿÇpDz–>šG ä¿Àn·ÿ,#Ðùøo&Hø/s£á~8ÐL^¼,Ò�A@T34yE„HüHþuoZsάxÝѤIw{5QTŸ‡ªh0þD›ø£…ÇÌç^ó_NWJ Š-U�•œò¢&xž¯£^ãäOä¿HïðŸ�9ÿ³@ÂÍ`dÄAÐk�^Ðd ãO�üM ˆxE“ÑGòß.U•ñäºRˆäÖTöC]Ôù–/Í…‡{¿t?ëép:Òn q´Ãÿ9}Y,O: vëú +Zàþ{¾›Ô«p¸ýçwøO‹bÿ‘ þÓ«ŒhÙD&àYQ�Šaê@ƒ +âx’Ž[‘>’ÿ5ºY*¶Ÿ[Þ¸uk¼Ç»]vH·*ݹn\Íw¤TAÝôd¥³æÿ¶œ®˜Ÿ¯Èº”éãmŠ,fòºØ©í+pŸà%þGôÏÿ±ÿG²þ7mÂ>÷ÿÌ ÿ%Þ0eW€)˜ÿ‚N²:ÐE^0eQ¦ ýCùo‘æòÎð 4T·r{q_y¬tËÃn™¹–^¿ ŽA¨øzÓ-lðKN×üOŠß5°]ÅWø¨œ›8ÈN\ñŸ¸8ÿS>ÿ› þš ÐP€À€˜ú<Ï1@9H‚dB–cä?”ÿå*ð‚ÅÝLŸŠÞÓ¸ õ2ç%M yµºˆ7ï5¿Û½ªô×üßÓù[¸ì]ÌßøñW¤ý +/ð?rŽÜ8ÜÿgvÇÿX6÷ÿÎiü·ÂÉH“$ÀȃíC2Ã耗D Jœ,(èÝñß?Âÿ›¢3ªWÃÀ¸÷GöãÌ÷Qý¢] 3{4gô‹ñ¿]9])&»k5@¬ÿñ»º�{~•ð2ÿÛ8ÜÿÖí¿”ðŸÉÇÿ3AÂEb‘™` HXϳØþg4 ²¢!ÐC‹û‘üïWV+𦛶çõ–8U¯.î½I¥p_ÒçRí®<íÖçÆCx½Åÿ—{�åwY»Õ|-s`›ÿd5N�¥Æ›ÇQ�‡ù/í¶ÿœ˜ûÿd‚4þ“QLÅÐ’õ÷ÿE2o2€ÑDÖÔxW þÃü'’t€ÿ¥ùÜ[´Íöà‘¡ËåÆpŠò|o^jwwsðØoø·÷Á¸àÞðI<ø‹rºR�Er„ +d«$Â$þÅ߃,5A|OKMðJm_B¼Àd~·¨�ò_ÚŸÿÏýÿ²AÂi“•€ç p‰ +gQ£ ¨¼;þûGøïLü;E+[ö¢8³Ú°®ø §\òŠÉ(;ÃÖ Õ +ÅZ”:kþïËéJ\ćö5�uÝœðMMðB½^Uðÿ#çÈÀáþ¿°Ë)ïÿgƒÔÿG×ĈБ"^€dêOD�a>A]B²Äüøüÿ;øߺ:A“kê²Á̹>š.`á¶ÌD¨Î§œ)ݵiD¯ùÿ‚œnt´°^ªñÏKýKþGáÀõÅq¿§8Ćvã¿8)ïÿgl‡™XäSnâö8²í”]ˆœÈU~qïÏíË~¹9jêuÛÔƒÇîÔ¼n/†%^2£¦aöÿL|ù³!å¿î?íà +‡øϲìnü—ÛÿÙ ø(¸väì£çÈòÑ9a N¡ïXNÿœÂƘLÓ»‡‘ï»>>ÈÒŠHŠ…¦…í0ª¼¸ê-f—åVw8¿ºèF7ó,ŸTؾ~´š¿Ì•E¦HùOâS?ÿ³ÿͳRîÿ— âî°?ß`nœ™Å´ü $qÊ$L9´Æhá:hë¤ËÈw=ôí)ò-}Dzû‰Å¿•bMQDŸ¬c¦7j:¤<”Nä?²•û6-Ôº·Åd+ÝÆs¹Â¶›y¢/,c:ôæR×usåñ½Xòß2ÍOã?³;þGøŸûÿe‚x†lçs°-ª 7ûìª÷,;-{›ªL:cx9˜uÕIUV…Û00œp(Wa]é¯û´]iî>èæ)™~HùOºŸgÿsÄÿ_ Iò'oçív€¶íNUË ùH<Û…F°l§W©Vô$9@<S®Ÿ`‰ñ\úsugÖ8«ñ²,s¸'òrÿ¢£”=s¨qZ¡~ý|u·Üу¢ý8U¡(ÜÏ]%”óaƒ,òß“d7ýãç~'8ØþoÿÿÑ\Þþg‚¡‡úêsmâ +CIÂáÄíðÊÝÜtÚƒ+T¦ÉÈ}œßß5ýÛ^eÖ¿jëÍI›/~#§ï[üÿ à ÿYq×þçùÜÿ?þFî…÷Cù#¿{oQ>ó†Òõ,¾ù<-”†L=2KÈÓ›hðp7¾±|Ný?RþÛn¿{xŸ“ÿ•áø½öŸÎãÿ3A<Œ;ý2m>°zêFp†ÁÂVØ2œ ý‹ªõLÏKú°`êÆLb§Ì¢ÍÔc&ÂB®þ�Hù?†–ýyãÂ^þ?VÊý2ÁVÆãÕ¼7ðT"”ßë‡R4¸‡æ=ëôaM}êÜ—£ù5k\Ò‹Ž,Ê‹»ZË^ܺù´Þïkþ“H âùø ë¿Òônû/ryþ¿L0FAÞþ‹d!¦¬€Ò#ßGNhÏɲkȧ6eƒê"*¸‘mP¢Hu²ëã“Ϩö�:#jîF”éú䟤7¶ùÝé¶÷àl€BõÑ2ý²$U.ý]iˆV·-O[á°õäbI©û‘kvÛ7Ÿ™9ýÏ%ÿ‘¥ÎÑ™¯ÿÆ3»ýÿ|ý·¬Æÿ ‘ãu(�1à¡, è,ÒYÖàu‘SŽ¹þ[U-dÆ JóNƒŸ>Е~GÅÚóhQ•¥àn6„Fy¨Œiìï›JæÚ½wן"²{Šï!ÉL{éžÞYÎ( |D²Ø$q&½´púÕW‰Ûâ?Éýë¿I{í?Ïäí&Hã¡© ¤i@‘! xƒ–”e °bäcò?€Þ¥ÅöJ÷Z™7®Ûj·ýÀN:FC,µô+ú3ó64 +w‰¿,™KöÈŽ„‰Kþñ7b®‡0/†Qðå™þ26ùoº.î~‚ý/ìµÿ"›ûÿf‚4ÿ4!p ³ÞP s¢4Éé²!±Â1ù/Í}»+,”…ÑgQ1Ò‹låþùñ¶Um˜WŠÝj¶ê|Ië–¥BYùŸHæR”“½mâ·âÞ‹ƒ»ãX/ä¬6ùO:zŸÿÉ{óÿ¬Ïÿe‚´ý×EÑ%È,CÚVÆ–€hÍ@<uѤ•wÇÿ¿‡ÿ ¶ ¹¡é^?Œh“k g7"£Í›òC± y‹^©Q·z`ä¸rÌ"™©}-‡ràÄêÇDß5ýcE$KBçJà6ùOæ‚?eýgi/þÏý³AÂQÖH4 Üëç…•Y 1Š.J¬a2<wLþ/ª`òÀ,MxwUcdã¹ÐT/¢J}(Ê7“öL*ÞÚª\ÑgIûKæR´ãmÒÇ䬄ñ?Q®"÷°]Ció4"9×{Hùï!?¶œ>cüŸ¡÷ü1ÿËñúÉêÏý4bg‰?/}¢q<¿ç#Ïwu«xžþÂòÒ¡ÊÓ<9s{}Âd}C²Öó·_Îþþçá,üÕsú¿ö-óס‡þ£ÿ+¾À¯ÃàWKw ¦æ¯¦=ùUï[¿jŸhÿjØö¯h†~…÷ÿùÍ"+1¢™nG$ùïªâo¸â œcvÿ{±ÅOô_¾}#§Â11~þ¥úE»wüóçô/‚Æ?ÐFÿÄ÷OÕÜ÷-"Çøù[Røó·äÍ5æøtæŸgཟ½¶(‹Dgì4憎þ‹ÜÚ_©)(Ÿn’Ó)lŠ„+ ’5+Ï~þæáÊ“j¿Å7sz2|Ç«ÆBh£xµLu¸I±‚ÂÒ=¯5¿lìú¸Ð¾Æ–ÝÀ¼x6/Êý‡&ý|aÌfÝÁô²·Å‡Üuóë Õÿ~ðQ‹?þå=ñß{þŸŒ˜ûd}�Ù‰ÖØ´¨NOp?j$acâ!Êð‰…¦ê8¶±Ì|ϬnÛ¾’jµ/zs1ãVÇœö™º÷+Aç•x[¹i8 »”/™Rþ“¹ÿOóÿJò¿nçÈã?²AÒÿ3EÆ‘)Þ9üé�ê +h]‘EÖ„Š©K'ÉÝULì84‚ö ñKggþ…fpìÙèLwÇ'íöa¢E–v%Osñ>ÙâÓ8)ó9õÌÈ~Ã?±œ“d-Z\‡õ0U4I,ÚYýYõ›ds"gD#ÑÛh©x¾C-æm%ë]·ÍÂ]óRµÆÅy½ÚŸÕíg£,.®9Oš?ÿ)£ËSþÇ‹ÿžõmWƒÇ÷=ÄÞóÿ–Øœÿ™À„Üùrâ¬mÖ%™Ñâ~Ô·‰cœ-Ýw×ÏÈY«ëcöF¾½Ü +Ð:wTÒ'D0Œü$&3I“dUó,Xun¶â®‘eZzšj-=cy‡Ëý$÷óV]‰‚À +Ä=ÿ-¾¿ÐáïG‘„ªÅÆFçB¸°uK/?±…@\\Bq1iÛÅ?¶Úÿ?+þ‹ßÿáù|ü'ÄímÌ‘;È ‡h7¡öXUæÁ\«6ÄÚâfÈ¡Õ`ŒÂ¨Þ›%Ò‚_þÐôøÓƒ$ÿ8Pb‹î£†�ó¯ÿ/Šùüo&XexˆÆc’ÐÁFNŸ4Ÿ‡39GhªIR³X¿åTøX½<Ù“¥¾¦Ó\m2¾úŻŽ- òH°ß/ˆ!ufÚ®û1©bÿãvý?y†ÉÛÿL€»ÿªëØó¥myj:Ü'Ðdgj9†;=§8¢b«{y8Ù[Oî—NϬ.Ð=Ó’‡·cå¾5™™’Ó¨!¹ÔZ€Ót¶ÛªÕ‹nkŒŒóÿC£?ò_Úÿã$>ÿÏéb1Oý1¡.™•<§þúŸqBGà +ð‹™2ö÷_?ýâüâ–ó$ª"ùuëµÇÀ\§4„j DÁúO2¸|×pFjè¹>6Çù鋸NúÜ{šo!󿈇n[ú[©ÉD*qó \ŸÒ]oN +¡càŽ@ÌXÊ +)ËÁwתùî”< ¹ròLÉ5®ý¿HaÞ¾<§ÈDnrÀNÜG]sû®¬d:×Gä–f£øYÚ«{A3ÏòQ€¯Œ�Q~@rOø7rOS˶ñ«ñ<üb,3¾Å¤B|KF\�Ôæ«¢BÇÅß#ˆ´!ÒIZÎBz+[÷¹ü$æî…o¶óÈxlL]ßPñÍ¢ð{?xü£8˜fYÏ:Øï‡Àvûä•óûâ×HÊR(¯¾óúSá÷G‘6„0’×wtDž.½rø{‘\ˆq@#>c j:@>ŠËH-äe¤ŽÉÛ8£®Ã•(@3Dþû¤áô»…¡‰ˆÆŠ“1Sñƒn9?¿W|Ô·‚¬vŒ»ûˆL½K*âpQ¸·ÀWÜ®=„´Füô+ùHæŒú3ËAüŽâïŸv®·ÿÿ4®_œøÌl^wù×7NŠ ë̈Œxâ»%é8É5È“&3ÉCÇoþgysò’×—}§žqv¾ëëñur\Ë·ïN ¦‰Ãß#WÛAÄËÚâ/¿Hréù½JO*! +±Y|¿*"¾¤øWâsl©ÁzÊóìtš!þÁ†\oÅ¿§wB-ï䌪“olm´qÉ!´ùI|¤#{‰¶ÇŸó:^ŠZN,yŠjn„«Ã2¼ú‚?íÄO±4%Õ¥ï5–‘ûÔßWOTÁêüã•4"o®øÍÅï;ïþlM>dXa,¹ü(‰s¼ÔÏä _oÓÔy¡ÁK¤bYáŸÞÞù,M•~ðy‹úû’ûkAÒR÷òï£UgGŒÒê¾³{ð½‘^eýIÿâx±¬ïƒŸcy™|W²‘1Ã5ëî„cë—ÏQ³W¹Óf\Ë3J•èy¦Øêâ&¬M¬Á³qñ§LHÿø.îÎâæÊ™Ýèø³@ý¿öü?D\šÿdÄÿ‹g5Q`9(4m�^“X�%‰Š®ëâ/À£æÿ +‹»jݸ)>_ÐZuÒ2ÂÐAÚÈóoŠr_eËWÏÓ»Y¸iþ¥l®‚�Ë’8ÇiêFb¬ µCÒmùc+°±{£�êë+ëÅÁ?û|&6øá†× ‰]ŒŽ;tÿÌÿ)Ïÿ‘ Òü?<£À xQÌš:`DÉD’¢h†®“ÿÆ }Ç–j¡ð,>><*AôPònÚDôF×÷Ó[¿S¯{¾Ü»Nø¿)›k°Yº£˜\¼1ÿ?ÙÿCâ^ðÿÈÛÿL°jYÏ©U“zûaÎÕÄ»;f¸ã†¸$öæÜž0ZúmM+,‹÷:Ø;–¦Õº`»]ÕWFª—õ½=î¸wÖÞSrÆòø95±p×ÂõS²:ï$}ü1 +îÎBäñ³ì̯¨¤cîFø…È"OÓë£A觞6ñ…¿£Ãâó£é ^¥¯»ÕÎSi!ñ|OgÄËú€“ž= *õAk|—»ÞåÈ‘#GŽ9räÈ‘#GŽ9räÈ‘#Ç×Åÿ!k �¸������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� \ No newline at end of file diff --git a/core/tests/fixtures/config_install/testing_config_install.tar.gz b/core/tests/fixtures/config_install/testing_config_install.tar.gz index 8e2ecd3d44c6..8bbe94512532 100644 --- a/core/tests/fixtures/config_install/testing_config_install.tar.gz +++ b/core/tests/fixtures/config_install/testing_config_install.tar.gz @@ -1,53 +1,37 @@ -‹�¬ú,]�ì[s⺲€ç™_ÁÛ¼lÍòE²ì¼q !@ Ô®rI²ÛÛܲëü÷#_H3ÃbÖÞåNUbdÅ6vVKjSwÊ&?hò;ŒH01‰å9þµç~;–HB4ã¿2FÒÛ¿±Èâ盬ªË–UüM’Ò´oEéhWð…Ìão],~£<°œàózûöÿ—Ê|îXgE¬©ê*S@Ž1 Š,¢cA…²‚Kü!›Zü¬hq×¢yxVŒ‚9/X|Æ}‹ûÌááY¡XdSßv†ñV±Šá:Œ¸÷ÃãþüG¢\¢Ü›Zs—¿¯!>D#îmJcu,˜l$E·ÉÜÌôà戄£³bõ¡TÆ—¤d—®xPòÖ]½¬4€ö´rØÜð¥[Ö¸ŸU�Zâ/úFÅéɲÓ|èL}ñɱ8%i;A–ÜŽ¢³¢\˜Ó…Øœý¹ëfî|èˆêßÓK7ã/g&%ÿ^y9þ0¹ñ™?¯Y,º„r÷¬XŠ?;aH\‹(ßœôõ%UMË g.YŸNèP—Ç;ø">†œÜ©Y$î$6ùjF|Ë$®k:â�âÙÄ y!ù?Çu"qŒÿ‹ÿWøÓz˜ËŸºcÿi 4Fhîñš€=ö_ÂHí¿"‹_2V„ýׄÉÉíÿ)$µÿÌâ–,3tUb�2B®)Ò™@•Xè'ìÿ±¬»Ýi<¶Ê†Ü[UçÍÉs¥£Ê!YÚöD=®£)åŽ:œÃ7ÖýE?6ð#N„E}µìÒg–=3×/KMöŽUÿ¸Ö«Eÿ~'¬nñeï÷ƒLúw)®7¹Š6ÝépšÝæ7¥>‰¿Ùvi(*?+?ÌÄïò/6‰k·AáQŒÀ>þ5UÙâ+8÷ÿN")ÿTDz:PüC� -0‹ -‰,!Ýø þô[ÛöÚ T¾{FQmüà݇ÜâáܯúçÎb1ùW~yìêÖùÐßiêÇ´‹³DÜß8r@þøwGû÷êl`¿ ëbâ׳Zï¡ïÂÇÈÿ!ì3þ#NŽCÿüÃök(çÿ’òä’ -%` ‰�ˆ% D°ê -ã -ƒ6ü;ùg@Ò(=w;}6¼¡;Áp6võ<‚àüª¶n9½A“êWýþM=~eýɱ¾dÿmWò»„†b×J¬Äkërq™Ö¦ä´†à#þ‡§ÿH’·øGçüŸDRþuÝ2l)€b®ˆ¨ -B5À8DšN¨maý—ýáž¿b`Û½óÊlµj4ëµNSéÜlŽï&l¦¶ÆCÿ>`À]ûíËú;£0ü¹ØΧ&!¾îôpŸX„ -W 2õ}¾g-Î#ÁrH">Þ»Ùmù$ s*+°Ë¿ÇÃù±ÿo‡ð¯m·ÿª$çüŸBRþ %È@*¿0P±)0dÎR4M¡Œ(H% ÿš-k¢Ú³fce®Vå.{Vº²\½†ç=ùÝ /]½öZXzc^ø“þ¿ ÞÉçÖÁA€—#~تõ&Ü«âËþÃÃ�'0»üÏÄ5š‘¹üX`/ÿòvû¯¡¼ÿÉü3™X2@Èí?$ H¶f¶!ÛŠUŽÿNÿ__Ï¢ª=+¾æ‹Þ3ôoÑÂp9ZµŸ*å¦ïø£{¥~%߀¾ÑÔÝõSÐ7‡ú„ñ -¼»Npñ½’:ÿðîþŽìòM§îÿoŒÿJ;ã¿ššûÿ'‘,þO5(q]*F€6“Á T¤r›[Pæá(㿉rÑCXUnœñµU–Aoø¸jDªÊæÌÒ«ÖùÈnú«ÇÓÇýÑå8|c8Ò«8FáƒQÝäàÿf5_-ÉMÜWòŽ6îßݖ螘ö4ðHôCÔs)Öàx`_û¯jx»ý—PÎÿI$›ÿ¡+щ4U4ýPXa Læ€"Ubš¡z(ÿ©^}-ž¸w¨þð,ŸïÉí¬?¨•BmÉVzO©ÕäG¬ÞØAÔ óEïQÊÂK›[K”5ntcÝÿ|æ:ß1XÜÊ®kF¢ˆ1¦Õ½¿¬¿ú¬\ž‰jú¶ÿcd‡ÿQä ;# -"Ç;R`?ÿÛþ¿P@)çÿ’òÏmY•)A@²1k”aÀ1TUÒ9cô˜üWvÅ]êǺÅÍà€‡ ¬ª½ûéMý\½ó”VgàÖæ)ÿï”òÕ\v›×ÅjVú)ú}àëß]ýYx““¿%ŸóºøŸpýóù?H²þ?$œ0(þ%@Ö�QUÑþÛÜ€ŠD‘xHÇäÿü¦íF½ö7dZ¯ì ->:¦Ë+çWc4w¤nÈŠ5¿ÝÉ{þwÙÿŒûûœö}ò1ÿÞÔFG3�¿À?ÔrþO")ÿ¶¦ª¶%ºþ6×Dû¯+ˆæ_ü’0¡¶®<ÿûþ¸1¯ô–MóÁê¶×lêFóGÕÔ-½6˜t[ZcØZÖ$ÞÜðŸ(å{ÐŒ‹¾°�9ÿûäcþçûDz—¸ÿWpîÿŸD²øÒ,¬©¢ë/S#nÿu@5Í°,s•a|ðøß!ü7ñúÉaýIOÕF5šVP"å²3õªòÍz>®‰‚¶¡Þøÿ»¾÷+¿?qøs|Ìÿ’ó#�ÅÿrþO Ùø¿„TŒ¨,ÇÿUÙºAl``ÑàŠ.#é¨ýÿe£ -Âé½¹¬ ÊbX‡+•jwõç`Íe¼ž<[ËÀ/Í&vì”ïù%Ÿ·þÿ~xÈéß'ó¿æ$py'°—´Å¿Ï�Èù?…¤ü«ša(œZÀÐÐRáú‹öº%K:³ûàõ?‡ðîgdÙ·ç·•Éôög·DêVk7Š5tê—v÷Ù¹Š–®×[± ÿï”ò½!èg»’Ñ€Ï,Bø@>çÿ”í?ÚmÿsþO")ÿ§˜!†à_µÅ–…FÁ¶‰F%Æcò3æ§=4:ô¾˜úøæ²|mÀΰÍoŸñrf·.†¬ýLÞó¿‹ýçqÿÜ÷?@vøw§Ç\ú›ÈO·ÿ2Êãÿ'’,þÏ(d:¦@Vd @„ÿˆk�nhŠN$¬ÕÿŸõðáqTž_ÒëæRLòù`<|º[jåšÇhïÁ\^3»E§…tí?|E¿š1)ÜjðÓI.àþ«X+ŽÿUÌÇý?“þ=n9sï¤ëTm{ý/B8ŸÿÉæÿ@MEÒV ¶T CÑ° Á©DݦGõÿýçkdI -lë¦Þu»Ú¼VšXu={â]NÜ« -P#(¥ñ¿T)w,@Z¼ÇäS¾’þÃÑ4ˆŽë�ìoÿ·ýQÿ;‰dýÑý·%ÙDÃz<€…ë¯È€(TEP²5Í:xþÿ!ü—Üg¾^G%½î—‡«ú…q©ôªWýP\ú`¬;aµá¹t°ÌöÄJ¹ƒRº‡þý¯%áŸû‘`zâ ÿˆ×&þˆ§D‡â6þýñ¿íù¿J¼?çÿ’ÿ«2bIÔs@áûa¸¥Ù2‘Dåƒýÿ×ÿîIôã>Žºl†Ðúš×xp}3º½h\¦tо²&¥Úýýzrgž.õ}§Ÿ/v¡óòY<Ð!Î¥î®g<[k˽$ÍùÓ·ý#où_8|™òïÇ¿ì¹ëž$ÿŠwóÿäñÿÓHÖþÛS°‚Dû¯ ÿß`P5^ HmFUj©ð³ñÿ´½ýÚ�ÄÚ´oB Duu1Xø‚Ùº1|0:ÊèB©¯jÎ"úRty¦ÁWݬ^Vü}ÿÀ$‘›€mù‚ÿ <Ò2Àýþÿöú,«yüï$’ñUÛ†LŠmqüOøÿTÕ�䶎UÉf’òIÿÿHü/Üþs�‚™bæ´Ý�†µ±ûÔy†ä±©°LöuëbY zþ…‚¾¶ýww9ó¿"_ðr°‘鈻ú-C°()Ûþ?Fyüï$’ò/#UÖã ¿² ^Xª* - ºmY2‹?éÿ‰û¾f_-Ì‹çrç,gKjWQïÇþˆžß<^hî¢c©sÂXÃÿ[}õî’ÂbR˜û{e?ÿÅãú°—e»ÿ/ËÎù?…dí¿bS#AŸÄóÿUU†¦YÀÂ6Ñ™f‹^ÀßÛþk•›6ß*jÑËê?´5ÚÕ+ö} -ÊýÆÍ]Å|ìÃsuÐÜá?UÐm–nÒý8þP…Ù<3/ø8 ý;$þ·ÿkRžÿç$’ñϸ¡s]2T�m®¨¨qüŸK²Õƒ×ÿý -þÍgãé!'½~CòÆÒE5Ðãv»ˆ -侉}+³õ‡üSý|á¾›~ÊÙþ9ù˜ÿ$¾Ê¦ÞŒ°#ŒîçmûÿÂ)Èù?…dëÿeMf²¢¦KR<ÿŠm[²060ã¿‘ÿÿ€ø?–+w¥À¼nݲá\«jã:¬·\¹QêNÈÈãë^|Þ-=¬‰>ÜÄÿ3ý|1�•ìcýÿù‚ÿ“Åÿašÿëmû¯æíÿi$åJº&I -Ô@€Š!CápY—m&Qþ†ÿ€ðÚõšiOûcÏ¿¿ŒæŒUa¥K®ÎÍÚìF.«–Y 'ÏÑŨ¹1�ïâÿ1þŸn77{%åq?t¦ÇMûý*{ùßnÿe(Á|üï$²!5ÍI—d³Äö0Û\ûÄsXšk3'.·îZ/›îk¡ÅYë¤$a?œ‹Ê>ÅÉó³m?±!ñÖöAÓlwév$”2ÝŠ™M·â×£y$Îv'´¦ðš,0Éà—%éK/&«¸Çèt`½*nõòqEÝkv!]ãæ0¼^Øåz³´pÌp2÷ZµörRÝJ~ð§Ú%á?IÍ[tñ “ü„®ãOÌé‚cý~&ð}üËÛùÿIÍóÿžF‚•äM5‡eî²ú¸Ô“¢h‡cϹYªúb9ë7)(¯0›wµ!}jôºýæÿ,3ÿK’˜ú/ÉJÿLû/Ãíõ?Pø¢9ÿ§`ºÖÞs¢¬Qýš~®ë*¹ƒH^Ö‚pm¹ýÒáíà¦U¹³;k©MFãù’"=§ÿ¿B?îOóàÿr>þw™ÍEÙ¤$b#3tžhŸð¯&R·Ô.?»)Røȹ¬cZ?¿½¾p¤rÿi°¸µÎ}\Ùs)7ÿtÉø¦è‹¥ã~tjOûþ/e{ü¡<þÉòÿX²#ÌåJ<þ'iÀP%$•1KCW~æýŒÿ¥›q§~ßLàroŠŸnžˆ3 m³S1Âë>ªO«ÙèN…Œïë—w¥Šwÿf&P¬²…D•³7ã&YX;Ú¦›ñU˜K'oîÅïâÛ$ëO»@Ùõ§—û~e#B |’fЗQ@üÐ%¡îKD1™yôºjƃР³ÓùS3¹È—ûÆ„òM=3£ïå'}þq¼äonþÈÿ±=ÿ_Õòù§‹‡,pfq� ysÏ+ ‰¢&ï—ð‡ñ[%dE/8,%ngBi×énþJy ÿŠ•é¯¸RXðÈ„›srËôˆ/ÔÛ2ãÝ¡qo&ô=þçTß¿¶iN¦}Ÿ¬]ÖŠñ|‚ÔWZ£Û˨j¬€äÓapøIC¶?²Å¿3—8¾?þcš‚=ü˲´“ÿS’óüŸ'‘¬ýGÐà -´€p¼d�-L€Î5PkLÖ(ƒð¨ùZõF9Ò&Ks~;jÕ¥§¨£TýŽ½»›a©mpÛ€wæø‘¶iƒþ½RiOàKµõ¬¸Q××7õÈR!UéÄI7Í$}0td–9%ÉšÇ}ɮͻwÒ -Iá»o¼}ŸxRá½ñzæyàîœQ”ý™¶Î“|z{óÅPcesz2¦³HJÿþè{Ër9Ždöÿoõ�÷ùŠ²½þ*JîÿD^Þ¬d~`S‰»$ëÐGÓ¥ùZ¦ã‡ùn5çvÜT¬²ióZ —µîõÒwÌPOФŠµj×£U)÷ÝþŒ¼ÓgsÀ~ØGÌûø"ûù߉ÿ"œÇO"©ÿ§Q i(Nø¢j*€†N.ëPå*‘¹ªÚ?ùþ‡ÄÝxœ]ÄÎQáÿÙ»ÒÝÆ‘$=¿ë)´ƒmxXÚ¼B¡gtX²û²¤Â�B2™IQâeºàÚù¿oÐ/¶L’’u¸Jîn[®n3~TId*MËùEFDF|‘øqŸE3ðvº+îÇXÞû;ùHrˆÿÐÖ^]œŒÿ‡ùŸ¼$dùg‘”ÿÆàhLDŠÀDÈS² ó`1ƒŒ9ýyEÿ5†¢Y+VK`$sv±>aéúŠ¢¨ÍUU£lÎeš-U‹Ewžæ{ÛÚ6ѳáØ9ßýõ?ÐÀƯÿ¹ø–Ra÷yaßû{þQåÿëå«õ~N~;þ:³ÿÏ# þUAâx,ÒÆ*Cø $Z¡ ¦Y#Y’Ñ«ò?rBáj¯± - Έ–Ëõ¸Ò›‡‹ÛéHíAËêPÁ0á‹Våþëš$‡.ßÄ?—áÿ%²Å¿}§o8‰ÿ#þ'žÏìÿóHôg'(½°‹Ï9[%IÙ$Pn½^GX]O¨ °ýø,6’ÛÔdvpÁr.@‚Æý+öÁ¬¾~pNü§+'΋ë$B¾- ÕèãFØÎ*…ù¨ßøÚº5ìup4]Ëÿ'qÿÙâßFº xƒ*Ó翇ñ?¥³ýÿ,â#ßOÏ~]àÅ›Uñ)=¿ðÐ#A?“±ë!l,Éâ(=ŒÀÑç..LöþU™Ñ&´ñ}#@ãÒ'0^£ÖmïV îÅÁÃÚò{ªTÇ¢!¬Zƒaw™o0KTƒ£r[Í΀£lñONþß)ÿó8ÿ‹§Ù,ÿë,ÌàÔòcÃŽT�Ž,òýË)µâþEr”™ 5ôâ¨oMµ³»|Þ)ÛÌšè -d“9´ÍÙæfµf¿²ìépõ[$ÒSËý«Ôæ8ƒäpåžyàÍû}¥¥=8aùáÞG»Æüzê;£êR5ìró¶—£‰Á¯Øf¯Ñnß3W>)Ì{×ó?†{àŸÉú?œGâê˱xÉ‘~ì+o’ÑÙºiÄülq`~ -æ I;ÈÛ Ãß~6zèG“§Æƒ‡,'šØ‘@VÝpHfXšçñ“ë9Óh^ê§9IŒ¬ÑŸ¶{”ë\ì|ÈG^4düÄõ> ×ÿ|u…÷RóB˜—Ž§ÇYiþÕ΃ùW?Åik›uuúg’ZÈ…G,–$gÓX?WìÞµ`oDšCºq‹…X½Ìie¿ò7%°$gƒØBþUú‹=óÀÑ@ƒdÍãJJfþ¾‚]m„®©q¾}Ý+6¾Ú¦\¨—» -åßÛEݯó£ÛÚÌmú™Ùôa%%R{×ü_æˆÿ—E.Óÿç¢ f‘”¸œþEyl³>,vá°ß¬uG·%…r'Ó&ÿÀ‰¶mƒú Ñ7KË뇯ë -ÓÏË- åÂ%ˆ#èqýOä“›ˆìÓðµbA§ðÏó‡ùÑݬÿÏYd“ÿ}弦Q< üÍR -ËË¢EEÀ+PTÞ’ÿ/à¹æÃbÝâŠ=æÞõÕÆJ¬.êÖxÝòT×½¶¾-úÙ_§;ÍÈÕN�OÕ?®ê1“³ÎÏ{|&C.ž¼ÙäDé/ŸâúþãÒ ?0àlõ:Jà$þ…#þoÏðIù¿$È4((“þŸHÅ”‚h†’‘†X¬0¿<ÿÿ÷àßoª¬x×]q¸âfó=5Äñ¤þ0‹ãÍÕ¹7[»Ìjè'ü¯Ó¨G·6* —yV|kž£¾…ÿÐ~= pÿ"}ÄÿÕÿžGÒþ¿˜C¢ˆ%И¥x^Q)Eå!ÅhˆAVÞÿf©®XóÛJ>”»Ù¨°Ø仞´ -÷-¯ÔZŽ XÌÔª&Îð°NŸ×�›A'tÀá\A<ƒ×s’@Ýk9�§÷ÿ#û_b³üϳHºÿs -/R*ÇóÏÊ2¥JG ¬Äp"f5UySü7èN©Ð{0ª¼Vu¼Ë;vJw+ƒÔnVùZ)uª‰]Yyjÿs°N·Èo%—·àœèy£×1Ûà·5ÀÁlûDžÃ¨’ ÿñÄÿ%ILvþsIù¿(BYf)0ÉÿäJážÒ p*d$™Go‰¶ „e¹Qô0hT»Z«“ŸLò~iPþúµÂ´îškIƒBEïØÿûëô ÿÉåE�ö§øˆ!€gðïƒùkFÿ^²ÿñ3Rÿ?‹¤ùß²JC‚Húÿ € -9"’ÕÈ5ç5ôþŸ¯ƒÿÚDó¯ÚØ-ŸÅS„ˆ_Ͻö8¸¾wpmÀ‚Ô]å©ýÏî:Ý‚ÿÚNº{È‹¬þT„ßÕ;Ó|@ðþCû•=€Óþÿÿ/›õÿ:¤ý¿EV€œ‚) ÒÅ«‘' ` QÓ¬¬AÌBü¦ñÿ»‚Lm6ë¯UWúÌ.¦ŽšÅ^=h/ÍÙÊšÚö”‚Åýÿpn•@YÎüɈ¬ëE.ÀÑ„@<ÿ×õ�NïÿGýX!ÛÿÏ")þ±ŒYV”$cHñ¨P–B©VZÆ/®ÿü=ø/JCy¢”æbÖVV‚e÷Ù»µ¾ÞóoÊjë^̧f~t½‡ÿç=€þæÆ‹|€Ãi>–°Òja7‚Ç/_GœÆÿaÿOšÏø¿Ï#)ÿ—¬+9õÓ(ž#ž€ªr”,Ð2 óê7úÿ¾Nÿ¯Òjå®{¸72t¹Ü^Pœ¢<´ðµZ«¼ÉPo{ÕÖ½oå;~Ûþçxn@ÜÉ”ÛÔÄŸø‡ÿóFÄÏ´ÑߘíCh€gð ‘ùŠ -à$þë?YZ2üŸEÒø?‘Ñ�%²P¤xš…”ÌŠþ^F¤+¾˜ÿå÷àßž{5E-æº0·XuÚT¼¶].¹…¼¤ -ýiwÒíb£K•úOø?^§OÍÀâ[Ç tB;ø®&xfÞ¿®*xÿ¡ýÊÀiÿÿÈþ—2ÿÿ<’à_£#„k$õ‡UØÿX¥dZ)NPÌp ßÿþ»-¿?ô;\ʳât´Xƒ|u�˜‰`¼Z‡–j=[šÑOøfî¸�êï°ž›ñ¯ýX6øƒ‰ãkô%�'óÿÅcþ.;ÿ;‹Z£¸ÒGK>Åf´“Κ߇ìZä4_®óë–·2¯õrgÖMC8XàÛÞzZâá”™u4¬g5�?®¤ø‡Þ[5ÿüÛøó£ÿÅŒÿû,L<äO3.röÐChxÈBvàÀ³ [ÿœ‹þ$2MÞFžçx¤-�ˆ4apÔõdô ½!´ -ˬ˜ë.7y±š™F¡PË{–À¸EªkyC4*"I£G™Þx{IñOÊSß ÿw˜ÿÇq\æÿŸEbwØ[íÀ5ækÁ†ç¤L™T)†…ÖŽö]‡žã¢«¯¡gÀɦKolñïBì°ÈR¤½)™Þ™é‘½ҽ![iõh¡1¨VÌVí‡r…íu*ò® m1uWÒÀq2ñ[eƒã÷ÛÿéÃü¿èMæÿŸEâ²eÌç`6òÇ&Z¼‘³ÛK‘`˜éµïC•�Ûדå`<¯Ëc¡øšLå:h*ýÂÍP§Í†Hs-1ü’â?nö~ö?Éÿ¢A‹ðÏgçÿg`šÎblØ>‚¡‡Æ¡k:€ô§Köé-Õ -LÈâ“røiÛÂkl¥a…Ö8n_Ç2âÉÂ/ëžRZðTåÔ|óöᦶžÔèâ¤`'âX(•£r68‡¤ø7,Âu£¿>÷;‘“ñ¿cþw:‹ÿŸG¦.ÒÇaÚÐRN·ƒ<»»ë÷&7¨LÛó™3\µj¯:ª,õ›Î´Ù™÷ø²àµ3øþdÿod�œÄ?ÈÿHŒÿçÀqÌ™yáºvŠÏ0ô7 Š -à×”kð‡E¾4eš!.!Úwáä¾fU‡‚ßûWÌä;’â? ß¾ÿ+#öÿäéÌþ?ÄaüÈ韓có‰q2S7ä({ê¯M…-ƒåÔ+ÖzU‚Ó<†ÚRb̺Ç4m)‚¬¥ÛŸARü[À0ßÍÿgÄ#þ?ŽÏâÿg‘=ÆãmHÞ¸c²$N(o¤R8iÜbm4Æ_ûr¸ºå«Ú5½îË¢¼®5ºæºê\gÊàÇ”'ü“J ’ùxþþ}ÔÿQÌú¿œG,äûqðîâ_„„8‡ü ‡Hálèùès»#×pB?ç#ϱã{ -¢a¹Àûõýœj ;øõÿ‚Ë\yÐ ÷çNà!ÂpÝŠ>~±¯¾¯Z¾ -õ¡½²$U®óú’®´EcГÝ`ZGr¡¤4½ÐÁƒÞœi“? ü#;¼L“£ÏÞÿgŽú¿ÐlæÿŸERþbÈr¥�†äÿò¥Àè¨p‚Ì@šóšýßêãÂDf¿´ê·ùÅ=]Ñûã†Vh<ÌÖuYòkË)(jå©bÙ‹8ß7]™Oé½;¹ü9+®ð×PÂLgé^Ô{æG -Š°Øk„ˆ$“ŒÞ9Ú+¸øè]âöðOx ߥÿÛQüŸÏêÏ#)ÿŸ -$–Å,%I -¢xÑ(•á9 -«�ò<Ab_ÿ>p¯ vTª8·Êª}ÛôÛ{vÞ×Úb©oè{çW= åkI¾¼27èÏ“7„ã#NÉ?�þîÍëðg$‹aæx¤?/»øÇŽ9ƒï`ÿùÿ¼(füg‘”ÿGÑCH±"ÍQ<Ö0¥²¬FѲªbYùuû?K+Ïkeé,*„°ÀVZÃj·ÞÆ7ŠÙít›|I”¥|&äã•ùDñeD›º†R:}Ð%^Œacdzbý¡ÿ»²‹âë½Gý'õã2þ¿óH‚1P`ešRe R¼ÌcJF|d ÈRdþ�öU÷ÿ6ÛÜ;·÷3sÝéòn(2êªÓ.ßòª»•ÚMcDÍlGŽñOV浯açl07ôàÏ*�?i ÿ”ì⟜¿Oÿç£ý_ÈêÿÎ# þI¢Y(P‘õ¥P -£Ð¬ )€ øªþ¡X§æ÷Ìzݵ›#kùθVšS9_¾›÷–R¡jŽå -\&û¼27 - FônõqD€K ÿ?9ÈŽ-2ÔUZ’œ©‚CIñï"/¶˜Þ#þÏÐGù?¼Ädñÿ³HÜÿ1éþ¬§ûX&ù¼ô'èÇõü®‡\ÏÈ÷·õ<úÚpÓ7øÁ˜§y2r¿=aÒÞ0úÐÅÕ¿/ÿñÏÏÁ2xtmýQ7ðãÔEÿÔ£ð8õ è<úüˆÍù#ÔGDÍGÍ4Ñ=ßýù¿¯Òˆ-¡òßíÄWÑÄ~°ŠÀýg±Å¿ÑÏÿ¾º"Ã'EL†/ÿUj{£Öu|á—/é¿h¿| ŒÀD¿DÏŸk8A®ì„¶öå*¹øå*¢:Ú*Îü²3"z÷Åý¥7AqY$òIœ±ß©åþþ/òhÏ-€Ÿ³£á˜ÏE¦H01âÓyäb¹r£É“i¯â‡¹ø4}ÁWUÅÝ2ÇO…›9VPXúdæµÊF_¶7¥Ì¦•ïݪšàâ.–õûýPÔ–ËÁdñ�Øjá>KÝü8’êÏ«æ{Aý{”ÿÁfõ_ç8¶ÌDkìTŸ"?Êò“Â0‹dˆ2¤|n ÅØŠUC´f~ˉnϼ‘/º¼«ÛÇ)Ò£PñûETâMå®m·ÍR?S9g“ÿäìÿÝò¿"kï˜ÿ!‹ÿžERþG�iM -%@@H h’!’)(ª‚i@•û”6è.Æ ÎÝÚÄ1s½Èô1lýâÉKOjþ…–ÀrMt ë“o::H4ÊÆÆäi.~O^ñ高 ùsÎ^E1ìOI_ÚhÀ U:I]Úú„t�'ÌN¤h'z_m”ÐoPQ«!Ð:×’t¨Š¨-';k€›Ÿ«vwÞ+‹“&ïæõʾý«¨¨ÿqóßKÝtTðúy §ð/°Gùß’íÿgæ‘óeǬm†…f´ØºšÛÚ¥e@Ïñ\’QÛ~õ1bCÏܼòÑwTâ"„^˜PÆ$¬j®És³w3rlÀ”j-±yÂÍû„ûyo®D)DJÃùüòGü¾*¨ÞÌdo]e+õN a'XöLSnKz%z<h²•²0µ‡ -üsÓÔìáÿ½ê¿û?2œÅÎ#ñcd‹ò…ÌNÀC4Û‚ÐÖ••¿Rëm±±¾›òZ`´-?kŽ–Z‰ìÚ”7žÍþÔðøË!ÿ¸ôQ@l¸· -œÆÿQý§”åžG¶¡eBÙ:Ù>O39fh¡JR§Ð¬rc0¬·|WveIW!Í5æVQеuË”&÷Y%Ø+ĺĦ㼠õC,'ã¼pˆFÈüÿ³HäþÛ\mŒhçá>&oÿßÞ‘-%®Dßç+ºæÅ™*c%@ØÞtœTp\p´¨,‰B;į¿çtwÂæ·Poyû¼ÑMNŸ½·ÓÝ~à†ã*Éc@à£î´ZüJëW¹ûå¤ã=Ðc£U¾9TŽ[£{¯ünÐò~ÜhiyÛɵó½ßg±ŠoÜÿ_õôç‹þ_Âdïÿ×uuþóM@>vÀý” ÐuqW²J>ÿå:º~õ‰†kWÛ—Áe°›îwâ© -ñ5™à1°ô8ø:±) ÈÀr)±ò—«Ãbè„C¨›ÀD~ü(‚0ŸÀì]³™O½+Ìàpú¾s£T±‘ŠY$dÄ £ Z¾Iü„øPDZÚ,#'زàI´©ö+,l4Ûß«7rEE_¤†Þ<U¾ØÎetDYìÛ}Êyig´ÐûÈg4†–J\`i‚ozHÓØï÷A4Q‚ñ=N¢@$¹•¦‘YQ‘„ZƒÏ xhßP¯åÜ•¤ÌÑ™jÃa<¢³àlCævXš¬«pþ?L“âá ÿ{è‡×(²Mêįᕥ_EÎô<UÈ`ŸTrñÇ"w’l‹ëïBÄV°ÎâdÜ£Œò2Ä‚ÂàT¤ÒØ!µ$3ËK([ͶÖ6†?ôäð˘ gt.éyUk¯¥âkbQ<0µ’Uðã¢Öô¸´8‚ÄÜgö! f‡|d;à2âú—“ëùúmþ)GcÎÌl»©§„c1z7ÄO ¯ãÄ6S±1#˜æ’¿Òvª(äi³+Æ™`A¯O+ñiƒ -Â.Ø7GV¿+/_Å®Ú=4ƒ˜±…×ü| QÖó_µi!.M`X¯Š0—ÌÌgÓVq*Šúr›0c× ]gÈDUЬ¤„¤”ì&êØŸéãDU £Å³gF{P!Åá5ŠÒòny3Ú²Ã! Î4¸½lÛÜš:)×5Çëiƒ|ÉXÇ@ àë3j]ÈóÊârãÒ§î‚äw¦®G]?ávûʬˆfþÐÏhÅn¯3;Ðy¤»6‘"üð£÷ŠSRÚûÅ+ò%õü©!Ù2·|M3Êæ;f$ѽ²£ËV¦\ˆÙÅæØHñ½2i3_׺f¤vöÐpONÏs–ïõïÙÏVû°æßµYïºö`Ÿæ¾i½?‡æ~à×>æ*_ÿa!Lg¡» -&ƒp¸ù] ó¿–îÿ1¡Lÿ¼ˆü¯œ[¡z™šše˜Pñlº–£¦n›¦é¸¶»Éó?7æÃáQÓïÝ}Óí£QËMzæ µo#Vß+_ws?ÎÝõ¼¨þÊû?RÛÌî¦%ü:-™†güXŽDäŠvDÙÀclñllAÄ¢q<}ü½uðž0ãÿCèzƒÇÅt³›A/ú¿±äÿżºÿãM@øÉÉA_—4S÷òZ¡lRR4Šš‘·]»X1Ï)nÒÿݺ~˜Ûo´nÌ»âùéÅîÏxxºÕÛ:·µãñ;i6#VîÔ„ÿÏÚæ4Ì–.ÄCÅ•€ûÿ;ç”–ßÿ*jÿ÷M ëY«Dt©ôÏÂœtE>7÷ï L „çrÎoMùÍm*¤ÅKì…Št”½ -¶8É*žX§Nñ=¿ê¸ô¯¥&ñ´¾JF>L-B&#Hö¿O’ýMzáÂ3䜗…Ý•.NÌÃ!¤\,èú´6N˜Ì³á ¯1açÂETÚ+4lÖ?-PzqØh ÚíÈû#í`|ÑÌ}7¼Vë@ÿ_Æ3 -(P @ -(P @óð‹`Á�h� \ No newline at end of file +‹�3Õ¸]�í}{sâJ²çüíOÁNì„g"N¹õ~8NÌ^ÆƘ—¾ç†¢$•@ —õൽßgïÿû æ‹m•$À€mè>4>sZÙn©T”JRþ²²²²2UËÕ&Wjü7¡?Q n›ÎÕ¶þr*¢(Jà¸ù_øøŠIÎ Ñø_ŽfYQ¤‘fÅE<Cý%G¬PDžwų 6ú ®f\Ož%·þÿß„¢ÈÔ¯s¢ÀjœÄª�‰ª8$Š@eÐ4„’Èð£jt†š«£ëœá_à×FÁu.ô#t¡#9:r4×¹œæ:†9$G¹È‹ Dö•œè*f.\n»zd¡íø$!{SJØñBÑ\?.Ò‘#+T’Æ•F×¹R/_ï`ÞÈß#?o/:R©áenj‘ìPMúä•|�êœvAô‹_$7Ko㣡é:øÌÔ‘ +}Å0ý ¼˜!s8 +¯sô…ç»S|É¿Î9‘e]xV44qõˤë +y8%FÑuÜøåE€ÂÐt†ñû w~¿f.gAY×¹<97ƒÐ‡!î.ßÜtý†âªŠn˜_×¹©˜ª…È4%mÐñ›òBün(|ˆættZ–bâð3 ‹øw¦e†¸ÿËýŸ‹ÏæÃŒ>‡Ô=ù¯ú˜c0çžn8 ÿ)‘g‰üghü‡,ÿE†2ùJ俦#¦5H,¥Nƒ*Y�´Ê 9êü7ÈÿSIwã±Ú¯dº;/Moj“eñQz.pf…ò‹j#fº*2ÙaĽ’î+~[ÀÄu-Ù©÷${*®W%"{Oª¿]k-Ñ/ÛXêæVW/é—©H ð˺ék~Uê@òd»¥®´ü8¿|-jd +N"á_`™mü3ÃfúßY(Á¿*‰´!É`x㟠P9†š®B•ƒ4ÅKò7àÿ›Þ4»ò…ö’Ëãžý<ŠuDNɹ1§S×sîÂØ’ªõ›W@ßâÔ·ÑŽï"g£Èú]ÀoµöÜߪ³{Ó7mè/r±^—Kkmƒž¼…·!ÿIÙ{øa09 úÀ?·7þ‹´˜áÿ”àŸç9D±dž‚€)@^å«ÄhˆÑ8ƒû‘ø×�%¨êõ8àƒª=´&"çyÃNOfoBÜÜ—u³û\S¥ûÁþcN=ýÌôÇm}ˆý×5ÖÈï@58æ¤V,%Ö£w€p7õMÉyÁ[øž×þC <½ƒg2üŸ…üK’.Ï�UDàx•2T !Ž$¨º(}·þÕSÿ{„ײÚN¯ ÍçÕZ¥üX“5RjãöDóØúøvè<ù°N뮲%†ßfÛyW$~'ͽ#ö*lT¢ë8hŽïš‹BŒå�†(ò·Uôµ¼cÐ9—ØÇ¿‚�Ñ©ÿ¿ƒaoþϲþÏA þ¡ +y™gy¬ðc!À1† +d!À3‚À¨dx~ÂüŸ¯Õõ kxµê\™ÏmÉthºôÀõoºôßÞYR!èå ÿJ¬øù?F½Eô£�«?6ìÔzeˆßUnuýx3À„À>þ=ÜG%4CJÄ?½;þ‹|6ÿ?¥ú?#j4ÔiÀó2ÿ9(•§ j†LͱHü‘ú¿´ðÂ’!ôüþ-д»äœ&?5|±Î[/ÅBÍ1ÑS¹§‡¯€¾áÔ#Õö] ošzã{6ððsÅuþàÓý=ÚÇèºÖ ÿ¿±þKí¯ÿ +™þJíÿªÀQHb�+ò2à2’5Àò,2αX<œdý7f®jóbÃ?èt‡ýyK†T‰V<]šÎë7#£æÌûÏš4ŒîÆÁ+Á‘ôâs„7VuãÆZÿMk®%IƒÌ‚£´ƒ“û’·{¥ãé‰b¸¾ Ã+\ÏR!–§“�‡ÆVwÇ\3Ãÿ9(õÿJP‹‡~Ka Éš„ÅŠ51M0DŽ=ÿ _}[qbµùJ¯ïÏ–O°é žËù@˜is©Ë”Ët_d†v‚i4Mìý+¦¼X¹å˜YÉ Kx—üï#Ï2//°žö˃aˆ|ÓÒ/9û‹þe€ÅÊÝ5®öÙ¯ýC{ø…6–3¸à|ó<ôgëÿŸD©þÏA5Ž”Aáù¿lP�²,Æ¿dŽ¡T¤Sâÿ¦Ñ²Ân«i5¡Ûb|ížë›Š…Š7÷c>2©Î# =jƒÎ$Æÿš)×à®S{È•pÉ{�èÎÑûøMûD2àðøOï®ÿS“áÿ”à4K«ÇøUÀ!YÕD€DŽaXJBš¦žÿã¹Q´fÏ•Ç~Eצ5ÿ€ÞD{ž—n»On£röm¦þøl•£›mü¦Ü—¤ôÝ¡?¿uð°4²‘‡ÞÆ¿í:áèd +ÀwŒÿÿg¡ÿ†À²†Ž§þ0þ%Fþø%BÕ$Yåöÿ>ÿÏb5*vg5¥§wêÓ͵¨Ï*’ •Ÿ'ºPÖge +Õ6ø™rü5Rô¡ý½ÿÓý„âŸÛ³ÿ3L6þŸ…Rû/è¢Àâ©?ÊDÿ—€*H*d]×EÄj¢xôúß1ø¯‰‹SLº¬0z\ðž¬ûyx[(˜£Q·D7ѸŒZ2ûüjüßû;ûñ€Ÿ÷èmüÏ:¡ð{æÿ—áÿ”®ÿS<+òªtžØÿYZ’ ‹Å F¢yê¤úÿ¬Zâzû¤ÌÊÃ)3V8[ËçËíÊÒ_ Z\L–úÌwòÞÄlðO˜rÿ=\òþèÿ[¯—¡ÿ½ÿ‚þ9ñÏïã?³ÿŸ…üSH5¨q�BYÃø7ð‘ÎC 3È0 RÒO‰ÿÆMÌVÔ—Õ§£HãÆ]áA懃Ô|é‹3ϨߵÖÒeÿ#L¹ÿ.yÞŸýGÐûø·Pœf!à þùñeþÿç¡ÿ¬ c¨«:ˆñ¯32žúcýŸ—%¦$MgŒ£÷ÿƒþɃ³š_mÞ4‹·Á ¼&¤:¥rƒÑ‡fåÎè,ÍûpfÙݹ¶ÿ5Sîr)^ |O"dëoÐþ-÷”[cúfüÓB¶þw&J×ÿ4•Ó$Q4C€ãE<þóH�<D²ÀH¥“êÿîP +zýQ!ºSj3¶èš…›çñ𥽕e[S»=eö uÕ½HöÞ8Ã5âKI‹qáà'—`ý’+çÆ¿ä²uÿ÷hÿ6ÒÍÈ>ëþV`ö÷ÿdþÿg¡Ôÿ‡X^ç%€'^p¢Î‰Ãê€ÎÉH¥TF2Ô“ŽÿÎò×1ÔÇýJ_‘:VGˆÊùHYË6&öÝĺ/Æ”ý|bÿK˜rO$Åd@æúóíá?¹~xZàðø¿;ÿ8*³ÿ…Rý«ÿEë� +¢DD<õgh�•å9Êýhÿÿc🷖h±óRÅ)ç•[ùŽé–î[¼•¥ç±°xJUÛRŸgéÆ”{ðK ?ƒþÇã9¡.b Øø_‘½‰WÄ%:À¯ñÇÏÿwýñQfÿ;¥ëÿ,Ík±Õ_D2à°î$^äÒƒ†O©ôÑúÿÛûú±ú£ŽæñüâA[,Äç‡Æ¨y[½}vÕçÖ½>É—ŸzOìC€Ì(Ùê»ÅŸ+¹ð¸:ÇtˆÂ›˜©;¥{m5üWAs>ûµÿaè5þ§&š%øwÈ#²¬³ÄÿaÅýø?™ýï<”Žÿ†®1"Ããñ_Àú¿¬A ²d' jh*«ê,÷Þú2Þ~,�7r¶ü°âÌoÇϺx¡wÏ7dDC“Ý2•yÙœ†C‡ +ïA² °fÐÍŽ�|²Úñwù†ˆ;‘‰€]ú�ÿ~p¢m€‡õaßÿ7³ÿ…Rüs¬apÉýëÿ*+�’ÈR†F1ïÌÿO„ÿ©5XúÀ÷C®×<в|.(—Ç S¶æbÉd<ÔogE¿»Á?fÐõØßng˜ÿú�ÿ‚¾6RLüaç¿KÂ?GíŽÿ´Heö¿³P‚šgiAqø¥1ê±$PY†P2tÖˆsÀ;óÿáßx*÷SåvYx¼3ïñN5J<dŸÆÎH½iôokú¨³Ô´Áÿ¯t´ãÂ\\˜éé0þ}àÏõ{ÀAü3»ó†fèÿç tügUŽ¡‰ÿ?˲@è¢%M0ð,àÇŽÿÂm±Ñã&ó¨êê]žôZ‚Ú‘ŠÆúâÕF»¨ôÜ û\Ûà» )Ý„û1! +^”M¶èü‡'°þcÿcwõžËâÿœ…RükH–„€DÉ,à‘ê€%öDѲȽÿ÷{à_[Ê/=ŸžtUÊ?æoKÏ÷ÛBs>3rÑÑCà-zˆÛÀ?áÏî;ÉY†ío£·ñÛW5×ö v‚µÀÃøçwñ/²Ùüÿ,”îÿ¥Z£hEÿ¨¢!Æ tQ”E ýŽøÿGØÿEºØÎûÊC½© #¡$Œ+\¥nÑÕ|gG6ZtË…›N¾·€ÒpcÿOùs%�Šéifýÿú�ÿg³ÿsIü¯-û6þŸ‡üs”$àoÂUæÀ1:dšÃJ�¢%ÚÐ(•æ~‡þ„�°[•²b¸ƒ±í<µ}¹æi%®Ø÷7JÙkÐùEIWJÁdÞŽj°eÿ'ðÑv¸ÝL¤ÿó9éž6ì÷šáŸ§ÈøÏóÍ3,#ä(š§2ÿßóЩILº8zœŽ‡éᶩ%±6SàrÃD–¾:´Ö…VH¢ÖQqÀ:gá¥g$x~zìÄ2„í6êÁp¤@Ë„AržD¿KŽC̤ÉÁprDÒ¥ÙD¿Ã¯üb<0Žè—íK:—V< „¹JÒ]®ZÚ-õ Ö†ÁÃÔ(Tjù©©“È®—[³Ii'ÂgÄßA1þãÐŒD¢ãÇ'´Lg¢¸Säû¦þû#Â?½ÿŸÁÙøÂ@À؈3Õ¹Gˆù.vA+ÛfcÆö¤éÌÔTPX� ÔÚå¡úRívµ? FþÌ‹ú«U°ÒÏÿinwÿ'ò™ÿÏYÈwgXÚÛf˜¢£Io?¤ge?XèÖ ËK\ó¹Q/¶ÇU +'Ïruy§òR†þŠõ¸ÏÆ?Ïíã?[ÿ;yž"+*µ‘˜KŒVþpî'T'ß*,ºË3hdÞUDµrÓ|¸5©ÂàåyÚÔo±82"*tJñº>ž‹%ë~ª«/Λÿ‹ÙÍÿ'p™ýÿ<”ÆÿÑiCâETÄõ?J�2Kñ€b5M—xŠ“˜oÉÿ÷Æú_rH&ñ‡<]W|iô^ ù[ÊcQ|Å-U½Q›å¦¢øT¹kç‹öÓ+O ²1+§™qã‚Ô¬n–“CÒef†XâE6ÉÅ· ÖŸLÒþ'ÝÝÞY¤A_7˜DЧ/B:C¨Z+‹bìy´Þå!?0ƒôvŽ«Ä\½7 3Ÿk+)úV·8ë÷'ö‘<üÿgwÿ/'dþç!šozÄ�gîY$fÔ8¿„3$Y%hFº0µ¤–núHÃL»H2Ü|Ið|!Ìô…T +.l8AJäDÒ:˜½u…\”Ùæwòã„ß?–¬MÜþÀs^ ï*rQ^Þ ÊIÕ{¡*òÍ»°$Ïå¨ÃÌàð”˜l¯ÒÍ¿¦£ÏJQp�ÿ4Míåÿ¹,þçY(ÿyNF§ž§hÀé" ¢ Ñ‚ªqÜIãÕ+ÕB(LfJÔÕ+ÔKøÈ”œGC´Ûa¾¥ÏŖ̵«µq_m]$úe‡,RåTŸ8ð%ÜzÛ°ë:SM]$,+"É¡‡Â‚z©RïyÜ»_ÚäÞI*Ä…[OK +^ç+l+ë;G¾µwG\öwÚ¹O|öú6ÊJP‹Ìæö0 +]o¯qéïï§æ-Ëè4”ÊÿªÒÿf7ÿ+Oó™þwZeVRީКÁE #w¦¬ëi#×ÔÐqº[ÙlŽklO/(Š•óbAè<ÌSéjϪ&ü-§2ú¼U çùLwûZ-Ó§>`WÆ ã¾®è0þwí¿<Ïföß³P¢ÿ *Å< ø +,àdI-! s,b!XÖøÆü±º±vÎ.ûøâè"™7ÆyЕ]qÛÆòÙïäg¢]üGŽ~rpÐþÃS»øéÌÿã,”Æ£²” "›À/q�2mȆÁëÏ ç¨Þ¬‡bµëk#†ª-��ŠªfÙšJSª‹Þ4õ÷vôµ£gÝur÷¯ÿÖLÃü×_¾'T˜í(°Ÿýžÿ¨´‹ÿåü÷íõ~‹¾ÿ™þJð¯ò"ËC¥Iü @‘’fPe I”ÐIã?²|=ÕYBsjCjh>_*·i4«ŒºòÜÑlû„ý$þæÊ-üCϳL,º¼‹6Ãÿ1´Æ¿ßé²�Äÿnü'šç2ýÿ<„?;Aé¥ã^^ç•8a#@¼/1V—#0‚NŸp¶*H.ƒÑd§Àvw +4‚Æíg§Õ`¸S ‚MÉõâZ‰ƒˆkñ¨ê]£µò½ÛÂtÐ?7+¦³oÂF½m"§íÒÿº¡ ðäðúï®ýOÀGþÏA +‚tí׃>´Q¼cÅéúEàF>1úÅ4<æœü >@éb„wyI`êÚÐt¶KdáAéÊ‚"%…ôŒG7¨YéTäðIè½,í £Š5£Y4ùE³×oÏóuzŽ´A¹¥fkÀßHkü“•ÿOòÿÜ÷ÿâD>óÿ:A+8XC^1,¬‘o§¡·ÉRf‚ÔÈ] ÞkêÕèrýjsتÕDV ‡´¡¯Ö6W•Àº™íe›ÅÕ÷~H*¤«–Û¥`µœA|¸rotø¨v?Zú‹•_žT¿¯OoÆ;¨ÎUÓ)7*¨8ŒLnÁ4:õVSùL_ùdcÞ§®ÿѳÿ§³üç¡x÷¥„~²¤Ï•WNHAÎÐ2ãøl±a~§0qÛñ[!#Xÿ6zàÆSåÁG¶‹Û„Ö×½ñKý<þæùî·þ6%®“XýÛzŒòÜËW? +«(›Xï£0ô‚ë/_ŒÐ»Òýȃ֕ëc¯´àË«Ž_þ»nõåð=É^È™O4–ÄgÓ\n–+^_uÜp«FêCyqŠ…X¼L!Ie¿6[^](ø’>ØÆMâ5*+‘”´ü±ÒÚú�Ý�%ߺéëÏŽ%j嶂'‡ài™T&^³ÐÍÔ¦Ÿ–Ò@jŸêÿKïÆÿ¥9æ3ù"ê6qùˆ·Ïå×Á4jýb[ëwíA¥$o4np/¬à8¬õê]«4¿yy^ÞÒÝL°ü±) ±pcz¼ÿÏÉ-DÆiíT¶ Cøç8n7þÇfùÎB+ÿZä9]$ñÿDŠ2ÃI�Q‚¡ “5Aþ‘ñÿBŽm¼Ì–M¶ØQµ<¶ƒ^µ¾ª³š,Û£¾Ëjh»‚ß®7ýlóé«ä@¤ôU&€ÍîÏŠ†&Q“µÎë®I•ËÍl6YQúÓ»¸¾ÿxëFšÚdq!pÿü^üoNÌðJã‰<”((M"ù?‘j�Q4ŽC¦‘q¼ÿÿ÷à?h¨Œpß^°Æ×›L©Þ .(£ÚËXtÚŸªS²ôèÅRüïóéZÔð¥•È%UÞ”ïµóóH÷ð9§“�ñ/ìÆÿc¨lÿïy(Íÿk°HxÊ`�ÇÉ*UN´ŽhÄ*DüÅ¿UªÉö´r›¤öLòC\Û}þ©é—šógµª“üïðéÛ`Ué€ØmëgoàßóÝÄPwª ÀáñOÿ„Ìÿó,”Žÿ¬Œ Ë @e9pŒ$UäYÀ3"Í +£«òÅz,:/f•Ó«nó8·ÇŒ©ömo¡éw‹üCÉ5Ð0<IÞ¤ÿÙáÓ5ò›Iñü¡‹û‹ãhƒïK€Ö~ìzÿ‘JŒþgÄÿnü/Œ.[ÿ9¥ñ¿¡ h’Ä�Äÿ“•ÌÊÐ5^fU%ýHü39*Kõ~…õj[o>æG£|Pê•ŸŸoéæ}£`Ï)X¸Õ•Wúÿ6ŸnðŸeØnâg4¼ÿ�NOiý;füß‹ÿM3™ýÿ,”úK*¥QløÐHþ?(Óx IÅSsNGïäÿ< þFzà>7¯ÆÃ|/BÜrê·”ðæÉ5¡VG¸¿Ý¤ÿyͧkðß8IV`ùXëOe@ô¡xÕÌO(�ÞÀäœxpxþ¿ÿ—Éò‡ÒüßÃk¬l�Q£DÀ©x& "†A1’®ŒfüPûÿ}ÁÇŽ5ja WÉ՟»!j;µ°5·&{ì8c _ÿ»|ºÈv§› �Öþí£¦�{ þ‚àmüŸvpxüßÍÿC3T6þŸ…Rü’Á0²DÉÐ�§A@•f�2ªQªLIÆÑû?¿ÿE±/ärÏšMZò‚·.s¿ÂçJ1¯kÂ]Ym>©£éØÊn¶ðÿö »ºpÔ`·™ŸK ØÆ?I ĉ ”øð4à0þwçÿ4›Åÿ>¥ñ¿$ʆ,’U?p,™ ¨*$ž’X‡§¾“ÿ÷4ù¿J‹…·ìQŸ¦ÊåÖ°²üÒ4nÔ‡‡…?ê[~µùØy÷ž[§ÿÙçÓµ�(+¹p„r«}'ñ/þüc% â>$Á;ýà ükÐÑuBpÿ»û?š§2üŸ…Rû?yÖ!M�Åh@bŒ™“C6è +GÇùü;SÿAV˦µ,LmF7d¿å”K^!/ê…BwܵۡPoƒRwƒÿ}>Ý$‹/íK€Ô47rÂ%ÁíþyEÁøœk�‡çÿ{ú¿˜ÍÿÏC þu +#\'®?ŒÌ`ü*(A�,¯B +c”Œ¾ßþþÛÍ ÛÙGMÒé;D³%ÌW{ÆH„ÊbÖﳆøÐqÄ µÁÿ|új + ~‡ðV‹^èÇ´ÂŽ\ß\¢±àþia/þ+dëg!²×(Þid`–O±‰Çc’YócÈ.V¤·lúëfX~œ<j ËЂ~ofT:Ëq‰ÓÆôäQ7†Ù€?.¥ø×ü•üó/GÄÜõÿ¥9–Î⟅‘‚‘kÅ›œ}ô™>²‘ÊúŽé¯sø“Hµ{ù¾ë“´�”,P$‚ãp˜Ô> 7øæLfè}Ó4ÊuYš-&–Y(<ä}›§½"hÛ~ ŠHÔ©A&7~<¥ø'ÛS? ÿ,»—ÿ‹²ùÿY(žû‹Wp㵦„d›2Ù¥š6ZºÚªtù®‡¾<G¾©VYyc+ Ä«(òlÒ^m™~ÕÒ¡@ +Or7òûÌm³Cñõ^õV6˜Û^ë¥|Ëto¥©¶4õÙØ[ˆ=×Í$Æ·Ò +ÿ¦a|ÞøOíåÿd„lþŠWÈæq<ËtP Xêñ@ά‹ðüÀ´Ò²¡J÷ cÛѼ§Lk’ÂWÃ@w±Tƒ ¹[¸ë)«.Pl3èeþ”â?Nöyú?ñÿáq-š% þÅlýÿ,-Ë)¦ -ò‘y–I~ºdœ^‡ZÑ’à�ñJ¹v±Ná¥ØpnÚ‘ÄéëZ8˜A8ä¤a±+—–c¬²j¾Qy¹{XŽ¨â¨`õG‚Âøæ•C)3œƒRü›6‰u3<}ìwBíûñŸ©Ìþ{h¨¼DiBK‘?¸Þ“ûûngt‡Ê”3¸ýEóáѯnçûÇqãqÚáʼßÊàûï@[øÿA +ÀAüs{ñ96³ÿ…B×µ&&ž…õCñ#¿w«¨�_8]îy&÷ø2Ë—Æt#2JÈÓœûhôô`W뻩‚?û3ú€Rü§æÛωÿJó»ù?91ÓÿÏC±Oú§dÙ|dôÔXàŒƒ¥%3e8ûÅšùB-JÚ8ohú\dfô²C7d}.À,¥Û¿¥ø·¡i}ÚüŸöâÿ1bfÿ?mE<^›ä½‘§–8 üÁ0£QMƺòÜm–£E…«ê7Ô²+ Òò¡Þ¶–U÷&LÚàŸì” žçÏÿÈR{ù…,ÿËyÈFAï.ÿƒ!Ρ Ì!²q6òúÜkÆÈÕÝ(ÈÈwøšB\-úÿú¿AN5‘þëÿ…W¹ò5“\Ÿº¡H„c| ÿür[|,ZžùZß4ü²(ÞÞä‡sê¶%˜½Ž4k‡ãr4 +%¹áG®ÑëÜK™4ù´Â?r¢«Ô9úìùß8z/ÿ³Ègóÿ³PÿCÐay Cšøÿr:5|*È,/ÑÅ +>eþ·šRI´”Ý7{¢n‡]¥®ê/“eMƒ‡ùõòX¶Yìï›ræƽ÷•/ÎŽwøë(‰L{é^>˜Î$ÀŠD±×I âL<z§hk#ÀåÏž%nÿ$ô§äÛ³ÿsÙþßóPÿO…"ÃEN§u Òj‡x,™Sâ?€ÞÉJ·nE^´*¥7¬<1Ó®ÞJmíŽzbü¢õüCâïsæ +ýyrBb|Ä.ù;À}c=„Á„x1L‚ŸéoÓkü®‹'ƒŸ ÿïÍÿyÉâÿ…Òø?²Žh +j€(p†n�•at@IªjHOK§Íÿ,.|«Ç/å¥>dP!Ò +Ìmó¥_m×ZÆlµÛ ®¤öÊb¾¬%™äcÎÜ„ø2ñ ®£4œÇ¶�h“YŒé®oÇò!Cÿ‡ôÿd®÷ûXawýg²øç¡ÿ4¢5ž‘( J¢8‰3€„8¬ H"Vÿy¨Aæ¤ã‹y„ìØp+OÊ`Ûãù}_ ÕÅc«üTÈ«ÞrPj5̘8®ãŸpæ«Ð¾¦“sàÔÆ�S�IJèü‡è5þÉZðçäÞÿ¹lÿßy(Á¿,Šch@Yã'2i™È`x]†¯ 'ÿŠ50}¢—ËGøpW§%ý%ÿ¨£ÛÆXʗ粒X¨ZŠt«Í“ñ?æÌ•�hD¡‰Ï¶Q[Hµò¿ä\#Dž8èXUPé–äLìRŠù±ÆôöšÚóÿá>³ÿŸ…âüIöçaºc߆óÄŸ—ºÐ‚x?¿ç#Ïw5ëý<Ã¥é¥'B…£8Rs;=a’ÞÿèòËoWÿ_×á<üê9ïCÓø:öÐÿ~Å7ø:¾ššû5˜_ kúUš_Uˆ+Z_uËúŠæè+¼üÏ/&IĈ暑à¿ë†¿à†ƒpÁý5öb‹Ÿè¿}ùBªB›¨¿þR£Ø4oâ‚þšþEPÿ篡Z蟸ÿ¹ºæÊnäè¿~I +ý’TQ]}«Óÿ|UŸýêý³3Bñ¶H;c÷ñ!÷×ÿ ]ûknƒœƒ«¤z«"áÈŒO¦xŠýë7ž4û%îÌåÅøˆW™ÐBq¶Le³q3Çð2Cô¼Vü²ý1°v¾SQu42Š/F±<|z¤^Šú|ÞÍ^ S-<e®›?¥òß~TòÇ¿±ÿƒÙóÿ ³ý_ç!mY‰ÔxP]^ày”$Ãlâ!J“=àSÍ; ˜g¾eE·c݉õú„¼‘1h»Ý5fCºH ^àmÐ-¢gÉ÷-§e•º™È9¥ø'kÿŸæÿʼn{þŸlfÿ=¥ñ¡F锯AŠâ¤! h¯Ê%@Me/ÒÝÅÔ¹ŠC”+×Áªé//ˆ¿XºRóhmÏBWšk_–;„‰DYé˜ÅÆçäˆKâ�Í×¹/duöþ‰é\$yiqÔÂTè$ûÒfÈŽHpÙ‰lB#Ò‰Ú–F+!ô "jчúã(>Ap+èó‘ÎLšè姪ӞvʨÁ¹}³q³p*•â?Nþ{5´\žÞôþyfÿ¼HgãÿYÈ€S<ùrâ¨m¦’Èhñ<êËÔѯlSóÝÀ5Â+Rk¯>Flä[«£�mbG%sBÃÈO¢Áa�“1IT5ÏÔÈ…õäfë"ž™†©¥¡ÖÒ«®Î“ØÏ[m%B ÷úø.~, +ªwÉ_V™ÛÚc¨n¹ZÙ·,©%oq÷4‹¹-óc§/kÿÞaj¶ðÿYû¿vó?Ò—ÙÎCñcdòB&à!X-ž¯÷kò"X¨µ–P_Þ9=4[´žŸ4s½DFmà+“É¿5<þôD‚\($:Ü2ÆÿÞþO!óÿ<#<D¶M:XÈ’áóp$‡ÂÍTQ|,4ª¬ûµfàIž$UbëS»È˦%Žž²`\"ŠÔ•a¹î ýÓAûÇïÙÿèlþÂÓÅu¬ÅJ‰6=%5÷ñ9™™Žîήs,±Ö½ºœœ®û¥;0jKÔ¤ÛÒ¸jËÍötnˆN«Ž¤RPoVÕ˜^»^ïZ½ “g¢ÿ?t÷çAü‹¿;þ³"›íÿ<¥Ébœú6.Y•¼Îýõ?『ºà³�Äö÷_¿üæüæäWëdWEòëÜ‚l[mÇÀXÏ©99ê(ÃÜãòuÜÂiaàFøÚOägo6à:éOð쨾‰Œÿ"šej¬¥&©ÄË#çú9Íõ¤::žøǦȜæL÷.nUõÝyrçä™’{Üú‘Âz£ss#¹É+quí^™Ér®¦ÈLÕBñ³tÖ}AsÏôQ€ïŒ�åtü€¤Oø7#Ò§™iYøÕx~1¦w1iwI› ÷úUåBí¿âïDêi$,g>íÊV?W_ÃÀ/ão¶óˆ 6f®¯+¸³(üÖÿ(ÞL³j'¾ñ÷3€åÉ+;å÷ů¥ ¶"¯¿óæSá÷—#cîeüúñ‰†ÈÓ¥!÷Š¿‰…HîB®ÁØC"7!Åe¤ò2â^¬ÞÆU®®Y!òã†Ëof†GD$VŒ9?è–Óó±ÜdK%Ù[»È†©£¸"Þ. +7Û-ð·[!m?ýš?R†¹Êý™ù ~Gñ÷O'×Û׉7ŽoN|f^ßwõ7'ÅuFD,ž¸·$'¹yÒda&yèøÍÿæ¬îsM^òæ¶GÊg绾ÿßg(ÇU0ûîZJ8ü¾êŒ þ2¤er‡Ukñ—ß$÷üQ¹'å…X¾]_RÜÁ5ûœšk°œò<+]fˆðŠ¯ñ×Õ"ßÇRÙ´'¹UO®r òÍWc\r ½þ$>ÒÙ{‰´ÇŸõ:NE M'æ¼W‚ªn„›Ã<¼þ‚¿ì3Ä/17%Í¥ïõu†oû¹¿¯‚õøÇŸ)B>þXñ{‹ß>ÒwÞüÕzH7Øoð£$>Ìq¢Ÿé‘ÃÞൢóÆp—ðĪÁ?½¶óYr*ýàóäUîï+äoIM}Ë¿‘Öó6J›ûÁ@Oï²yŠdvqºÇXµ÷ƒŸcu›|S˜‘JoY×»O}fÐ6 kî߶;ó¥ã†•¥úÄÁèñ/9æ}íÏi…Ší?¾‹§³x¸r¶~è ÿ×~üQÌÖÎB‰ÿ£Ëˆ’ ÍË€“ H<Mñ”Ê󼦫ú)÷ÿŒùåC¡ß^Š”Z›¶õpÄw‘:ñüû‚4T˜rÿîedx÷K7ÿ±âÍõ&Àüª$çq™z„‘=fj"©EÛC¾mV¶bo»ÄÁ&9øgƒÏ¤WøðÐë„D/F§]:ˆzÿ/dñ?ÎB þEÁc5%ž2XÀI<²@€fU]dZ34á”ø×辶Toù¡ÿôœ¿ ¢§’wß!R`0©4gU¿Ûhx¾4¨$øÍ›ðºtGЙ8Šbü²ÿ‡¸ŸÿKà³õß³Ðzd½Î%C*ºˆ½0JâÏãÛqC\ûrn/m¶ùm-*¬Š÷&Ø;V¦uV°Ý)ÈúÂ;vêU{[÷jíY˜’«ë×¹©‰§®ŸJu½‹ôñmŽÜ4äñ³ì¬®(dbîFø…HGQ›«Aè§~6ñ¿aÂ2ciîÙ\]õ'®ŠÐóC½mw:ž~oNAuöÜ`nh£Ý®R?¥<Ë(£Œ2Ê(£Œ2Ê(£Œ2Ê(£Œ2Êh›þ?ß5÷�h�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� \ No newline at end of file -- GitLab