From 206a64fc4cb96d66bf1a32e683817deeeea10598 Mon Sep 17 00:00:00 2001 From: Sergi Massaneda Date: Tue, 25 May 2021 14:49:51 +0200 Subject: [PATCH 01/61] [Security Solution] Application register deepLinks instead of meta.searchDeepLinks (#100129) * refactor meta.searchDeepLinks to deepLinks and remove meta * remove comments * obsolete snapshot removed * documentation updated * [deepLinks] refactor ml nav ids and translation keys * flaky test fix attempt [sync with glo] * default deepLinks navLinkStatus * api_docs restored Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...kibana-plugin-core-public.app.deeplinks.md | 39 ++++ .../kibana-plugin-core-public.app.keywords.md | 13 ++ .../public/kibana-plugin-core-public.app.md | 3 +- .../kibana-plugin-core-public.app.meta.md | 43 ---- .../kibana-plugin-core-public.appdeeplink.md | 26 +++ ...ana-plugin-core-public.appmeta.keywords.md | 13 -- .../kibana-plugin-core-public.appmeta.md | 23 -- ...gin-core-public.appmeta.searchdeeplinks.md | 13 -- ...na-plugin-core-public.appsearchdeeplink.md | 26 --- ...a-plugin-core-public.appupdatablefields.md | 2 +- .../core/public/kibana-plugin-core-public.md | 6 +- ...lugin-core-public.publicappdeeplinkinfo.md | 17 ++ ...kibana-plugin-core-public.publicappinfo.md | 5 +- ...na-plugin-core-public.publicappmetainfo.md | 16 -- ...core-public.publicappsearchdeeplinkinfo.md | 16 -- .../application/application_service.test.ts | 10 +- .../application/application_service.tsx | 11 + src/core/public/application/index.ts | 6 +- src/core/public/application/types.ts | 99 ++++----- .../application/utils/get_app_info.test.ts | 126 +++++------ .../public/application/utils/get_app_info.ts | 30 ++- .../chrome/nav_links/to_nav_link.test.ts | 6 +- src/core/public/index.ts | 6 +- src/core/public/public.api.md | 59 +++--- src/plugins/dev_tools/public/plugin.ts | 6 +- src/plugins/management/public/plugin.ts | 32 ++- .../management/public/utils/management_app.ts | 9 +- .../app/Main/route_config/index.tsx | 6 +- x-pack/plugins/apm/public/plugin.ts | 84 ++++---- .../public/providers/application.test.ts | 6 +- .../public/providers/get_app_results.test.ts | 200 ++++++++---------- .../public/providers/get_app_results.ts | 21 +- .../infra/public/pages/logs/page_content.tsx | 2 +- .../infra/public/pages/metrics/index.tsx | 2 +- x-pack/plugins/infra/public/plugin.ts | 114 +++++----- .../register_search_links.ts | 16 +- .../search_deep_links.ts | 78 +++---- .../detection_alerts/alerts_details.spec.ts | 2 +- .../public/app/search/index.test.ts | 9 +- .../public/app/search/index.ts | 18 +- .../security_solution/public/app/types.ts | 6 +- .../security_solution/public/plugin.tsx | 16 +- .../translations/translations/ja-JP.json | 20 +- .../translations/translations/zh-CN.json | 20 +- x-pack/plugins/uptime/public/apps/plugin.ts | 42 ++-- 45 files changed, 598 insertions(+), 725 deletions(-) create mode 100644 docs/development/core/public/kibana-plugin-core-public.app.deeplinks.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.app.keywords.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.app.meta.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.appdeeplink.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.appmeta.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.publicappdeeplinkinfo.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md diff --git a/docs/development/core/public/kibana-plugin-core-public.app.deeplinks.md b/docs/development/core/public/kibana-plugin-core-public.app.deeplinks.md new file mode 100644 index 00000000000000..0392cb7eaefb02 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.app.deeplinks.md @@ -0,0 +1,39 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [deepLinks](./kibana-plugin-core-public.app.deeplinks.md) + +## App.deepLinks property + +Input type for registering secondary in-app locations for an application. + +Deep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path` represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. + +Signature: + +```typescript +deepLinks?: AppDeepLink[]; +``` + +## Example + + +```ts +core.application.register({ + id: 'my_app', + title: 'Translated title', + keywords: ['translated keyword1', 'translated keyword2'], + deepLinks: [ + { id: 'sub1', title: 'Sub1', path: '/sub1', keywords: ['subpath1'] }, + { + id: 'sub2', + title: 'Sub2', + deepLinks: [ + { id: 'subsub', title: 'SubSub', path: '/sub2/sub', keywords: ['subpath2'] } + ] + } + ], + mount: () => { ... } +}) + +``` + diff --git a/docs/development/core/public/kibana-plugin-core-public.app.keywords.md b/docs/development/core/public/kibana-plugin-core-public.app.keywords.md new file mode 100644 index 00000000000000..585df1b48c16e7 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.app.keywords.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [keywords](./kibana-plugin-core-public.app.keywords.md) + +## App.keywords property + +Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. + +Signature: + +```typescript +keywords?: string[]; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.app.md b/docs/development/core/public/kibana-plugin-core-public.app.md index 9a508f293d8e8c..721d9a2f121c73 100644 --- a/docs/development/core/public/kibana-plugin-core-public.app.md +++ b/docs/development/core/public/kibana-plugin-core-public.app.md @@ -19,12 +19,13 @@ export interface App | [capabilities](./kibana-plugin-core-public.app.capabilities.md) | Partial<Capabilities> | Custom capabilities defined by the app. | | [category](./kibana-plugin-core-public.app.category.md) | AppCategory | The category definition of the product See [AppCategory](./kibana-plugin-core-public.appcategory.md) See DEFAULT\_APP\_CATEGORIES for more reference | | [chromeless](./kibana-plugin-core-public.app.chromeless.md) | boolean | Hide the UI chrome when the application is mounted. Defaults to false. Takes precedence over chrome service visibility settings. | +| [deepLinks](./kibana-plugin-core-public.app.deeplinks.md) | AppDeepLink[] | Input type for registering secondary in-app locations for an application.Deep links must include at least one of path or deepLinks. A deep link that does not have a path represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. | | [defaultPath](./kibana-plugin-core-public.app.defaultpath.md) | string | Allow to define the default path a user should be directed to when navigating to the app. When defined, this value will be used as a default for the path option when calling [navigateToApp](./kibana-plugin-core-public.applicationstart.navigatetoapp.md)\`, and will also be appended to the [application navLink](./kibana-plugin-core-public.chromenavlink.md) in the navigation bar. | | [euiIconType](./kibana-plugin-core-public.app.euiicontype.md) | string | A EUI iconType that will be used for the app's icon. This icon takes precendence over the icon property. | | [exactRoute](./kibana-plugin-core-public.app.exactroute.md) | boolean | If set to true, the application's route will only be checked against an exact match. Defaults to false. | | [icon](./kibana-plugin-core-public.app.icon.md) | string | A URL to an image file used as an icon. Used as a fallback if euiIconType is not provided. | | [id](./kibana-plugin-core-public.app.id.md) | string | The unique identifier of the application | -| [meta](./kibana-plugin-core-public.app.meta.md) | AppMeta | Meta data for an application that represent additional information for the app. See [AppMeta](./kibana-plugin-core-public.appmeta.md) | +| [keywords](./kibana-plugin-core-public.app.keywords.md) | string[] | Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. | | [mount](./kibana-plugin-core-public.app.mount.md) | AppMount<HistoryLocationState> | A mount function called when the user navigates to this app's route. | | [navLinkStatus](./kibana-plugin-core-public.app.navlinkstatus.md) | AppNavLinkStatus | The initial status of the application's navLink. Defaulting to visible if status is accessible and hidden if status is inaccessible See [AppNavLinkStatus](./kibana-plugin-core-public.appnavlinkstatus.md) | | [order](./kibana-plugin-core-public.app.order.md) | number | An ordinal used to sort nav links relative to one another for display. | diff --git a/docs/development/core/public/kibana-plugin-core-public.app.meta.md b/docs/development/core/public/kibana-plugin-core-public.app.meta.md deleted file mode 100644 index 574fa11605aec9..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.app.meta.md +++ /dev/null @@ -1,43 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [meta](./kibana-plugin-core-public.app.meta.md) - -## App.meta property - -Meta data for an application that represent additional information for the app. See [AppMeta](./kibana-plugin-core-public.appmeta.md) - -Signature: - -```typescript -meta?: AppMeta; -``` - -## Remarks - -Used to populate navigational search results (where available). Can be updated using the [App.updater$](./kibana-plugin-core-public.app.updater_.md) observable. See [PublicAppSearchDeepLinkInfo](./kibana-plugin-core-public.publicappsearchdeeplinkinfo.md) for more details. - -## Example - - -```ts -core.application.register({ - id: 'my_app', - title: 'Translated title', - meta: { - keywords: ['translated keyword1', 'translated keyword2'], - searchDeepLinks: [ - { id: 'sub1', title: 'Sub1', path: '/sub1', keywords: ['subpath1'] }, - { - id: 'sub2', - title: 'Sub2', - searchDeepLinks: [ - { id: 'subsub', title: 'SubSub', path: '/sub2/sub', keywords: ['subpath2'] } - ] - } - ], - }, - mount: () => { ... } -}) - -``` - diff --git a/docs/development/core/public/kibana-plugin-core-public.appdeeplink.md b/docs/development/core/public/kibana-plugin-core-public.appdeeplink.md new file mode 100644 index 00000000000000..5aa951cffdcb54 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.appdeeplink.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppDeepLink](./kibana-plugin-core-public.appdeeplink.md) + +## AppDeepLink type + +Input type for registering secondary in-app locations for an application. + +Deep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path` represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. + +Signature: + +```typescript +export declare type AppDeepLink = { + id: string; + title: string; + keywords?: string[]; + navLinkStatus?: AppNavLinkStatus; +} & ({ + path: string; + deepLinks?: AppDeepLink[]; +} | { + path?: string; + deepLinks: AppDeepLink[]; +}); +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md deleted file mode 100644 index 13709df68e76a1..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) > [keywords](./kibana-plugin-core-public.appmeta.keywords.md) - -## AppMeta.keywords property - -Keywords to represent this application - -Signature: - -```typescript -keywords?: string[]; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.md deleted file mode 100644 index a2b72f7ec799d2..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.appmeta.md +++ /dev/null @@ -1,23 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) - -## AppMeta interface - -Input type for meta data for an application. - -Meta fields include `keywords` and `searchDeepLinks` Keywords is an array of string with which to associate the app, must include at least one unique string as an array. `searchDeepLinks` is an array of links that represent secondary in-app locations for the app. - -Signature: - -```typescript -export interface AppMeta -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [keywords](./kibana-plugin-core-public.appmeta.keywords.md) | string[] | Keywords to represent this application | -| [searchDeepLinks](./kibana-plugin-core-public.appmeta.searchdeeplinks.md) | AppSearchDeepLink[] | Array of links that represent secondary in-app locations for the app. | - diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md deleted file mode 100644 index 7ec0bbaa4b418b..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) > [searchDeepLinks](./kibana-plugin-core-public.appmeta.searchdeeplinks.md) - -## AppMeta.searchDeepLinks property - -Array of links that represent secondary in-app locations for the app. - -Signature: - -```typescript -searchDeepLinks?: AppSearchDeepLink[]; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md b/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md deleted file mode 100644 index 29aad675fb105d..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md +++ /dev/null @@ -1,26 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppSearchDeepLink](./kibana-plugin-core-public.appsearchdeeplink.md) - -## AppSearchDeepLink type - -Input type for registering secondary in-app locations for an application. - -Deep links must include at least one of `path` or `searchDeepLinks`. A deep link that does not have a `path` represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. - -Signature: - -```typescript -export declare type AppSearchDeepLink = { - id: string; - title: string; -} & ({ - path: string; - searchDeepLinks?: AppSearchDeepLink[]; - keywords?: string[]; -} | { - path?: string; - searchDeepLinks: AppSearchDeepLink[]; - keywords?: string[]; -}); -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md b/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md index 55672d9339f615..d7b12d4b707010 100644 --- a/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md +++ b/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md @@ -9,5 +9,5 @@ Defines the list of fields that can be updated via an [AppUpdater](./kibana-plug Signature: ```typescript -export declare type AppUpdatableFields = Pick; +export declare type AppUpdatableFields = Pick; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index 3972f737f66183..6239279f275d1c 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -37,7 +37,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [AppLeaveDefaultAction](./kibana-plugin-core-public.appleavedefaultaction.md) | Action to return from a [AppLeaveHandler](./kibana-plugin-core-public.appleavehandler.md) to execute the default behaviour when leaving the application.See | | [ApplicationSetup](./kibana-plugin-core-public.applicationsetup.md) | | | [ApplicationStart](./kibana-plugin-core-public.applicationstart.md) | | -| [AppMeta](./kibana-plugin-core-public.appmeta.md) | Input type for meta data for an application.Meta fields include keywords and searchDeepLinks Keywords is an array of string with which to associate the app, must include at least one unique string as an array. searchDeepLinks is an array of links that represent secondary in-app locations for the app. | | [AppMountParameters](./kibana-plugin-core-public.appmountparameters.md) | | | [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) | A plugin with asynchronous lifecycle methods. | | [Capabilities](./kibana-plugin-core-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. | @@ -144,10 +143,10 @@ The plugin integrates with the core system via lifecycle events: `setup` | Type Alias | Description | | --- | --- | +| [AppDeepLink](./kibana-plugin-core-public.appdeeplink.md) | Input type for registering secondary in-app locations for an application.Deep links must include at least one of path or deepLinks. A deep link that does not have a path represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. | | [AppLeaveAction](./kibana-plugin-core-public.appleaveaction.md) | Possible actions to return from a [AppLeaveHandler](./kibana-plugin-core-public.appleavehandler.md)See [AppLeaveConfirmAction](./kibana-plugin-core-public.appleaveconfirmaction.md) and [AppLeaveDefaultAction](./kibana-plugin-core-public.appleavedefaultaction.md) | | [AppLeaveHandler](./kibana-plugin-core-public.appleavehandler.md) | A handler that will be executed before leaving the application, either when going to another application or when closing the browser tab or manually changing the url. Should return confirm to prompt a message to the user before leaving the page, or default to keep the default behavior (doing nothing).See [AppMountParameters](./kibana-plugin-core-public.appmountparameters.md) for detailed usage examples. | | [AppMount](./kibana-plugin-core-public.appmount.md) | A mount function called when the user navigates to this app's route. | -| [AppSearchDeepLink](./kibana-plugin-core-public.appsearchdeeplink.md) | Input type for registering secondary in-app locations for an application.Deep links must include at least one of path or searchDeepLinks. A deep link that does not have a path represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. | | [AppUnmount](./kibana-plugin-core-public.appunmount.md) | A function called when an application should be unmounted from the page. This function should be synchronous. | | [AppUpdatableFields](./kibana-plugin-core-public.appupdatablefields.md) | Defines the list of fields that can be updated via an [AppUpdater](./kibana-plugin-core-public.appupdater.md). | | [AppUpdater](./kibana-plugin-core-public.appupdater.md) | Updater for applications. see [ApplicationSetup](./kibana-plugin-core-public.applicationsetup.md) | @@ -161,9 +160,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [NavType](./kibana-plugin-core-public.navtype.md) | | | [PluginInitializer](./kibana-plugin-core-public.plugininitializer.md) | The plugin export at the root of a plugin's public directory should conform to this interface. | | [PluginOpaqueId](./kibana-plugin-core-public.pluginopaqueid.md) | | +| [PublicAppDeepLinkInfo](./kibana-plugin-core-public.publicappdeeplinkinfo.md) | Public information about a registered app's [deepLinks](./kibana-plugin-core-public.appdeeplink.md) | | [PublicAppInfo](./kibana-plugin-core-public.publicappinfo.md) | Public information about a registered [application](./kibana-plugin-core-public.app.md) | -| [PublicAppMetaInfo](./kibana-plugin-core-public.publicappmetainfo.md) | Public information about a registered app's [keywords](./kibana-plugin-core-public.appmeta.md) | -| [PublicAppSearchDeepLinkInfo](./kibana-plugin-core-public.publicappsearchdeeplinkinfo.md) | Public information about a registered app's [searchDeepLinks](./kibana-plugin-core-public.appsearchdeeplink.md) | | [PublicUiSettingsParams](./kibana-plugin-core-public.publicuisettingsparams.md) | A sub-set of [UiSettingsParams](./kibana-plugin-core-public.uisettingsparams.md) exposed to the client-side. | | [ResolveDeprecationResponse](./kibana-plugin-core-public.resolvedeprecationresponse.md) | | | [SavedObjectAttribute](./kibana-plugin-core-public.savedobjectattribute.md) | Type definition for a Saved Object attribute value | diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappdeeplinkinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappdeeplinkinfo.md new file mode 100644 index 00000000000000..d3a6a4de905fdf --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.publicappdeeplinkinfo.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [PublicAppDeepLinkInfo](./kibana-plugin-core-public.publicappdeeplinkinfo.md) + +## PublicAppDeepLinkInfo type + +Public information about a registered app's [deepLinks](./kibana-plugin-core-public.appdeeplink.md) + +Signature: + +```typescript +export declare type PublicAppDeepLinkInfo = Omit & { + deepLinks: PublicAppDeepLinkInfo[]; + keywords: string[]; + navLinkStatus: AppNavLinkStatus; +}; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md index 9f45a06935fe4c..a5563eae83563f 100644 --- a/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md +++ b/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md @@ -9,10 +9,11 @@ Public information about a registered [application](./kibana-plugin-core-public. Signature: ```typescript -export declare type PublicAppInfo = Omit & { +export declare type PublicAppInfo = Omit & { status: AppStatus; navLinkStatus: AppNavLinkStatus; appRoute: string; - meta: PublicAppMetaInfo; + keywords: string[]; + deepLinks: PublicAppDeepLinkInfo[]; }; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md deleted file mode 100644 index 3ef0460aec4670..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md +++ /dev/null @@ -1,16 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [PublicAppMetaInfo](./kibana-plugin-core-public.publicappmetainfo.md) - -## PublicAppMetaInfo type - -Public information about a registered app's [keywords](./kibana-plugin-core-public.appmeta.md) - -Signature: - -```typescript -export declare type PublicAppMetaInfo = Omit & { - keywords: string[]; - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; -}; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md deleted file mode 100644 index e88cdb7d55edd6..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md +++ /dev/null @@ -1,16 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [PublicAppSearchDeepLinkInfo](./kibana-plugin-core-public.publicappsearchdeeplinkinfo.md) - -## PublicAppSearchDeepLinkInfo type - -Public information about a registered app's [searchDeepLinks](./kibana-plugin-core-public.appsearchdeeplink.md) - -Signature: - -```typescript -export declare type PublicAppSearchDeepLinkInfo = Omit & { - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; - keywords: string[]; -}; -``` diff --git a/src/core/public/application/application_service.test.ts b/src/core/public/application/application_service.test.ts index 76b9c7a73d3bd1..2e2f1cad49f199 100644 --- a/src/core/public/application/application_service.test.ts +++ b/src/core/public/application/application_service.test.ts @@ -75,7 +75,10 @@ describe('#setup()', () => { const pluginId = Symbol('plugin'); const updater$ = new BehaviorSubject((app) => ({})); setup.register(pluginId, createApp({ id: 'app1', updater$ })); - setup.register(pluginId, createApp({ id: 'app2' })); + setup.register( + pluginId, + createApp({ id: 'app2', deepLinks: [{ id: 'subapp1', title: 'Subapp', path: '/subapp' }] }) + ); const { applications$ } = await service.start(startDeps); let applications = await applications$.pipe(take(1)).toPromise(); @@ -92,6 +95,11 @@ describe('#setup()', () => { id: 'app2', navLinkStatus: AppNavLinkStatus.visible, status: AppStatus.accessible, + deepLinks: [ + expect.objectContaining({ + navLinkStatus: AppNavLinkStatus.hidden, + }), + ], }) ); diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx index 4a93c98205b842..bbfea61220b513 100644 --- a/src/core/public/application/application_service.tsx +++ b/src/core/public/application/application_service.tsx @@ -19,6 +19,7 @@ import { AppRouter } from './ui'; import { Capabilities, CapabilitiesService } from './capabilities'; import { App, + AppDeepLink, AppLeaveHandler, AppMount, AppNavLinkStatus, @@ -166,6 +167,7 @@ export class ApplicationService { ...appProps, status: app.status ?? AppStatus.accessible, navLinkStatus: app.navLinkStatus ?? AppNavLinkStatus.default, + deepLinks: populateDeepLinkDefaults(appProps.deepLinks), }); if (updater$) { registerStatusUpdater(app.id, updater$); @@ -392,3 +394,12 @@ const updateStatus = (app: App, statusUpdaters: AppUpdaterWrapper[]): App => { ...changes, }; }; + +const populateDeepLinkDefaults = (deepLinks?: AppDeepLink[]): AppDeepLink[] => { + if (!deepLinks) return []; + return deepLinks.map((deepLink) => ({ + ...deepLink, + navLinkStatus: deepLink.navLinkStatus ?? AppNavLinkStatus.default, + deepLinks: populateDeepLinkDefaults(deepLink.deepLinks), + })); +}; diff --git a/src/core/public/application/index.ts b/src/core/public/application/index.ts index 1e9a91717e81ae..68e1991646afbd 100644 --- a/src/core/public/application/index.ts +++ b/src/core/public/application/index.ts @@ -18,8 +18,7 @@ export type { AppMountParameters, AppUpdatableFields, AppUpdater, - AppMeta, - AppSearchDeepLink, + AppDeepLink, ApplicationSetup, ApplicationStart, AppLeaveHandler, @@ -29,8 +28,7 @@ export type { AppLeaveConfirmAction, NavigateToAppOptions, PublicAppInfo, - PublicAppMetaInfo, - PublicAppSearchDeepLinkInfo, + PublicAppDeepLinkInfo, // Internal types InternalApplicationSetup, InternalApplicationStart, diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index 24f46752f28e58..ffc41955360bdf 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -63,7 +63,7 @@ export enum AppNavLinkStatus { */ export type AppUpdatableFields = Pick< App, - 'status' | 'navLinkStatus' | 'tooltip' | 'defaultPath' | 'meta' + 'status' | 'navLinkStatus' | 'tooltip' | 'defaultPath' | 'deepLinks' >; /** @@ -211,106 +211,92 @@ export interface App { */ exactRoute?: boolean; + /** Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. */ + keywords?: string[]; + /** - * Meta data for an application that represent additional information for the app. - * See {@link AppMeta} + * Input type for registering secondary in-app locations for an application. * - * @remarks - * Used to populate navigational search results (where available). - * Can be updated using the {@link App.updater$} observable. See {@link PublicAppSearchDeepLinkInfo} for more details. + * Deep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path` + * represents a topological level in the application's hierarchy, but does not have a destination URL that is + * user-accessible. * * @example * ```ts * core.application.register({ * id: 'my_app', * title: 'Translated title', - * meta: { - * keywords: ['translated keyword1', 'translated keyword2'], - * searchDeepLinks: [ - * { id: 'sub1', title: 'Sub1', path: '/sub1', keywords: ['subpath1'] }, + * keywords: ['translated keyword1', 'translated keyword2'], + * deepLinks: [ + * { + * id: 'sub1', + * title: 'Sub1', + * path: '/sub1', + * keywords: ['subpath1'], + * }, * { * id: 'sub2', * title: 'Sub2', - * searchDeepLinks: [ - * { id: 'subsub', title: 'SubSub', path: '/sub2/sub', keywords: ['subpath2'] } - * ] - * } + * deepLinks: [ + * { + * id: 'subsub', + * title: 'SubSub', + * path: '/sub2/sub', + * keywords: ['subpath2'], + * }, + * ], + * }, * ], - * }, * mount: () => { ... } * }) * ``` */ - meta?: AppMeta; -} - -/** - * Input type for meta data for an application. - * - * Meta fields include `keywords` and `searchDeepLinks` - * Keywords is an array of string with which to associate the app, must include at least one unique string as an array. - * `searchDeepLinks` is an array of links that represent secondary in-app locations for the app. - * @public - */ -export interface AppMeta { - /** Keywords to represent this application */ - keywords?: string[]; - /** Array of links that represent secondary in-app locations for the app. */ - searchDeepLinks?: AppSearchDeepLink[]; + deepLinks?: AppDeepLink[]; } /** - * Public information about a registered app's {@link AppMeta | keywords } + * Public information about a registered app's {@link AppDeepLink | deepLinks} * * @public */ -export type PublicAppMetaInfo = Omit & { - keywords: string[]; - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; -}; - -/** - * Public information about a registered app's {@link AppSearchDeepLink | searchDeepLinks} - * - * @public - */ -export type PublicAppSearchDeepLinkInfo = Omit< - AppSearchDeepLink, - 'searchDeepLinks' | 'keywords' +export type PublicAppDeepLinkInfo = Omit< + AppDeepLink, + 'deepLinks' | 'keywords' | 'navLinkStatus' > & { - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + deepLinks: PublicAppDeepLinkInfo[]; keywords: string[]; + navLinkStatus: AppNavLinkStatus; }; /** * Input type for registering secondary in-app locations for an application. * - * Deep links must include at least one of `path` or `searchDeepLinks`. A deep link that does not have a `path` + * Deep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path` * represents a topological level in the application's hierarchy, but does not have a destination URL that is * user-accessible. * @public */ -export type AppSearchDeepLink = { +export type AppDeepLink = { /** Identifier to represent this sublink, should be unique for this application */ id: string; /** Title to label represent this deep link */ title: string; + /** Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. */ + keywords?: string[]; + /** Optional status of the chrome navigation, defaults to `hidden` */ + navLinkStatus?: AppNavLinkStatus; } & ( | { /** URL path to access this link, relative to the application's appRoute. */ path: string; /** Optional array of links that are 'underneath' this section in the hierarchy */ - searchDeepLinks?: AppSearchDeepLink[]; - /** Optional keywords to match with in deep links search for the page at the path */ - keywords?: string[]; + deepLinks?: AppDeepLink[]; } | { /** Optional path to access this section. Omit if this part of the hierarchy does not have a page URL. */ path?: string; /** Array links that are 'underneath' this section in this hierarchy. */ - searchDeepLinks: AppSearchDeepLink[]; - /** Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. */ - keywords?: string[]; + deepLinks: AppDeepLink[]; } ); @@ -319,12 +305,13 @@ export type AppSearchDeepLink = { * * @public */ -export type PublicAppInfo = Omit & { +export type PublicAppInfo = Omit & { // remove optional on fields populated with default values status: AppStatus; navLinkStatus: AppNavLinkStatus; appRoute: string; - meta: PublicAppMetaInfo; + keywords: string[]; + deepLinks: PublicAppDeepLinkInfo[]; }; /** diff --git a/src/core/public/application/utils/get_app_info.test.ts b/src/core/public/application/utils/get_app_info.test.ts index 28824867234ff9..ef4a06707d6664 100644 --- a/src/core/public/application/utils/get_app_info.test.ts +++ b/src/core/public/application/utils/get_app_info.test.ts @@ -32,24 +32,20 @@ describe('getAppInfo', () => { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, appRoute: `/app/some-id`, - meta: { - keywords: [], - searchDeepLinks: [], - }, + keywords: [], + deepLinks: [], }); }); - it('populates default values for nested searchDeepLinks', () => { + it('populates default values for nested deepLinks', () => { const app = createApp({ - meta: { - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - searchDeepLinks: [{ id: 'sub-sub-id', title: 'sub-sub-title', path: '/sub-sub' }], - }, - ], - }, + deepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + deepLinks: [{ id: 'sub-sub-id', title: 'sub-sub-title', path: '/sub-sub' }], + }, + ], }); const info = getAppInfo(app); @@ -59,25 +55,23 @@ describe('getAppInfo', () => { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, appRoute: `/app/some-id`, - meta: { - keywords: [], - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - keywords: [], - searchDeepLinks: [ - { - id: 'sub-sub-id', - title: 'sub-sub-title', - path: '/sub-sub', - keywords: [], - searchDeepLinks: [], // default empty array added - }, - ], - }, - ], - }, + keywords: [], + deepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + keywords: [], + deepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: [], + deepLinks: [], // default empty array added + }, + ], + }, + ], }); }); @@ -110,22 +104,20 @@ describe('getAppInfo', () => { it('adds default meta fields to sublinks when needed', () => { const app = createApp({ - meta: { - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - searchDeepLinks: [ - { - id: 'sub-sub-id', - title: 'sub-sub-title', - path: '/sub-sub', - keywords: ['sub sub'], - }, - ], - }, - ], - }, + deepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + deepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: ['sub sub'], + }, + ], + }, + ], }); const info = getAppInfo(app); @@ -135,25 +127,23 @@ describe('getAppInfo', () => { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, appRoute: `/app/some-id`, - meta: { - keywords: [], - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - keywords: [], // default empty array - searchDeepLinks: [ - { - id: 'sub-sub-id', - title: 'sub-sub-title', - path: '/sub-sub', - keywords: ['sub sub'], - searchDeepLinks: [], - }, - ], - }, - ], - }, + keywords: [], + deepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + keywords: [], // default empty array + deepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: ['sub sub'], + deepLinks: [], + }, + ], + }, + ], }); }); }); diff --git a/src/core/public/application/utils/get_app_info.ts b/src/core/public/application/utils/get_app_info.ts index ca1e8ac8076463..4c94e24f501bc4 100644 --- a/src/core/public/application/utils/get_app_info.ts +++ b/src/core/public/application/utils/get_app_info.ts @@ -10,9 +10,9 @@ import { App, AppNavLinkStatus, AppStatus, - AppSearchDeepLink, + AppDeepLink, PublicAppInfo, - PublicAppSearchDeepLinkInfo, + PublicAppDeepLinkInfo, } from '../types'; export function getAppInfo(app: App): PublicAppInfo { @@ -28,29 +28,27 @@ export function getAppInfo(app: App): PublicAppInfo { status: app.status!, navLinkStatus, appRoute: app.appRoute!, - meta: { - keywords: app.meta?.keywords ?? [], - searchDeepLinks: getSearchDeepLinkInfos(app, app.meta?.searchDeepLinks), - }, + keywords: app.keywords ?? [], + deepLinks: getDeepLinkInfos(app.deepLinks), }; } -function getSearchDeepLinkInfos( - app: App, - searchDeepLinks?: AppSearchDeepLink[] -): PublicAppSearchDeepLinkInfo[] { - if (!searchDeepLinks) { - return []; - } +function getDeepLinkInfos(deepLinks?: AppDeepLink[]): PublicAppDeepLinkInfo[] { + if (!deepLinks) return []; - return searchDeepLinks.map( - (rawDeepLink): PublicAppSearchDeepLinkInfo => { + return deepLinks.map( + (rawDeepLink): PublicAppDeepLinkInfo => { + const navLinkStatus = + rawDeepLink.navLinkStatus === AppNavLinkStatus.default + ? AppNavLinkStatus.hidden + : rawDeepLink.navLinkStatus!; return { id: rawDeepLink.id, title: rawDeepLink.title, path: rawDeepLink.path, keywords: rawDeepLink.keywords ?? [], - searchDeepLinks: getSearchDeepLinkInfos(app, rawDeepLink.searchDeepLinks), + navLinkStatus, + deepLinks: getDeepLinkInfos(rawDeepLink.deepLinks), }; } ); diff --git a/src/core/public/chrome/nav_links/to_nav_link.test.ts b/src/core/public/chrome/nav_links/to_nav_link.test.ts index 41c4ff178d7378..db783d0028f075 100644 --- a/src/core/public/chrome/nav_links/to_nav_link.test.ts +++ b/src/core/public/chrome/nav_links/to_nav_link.test.ts @@ -17,10 +17,8 @@ const app = (props: Partial = {}): PublicAppInfo => ({ status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.default, appRoute: `/app/some-id`, - meta: { - keywords: [], - searchDeepLinks: [], - }, + keywords: [], + deepLinks: [], ...props, }); diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 129ae1c16f99b1..24b48683cdd937 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -89,13 +89,11 @@ export type { AppLeaveAction, AppLeaveDefaultAction, AppLeaveConfirmAction, - AppMeta, AppUpdatableFields, AppUpdater, - AppSearchDeepLink, + AppDeepLink, PublicAppInfo, - PublicAppMetaInfo, - PublicAppSearchDeepLinkInfo, + PublicAppDeepLinkInfo, NavigateToAppOptions, } from './application'; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 31e7a1e2321dfc..9f0c5135e702fa 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -58,12 +58,13 @@ export interface App { capabilities?: Partial; category?: AppCategory; chromeless?: boolean; + deepLinks?: AppDeepLink[]; defaultPath?: string; euiIconType?: string; exactRoute?: boolean; icon?: string; id: string; - meta?: AppMeta; + keywords?: string[]; mount: AppMount; navLinkStatus?: AppNavLinkStatus; order?: number; @@ -85,6 +86,20 @@ export interface AppCategory { order?: number; } +// @public +export type AppDeepLink = { + id: string; + title: string; + keywords?: string[]; + navLinkStatus?: AppNavLinkStatus; +} & ({ + path: string; + deepLinks?: AppDeepLink[]; +} | { + path?: string; + deepLinks: AppDeepLink[]; +}); + // @public export type AppLeaveAction = AppLeaveDefaultAction | AppLeaveConfirmAction; @@ -142,12 +157,6 @@ export interface ApplicationStart { navigateToUrl(url: string): Promise; } -// @public -export interface AppMeta { - keywords?: string[]; - searchDeepLinks?: AppSearchDeepLink[]; -} - // @public export type AppMount = (params: AppMountParameters) => AppUnmount | Promise; @@ -170,20 +179,6 @@ export enum AppNavLinkStatus { visible = 1 } -// @public -export type AppSearchDeepLink = { - id: string; - title: string; -} & ({ - path: string; - searchDeepLinks?: AppSearchDeepLink[]; - keywords?: string[]; -} | { - path?: string; - searchDeepLinks: AppSearchDeepLink[]; - keywords?: string[]; -}); - // @public export enum AppStatus { accessible = 0, @@ -194,7 +189,7 @@ export enum AppStatus { export type AppUnmount = () => void; // @public -export type AppUpdatableFields = Pick; +export type AppUpdatableFields = Pick; // @public export type AppUpdater = (app: App) => Partial | undefined; @@ -1071,23 +1066,19 @@ export interface PluginInitializerContext export type PluginOpaqueId = symbol; // @public -export type PublicAppInfo = Omit & { - status: AppStatus; - navLinkStatus: AppNavLinkStatus; - appRoute: string; - meta: PublicAppMetaInfo; -}; - -// @public -export type PublicAppMetaInfo = Omit & { +export type PublicAppDeepLinkInfo = Omit & { + deepLinks: PublicAppDeepLinkInfo[]; keywords: string[]; - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + navLinkStatus: AppNavLinkStatus; }; // @public -export type PublicAppSearchDeepLinkInfo = Omit & { - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; +export type PublicAppInfo = Omit & { + status: AppStatus; + navLinkStatus: AppNavLinkStatus; + appRoute: string; keywords: string[]; + deepLinks: PublicAppDeepLinkInfo[]; }; // @public diff --git a/src/plugins/dev_tools/public/plugin.ts b/src/plugins/dev_tools/public/plugin.ts index e9f5d206de9180..5ccf614533164a 100644 --- a/src/plugins/dev_tools/public/plugin.ts +++ b/src/plugins/dev_tools/public/plugin.ts @@ -7,7 +7,7 @@ */ import { BehaviorSubject } from 'rxjs'; -import { Plugin, CoreSetup, AppMountParameters, AppSearchDeepLink } from 'src/core/public'; +import { Plugin, CoreSetup, AppMountParameters, AppDeepLink } from 'src/core/public'; import { AppUpdater } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { sortBy } from 'lodash'; @@ -86,7 +86,7 @@ export class DevToolsPlugin implements Plugin { this.appStateUpdater.next(() => ({ navLinkStatus: AppNavLinkStatus.hidden })); } else { this.appStateUpdater.next(() => { - const deepLinks: AppSearchDeepLink[] = [...this.devTools.values()] + const deepLinks: AppDeepLink[] = [...this.devTools.values()] .filter( // Some tools do not use a string title, so we filter those out (tool) => !tool.enableRouting && !tool.isDisabled() && typeof tool.title === 'string' @@ -96,7 +96,7 @@ export class DevToolsPlugin implements Plugin { title: tool.title as string, path: `#/${tool.id}`, })); - return { meta: { searchDeepLinks: deepLinks } }; + return { deepLinks }; }); } } diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index 0429ea8c9bd7bd..1f96ec87171c5c 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -20,7 +20,7 @@ import { AppUpdater, AppStatus, AppNavLinkStatus, - AppSearchDeepLink, + AppDeepLink, } from '../../../core/public'; import { MANAGEMENT_APP_ID } from '../common/contants'; @@ -38,22 +38,20 @@ export class ManagementPlugin implements Plugin(() => { - const deepLinks: AppSearchDeepLink[] = Object.values( - this.managementSections.definedSections - ).map((section: ManagementSection) => ({ - id: section.id, - title: section.title, - searchDeepLinks: section.getAppsEnabled().map((mgmtApp) => ({ - id: mgmtApp.id, - title: mgmtApp.title, - path: mgmtApp.basePath, - meta: { ...mgmtApp.meta }, - })), - })); - - return { - meta: { searchDeepLinks: deepLinks }, - }; + const deepLinks: AppDeepLink[] = Object.values(this.managementSections.definedSections).map( + (section: ManagementSection) => ({ + id: section.id, + title: section.title, + deepLinks: section.getAppsEnabled().map((mgmtApp) => ({ + id: mgmtApp.id, + title: mgmtApp.title, + path: mgmtApp.basePath, + keywords: mgmtApp.keywords, + })), + }) + ); + + return { deepLinks }; }); private hasAnyEnabledApps = true; diff --git a/src/plugins/management/public/utils/management_app.ts b/src/plugins/management/public/utils/management_app.ts index c9385463def5b4..3578b2ab0b7f2d 100644 --- a/src/plugins/management/public/utils/management_app.ts +++ b/src/plugins/management/public/utils/management_app.ts @@ -6,28 +6,25 @@ * Side Public License, v 1. */ -import { AppMeta } from 'kibana/public'; import { CreateManagementItemArgs, Mount } from '../types'; import { ManagementItem } from './management_item'; export interface RegisterManagementAppArgs extends CreateManagementItemArgs { mount: Mount; basePath: string; - meta?: AppMeta; + keywords?: string[]; } export class ManagementApp extends ManagementItem { public readonly mount: Mount; public readonly basePath: string; - public readonly meta: AppMeta; + public readonly keywords: string[]; constructor(args: RegisterManagementAppArgs) { super(args); this.mount = args.mount; this.basePath = args.basePath; - this.meta = { - keywords: args.meta?.keywords || [], - }; + this.keywords = args.keywords || []; } } diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx index 9410fd00411e38..89b8db5f386dcd 100644 --- a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx @@ -173,7 +173,7 @@ export const routes: APMRouteDefinition[] = [ render: renderAsRedirectTo('/services'), breadcrumb: 'APM', }, - // !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/apm/public/plugin.ts + // !! Need to be kept in sync with the deepLinks in x-pack/plugins/apm/public/plugin.ts { exact: true, path: '/services', @@ -182,7 +182,7 @@ export const routes: APMRouteDefinition[] = [ defaultMessage: 'Services', }), }, - // !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/apm/public/plugin.ts + // !! Need to be kept in sync with the deepLinks in x-pack/plugins/apm/public/plugin.ts { exact: true, path: '/traces', @@ -328,7 +328,7 @@ export const routes: APMRouteDefinition[] = [ component: TraceLink, breadcrumb: null, }, - // !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/apm/public/plugin.ts + // !! Need to be kept in sync with the deepLinks in x-pack/plugins/apm/public/plugin.ts { exact: true, path: '/service-map', diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index b76849ccf30115..10af1837dab42f 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -140,32 +140,30 @@ export class ApmPlugin implements Plugin { appRoute: '/app/apm', icon: 'plugins/apm/public/icon.svg', category: DEFAULT_APP_CATEGORIES.observability, - meta: { - // !! Need to be kept in sync with the routes in x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx - searchDeepLinks: [ - { - id: 'services', - title: i18n.translate('xpack.apm.breadcrumb.servicesTitle', { - defaultMessage: 'Services', - }), - path: '/services', - }, - { - id: 'traces', - title: i18n.translate('xpack.apm.breadcrumb.tracesTitle', { - defaultMessage: 'Traces', - }), - path: '/traces', - }, - { - id: 'service-map', - title: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { - defaultMessage: 'Service Map', - }), - path: '/service-map', - }, - ], - }, + // !! Need to be kept in sync with the routes in x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx + deepLinks: [ + { + id: 'services', + title: i18n.translate('xpack.apm.breadcrumb.servicesTitle', { + defaultMessage: 'Services', + }), + path: '/services', + }, + { + id: 'traces', + title: i18n.translate('xpack.apm.breadcrumb.tracesTitle', { + defaultMessage: 'Traces', + }), + path: '/traces', + }, + { + id: 'service-map', + title: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { + defaultMessage: 'Service Map', + }), + path: '/service-map', + }, + ], async mount(appMountParameters: AppMountParameters) { // Load application bundle and Get start services @@ -196,24 +194,22 @@ export class ApmPlugin implements Plugin { navLinkStatus: config.ui.enabled ? AppNavLinkStatus.default : AppNavLinkStatus.hidden, - meta: { - keywords: [ - 'RUM', - 'Real User Monitoring', - 'DEM', - 'Digital Experience Monitoring', - 'EUM', - 'End User Monitoring', - 'UX', - 'Javascript', - 'APM', - 'Mobile', - 'digital', - 'performance', - 'web performance', - 'web perf', - ], - }, + keywords: [ + 'RUM', + 'Real User Monitoring', + 'DEM', + 'Digital Experience Monitoring', + 'EUM', + 'End User Monitoring', + 'UX', + 'Javascript', + 'APM', + 'Mobile', + 'digital', + 'performance', + 'web performance', + 'web perf', + ], async mount(appMountParameters: AppMountParameters) { // Load application bundle and Get start service const [{ renderApp }, [coreStart, corePlugins]] = await Promise.all([ diff --git a/x-pack/plugins/global_search_providers/public/providers/application.test.ts b/x-pack/plugins/global_search_providers/public/providers/application.test.ts index 9b084d7bb9a6ad..2d555f38d16d1e 100644 --- a/x-pack/plugins/global_search_providers/public/providers/application.test.ts +++ b/x-pack/plugins/global_search_providers/public/providers/application.test.ts @@ -29,10 +29,8 @@ const createApp = (props: Partial = {}): PublicAppInfo => ({ status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, chromeless: false, - meta: { - keywords: props.meta?.keywords || [], - searchDeepLinks: [], - }, + keywords: props.keywords || [], + deepLinks: [], ...props, }); diff --git a/x-pack/plugins/global_search_providers/public/providers/get_app_results.test.ts b/x-pack/plugins/global_search_providers/public/providers/get_app_results.test.ts index 8b875dbb7ed9bc..251dd84395aa00 100644 --- a/x-pack/plugins/global_search_providers/public/providers/get_app_results.test.ts +++ b/x-pack/plugins/global_search_providers/public/providers/get_app_results.test.ts @@ -26,7 +26,8 @@ const createApp = (props: Partial = {}): PublicAppInfo => ({ status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, chromeless: false, - meta: { keywords: [], searchDeepLinks: [] }, + keywords: [], + deepLinks: [], ...props, }); @@ -34,7 +35,7 @@ const createAppLink = (props: Partial = {}): AppLink => ({ id: props.id ?? 'app1', path: props.appRoute ?? '/app/app1', subLinkTitles: [], - keywords: props.meta?.keywords ?? [], // start off with the top level app keywords + keywords: props.keywords ?? [], // start off with the top level app keywords app: createApp(props), }); @@ -51,30 +52,37 @@ describe('getAppResults', () => { expect(results[0]).toEqual(expect.objectContaining({ id: 'dashboard', score: 100 })); }); - it('creates multiple links for apps with searchDeepLinks', () => { + it('creates multiple links for apps with deepLinks', () => { const apps = [ createApp({ - meta: { - searchDeepLinks: [ - { id: 'sub1', title: 'Sub1', path: '/sub1', searchDeepLinks: [], keywords: [] }, - { - id: 'sub2', - title: 'Sub2', - path: '/sub2', - searchDeepLinks: [ - { - id: 'sub2sub1', - title: 'Sub2Sub1', - path: '/sub2/sub1', - searchDeepLinks: [], - keywords: [], - }, - ], - keywords: [], - }, - ], - keywords: [], - }, + deepLinks: [ + { + id: 'sub1', + title: 'Sub1', + path: '/sub1', + deepLinks: [], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + { + id: 'sub2', + title: 'Sub2', + path: '/sub2', + deepLinks: [ + { + id: 'sub2sub1', + title: 'Sub2Sub1', + path: '/sub2/sub1', + deepLinks: [], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: [], }), ]; @@ -89,21 +97,20 @@ describe('getAppResults', () => { ]); }); - it('only includes searchDeepLinks when search term is non-empty', () => { + it('only includes deepLinks when search term is non-empty', () => { const apps = [ createApp({ - meta: { - searchDeepLinks: [ - { - id: 'sub1', - title: 'Sub1', - path: '/sub1', - searchDeepLinks: [], - keywords: [], - }, - ], - keywords: [], - }, + deepLinks: [ + { + id: 'sub1', + title: 'Sub1', + path: '/sub1', + deepLinks: [], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: [], }), ]; @@ -112,11 +119,7 @@ describe('getAppResults', () => { }); it('retrieves the matching results from keywords', () => { - const apps = [ - createApp({ - meta: { searchDeepLinks: [], keywords: ['One'] }, - }), - ]; + const apps = [createApp({ deepLinks: [], keywords: ['One'] })]; const results = getAppResults('One', apps); expect(results.map(({ title }) => title)).toEqual(['App 1']); }); @@ -124,27 +127,34 @@ describe('getAppResults', () => { it('retrieves the matching results from deeplink keywords', () => { const apps = [ createApp({ - meta: { - searchDeepLinks: [ - { id: 'sub1', title: 'Sub1', path: '/sub1', searchDeepLinks: [], keywords: [] }, - { - id: 'sub2', - title: 'Sub2', - path: '/sub2', - searchDeepLinks: [ - { - id: 'sub2sub1', - title: 'Sub2Sub1', - path: '/sub2/sub1', - searchDeepLinks: [], - keywords: ['TwoOne'], - }, - ], - keywords: ['two'], - }, - ], - keywords: [], - }, + deepLinks: [ + { + id: 'sub1', + title: 'Sub1', + path: '/sub1', + deepLinks: [], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + { + id: 'sub2', + title: 'Sub2', + path: '/sub2', + deepLinks: [ + { + id: 'sub2sub1', + title: 'Sub2Sub1', + path: '/sub2/sub1', + deepLinks: [], + keywords: ['TwoOne'], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: ['two'], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: [], }), ]; @@ -187,26 +197,17 @@ describe('scoreApp', () => { describe('when the term is included in the keywords but not in the title', () => { it(`returns 100 * ${keywordScoreWeighting} if one of the app meta keywords is an exact match`, () => { expect( - scoreApp( - 'bar', - createAppLink({ title: 'foo', meta: { keywords: ['bar'], searchDeepLinks: [] } }) - ) + scoreApp('bar', createAppLink({ title: 'foo', keywords: ['bar'], deepLinks: [] })) ).toBe(100 * keywordScoreWeighting); expect( - scoreApp( - 'bar', - createAppLink({ title: 'foo', meta: { keywords: ['BAR'], searchDeepLinks: [] } }) - ) + scoreApp('bar', createAppLink({ title: 'foo', keywords: ['BAR'], deepLinks: [] })) ).toBe(100 * keywordScoreWeighting); }); it(`returns 90 * ${keywordScoreWeighting} if any of the keywords start with the term`, () => { expect( scoreApp( 'viz', - createAppLink({ - title: 'Foo', - meta: { keywords: ['Vizualize', 'Viz view'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Foo', keywords: ['Vizualize', 'Viz view'], deepLinks: [] }) ) ).toBe(90 * keywordScoreWeighting); }); @@ -214,19 +215,13 @@ describe('scoreApp', () => { expect( scoreApp( 'board', - createAppLink({ - title: 'Foo', - meta: { keywords: ['dashboard app'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Foo', keywords: ['dashboard app'], deepLinks: [] }) ) ).toBe(75 * keywordScoreWeighting); expect( scoreApp( 'shboa', - createAppLink({ - title: 'Foo', - meta: { keywords: ['dashboard app'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Foo', keywords: ['dashboard app'], deepLinks: [] }) ) ).toBe(75 * keywordScoreWeighting); }); @@ -235,26 +230,17 @@ describe('scoreApp', () => { describe('when the term is included in the keywords and the title', () => { it('returns 100 if one of the app meta keywords and the title is an exact match', () => { expect( - scoreApp( - 'home', - createAppLink({ title: 'Home', meta: { keywords: ['home'], searchDeepLinks: [] } }) - ) + scoreApp('home', createAppLink({ title: 'Home', keywords: ['home'], deepLinks: [] })) ).toBe(100); expect( - scoreApp( - 'Home', - createAppLink({ title: 'Home', meta: { keywords: ['HOME'], searchDeepLinks: [] } }) - ) + scoreApp('Home', createAppLink({ title: 'Home', keywords: ['HOME'], deepLinks: [] })) ).toBe(100); }); it('returns 90 if either one of the keywords or the title start with the term', () => { expect( scoreApp( 'vis', - createAppLink({ - title: 'Visualize', - meta: { keywords: ['Visualise'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Visualize', keywords: ['Visualise'], deepLinks: [] }) ) ).toBe(90); }); @@ -262,19 +248,13 @@ describe('scoreApp', () => { expect( scoreApp( 'board', - createAppLink({ - title: 'Dashboard', - meta: { keywords: ['dashboard app'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Dashboard', keywords: ['dashboard app'], deepLinks: [] }) ) ).toBe(75); expect( scoreApp( 'shboa', - createAppLink({ - title: 'dashboard', - meta: { keywords: ['dashboard app'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'dashboard', keywords: ['dashboard app'], deepLinks: [] }) ) ).toBe(75); }); @@ -285,19 +265,13 @@ describe('scoreApp', () => { expect( scoreApp( '0123456789', - createAppLink({ - title: '012345', - meta: { keywords: ['0345', '9987'], searchDeepLinks: [] }, - }) + createAppLink({ title: '012345', keywords: ['0345', '9987'], deepLinks: [] }) ) ).toBe(60); expect( scoreApp( '--1234567-', - createAppLink({ - title: '123456789', - meta: { keywords: ['--345--'], searchDeepLinks: [] }, - }) + createAppLink({ title: '123456789', keywords: ['--345--'], deepLinks: [] }) ) ).toBe(60); }); @@ -305,13 +279,13 @@ describe('scoreApp', () => { expect( scoreApp( '0123456789', - createAppLink({ title: '12345', meta: { keywords: ['12', '34'], searchDeepLinks: [] } }) + createAppLink({ title: '12345', keywords: ['12', '34'], deepLinks: [] }) ) ).toBe(0); expect( scoreApp( '1-2-3-4-5', - createAppLink({ title: '123456789', meta: { keywords: ['12-789'], searchDeepLinks: [] } }) + createAppLink({ title: '123456789', keywords: ['12-789'], deepLinks: [] }) ) ).toBe(0); }); diff --git a/x-pack/plugins/global_search_providers/public/providers/get_app_results.ts b/x-pack/plugins/global_search_providers/public/providers/get_app_results.ts index f5f0a2d34e91c1..3ae1a082cdebfa 100644 --- a/x-pack/plugins/global_search_providers/public/providers/get_app_results.ts +++ b/x-pack/plugins/global_search_providers/public/providers/get_app_results.ts @@ -6,10 +6,10 @@ */ import levenshtein from 'js-levenshtein'; -import { PublicAppInfo, PublicAppSearchDeepLinkInfo } from 'src/core/public'; +import { PublicAppInfo, PublicAppDeepLinkInfo } from 'src/core/public'; import { GlobalSearchProviderResult } from '../../../global_search/public'; -/** Type used internally to represent an application unrolled into its separate searchDeepLinks */ +/** Type used internally to represent an application unrolled into its separate deepLinks */ export interface AppLink { id: string; app: PublicAppInfo; @@ -27,7 +27,7 @@ export const getAppResults = ( ): GlobalSearchProviderResult[] => { return ( apps - // Unroll all searchDeepLinks, only if there is a search term + // Unroll all deepLinks, only if there is a search term .flatMap((app) => term.length > 0 ? flattenDeepLinks(app) @@ -37,7 +37,7 @@ export const getAppResults = ( app, path: app.appRoute, subLinkTitles: [], - keywords: app.meta?.keywords ?? [], + keywords: app.keywords ?? [], }, ] ) @@ -56,7 +56,7 @@ export const scoreApp = (term: string, appLink: AppLink): number => { const appScoreByTerms = scoreAppByTerms(term, title); const keywords = [ - ...appLink.app.meta.keywords.map((keyword) => keyword.toLowerCase()), + ...appLink.app.keywords.map((keyword) => keyword.toLowerCase()), ...appLink.keywords.map((keyword) => keyword.toLowerCase()), ]; const appScoreByKeywords = scoreAppByKeywords(term, keywords); @@ -115,10 +115,7 @@ export const appToResult = (appLink: AppLink, score: number): GlobalSearchProvid }; }; -const flattenDeepLinks = ( - app: PublicAppInfo, - deepLink?: PublicAppSearchDeepLinkInfo -): AppLink[] => { +const flattenDeepLinks = (app: PublicAppInfo, deepLink?: PublicAppDeepLinkInfo): AppLink[] => { if (!deepLink) { return [ { @@ -126,9 +123,9 @@ const flattenDeepLinks = ( app, path: app.appRoute, subLinkTitles: [], - keywords: app.meta?.keywords ?? [], + keywords: app?.keywords ?? [], }, - ...app.meta.searchDeepLinks.flatMap((appDeepLink) => flattenDeepLinks(app, appDeepLink)), + ...app.deepLinks.flatMap((appDeepLink) => flattenDeepLinks(app, appDeepLink)), ]; } return [ @@ -143,7 +140,7 @@ const flattenDeepLinks = ( }, ] : []), - ...deepLink.searchDeepLinks + ...deepLink.deepLinks .flatMap((deepDeepLink) => flattenDeepLinks(app, deepDeepLink)) .map((deepAppLink) => ({ ...deepAppLink, diff --git a/x-pack/plugins/infra/public/pages/logs/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/page_content.tsx index d43fe198c50770..9ae127a8eca664 100644 --- a/x-pack/plugins/infra/public/pages/logs/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/page_content.tsx @@ -40,7 +40,7 @@ export const LogsPageContent: React.FunctionComponent = () => { initialize(); }); - // !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/infra/public/plugin.ts + // !! Need to be kept in sync with the deepLinks in x-pack/plugins/infra/public/plugin.ts const streamTab = { app: 'logs', title: streamTabTitle, diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index b43d7640f63907..819c764bfb7ba5 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -120,7 +120,7 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { > - {/** !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/infra/public/plugin.ts */} + {/** !! Need to be kept in sync with the deepLinks in x-pack/plugins/infra/public/plugin.ts */} { // mount callback should not use setup dependencies, get start dependencies instead @@ -115,32 +113,30 @@ export class Plugin implements InfraClientPluginClass { order: 8200, appRoute: '/app/metrics', category: DEFAULT_APP_CATEGORIES.observability, - meta: { - // !! Need to be kept in sync with the routes in x-pack/plugins/infra/public/pages/metrics/index.tsx - searchDeepLinks: [ - { - id: 'inventory', - title: i18n.translate('xpack.infra.homePage.inventoryTabTitle', { - defaultMessage: 'Inventory', - }), - path: '/inventory', - }, - { - id: 'metrics-explorer', - title: i18n.translate('xpack.infra.homePage.metricsExplorerTabTitle', { - defaultMessage: 'Metrics Explorer', - }), - path: '/explorer', - }, - { - id: 'settings', - title: i18n.translate('xpack.infra.homePage.settingsTabTitle', { - defaultMessage: 'Settings', - }), - path: '/settings', - }, - ], - }, + // !! Need to be kept in sync with the routes in x-pack/plugins/infra/public/pages/metrics/index.tsx + deepLinks: [ + { + id: 'inventory', + title: i18n.translate('xpack.infra.homePage.inventoryTabTitle', { + defaultMessage: 'Inventory', + }), + path: '/inventory', + }, + { + id: 'metrics-explorer', + title: i18n.translate('xpack.infra.homePage.metricsExplorerTabTitle', { + defaultMessage: 'Metrics Explorer', + }), + path: '/explorer', + }, + { + id: 'settings', + title: i18n.translate('xpack.infra.homePage.settingsTabTitle', { + defaultMessage: 'Settings', + }), + path: '/settings', + }, + ], mount: async (params: AppMountParameters) => { // mount callback should not use setup dependencies, get start dependencies instead const [coreStart, pluginsStart] = await core.getStartServices(); diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts index 6c219340da817d..dd3ca0bb8fa309 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts @@ -9,20 +9,18 @@ import { i18n } from '@kbn/i18n'; import { BehaviorSubject } from 'rxjs'; import { AppUpdater } from 'src/core/public'; -import { getSearchDeepLinks } from './search_deep_links'; +import { getDeepLinks } from './search_deep_links'; export function registerSearchLinks( appUpdater: BehaviorSubject, isFullLicense: boolean ) { appUpdater.next(() => ({ - meta: { - keywords: [ - i18n.translate('xpack.ml.keyword.ml', { - defaultMessage: 'ML', - }), - ], - searchDeepLinks: getSearchDeepLinks(isFullLicense), - }, + keywords: [ + i18n.translate('xpack.ml.keyword.ml', { + defaultMessage: 'ML', + }), + ], + deepLinks: getDeepLinks(isFullLicense), })); } diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index d248df90889897..d682a93fa274c4 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -7,35 +7,35 @@ import { i18n } from '@kbn/i18n'; -import type { AppSearchDeepLink } from 'src/core/public'; +import type { AppDeepLink } from 'src/core/public'; import { ML_PAGES } from '../../../common/constants/ml_url_generator'; -const OVERVIEW_LINK_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlOverviewSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.overview', { +const OVERVIEW_LINK_DEEP_LINK: AppDeepLink = { + id: 'mlOverviewDeepLink', + title: i18n.translate('xpack.ml.deepLink.overview', { defaultMessage: 'Overview', }), path: `/${ML_PAGES.OVERVIEW}`, }; -const ANOMALY_DETECTION_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlAnomalyDetectionSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.anomalyDetection', { +const ANOMALY_DETECTION_DEEP_LINK: AppDeepLink = { + id: 'mlAnomalyDetectionDeepLink', + title: i18n.translate('xpack.ml.deepLink.anomalyDetection', { defaultMessage: 'Anomaly Detection', }), path: `/${ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE}`, }; -const DATA_FRAME_ANALYTICS_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlDataFrameAnalyticsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.dataFrameAnalytics', { +const DATA_FRAME_ANALYTICS_DEEP_LINK: AppDeepLink = { + id: 'mlDataFrameAnalyticsDeepLink', + title: i18n.translate('xpack.ml.deepLink.dataFrameAnalytics', { defaultMessage: 'Data Frame Analytics', }), path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE}`, - searchDeepLinks: [ + deepLinks: [ { - id: 'mlTrainedModelsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.trainedModels', { + id: 'mlTrainedModelsDeepLink', + title: i18n.translate('xpack.ml.deepLink.trainedModels', { defaultMessage: 'Trained Models', }), path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MODELS_MANAGE}`, @@ -43,47 +43,47 @@ const DATA_FRAME_ANALYTICS_SEARCH_DEEP_LINK: AppSearchDeepLink = { ], }; -const DATA_VISUALIZER_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlDataVisualizerSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.dataVisualizer', { +const DATA_VISUALIZER_DEEP_LINK: AppDeepLink = { + id: 'mlDataVisualizerDeepLink', + title: i18n.translate('xpack.ml.deepLink.dataVisualizer', { defaultMessage: 'Data Visualizer', }), path: `/${ML_PAGES.DATA_VISUALIZER}`, }; -const FILE_UPLOAD_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlFileUploadSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.fileUpload', { +const FILE_UPLOAD_DEEP_LINK: AppDeepLink = { + id: 'mlFileUploadDeepLink', + title: i18n.translate('xpack.ml.deepLink.fileUpload', { defaultMessage: 'File Upload', }), path: `/${ML_PAGES.DATA_VISUALIZER_FILE}`, }; -const INDEX_DATA_VISUALIZER_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlIndexDataVisualizerSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.indexDataVisualizer', { +const INDEX_DATA_VISUALIZER_DEEP_LINK: AppDeepLink = { + id: 'mlIndexDataVisualizerDeepLink', + title: i18n.translate('xpack.ml.deepLink.indexDataVisualizer', { defaultMessage: 'Index Data Visualizer', }), path: `/${ML_PAGES.DATA_VISUALIZER_INDEX_SELECT}`, }; -const SETTINGS_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlSettingsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.settings', { +const SETTINGS_DEEP_LINK: AppDeepLink = { + id: 'mlSettingsDeepLink', + title: i18n.translate('xpack.ml.deepLink.settings', { defaultMessage: 'Settings', }), path: `/${ML_PAGES.SETTINGS}`, - searchDeepLinks: [ + deepLinks: [ { - id: 'mlCalendarSettingsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.calendarSettings', { + id: 'mlCalendarSettingsDeepLink', + title: i18n.translate('xpack.ml.deepLink.calendarSettings', { defaultMessage: 'Calendars', }), path: `/${ML_PAGES.CALENDARS_MANAGE}`, }, { - id: 'mlFilterListsSettingsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.filterListsSettings', { + id: 'mlFilterListsSettingsDeepLink', + title: i18n.translate('xpack.ml.deepLink.filterListsSettings', { defaultMessage: 'Filter Lists', }), path: `/${ML_PAGES.SETTINGS}`, // Link to settings page as read only users cannot view filter lists. @@ -91,19 +91,19 @@ const SETTINGS_SEARCH_DEEP_LINK: AppSearchDeepLink = { ], }; -export function getSearchDeepLinks(isFullLicense: boolean) { - const deepLinks: AppSearchDeepLink[] = [ - DATA_VISUALIZER_SEARCH_DEEP_LINK, - FILE_UPLOAD_SEARCH_DEEP_LINK, - INDEX_DATA_VISUALIZER_SEARCH_DEEP_LINK, +export function getDeepLinks(isFullLicense: boolean) { + const deepLinks: AppDeepLink[] = [ + DATA_VISUALIZER_DEEP_LINK, + FILE_UPLOAD_DEEP_LINK, + INDEX_DATA_VISUALIZER_DEEP_LINK, ]; if (isFullLicense === true) { deepLinks.push( - OVERVIEW_LINK_SEARCH_DEEP_LINK, - ANOMALY_DETECTION_SEARCH_DEEP_LINK, - DATA_FRAME_ANALYTICS_SEARCH_DEEP_LINK, - SETTINGS_SEARCH_DEEP_LINK + OVERVIEW_LINK_DEEP_LINK, + ANOMALY_DETECTION_DEEP_LINK, + DATA_FRAME_ANALYTICS_DEEP_LINK, + SETTINGS_DEEP_LINK ); } diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts index 5af5a8adf95b7f..aeee7077ec9c04 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts @@ -23,7 +23,7 @@ import { unmappedRule } from '../../objects/rule'; import { DETECTIONS_URL } from '../../urls/navigation'; describe('Alert details with unmapped fields', () => { - before(() => { + beforeEach(() => { cleanKibana(); esArchiverLoad('unmapped_fields'); loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); diff --git a/x-pack/plugins/security_solution/public/app/search/index.test.ts b/x-pack/plugins/security_solution/public/app/search/index.test.ts index d6c36e89558d02..328395f9b85c9e 100644 --- a/x-pack/plugins/security_solution/public/app/search/index.test.ts +++ b/x-pack/plugins/security_solution/public/app/search/index.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { getSearchDeepLinksAndKeywords } from '.'; +import { getDeepLinksAndKeywords } from '.'; import { SecurityPageName } from '../../../common/constants'; describe('public search functions', () => { @@ -13,10 +13,9 @@ describe('public search functions', () => { const platinumLicense = 'platinum'; for (const pageName of Object.values(SecurityPageName)) { expect.assertions(Object.values(SecurityPageName).length * 2); - const basicLinkCount = - getSearchDeepLinksAndKeywords(pageName, basicLicense).searchDeepLinks?.length || 0; - const platinumLinks = getSearchDeepLinksAndKeywords(pageName, platinumLicense); - expect(platinumLinks.searchDeepLinks?.length).toBeGreaterThanOrEqual(basicLinkCount); + const basicLinkCount = getDeepLinksAndKeywords(pageName, basicLicense).deepLinks?.length || 0; + const platinumLinks = getDeepLinksAndKeywords(pageName, platinumLicense); + expect(platinumLinks.deepLinks?.length).toBeGreaterThanOrEqual(basicLinkCount); expect(platinumLinks.keywords?.length).not.toBe(null); } }); diff --git a/x-pack/plugins/security_solution/public/app/search/index.ts b/x-pack/plugins/security_solution/public/app/search/index.ts index 110356269e8917..93d931fc4d1370 100644 --- a/x-pack/plugins/security_solution/public/app/search/index.ts +++ b/x-pack/plugins/security_solution/public/app/search/index.ts @@ -11,7 +11,7 @@ import { Subject } from 'rxjs'; import { AppUpdater } from 'src/core/public'; import { LicenseType } from '../../../../licensing/common/types'; import { SecuritySubPluginNames, SecurityDeepLinks } from '../types'; -import { AppMeta } from '../../../../../../src/core/public'; +import { App } from '../../../../../../src/core/public'; const securityDeepLinks: SecurityDeepLinks = { detections: { @@ -198,10 +198,10 @@ const subpluginKeywords: { [key in SecuritySubPluginNames]: string[] } = { * @param subPluginName SubPluginName of the app to retrieve meta information for. * @param licenseType optional string for license level, if not provided basic is assumed. */ -export function getSearchDeepLinksAndKeywords( +export function getDeepLinksAndKeywords( subPluginName: SecuritySubPluginNames, licenseType?: LicenseType -): AppMeta { +): Pick { const baseRoutes = [...securityDeepLinks[subPluginName].base]; if ( licenseType === 'gold' || @@ -214,29 +214,27 @@ export function getSearchDeepLinksAndKeywords( if (premiumRoutes !== undefined) { return { keywords: subpluginKeywords[subPluginName], - searchDeepLinks: [...baseRoutes, ...premiumRoutes], + deepLinks: [...baseRoutes, ...premiumRoutes], }; } } return { keywords: subpluginKeywords[subPluginName], - searchDeepLinks: baseRoutes, + deepLinks: baseRoutes, }; } /** * A function that updates a subplugin's meta property as appropriate when license level changes. - * @param subPluginName SubPluginName of the app to register searchDeepLinks for + * @param subPluginName SubPluginName of the app to register deepLinks for * @param appUpdater an instance of appUpdater$ observable to update search links when needed. * @param licenseType A string representing the current license level. */ -export function registerSearchLinks( +export function registerDeepLinks( subPluginName: SecuritySubPluginNames, appUpdater?: Subject, licenseType?: LicenseType ) { if (appUpdater !== undefined) { - appUpdater.next(() => ({ - meta: getSearchDeepLinksAndKeywords(subPluginName, licenseType), - })); + appUpdater.next(() => ({ ...getDeepLinksAndKeywords(subPluginName, licenseType) })); } } diff --git a/x-pack/plugins/security_solution/public/app/types.ts b/x-pack/plugins/security_solution/public/app/types.ts index a617c6f14b9c48..77d5b99e1c3a3b 100644 --- a/x-pack/plugins/security_solution/public/app/types.ts +++ b/x-pack/plugins/security_solution/public/app/types.ts @@ -17,7 +17,7 @@ import { CombinedState, } from 'redux'; -import { AppMountParameters, AppSearchDeepLink } from '../../../../../src/core/public'; +import { AppMountParameters, AppDeepLink } from '../../../../../src/core/public'; import { StartServices } from '../types'; /** @@ -58,8 +58,8 @@ export type SecuritySubPluginKeyStore = export type SecuritySubPluginNames = keyof typeof SecurityPageName; interface SecurityDeepLink { - base: AppSearchDeepLink[]; - premium?: AppSearchDeepLink[]; + base: AppDeepLink[]; + premium?: AppDeepLink[]; } export type SecurityDeepLinks = { [key in SecuritySubPluginNames]: SecurityDeepLink }; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index efbe857d168d85..c1f501d3f70945 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -47,7 +47,7 @@ import { } from '../common/constants'; import { SecurityPageName } from './app/types'; -import { registerSearchLinks, getSearchDeepLinksAndKeywords } from './app/search'; +import { registerDeepLinks, getDeepLinksAndKeywords } from './app/search'; import { manageOldSiemRoutes } from './helpers'; import { OVERVIEW, @@ -258,7 +258,7 @@ export class Plugin implements IPlugin { const [coreStart, startPlugins] = await core.getStartServices(); const { timelines: subPlugin } = await this.subPlugins(); @@ -300,7 +300,7 @@ export class Plugin implements IPlugin { const [coreStart, startPlugins] = await core.getStartServices(); const { management: managementSubPlugin } = await this.subPlugins(); @@ -366,19 +366,19 @@ export class Plugin implements IPlugin { if (currentLicense.type !== undefined) { - registerSearchLinks(SecurityPageName.network, this.networkUpdater$, currentLicense.type); - registerSearchLinks( + registerDeepLinks(SecurityPageName.network, this.networkUpdater$, currentLicense.type); + registerDeepLinks( SecurityPageName.detections, this.detectionsUpdater$, currentLicense.type ); - registerSearchLinks(SecurityPageName.hosts, this.hostsUpdater$, currentLicense.type); - registerSearchLinks(SecurityPageName.case, this.caseUpdater$, currentLicense.type); + registerDeepLinks(SecurityPageName.hosts, this.hostsUpdater$, currentLicense.type); + registerDeepLinks(SecurityPageName.case, this.caseUpdater$, currentLicense.type); } }); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 134f58236cfee3..af6cdd1d672a17 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -15978,16 +15978,16 @@ "xpack.ml.ruleEditor.selectRuleAction.orText": "OR ", "xpack.ml.ruleEditor.typicalAppliesTypeText": "通常", "xpack.ml.sampleDataLinkLabel": "ML ジョブ", - "xpack.ml.searchDeepLink.anomalyDetection": "異常検知", - "xpack.ml.searchDeepLink.calendarSettings": "カレンダー", - "xpack.ml.searchDeepLink.dataFrameAnalytics": "データフレーム分析", - "xpack.ml.searchDeepLink.dataVisualizer": "データビジュアライザー", - "xpack.ml.searchDeepLink.fileUpload": "ファイルアップロード", - "xpack.ml.searchDeepLink.filterListsSettings": "フィルターリスト", - "xpack.ml.searchDeepLink.indexDataVisualizer": "インデックスデータビジュアライザー", - "xpack.ml.searchDeepLink.overview": "概要", - "xpack.ml.searchDeepLink.settings": "設定", - "xpack.ml.searchDeepLink.trainedModels": "学習済みモデル", + "xpack.ml.deepLink.anomalyDetection": "異常検知", + "xpack.ml.deepLink.calendarSettings": "カレンダー", + "xpack.ml.deepLink.dataFrameAnalytics": "データフレーム分析", + "xpack.ml.deepLink.dataVisualizer": "データビジュアライザー", + "xpack.ml.deepLink.fileUpload": "ファイルアップロード", + "xpack.ml.deepLink.filterListsSettings": "フィルターリスト", + "xpack.ml.deepLink.indexDataVisualizer": "インデックスデータビジュアライザー", + "xpack.ml.deepLink.overview": "概要", + "xpack.ml.deepLink.settings": "設定", + "xpack.ml.deepLink.trainedModels": "学習済みモデル", "xpack.ml.settings.anomalyDetection.anomalyDetectionTitle": "異常検知", "xpack.ml.settings.anomalyDetection.calendarsText": "システム停止日や祝日など、異常値を生成したくないイベントについては、カレンダーに予定されているイベントのリストを登録できます。", "xpack.ml.settings.anomalyDetection.calendarsTitle": "カレンダー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 67677f86ddbf78..c8376b72daef17 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16203,16 +16203,16 @@ "xpack.ml.ruleEditor.selectRuleAction.orText": "或 ", "xpack.ml.ruleEditor.typicalAppliesTypeText": "典型", "xpack.ml.sampleDataLinkLabel": "ML 作业", - "xpack.ml.searchDeepLink.anomalyDetection": "异常检测", - "xpack.ml.searchDeepLink.calendarSettings": "日历", - "xpack.ml.searchDeepLink.dataFrameAnalytics": "数据帧分析", - "xpack.ml.searchDeepLink.dataVisualizer": "数据可视化工具", - "xpack.ml.searchDeepLink.fileUpload": "文件上传", - "xpack.ml.searchDeepLink.filterListsSettings": "筛选列表", - "xpack.ml.searchDeepLink.indexDataVisualizer": "索引数据可视化工具", - "xpack.ml.searchDeepLink.overview": "概览", - "xpack.ml.searchDeepLink.settings": "设置", - "xpack.ml.searchDeepLink.trainedModels": "已训练模型", + "xpack.ml.deepLink.anomalyDetection": "异常检测", + "xpack.ml.deepLink.calendarSettings": "日历", + "xpack.ml.deepLink.dataFrameAnalytics": "数据帧分析", + "xpack.ml.deepLink.dataVisualizer": "数据可视化工具", + "xpack.ml.deepLink.fileUpload": "文件上传", + "xpack.ml.deepLink.filterListsSettings": "筛选列表", + "xpack.ml.deepLink.indexDataVisualizer": "索引数据可视化工具", + "xpack.ml.deepLink.overview": "概览", + "xpack.ml.deepLink.settings": "设置", + "xpack.ml.deepLink.trainedModels": "已训练模型", "xpack.ml.settings.anomalyDetection.anomalyDetectionTitle": "异常检测", "xpack.ml.settings.anomalyDetection.calendarsSummaryCount": "您有 {calendarsCountBadge} 个{calendarsCount, plural, other {日历}}", "xpack.ml.settings.anomalyDetection.calendarsText": "日志包含不应生成异常的已计划事件列表,例如已计划系统中断或公共假期。", diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 0832274f0785a1..80a131676951e4 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -104,28 +104,26 @@ export class UptimePlugin order: 8400, title: PLUGIN.TITLE, category: DEFAULT_APP_CATEGORIES.observability, - meta: { - keywords: [ - 'Synthetics', - 'pings', - 'checks', - 'availability', - 'response duration', - 'response time', - 'outside in', - 'reachability', - 'reachable', - 'digital', - 'performance', - 'web performance', - 'web perf', - ], - searchDeepLinks: [ - { id: 'Down monitors', title: 'Down monitors', path: '/?statusFilter=down' }, - { id: 'Certificates', title: 'TLS Certificates', path: '/certificates' }, - { id: 'Settings', title: 'Settings', path: '/settings' }, - ], - }, + keywords: [ + 'Synthetics', + 'pings', + 'checks', + 'availability', + 'response duration', + 'response time', + 'outside in', + 'reachability', + 'reachable', + 'digital', + 'performance', + 'web performance', + 'web perf', + ], + deepLinks: [ + { id: 'Down monitors', title: 'Down monitors', path: '/?statusFilter=down' }, + { id: 'Certificates', title: 'TLS Certificates', path: '/certificates' }, + { id: 'Settings', title: 'Settings', path: '/settings' }, + ], mount: async (params: AppMountParameters) => { const [coreStart, corePlugins] = await core.getStartServices(); From 60b5c842cd0405e24901b4944f51e555358679f6 Mon Sep 17 00:00:00 2001 From: Sandra Gonzales Date: Tue, 25 May 2021 08:51:24 -0400 Subject: [PATCH 02/61] [Metrics UI] use EuiTooltip to control tooltip component and simplify ConditionalTooltip (#99224) * use EuiTooltip to control tooltip component * fix style * update unit tests * add functional waffle map tooltip tests * remove reload() from useEffect * fix type * update unit test --- .../conditional_tooltip.test.tsx.snap | 226 +++++++++++++----- .../waffle/conditional_tooltip.test.tsx | 106 ++------ .../components/waffle/conditional_tooltip.tsx | 168 +++++-------- .../inventory_view/components/waffle/node.tsx | 15 +- .../test/functional/apps/infra/home_page.ts | 3 +- .../page_objects/infra_home_page.ts | 29 +++ 6 files changed, 277 insertions(+), 270 deletions(-) diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap index a5d97813e4b14a..91bafb3b15e4db 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ConditionalToolTip should just work 1`] = ` +exports[`ConditionalToolTip renders correctly 1`] = `
- - CPU usage - - - 10% - + +
+ CPU usage +
+
+ +
+ 10% +
+
+
- - Memory usage - - - 80% - + +
+ Memory usage +
+
+ +
+ 80% +
+
+
- - Outbound traffic - - - 8Mbit/s - + +
+ Outbound traffic +
+
+ +
+ 8Mbit/s +
+
+
- - Inbound traffic - - - 8Mbit/s - + +
+ Inbound traffic +
+
+ +
+ 8Mbit/s +
+
+
- - My Custom Label - - - 34.1% - + +
+ My Custom Label +
+
+ +
+ 34.1% +
+
+
- - Avg of host.network.out.packets - - - 4,392.2 - + +
+ Avg of host.network.out.packets +
+
+ +
+ 4,392.2 +
+
+
`; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx index 6dde53efae761b..ac4fac394dacc5 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx @@ -7,15 +7,10 @@ import React from 'react'; import { mount } from 'enzyme'; -// import { act } from 'react-dom/test-utils'; +import toJson from 'enzyme-to-json'; import { EuiThemeProvider } from '../../../../../../../../../src/plugins/kibana_react/common'; -import { EuiToolTip } from '@elastic/eui'; import { ConditionalToolTip } from './conditional_tooltip'; -import { - InfraWaffleMapNode, - InfraWaffleMapOptions, - InfraFormatterType, -} from '../../../../../lib/lib'; +import { InfraWaffleMapNode } from '../../../../../lib/lib'; jest.mock('../../../../../containers/metrics_source', () => ({ useSourceContext: () => ({ sourceId: 'default' }), @@ -38,61 +33,12 @@ const NODE: InfraWaffleMapNode = { metrics: [{ name: 'cpu' }], }; -const OPTIONS: InfraWaffleMapOptions = { - formatter: InfraFormatterType.percent, - formatTemplate: '{value}', - metric: { type: 'cpu' }, - groupBy: [], - legend: { - type: 'steppedGradient', - rules: [], - }, - sort: { by: 'value', direction: 'desc' }, -}; - export const nextTick = () => new Promise((res) => process.nextTick(res)); -const ChildComponent = () =>
child
; describe('ConditionalToolTip', () => { - afterEach(() => { - mockedUseSnapshot.mockReset(); - mockedUseWaffleOptionsContext.mockReset(); - }); - - function createWrapper(currentTime: number = Date.now(), hidden: boolean = false) { - return mount( - - - - ); - } - - it('should return children when hidden', () => { - mockedUseSnapshot.mockReturnValue({ - nodes: [], - error: null, - loading: true, - interval: '', - reload: jest.fn(() => Promise.resolve()), - }); - mockedUseWaffleOptionsContext.mockReturnValue(mockedUseWaffleOptionsContexReturnValue); - const currentTime = Date.now(); - const wrapper = createWrapper(currentTime, true); - expect(wrapper.find(ChildComponent).exists()).toBeTruthy(); - }); + const currentTime = Date.now(); - it('should just work', () => { - jest.useFakeTimers(); - const reloadMock = jest.fn(() => Promise.resolve()); + it('renders correctly', () => { mockedUseSnapshot.mockReturnValue({ nodes: [ { @@ -121,13 +67,9 @@ describe('ConditionalToolTip', () => { error: null, loading: false, interval: '60s', - reload: reloadMock, + reload: jest.fn(() => Promise.resolve()), }); mockedUseWaffleOptionsContext.mockReturnValue(mockedUseWaffleOptionsContexReturnValue); - const currentTime = Date.now(); - const wrapper = createWrapper(currentTime, false); - expect(wrapper.find(ChildComponent).exists()).toBeTruthy(); - expect(wrapper.find(EuiToolTip).exists()).toBeTruthy(); const expectedQuery = JSON.stringify({ bool: { filter: { @@ -154,6 +96,14 @@ describe('ConditionalToolTip', () => { type: 'custom', }, ]; + const wrapper = mount( + + + + ); + const tooltip = wrapper.find('[data-test-subj~="conditionalTooltipContent-host-01"]'); + expect(toJson(tooltip)).toMatchSnapshot(); + expect(mockedUseSnapshot).toBeCalledWith( expectedQuery, expectedMetrics, @@ -162,36 +112,8 @@ describe('ConditionalToolTip', () => { 'default', currentTime, '', - '', - false + '' ); - wrapper.find('[data-test-subj~="conditionalTooltipMouseHandler"]').simulate('mouseOver'); - wrapper.find(EuiToolTip).simulate('mouseOver'); - jest.advanceTimersByTime(500); - expect(reloadMock).toHaveBeenCalled(); - expect(wrapper.find(EuiToolTip).props().content).toMatchSnapshot(); - }); - - it('should not load data if mouse out before 200 ms', () => { - jest.useFakeTimers(); - const reloadMock = jest.fn(() => Promise.resolve()); - mockedUseSnapshot.mockReturnValue({ - nodes: [], - error: null, - loading: true, - interval: '', - reload: reloadMock, - }); - mockedUseWaffleOptionsContext.mockReturnValue(mockedUseWaffleOptionsContexReturnValue); - const currentTime = Date.now(); - const wrapper = createWrapper(currentTime, false); - expect(wrapper.find(ChildComponent).exists()).toBeTruthy(); - expect(wrapper.find(EuiToolTip).exists()).toBeTruthy(); - wrapper.find('[data-test-subj~="conditionalTooltipMouseHandler"]').simulate('mouseOver'); - jest.advanceTimersByTime(100); - wrapper.find('[data-test-subj~="conditionalTooltipMouseHandler"]').simulate('mouseOut'); - jest.advanceTimersByTime(200); - expect(reloadMock).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx index 6e334f4fbca752..a47512906abd13 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import React, { useCallback, useState, useEffect } from 'react'; -import { EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { first } from 'lodash'; import { getCustomMetricLabel } from '../../../../../../common/formatters/get_custom_metric_label'; import { SnapshotCustomMetricInput } from '../../../../../../common/http_api'; @@ -18,7 +18,7 @@ import { SnapshotMetricType, SnapshotMetricTypeRT, } from '../../../../../../common/inventory_models/types'; -import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib'; +import { InfraWaffleMapNode } from '../../../../../lib/lib'; import { useSnapshot } from '../../hooks/use_snaphot'; import { createInventoryMetricFormatter } from '../../lib/create_inventory_metric_formatter'; import { SNAPSHOT_METRIC_TRANSLATIONS } from '../../../../../../common/inventory_models/intl_strings'; @@ -27,113 +27,69 @@ import { createFormatterForMetric } from '../../../metrics_explorer/components/h export interface Props { currentTime: number; - hidden: boolean; node: InfraWaffleMapNode; - options: InfraWaffleMapOptions; - formatter: (val: number) => string; - children: React.ReactElement; nodeType: InventoryItemType; theme: EuiTheme | undefined; } - -export const ConditionalToolTip = withTheme( - ({ theme, hidden, node, children, nodeType, currentTime }: Props) => { - const { sourceId } = useSourceContext(); - const [timer, setTimer] = useState | null>(null); - const model = findInventoryModel(nodeType); - const { customMetrics } = useWaffleOptionsContext(); - const requestMetrics = model.tooltipMetrics - .map((type) => ({ type })) - .concat(customMetrics) as Array< - | { - type: SnapshotMetricType; - } - | SnapshotCustomMetricInput - >; - const query = JSON.stringify({ - bool: { - filter: { - match_phrase: { [model.fields.id]: node.id }, - }, +export const ConditionalToolTip = withTheme(({ theme, node, nodeType, currentTime }: Props) => { + const { sourceId } = useSourceContext(); + const model = findInventoryModel(nodeType); + const { customMetrics } = useWaffleOptionsContext(); + const requestMetrics = model.tooltipMetrics + .map((type) => ({ type })) + .concat(customMetrics) as Array< + | { + type: SnapshotMetricType; + } + | SnapshotCustomMetricInput + >; + const query = JSON.stringify({ + bool: { + filter: { + match_phrase: { [model.fields.id]: node.id }, }, - }); - const { nodes, reload } = useSnapshot( - query, - requestMetrics, - [], - nodeType, - sourceId, - currentTime, - '', - '', - false // Doesn't send request until reload() is called - ); - - const handleDataLoad = useCallback(() => { - const id = setTimeout(reload, 200); - setTimer(id); - }, [reload]); - - const cancelDataLoad = useCallback(() => { - return (timer && clearTimeout(timer)) || void 0; - }, [timer]); + }, + }); + const { nodes } = useSnapshot(query, requestMetrics, [], nodeType, sourceId, currentTime, '', ''); - useEffect(() => { - return cancelDataLoad; - }, [timer, cancelDataLoad]); - - if (hidden) { - return children; - } - const dataNode = first(nodes); - const metrics = (dataNode && dataNode.metrics) || []; - const content = ( -
-
- {node.name} -
- {metrics.map((metric) => { - const metricName = SnapshotMetricTypeRT.is(metric.name) ? metric.name : 'custom'; - const name = SNAPSHOT_METRIC_TRANSLATIONS[metricName] || metricName; - // if custom metric, find field and label from waffleOptionsContext result - // because useSnapshot does not return it - const customMetric = - name === 'custom' ? customMetrics.find((item) => item.id === metric.name) : null; - const formatter = customMetric - ? createFormatterForMetric(customMetric) - : createInventoryMetricFormatter({ type: metricName }); - return ( - - - {customMetric ? getCustomMetricLabel(customMetric) : name} - - - {(metric.value && formatter(metric.value)) || '-'} - - - ); - })} + const dataNode = first(nodes); + const metrics = (dataNode && dataNode.metrics) || []; + return ( +
+
+ {node.name}
- ); - - return ( - -
- {children} -
-
- ); - } -); + {metrics.map((metric) => { + const metricName = SnapshotMetricTypeRT.is(metric.name) ? metric.name : 'custom'; + const name = SNAPSHOT_METRIC_TRANSLATIONS[metricName] || metricName; + // if custom metric, find field and label from waffleOptionsContext result + // because useSnapshot does not return it + const customMetric = + name === 'custom' ? customMetrics.find((item) => item.id === metric.name) : null; + const formatter = customMetric + ? createFormatterForMetric(customMetric) + : createInventoryMetricFormatter({ type: metricName }); + return ( + + + {customMetric ? getCustomMetricLabel(customMetric) : name} + + + {(metric.value && formatter(metric.value)) || '-'} + + + ); + })} +
+ ); +}); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx index e972f9ca4f345f..031b826265e16f 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { first } from 'lodash'; -import { EuiPopover } from '@elastic/eui'; +import { EuiPopover, EuiToolTip } from '@elastic/eui'; import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common'; import { InfraWaffleMapBounds, @@ -64,13 +64,10 @@ export class Node extends React.PureComponent { const nodeBorder = this.state.isOverlayOpen ? { border: 'solid 4px #000' } : undefined; const button = ( - + ); return ( diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 1cc7c87f3a1a84..7578abbad33e75 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -38,9 +38,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); after(async () => await esArchiver.unload('infra/metrics_and_logs')); - it('renders the waffle map for dates with data', async () => { + it('renders the waffle map and tooltips for dates with data', async () => { await pageObjects.infraHome.goToTime(DATE_WITH_DATA); await pageObjects.infraHome.getWaffleMap(); + await pageObjects.infraHome.getWaffleMapTooltips(); }); it('renders an empty data prompt for dates with no data', async () => { diff --git a/x-pack/test/functional/page_objects/infra_home_page.ts b/x-pack/test/functional/page_objects/infra_home_page.ts index 04dfbe5da00024..2f4575d45cc20f 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -5,6 +5,7 @@ * 2.0. */ +import expect from '@kbn/expect/expect.js'; import testSubjSelector from '@kbn/test-subj-selector'; import { FtrProviderContext } from '../ftr_provider_context'; @@ -34,6 +35,34 @@ export function InfraHomePageProvider({ getService }: FtrProviderContext) { return await testSubjects.find('waffleMap'); }, + async getWaffleMapTooltips() { + const node = await testSubjects.findAll('nodeContainer'); + await node[0].moveMouseTo(); + const tooltip = await testSubjects.find('conditionalTooltipContent-demo-stack-redis-01'); + const metrics = await tooltip.findAllByTestSubject('conditionalTooltipContent-metric'); + const values = await tooltip.findAllByTestSubject('conditionalTooltipContent-value'); + expect(await metrics[0].getVisibleText()).to.be('CPU usage'); + expect(await values[0].getVisibleText()).to.be('1%'); + expect(await metrics[1].getVisibleText()).to.be('Memory usage'); + expect(await values[1].getVisibleText()).to.be('15.9%'); + expect(await metrics[2].getVisibleText()).to.be('Outbound traffic'); + expect(await values[2].getVisibleText()).to.be('71.9kbit/s'); + expect(await metrics[3].getVisibleText()).to.be('Inbound traffic'); + expect(await values[3].getVisibleText()).to.be('25.6kbit/s'); + await node[1].moveMouseTo(); + const tooltip2 = await testSubjects.find('conditionalTooltipContent-demo-stack-nginx-01'); + const metrics2 = await tooltip2.findAllByTestSubject('conditionalTooltipContent-metric'); + const values2 = await tooltip2.findAllByTestSubject('conditionalTooltipContent-value'); + expect(await metrics2[0].getVisibleText()).to.be('CPU usage'); + expect(await values2[0].getVisibleText()).to.be('1.1%'); + expect(await metrics2[1].getVisibleText()).to.be('Memory usage'); + expect(await values2[1].getVisibleText()).to.be('18%'); + expect(await metrics2[2].getVisibleText()).to.be('Outbound traffic'); + expect(await values2[2].getVisibleText()).to.be('256.3kbit/s'); + expect(await metrics2[3].getVisibleText()).to.be('Inbound traffic'); + expect(await values2[3].getVisibleText()).to.be('255.1kbit/s'); + }, + async openInvenotrySwitcher() { await testSubjects.click('openInventorySwitcher'); return await testSubjects.find('goToHost'); From ca324c63be2d9f9bda21d372c125ac07d924dd25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20S=C3=A1nchez?= Date: Tue, 25 May 2021 15:19:42 +0200 Subject: [PATCH 03/61] Removes event filters feature flag and exposes this feature by default (#100389) * Removes event filters feature flag and expose this feature by default * Fixes manifest unit test * Fixes functional test adding event filter list case Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../exception_list_client.mock.ts | 6 +- .../common/experimental_features.ts | 1 - .../public/common/mock/global_state.ts | 1 - .../components/administration_list_page.tsx | 22 ++-- .../event_filter_delete_modal.test.tsx | 1 - .../view/event_filters_list_page.test.tsx | 1 - .../public/management/pages/index.tsx | 7 +- .../timeline/body/actions/index.tsx | 7 +- .../server/endpoint/lib/artifacts/mocks.ts | 30 +++++ .../manifest_manager/manifest_manager.mock.ts | 17 +-- .../manifest_manager/manifest_manager.test.ts | 45 +++++++- .../manifest_manager/manifest_manager.ts | 5 +- .../factory/hosts/details/index.test.tsx | 1 - .../apps/endpoint/policy_details.ts | 108 ++++++++++++++++++ 14 files changed, 204 insertions(+), 48 deletions(-) diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts index 973f5822cae2b2..1566241e7351e0 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts @@ -32,9 +32,11 @@ export class ExceptionListClientMock extends ExceptionListClient { public createEndpointList = jest.fn().mockResolvedValue(getExceptionListSchemaMock()); } -export const getExceptionListClientMock = (): ExceptionListClient => { +export const getExceptionListClientMock = ( + savedObject?: ReturnType +): ExceptionListClient => { const mock = new ExceptionListClientMock({ - savedObjectsClient: savedObjectsClientMock.create(), + savedObjectsClient: savedObject ? savedObject : savedObjectsClientMock.create(), user: 'elastic', }); return mock; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 8d1cc4ca2c1f07..6195dd61a79841 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -14,7 +14,6 @@ export type ExperimentalFeatures = typeof allowedExperimentalValues; const allowedExperimentalValues = Object.freeze({ trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, - eventFilteringEnabled: false, hostIsolationEnabled: false, }); diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index b1b3147f4f4941..af278b09e719c4 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -40,7 +40,6 @@ export const mockGlobalState: State = { { id: 'error-id-2', title: 'title-2', message: ['error-message-2'] }, ], enableExperimental: { - eventFilteringEnabled: false, trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, hostIsolationEnabled: false, diff --git a/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx b/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx index 02fbb4f4b02962..72a6de2a2de8d1 100644 --- a/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx +++ b/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx @@ -25,7 +25,6 @@ import { getEventFiltersListPath, getTrustedAppsListPath, } from '../common/routing'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; /** Ensure that all flyouts z-index in Administation area show the flyout header */ const EuiPanelStyled = styled(EuiPanel)` @@ -44,7 +43,6 @@ interface AdministrationListPageProps { export const AdministrationListPage: FC = memo( ({ beta, title, subtitle, actions, children, headerBackComponent, ...otherProps }) => { - const isEventFilteringEnabled = useIsExperimentalFeatureEnabled('eventFilteringEnabled'); const badgeOptions = !beta ? undefined : { beta: true, text: BETA_BADGE_LABEL }; return ( @@ -77,18 +75,14 @@ export const AdministrationListPage: FC diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx index cec3e34d9c98fd..c594aaa5c7e19d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx @@ -64,7 +64,6 @@ describe('When event filters delete modal is shown', () => { }; waitForAction = mockedContext.middlewareSpy.waitForAction; - mockedContext.setExperimentalFlag({ eventFilteringEnabled: true }); }); it('should display name of event filter in body message', async () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.test.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.test.tsx index 2fbabad746cad7..465f92dfda767f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.test.tsx @@ -41,7 +41,6 @@ describe('When on the Event Filters List Page', () => { waitForAction = mockedContext.middlewareSpy.waitForAction; act(() => { - mockedContext.setExperimentalFlag({ eventFilteringEnabled: true }); history.push('/event_filters'); }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/index.tsx b/x-pack/plugins/security_solution/public/management/pages/index.tsx index 4be75117daedad..8273f1a6e55c20 100644 --- a/x-pack/plugins/security_solution/public/management/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/index.tsx @@ -25,7 +25,6 @@ import { SecurityPageName } from '../../../common/constants'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { useIngestEnabledCheck } from '../../common/hooks/endpoint/ingest_enabled'; import { EventFiltersContainer } from './event_filters'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; const NoPermissions = memo(() => { return ( @@ -58,7 +57,6 @@ NoPermissions.displayName = 'NoPermissions'; export const ManagementContainer = memo(() => { const history = useHistory(); - const isEventFilteringEnabled = useIsExperimentalFeatureEnabled('eventFilteringEnabled'); const { allEnabled: isIngestEnabled } = useIngestEnabledCheck(); if (!isIngestEnabled) { @@ -70,10 +68,7 @@ export const ManagementContainer = memo(() => { - - {isEventFilteringEnabled && ( - - )} + = ({ const emptyNotes: string[] = []; const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); - const isEventFilteringEnabled = useIsExperimentalFeatureEnabled('eventFilteringEnabled'); - const handleSelectEvent = useCallback( (event: React.ChangeEvent) => onRowSelected({ @@ -116,8 +113,8 @@ const ActionsComponent: React.FC = ({ const eventType = getEventType(ecsData); const isEventContextMenuEnabled = useMemo( - () => isEventFilteringEnabled && !!ecsData.event?.kind && ecsData.event?.kind[0] === 'event', - [ecsData.event?.kind, isEventFilteringEnabled] + () => !!ecsData.event?.kind && ecsData.event?.kind[0] === 'event', + [ecsData.event?.kind] ); return ( diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts index 85857301d5f399..cda42bdf3f585e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts @@ -92,6 +92,36 @@ export const createPackagePolicyWithInitialManifestMock = (): PackagePolicy => { artifact_manifest: { value: { artifacts: { + 'endpoint-eventfilterlist-linux-v1': { + compression_algorithm: 'zlib', + decoded_sha256: 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-linux-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-macos-v1': { + compression_algorithm: 'zlib', + decoded_sha256: 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-macos-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-windows-v1': { + compression_algorithm: 'zlib', + decoded_sha256: 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, 'endpoint-exceptionlist-macos-v1': { compression_algorithm: 'zlib', encryption_algorithm: 'none', diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts index f471ace617a6dc..e0bbfc351a20f1 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts @@ -69,13 +69,16 @@ export interface ManifestManagerMockOptions { export const buildManifestManagerMockOptions = ( opts: Partial -): ManifestManagerMockOptions => ({ - cache: new LRU({ max: 10, maxAge: 1000 * 60 * 60 }), - exceptionListClient: listMock.getExceptionListClient(), - packagePolicyService: createPackagePolicyServiceMock(), - savedObjectsClient: savedObjectsClientMock.create(), - ...opts, -}); +): ManifestManagerMockOptions => { + const savedObjectMock = savedObjectsClientMock.create(); + return { + cache: new LRU({ max: 10, maxAge: 1000 * 60 * 60 }), + exceptionListClient: listMock.getExceptionListClient(savedObjectMock), + packagePolicyService: createPackagePolicyServiceMock(), + savedObjectsClient: savedObjectMock, + ...opts, + }; +}; export const buildManifestManagerContextMock = ( opts: Partial diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts index e1de39482428d7..7719dbf30c72bf 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts @@ -65,6 +65,9 @@ describe('ManifestManager', () => { const ARTIFACT_NAME_TRUSTED_APPS_MACOS = 'endpoint-trustlist-macos-v1'; const ARTIFACT_NAME_TRUSTED_APPS_WINDOWS = 'endpoint-trustlist-windows-v1'; const ARTIFACT_NAME_TRUSTED_APPS_LINUX = 'endpoint-trustlist-linux-v1'; + const ARTIFACT_NAME_EVENT_FILTERS_MACOS = 'endpoint-eventfilterlist-macos-v1'; + const ARTIFACT_NAME_EVENT_FILTERS_WINDOWS = 'endpoint-eventfilterlist-windows-v1'; + const ARTIFACT_NAME_EVENT_FILTERS_LINUX = 'endpoint-eventfilterlist-linux-v1'; let ARTIFACTS: InternalArtifactCompleteSchema[] = []; let ARTIFACTS_BY_ID: { [K: string]: InternalArtifactCompleteSchema } = {}; @@ -219,6 +222,9 @@ describe('ManifestManager', () => { ARTIFACT_NAME_TRUSTED_APPS_MACOS, ARTIFACT_NAME_TRUSTED_APPS_WINDOWS, ARTIFACT_NAME_TRUSTED_APPS_LINUX, + ARTIFACT_NAME_EVENT_FILTERS_MACOS, + ARTIFACT_NAME_EVENT_FILTERS_WINDOWS, + ARTIFACT_NAME_EVENT_FILTERS_LINUX, ]; const getArtifactIds = (artifacts: InternalArtifactSchema[]) => [ @@ -249,6 +255,11 @@ describe('ManifestManager', () => { context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({}); context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); const manifest = await manifestManager.buildNewManifest(); expect(manifest?.getSchemaVersion()).toStrictEqual('v1'); @@ -257,7 +268,7 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); - expect(artifacts.length).toBe(6); + expect(artifacts.length).toBe(9); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); @@ -280,6 +291,11 @@ describe('ManifestManager', () => { [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, [ENDPOINT_TRUSTED_APPS_LIST_ID]: { linux: [trustedAppListItem] }, }); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); const manifest = await manifestManager.buildNewManifest(); @@ -290,7 +306,7 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); - expect(artifacts.length).toBe(6); + expect(artifacts.length).toBe(9); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); @@ -304,6 +320,9 @@ describe('ManifestManager', () => { expect(await uncompressArtifact(artifacts[5])).toStrictEqual({ entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), }); + expect(await uncompressArtifact(artifacts[6])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] }); for (const artifact of artifacts) { expect(manifest.isDefaultArtifact(artifact)).toBe(true); @@ -323,7 +342,11 @@ describe('ManifestManager', () => { [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, }); context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); - + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); const oldManifest = await manifestManager.buildNewManifest(); context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({ @@ -339,7 +362,7 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); - expect(artifacts.length).toBe(6); + expect(artifacts.length).toBe(9); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); @@ -351,6 +374,9 @@ describe('ManifestManager', () => { expect(await uncompressArtifact(artifacts[5])).toStrictEqual({ entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), }); + expect(await uncompressArtifact(artifacts[6])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] }); for (const artifact of artifacts) { expect(manifest.isDefaultArtifact(artifact)).toBe(true); @@ -384,6 +410,12 @@ describe('ManifestManager', () => { TEST_POLICY_ID_2, ]); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); + const manifest = await manifestManager.buildNewManifest(); expect(manifest?.getSchemaVersion()).toStrictEqual('v1'); @@ -392,7 +424,7 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); - expect(artifacts.length).toBe(7); + expect(artifacts.length).toBe(10); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); @@ -412,6 +444,9 @@ describe('ManifestManager', () => { 'v1' ), }); + expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[9])).toStrictEqual({ entries: [] }); for (const artifact of artifacts.slice(0, 5)) { expect(manifest.isDefaultArtifact(artifact)).toBe(true); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts index fe4aba165d2bda..6c25b6152938f7 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts @@ -361,10 +361,7 @@ export class ManifestManager { const results = await Promise.all([ this.buildExceptionListArtifacts(), this.buildTrustedAppsArtifacts(), - // If Endpoint Event Filtering feature is ON, then add in the exceptions for them - ...(this.experimentalFeatures.eventFilteringEnabled - ? [this.buildEventFiltersArtifacts()] - : []), + this.buildEventFiltersArtifacts(), ]); const manifest = new Manifest({ diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx index 4474b9f288570e..e43db6b86f8b90 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx @@ -32,7 +32,6 @@ const mockDeps = { experimentalFeatures: { trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, - eventFilteringEnabled: false, hostIsolationEnabled: false, }, service: {} as EndpointAppContextService, diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts index d8bc9f6444f646..44348d1ad0d9c4 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts @@ -248,6 +248,42 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { relative_url: '/api/fleet/artifacts/endpoint-trustlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', }, + 'endpoint-eventfilterlist-linux-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-linux-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-macos-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-macos-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-windows-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, }, // The manifest version could have changed when the Policy was updated because the // policy details page ensures that a save action applies the udpated policy on top @@ -416,6 +452,42 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { relative_url: '/api/fleet/artifacts/endpoint-trustlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', }, + 'endpoint-eventfilterlist-linux-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-linux-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-macos-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-macos-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-windows-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, }, // The manifest version could have changed when the Policy was updated because the // policy details page ensures that a save action applies the udpated policy on top @@ -582,6 +654,42 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { relative_url: '/api/fleet/artifacts/endpoint-trustlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', }, + 'endpoint-eventfilterlist-linux-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-linux-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-macos-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-macos-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-windows-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, }, // The manifest version could have changed when the Policy was updated because the // policy details page ensures that a save action applies the udpated policy on top From 73b6048ba1076f53b826214ac9736bf7e2f8d5b4 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 25 May 2021 09:51:57 -0400 Subject: [PATCH 04/61] [Maps][Vega] Isolate mapbox-gl library into bazel package (#99931) --- package.json | 1 + packages/BUILD.bazel | 1 + packages/kbn-mapbox-gl/BUILD.bazel | 84 +++++++++++++++++++ packages/kbn-mapbox-gl/README.md | 3 + packages/kbn-mapbox-gl/package.json | 8 ++ packages/kbn-mapbox-gl/src/index.ts | 20 +++++ packages/kbn-mapbox-gl/src/typings.ts | 10 +++ packages/kbn-mapbox-gl/tsconfig.json | 16 ++++ .../vega_map_view/vega_map_view.scss | 2 - .../vega_view/vega_map_view/view.test.ts | 49 +++++------ .../public/vega_view/vega_map_view/view.ts | 13 +-- .../map_container/map_container.tsx | 1 - .../connected_components/mb_map/mb_map.tsx | 15 ++-- yarn.lock | 4 + 14 files changed, 180 insertions(+), 47 deletions(-) create mode 100644 packages/kbn-mapbox-gl/BUILD.bazel create mode 100644 packages/kbn-mapbox-gl/README.md create mode 100644 packages/kbn-mapbox-gl/package.json create mode 100644 packages/kbn-mapbox-gl/src/index.ts create mode 100644 packages/kbn-mapbox-gl/src/typings.ts create mode 100644 packages/kbn-mapbox-gl/tsconfig.json diff --git a/package.json b/package.json index 5737bce303e09c..73f3e5585faf74 100644 --- a/package.json +++ b/package.json @@ -130,6 +130,7 @@ "@kbn/config": "link:bazel-bin/packages/kbn-config/npm_module", "@kbn/config-schema": "link:bazel-bin/packages/kbn-config-schema/npm_module", "@kbn/crypto": "link:bazel-bin/packages/kbn-crypto/npm_module", + "@kbn/mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl/npm_module", "@kbn/i18n": "link:bazel-bin/packages/kbn-i18n/npm_module", "@kbn/interpreter": "link:packages/kbn-interpreter", "@kbn/io-ts-utils": "link:packages/kbn-io-ts-utils", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index ec8252cb6144da..43528e0ae41629 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -24,6 +24,7 @@ filegroup( "//packages/kbn-i18n:build", "//packages/kbn-legacy-logging:build", "//packages/kbn-logging:build", + "//packages/kbn-mapbox-gl:build", "//packages/kbn-plugin-generator:build", "//packages/kbn-securitysolution-list-constants:build", "//packages/kbn-securitysolution-io-ts-types:build", diff --git a/packages/kbn-mapbox-gl/BUILD.bazel b/packages/kbn-mapbox-gl/BUILD.bazel new file mode 100644 index 00000000000000..7d7186068832ec --- /dev/null +++ b/packages/kbn-mapbox-gl/BUILD.bazel @@ -0,0 +1,84 @@ + +load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") + +PKG_BASE_NAME = "kbn-mapbox-gl" +PKG_REQUIRE_NAME = "@kbn/mapbox-gl" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", + "README.md" +] + +SRC_DEPS = [ + "@npm//@mapbox/mapbox-gl-rtl-text", + "@npm//file-loader", + "@npm//mapbox-gl", +] + +TYPES_DEPS = [ + "@npm//@types/mapbox-gl", +] + +DEPS = SRC_DEPS + TYPES_DEPS + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + ], +) + +ts_project( + name = "tsc", + args = ['--pretty'], + srcs = SRCS, + deps = DEPS, + declaration = True, + declaration_map = True, + incremental = True, + out_dir = "target", + source_map = True, + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = DEPS + [":tsc"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ] +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-mapbox-gl/README.md b/packages/kbn-mapbox-gl/README.md new file mode 100644 index 00000000000000..c1fdea491feaae --- /dev/null +++ b/packages/kbn-mapbox-gl/README.md @@ -0,0 +1,3 @@ +# @kbn/mapbox-gl + +Default instantiation for mapbox-gl. \ No newline at end of file diff --git a/packages/kbn-mapbox-gl/package.json b/packages/kbn-mapbox-gl/package.json new file mode 100644 index 00000000000000..9de88dac54a5ab --- /dev/null +++ b/packages/kbn-mapbox-gl/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/mapbox-gl", + "version": "1.0.0", + "private": true, + "license": "SSPL-1.0 OR Elastic License 2.0", + "main": "./target/index.js", + "types": "./target/index.d.ts" +} diff --git a/packages/kbn-mapbox-gl/src/index.ts b/packages/kbn-mapbox-gl/src/index.ts new file mode 100644 index 00000000000000..117b874a28ffbd --- /dev/null +++ b/packages/kbn-mapbox-gl/src/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import './typings'; +import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; +// @ts-expect-error +import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; +// @ts-expect-error +import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; +import 'mapbox-gl/dist/mapbox-gl.css'; + +mapboxgl.workerUrl = mbWorkerUrl; +mapboxgl.setRTLTextPlugin(mbRtlPlugin); + +export { mapboxgl }; diff --git a/packages/kbn-mapbox-gl/src/typings.ts b/packages/kbn-mapbox-gl/src/typings.ts new file mode 100644 index 00000000000000..0cc6908aca4284 --- /dev/null +++ b/packages/kbn-mapbox-gl/src/typings.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// Mapbox-gl doesn't declare this type. +declare module 'mapbox-gl/dist/mapbox-gl-csp'; diff --git a/packages/kbn-mapbox-gl/tsconfig.json b/packages/kbn-mapbox-gl/tsconfig.json new file mode 100644 index 00000000000000..cf1cca0f5a0fd1 --- /dev/null +++ b/packages/kbn-mapbox-gl/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "incremental": true, + "outDir": "./target", + "declaration": true, + "declarationMap": true, + "rootDir": "src", + "sourceMap": true, + "sourceRoot": "../../../../packages/kbn-mapbox-gl/src", + "types": [] + }, + "include": [ + "src/**/*", + ] +} diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/vega_map_view.scss b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/vega_map_view.scss index 33e63e7ef317c1..3e3ef71faf0d7a 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/vega_map_view.scss +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/vega_map_view.scss @@ -1,5 +1,3 @@ -@import '~mapbox-gl/dist/mapbox-gl.css'; - .vgaVis { .mapboxgl-canvas-container { cursor: auto; diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.test.ts b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.test.ts index 4fd19aa45e69e7..ee3bf305e9427e 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.test.ts +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.test.ts @@ -29,30 +29,31 @@ import { } from '../../services'; import { initVegaLayer, initTmsRasterLayer } from './layers'; -// @ts-expect-error -import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; - -jest.mock('mapbox-gl/dist/mapbox-gl-csp', () => ({ - setRTLTextPlugin: jest.fn(), - Map: jest.fn().mockImplementation(() => ({ - getLayer: () => '', - removeLayer: jest.fn(), - once: (eventName: string, handler: Function) => handler(), - remove: () => jest.fn(), - getCanvas: () => ({ clientWidth: 512, clientHeight: 512 }), - getCenter: () => ({ lat: 20, lng: 20 }), - getZoom: () => 3, - addControl: jest.fn(), - addLayer: jest.fn(), - dragRotate: { - disable: jest.fn(), - }, - touchZoomRotate: { - disableRotation: jest.fn(), - }, - })), - MapboxOptions: jest.fn(), - NavigationControl: jest.fn(), +import { mapboxgl } from '@kbn/mapbox-gl'; + +jest.mock('@kbn/mapbox-gl', () => ({ + mapboxgl: { + setRTLTextPlugin: jest.fn(), + Map: jest.fn().mockImplementation(() => ({ + getLayer: () => '', + removeLayer: jest.fn(), + once: (eventName: string, handler: Function) => handler(), + remove: () => jest.fn(), + getCanvas: () => ({ clientWidth: 512, clientHeight: 512 }), + getCenter: () => ({ lat: 20, lng: 20 }), + getZoom: () => 3, + addControl: jest.fn(), + addLayer: jest.fn(), + dragRotate: { + disable: jest.fn(), + }, + touchZoomRotate: { + disableRotation: jest.fn(), + }, + })), + MapboxOptions: jest.fn(), + NavigationControl: jest.fn(), + }, })); jest.mock('./layers', () => ({ diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts index e899057819a192..835ac36ceee471 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts @@ -10,8 +10,9 @@ import { i18n } from '@kbn/i18n'; import type { Map, Style, MapboxOptions } from 'mapbox-gl'; import { View, parse } from 'vega'; -// @ts-expect-error -import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; + +import { mapboxgl } from '@kbn/mapbox-gl'; + import { initTmsRasterLayer, initVegaLayer } from './layers'; import { VegaBaseView } from '../vega_base_view'; import { getMapServiceSettings } from '../../services'; @@ -27,14 +28,6 @@ import { import { validateZoomSettings, injectMapPropsIntoSpec } from './utils'; import './vega_map_view.scss'; -// @ts-expect-error -import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; -// @ts-expect-error -import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; - -mapboxgl.workerUrl = mbWorkerUrl; -mapboxgl.setRTLTextPlugin(mbRtlPlugin); - async function updateVegaView(mapBoxInstance: Map, vegaView: View) { const mapCanvas = mapBoxInstance.getCanvas(); const { lat, lng } = mapBoxInstance.getCenter(); diff --git a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx index e0cfe978bf45cf..851fd583b4251f 100644 --- a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx +++ b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx @@ -30,7 +30,6 @@ import { registerLayerWizards } from '../../classes/layers/load_layer_wizards'; import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property'; import { GeoFieldWithIndex } from '../../components/geo_field_with_index'; import { MapRefreshConfig } from '../../../common/descriptor_types'; -import 'mapbox-gl/dist/mapbox-gl.css'; const RENDER_COMPLETE_EVENT = 'renderComplete'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx index ac3e72545033fb..355e49564620dd 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx @@ -7,9 +7,8 @@ import _ from 'lodash'; import React, { Component } from 'react'; -import { Map as MapboxMap, MapboxOptions, MapMouseEvent } from 'mapbox-gl'; -// @ts-expect-error -import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; +import type { Map as MapboxMap, MapboxOptions, MapMouseEvent } from 'mapbox-gl'; + // @ts-expect-error import { spritesheet } from '@elastic/maki'; import sprites1 from '@elastic/maki/dist/sprite@1.png'; @@ -17,6 +16,9 @@ import sprites2 from '@elastic/maki/dist/sprite@2.png'; import { Adapters } from 'src/plugins/inspector/public'; import { Filter } from 'src/plugins/data/public'; import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public'; + +import { mapboxgl } from '@kbn/mapbox-gl'; + import { DrawFilterControl } from './draw_control'; import { ScaleControl } from './scale_control'; import { TooltipControl } from './tooltip_control'; @@ -45,13 +47,6 @@ import { GeoFieldWithIndex } from '../../components/geo_field_with_index'; import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property'; import { MapExtentState } from '../../actions'; import { TileStatusTracker } from './tile_status_tracker'; -// @ts-expect-error -import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; -// @ts-expect-error -import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; - -mapboxgl.workerUrl = mbWorkerUrl; -mapboxgl.setRTLTextPlugin(mbRtlPlugin); export interface Props { isMapReady: boolean; diff --git a/yarn.lock b/yarn.lock index f1f421e2a766f5..9967cedea9fde1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2678,6 +2678,10 @@ version "0.0.0" uid "" +"@kbn/mapbox-gl@link:bazel-bin/packages/kbn-mapbox-gl/npm_module": + version "0.0.0" + uid "" + "@kbn/monaco@link:packages/kbn-monaco": version "0.0.0" uid "" From e2d47f72694014ff6063fc0c7858bed6ed07fb9c Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 25 May 2021 07:45:07 -0700 Subject: [PATCH 05/61] [DOCS] Remove redundant maps attribute (#100426) --- docs/maps/index.asciidoc | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/maps/index.asciidoc b/docs/maps/index.asciidoc index e4150fc280096c..45d24bfb5a7e4f 100644 --- a/docs/maps/index.asciidoc +++ b/docs/maps/index.asciidoc @@ -1,6 +1,5 @@ :ems-docker-repo: docker.elastic.co/elastic-maps-service/elastic-maps-server-ubi8 :ems-docker-image: {ems-docker-repo}:{version} -:hosted-ems: Elastic Maps Server [role="xpack"] [[maps]] From 662fe7475738d90120342503e5a56016c2a5ee95 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 25 May 2021 17:02:48 +0200 Subject: [PATCH 06/61] [Reporting] ILM policy for managing reporting indices (#100130) * wip; added logic for creating ILM policy at start up * added log when ilm policy is not created * added test for start function * updated ilm policy to not delete data * actually update jest snapshots and remove unused import * updated the ilm policy, removed the min_age for the hot phase * update jest snapshot * removed TODO comment * debug log -> info log Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/lib/store/report_ilm_policy.ts | 18 +++++ .../reporting/server/lib/store/store.test.ts | 39 +++++++++++ .../reporting/server/lib/store/store.ts | 66 +++++++++++++++---- x-pack/plugins/reporting/server/plugin.ts | 3 + 4 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 x-pack/plugins/reporting/server/lib/store/report_ilm_policy.ts diff --git a/x-pack/plugins/reporting/server/lib/store/report_ilm_policy.ts b/x-pack/plugins/reporting/server/lib/store/report_ilm_policy.ts new file mode 100644 index 00000000000000..f4cd69a0331d7d --- /dev/null +++ b/x-pack/plugins/reporting/server/lib/store/report_ilm_policy.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PutLifecycleRequest } from '@elastic/elasticsearch/api/types'; + +export const reportingIlmPolicy: PutLifecycleRequest['body'] = { + policy: { + phases: { + hot: { + actions: {}, + }, + }, + }, +}; diff --git a/x-pack/plugins/reporting/server/lib/store/store.test.ts b/x-pack/plugins/reporting/server/lib/store/store.test.ts index 7f96433fcc6ceb..fa35240dfc8fbd 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.test.ts @@ -7,6 +7,7 @@ import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { ElasticsearchClient } from 'src/core/server'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { ReportingCore } from '../../'; import { createMockConfigSchema, @@ -16,6 +17,8 @@ import { import { Report, ReportDocument } from './report'; import { ReportingStore } from './store'; +const { createApiResponse } = elasticsearchServiceMock; + describe('ReportingStore', () => { const mockLogger = createMockLevelLogger(); let mockCore: ReportingCore; @@ -403,4 +406,40 @@ describe('ReportingStore', () => { ] `); }); + + describe('start', () => { + it('creates an ILM policy for managing reporting indices if there is not already one', async () => { + mockEsClient.ilm.getLifecycle.mockRejectedValueOnce(createApiResponse({ statusCode: 404 })); + mockEsClient.ilm.putLifecycle.mockResolvedValueOnce(createApiResponse()); + + const store = new ReportingStore(mockCore, mockLogger); + await store.start(); + + expect(mockEsClient.ilm.getLifecycle).toHaveBeenCalledWith({ policy: 'kibana-reporting' }); + expect(mockEsClient.ilm.putLifecycle.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "body": Object { + "policy": Object { + "phases": Object { + "hot": Object { + "actions": Object {}, + }, + }, + }, + }, + "policy": "kibana-reporting", + } + `); + }); + + it('does not create an ILM policy for managing reporting indices if one already exists', async () => { + mockEsClient.ilm.getLifecycle.mockResolvedValueOnce(createApiResponse()); + + const store = new ReportingStore(mockCore, mockLogger); + await store.start(); + + expect(mockEsClient.ilm.getLifecycle).toHaveBeenCalledWith({ policy: 'kibana-reporting' }); + expect(mockEsClient.ilm.putLifecycle).not.toHaveBeenCalled(); + }); + }); }); diff --git a/x-pack/plugins/reporting/server/lib/store/store.ts b/x-pack/plugins/reporting/server/lib/store/store.ts index fc7bd9c23d7693..9fb203fd5627ab 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.ts @@ -14,6 +14,7 @@ import { ReportTaskParams } from '../tasks'; import { indexTimestamp } from './index_timestamp'; import { mapping } from './mapping'; import { Report, ReportDocument, ReportSource } from './report'; +import { reportingIlmPolicy } from './report_ilm_policy'; /* * When searching for long-pending reports, we get a subset of fields @@ -71,19 +72,22 @@ export class ReportingStore { return exists; } - const indexSettings = { - number_of_shards: 1, - auto_expand_replicas: '0-1', - }; - const body = { - settings: indexSettings, - mappings: { - properties: mapping, - }, - }; - try { - await client.indices.create({ index: indexName, body }); + await client.indices.create({ + index: indexName, + body: { + settings: { + number_of_shards: 1, + auto_expand_replicas: '0-1', + lifecycle: { + name: this.ilmPolicyName, + }, + }, + mappings: { + properties: mapping, + }, + }, + }); return true; } catch (error) { @@ -130,6 +134,44 @@ export class ReportingStore { return client.indices.refresh({ index }); } + private readonly ilmPolicyName = 'kibana-reporting'; + + private async doesIlmPolicyExist(): Promise { + const client = await this.getClient(); + try { + await client.ilm.getLifecycle({ policy: this.ilmPolicyName }); + return true; + } catch (e) { + if (e.statusCode === 404) { + return false; + } + throw e; + } + } + + /** + * Function to be called during plugin start phase. This ensures the environment is correctly + * configured for storage of reports. + */ + public async start() { + const client = await this.getClient(); + try { + if (await this.doesIlmPolicyExist()) { + this.logger.debug(`Found ILM policy ${this.ilmPolicyName}; skipping creation.`); + return; + } + this.logger.info(`Creating ILM policy for managing reporting indices: ${this.ilmPolicyName}`); + await client.ilm.putLifecycle({ + policy: this.ilmPolicyName, + body: reportingIlmPolicy, + }); + } catch (e) { + this.logger.error('Error in start phase'); + this.logger.error(e.body.error); + throw e; + } + } + public async addReport(report: Report): Promise { let index = report._index; if (!index) { diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index fc52e10dd0cf94..efe1d9450bef31 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -107,6 +107,9 @@ export class ReportingPlugin logger: this.logger, }); + // Note: this must be called after ReportingCore.pluginStart + await store.start(); + this.logger.debug('Start complete'); })().catch((e) => { this.logger.error(`Error in Reporting start, reporting may not function properly`); From a818b2ad9d188eae1d510157605e916fddfd4bfd Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 25 May 2021 17:03:44 +0200 Subject: [PATCH 07/61] [Reporting] ILM policy for managing reporting indices (#100130) * wip; added logic for creating ILM policy at start up * added log when ilm policy is not created * added test for start function * updated ilm policy to not delete data * actually update jest snapshots and remove unused import * updated the ilm policy, removed the min_age for the hot phase * update jest snapshot * removed TODO comment * debug log -> info log Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> From d8c259478947d647f2781296f2ef6c3ff1441d54 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Tue, 25 May 2021 18:56:29 +0300 Subject: [PATCH 08/61] [XY] [Lens] Adds opacity slider (#100453) * [XY] Add opacity slider and dots size slider * [Lens] Adds fill opacity slider * Make the new sliders to appear fullwidth * Change property name and fix unit tests * Add a comment * useDebouncedValue hook Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/__snapshots__/to_ast.test.ts.snap | 2 +- .../vis_type_xy/public/config/get_config.ts | 2 + .../__snapshots__/index.test.tsx.snap | 2 + .../__snapshots__/line_options.test.tsx.snap | 9 --- .../__snapshots__/point_options.test.tsx.snap | 46 ++++++++++++++ .../metrics_axes/chart_options.test.tsx | 14 +++++ .../options/metrics_axes/chart_options.tsx | 4 ++ .../options/metrics_axes/line_options.tsx | 11 ---- .../components/options/metrics_axes/mocks.ts | 1 + .../metrics_axes/point_options.test.tsx | 44 +++++++++++++ .../options/metrics_axes/point_options.tsx | 63 +++++++++++++++++++ .../components/options/metrics_axes/utils.ts | 1 + .../point_series/elastic_charts_options.tsx | 37 +++++++++-- .../point_series/point_series.mocks.ts | 2 + .../expression_functions/series_param.ts | 8 +++ .../public/expression_functions/xy_vis_fn.ts | 7 +++ .../public/sample_vis.test.mocks.ts | 3 + src/plugins/vis_type_xy/public/to_ast.ts | 2 + .../vis_type_xy/public/types/config.ts | 1 + src/plugins/vis_type_xy/public/types/param.ts | 3 + .../public/utils/render_all_series.test.tsx | 1 + .../public/utils/render_all_series.tsx | 14 ++++- .../vis_type_xy/public/vis_types/area.ts | 1 + .../vis_type_xy/public/vis_types/histogram.ts | 1 + .../public/vis_types/horizontal_bar.ts | 1 + .../vis_type_xy/public/vis_types/line.ts | 1 + .../__snapshots__/to_expression.test.ts.snap | 3 + .../public/xy_visualization/expression.tsx | 7 +++ .../public/xy_visualization/to_expression.ts | 1 + .../lens/public/xy_visualization/types.ts | 2 + .../fill_opacity_option.test.tsx | 35 +++++++++++ .../fill_opacity_option.tsx | 59 +++++++++++++++++ .../missing_values_option.tsx | 10 ++- .../visual_options_popover.test.tsx | 51 +++++++++++++++ .../visual_options_popover.tsx | 16 +++++ .../public/xy_visualization/xy_suggestions.ts | 1 + 36 files changed, 437 insertions(+), 29 deletions(-) create mode 100644 src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap create mode 100644 src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx create mode 100644 src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx create mode 100644 x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx create mode 100644 x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap index 3ca2834a54fca2..8b720568c4d2c4 100644 --- a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap @@ -8,7 +8,7 @@ Object { "area", ], "visConfig": Array [ - "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", + "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"circlesRadius\\":5,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", ], }, "getArgument": [Function], diff --git a/src/plugins/vis_type_xy/public/config/get_config.ts b/src/plugins/vis_type_xy/public/config/get_config.ts index 8ebac1b71940a1..ce01572060a408 100644 --- a/src/plugins/vis_type_xy/public/config/get_config.ts +++ b/src/plugins/vis_type_xy/public/config/get_config.ts @@ -39,6 +39,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { fittingFunction, detailedTooltip, isVislibVis, + fillOpacity, } = params; const aspects = getAspects(table.columns, params.dimensions); const xAxis = getAxis( @@ -63,6 +64,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { // NOTE: downscale ratio to match current vislib implementation markSizeRatio: radiusRatio * 0.6, fittingFunction, + fillOpacity, detailedTooltip, orderBucketsBySum, isTimeChart, diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap index 40e53d88f99cfc..05e2532073eaf4 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap @@ -7,6 +7,7 @@ exports[`MetricsAxisOptions component should init with the default set of props seriesParams={ Array [ Object { + "circlesRadius": 3, "data": Object { "id": "1", "label": "Count", @@ -79,6 +80,7 @@ exports[`MetricsAxisOptions component should init with the default set of props seriesParams={ Array [ Object { + "circlesRadius": 3, "data": Object { "id": "1", "label": "Count", diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap index 7b45423f5f861e..8764db1dea06ad 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap @@ -54,14 +54,5 @@ exports[`LineOptions component should init with the default set of props 1`] = ` /> - - `; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap new file mode 100644 index 00000000000000..fcd6f8d00a1385 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PointOptions component should init with the default set of props 1`] = ` + + + + + + + + +`; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx index def24d51f49f39..1d5c8be2b92464 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx @@ -12,6 +12,7 @@ import { shallow, mount } from 'enzyme'; import { ChartOptions, ChartOptionsParams } from './chart_options'; import { SeriesParam, ChartMode, AxisMode } from '../../../../types'; import { LineOptions } from './line_options'; +import { PointOptions } from './point_options'; import { valueAxis, seriesParam } from './mocks'; import { ChartType } from '../../../../../common'; @@ -41,6 +42,12 @@ describe('ChartOptions component', () => { expect(comp).toMatchSnapshot(); }); + it('should hide the PointOptions when type is bar', () => { + const comp = shallow(); + + expect(comp.find(PointOptions).exists()).toBeFalsy(); + }); + it('should show LineOptions when type is line', () => { chart.type = ChartType.Line; const comp = shallow(); @@ -48,6 +55,13 @@ describe('ChartOptions component', () => { expect(comp.find(LineOptions).exists()).toBeTruthy(); }); + it('should show PointOptions when type is area', () => { + chart.type = ChartType.Area; + const comp = shallow(); + + expect(comp.find(PointOptions).exists()).toBeTruthy(); + }); + it('should show line mode when type is area', () => { chart.type = ChartType.Area; const comp = shallow(); diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx index 23452a87aae605..34ee33781f269d 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx @@ -15,6 +15,7 @@ import { SelectOption } from '../../../../../../vis_default_editor/public'; import { SeriesParam, ValueAxis, ChartMode, AxisMode } from '../../../../types'; import { LineOptions } from './line_options'; +import { PointOptions } from './point_options'; import { SetParamByIndex, ChangeValueAxis } from '.'; import { ChartType } from '../../../../../common'; import { getConfigCollections } from '../../../collections'; @@ -143,6 +144,9 @@ function ChartOptions({ )} {chart.type === ChartType.Line && } + {(chart.type === ChartType.Area || chart.type === ChartType.Line) && ( + + )} ); } diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx index 140f190c77181e..75dfe8627d73ea 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx @@ -78,17 +78,6 @@ function LineOptions({ chart, setChart }: LineOptionsParams) { /> - - - - ); } diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts index 7451f6dea9039b..eed224cf2a514a 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts @@ -75,6 +75,7 @@ const seriesParam: SeriesParam = { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, valueAxis: defaultValueAxisId, }; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx new file mode 100644 index 00000000000000..68ac1832d28a89 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { shallow, mount } from 'enzyme'; +import { findTestSubject } from '@elastic/eui/lib/test'; + +import { SeriesParam } from '../../../../types'; +import { PointOptions, PointOptionsParams } from './point_options'; +import { seriesParam } from './mocks'; + +describe('PointOptions component', () => { + let setChart: jest.Mock; + let defaultProps: PointOptionsParams; + let chart: SeriesParam; + + beforeEach(() => { + setChart = jest.fn(); + chart = { ...seriesParam }; + + defaultProps = { + chart, + setChart, + }; + }); + + it('should init with the default set of props', () => { + const comp = shallow(); + + expect(comp).toMatchSnapshot(); + }); + + it('should disable the dots size range if the show dots switch is off', () => { + chart.showCircles = false; + const comp = mount(); + const range = findTestSubject(comp, 'circlesRadius'); + expect(range.at(1).props().disabled).toBeTruthy(); + }); +}); diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx new file mode 100644 index 00000000000000..d35a5a2374ca34 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; + +import { i18n } from '@kbn/i18n'; +import { EuiRange, EuiFormRow, EuiSpacer } from '@elastic/eui'; + +import { SwitchOption } from '../../../../../../vis_default_editor/public'; + +import { SeriesParam } from '../../../../types'; +import { SetChart } from './chart_options'; + +export interface PointOptionsParams { + chart: SeriesParam; + setChart: SetChart; +} + +function PointOptions({ chart, setChart }: PointOptionsParams) { + return ( + <> + + + + + { + setChart('circlesRadius', Number(e.currentTarget.value)); + }} + /> + + + ); +} + +export { PointOptions }; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts index d0d0c08060acf5..a8d53e45bc988b 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts @@ -26,6 +26,7 @@ export const makeSerie = ( type: ChartType.Line, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, lineWidth: 2, valueAxis: defaultValueAxis, diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx index 5398980e268d48..271c5445a95807 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx @@ -10,7 +10,7 @@ import React, { useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE } from '@kbn/analytics'; - +import { EuiFormRow, EuiRange } from '@elastic/eui'; import { SelectOption, SwitchOption, @@ -31,10 +31,14 @@ export function ElasticChartsOptions(props: ValidationVisOptionsProps const [palettesRegistry, setPalettesRegistry] = useState(null); const { stateParams, setValue, aggs } = props; - const hasLineChart = stateParams.seriesParams.some( + const isLineChart = stateParams.seriesParams.some( + ({ type, data: { id: paramId } }) => + type === ChartType.Line && aggs.aggs.find(({ id }) => id === paramId)?.enabled + ); + + const isAreaChart = stateParams.seriesParams.some( ({ type, data: { id: paramId } }) => - (type === ChartType.Line || type === ChartType.Area) && - aggs.aggs.find(({ id }) => id === paramId)?.enabled + type === ChartType.Area && aggs.aggs.find(({ id }) => id === paramId)?.enabled ); useEffect(() => { @@ -66,7 +70,7 @@ export function ElasticChartsOptions(props: ValidationVisOptionsProps }} /> - {hasLineChart && ( + {(isLineChart || isAreaChart) && ( }} /> )} + {isAreaChart && ( + + { + setValue('fillOpacity', Number(e.currentTarget.value)); + }} + /> + + )} ); } diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts index eb8d4d1c440d70..f23d9e4ada3361 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts @@ -410,6 +410,7 @@ export const getVis = (bucketType: string) => { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, @@ -838,6 +839,7 @@ export const getStateParams = (type: string, thresholdPanelOn: boolean) => { }, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 3, interpolate: 'cardinal', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts b/src/plugins/vis_type_xy/public/expression_functions/series_param.ts index 402187cea65866..3fd62e33e257fe 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts +++ b/src/plugins/vis_type_xy/public/expression_functions/series_param.ts @@ -29,6 +29,7 @@ export type ExpressionValueSeriesParam = ExpressionValueBoxed< mode: SeriesParam['mode']; show: boolean; showCircles: boolean; + circlesRadius: number; seriesParamType: SeriesParam['type']; valueAxis: string; } @@ -98,6 +99,12 @@ export const seriesParam = (): ExpressionFunctionDefinition< defaultMessage: 'Show circles', }), }, + circlesRadius: { + types: ['number'], + help: i18n.translate('visTypeXy.function.seriesParam.circlesRadius.help', { + defaultMessage: 'Defines the circles size (radius)', + }), + }, type: { types: ['string'], help: i18n.translate('visTypeXy.function.seriesParam.type.help', { @@ -121,6 +128,7 @@ export const seriesParam = (): ExpressionFunctionDefinition< mode: args.mode, show: args.show, showCircles: args.showCircles, + circlesRadius: args.circlesRadius, seriesParamType: args.type, valueAxis: args.valueAxis, }; diff --git a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts index b8b8c0e8b8cca8..29403a12fdce63 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts @@ -161,6 +161,12 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ defaultMessage: 'Defines the chart palette name', }), }, + fillOpacity: { + types: ['number'], + help: i18n.translate('visTypeXy.function.args.fillOpacity.help', { + defaultMessage: 'Defines the area chart fill opacity', + }), + }, xDimension: { types: ['xy_dimension', 'null'], help: i18n.translate('visTypeXy.function.args.xDimension.help', { @@ -242,6 +248,7 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ type: 'palette', name: args.palette, }, + fillOpacity: args.fillOpacity, fittingFunction: args.fittingFunction, dimensions: { x: args.xDimension, diff --git a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts b/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts index e15f9c42077020..39370d941b52ac 100644 --- a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts +++ b/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts @@ -1397,6 +1397,7 @@ export const sampleAreaVis = { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, @@ -1417,6 +1418,7 @@ export const sampleAreaVis = { palette: { name: 'default', }, + fillOpacity: 0.5, }, }, editorConfig: { @@ -1562,6 +1564,7 @@ export const sampleAreaVis = { }, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 5, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/to_ast.ts b/src/plugins/vis_type_xy/public/to_ast.ts index c0a0ee566a4453..f473cd77c2d2b7 100644 --- a/src/plugins/vis_type_xy/public/to_ast.ts +++ b/src/plugins/vis_type_xy/public/to_ast.ts @@ -98,6 +98,7 @@ const prepareSeriesParam = (data: SeriesParam) => { mode: data.mode, show: data.show, showCircles: data.showCircles, + circlesRadius: data.circlesRadius, type: data.type, valueAxis: data.valueAxis, }); @@ -207,6 +208,7 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params fittingFunction: vis.params.fittingFunction, times: vis.params.times.map(prepareTimeMarker), palette: vis.params.palette.name, + fillOpacity: vis.params.fillOpacity, xDimension: dimensions.x ? prepareXYDimension(dimensions.x) : null, yDimension: dimensions.y.map(prepareXYDimension), zDimension: dimensions.z?.map(prepareXYDimension), diff --git a/src/plugins/vis_type_xy/public/types/config.ts b/src/plugins/vis_type_xy/public/types/config.ts index f025a36a82410a..e52b47366bc857 100644 --- a/src/plugins/vis_type_xy/public/types/config.ts +++ b/src/plugins/vis_type_xy/public/types/config.ts @@ -116,6 +116,7 @@ export interface VisConfig { showValueLabel: boolean; enableHistogramMode: boolean; fittingFunction?: Exclude; + fillOpacity?: number; detailedTooltip?: boolean; isVislibVis?: boolean; } diff --git a/src/plugins/vis_type_xy/public/types/param.ts b/src/plugins/vis_type_xy/public/types/param.ts index f90899620126aa..7a2ff7e2402640 100644 --- a/src/plugins/vis_type_xy/public/types/param.ts +++ b/src/plugins/vis_type_xy/public/types/param.ts @@ -78,6 +78,7 @@ export interface SeriesParam { mode: ChartMode; show: boolean; showCircles: boolean; + circlesRadius: number; type: ChartType; valueAxis: string; } @@ -155,6 +156,7 @@ export interface VisParams { */ detailedTooltip?: boolean; palette: PaletteOutput; + fillOpacity?: number; fittingFunction?: Exclude; } @@ -186,6 +188,7 @@ export interface XYVisConfig { */ detailedTooltip?: boolean; fittingFunction?: Exclude; + fillOpacity?: number; xDimension: ExpressionValueXYDimension | null; yDimension: ExpressionValueXYDimension[]; zDimension?: ExpressionValueXYDimension[]; diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx b/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx index 628d3620090ca1..23dabef662d559 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx +++ b/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx @@ -31,6 +31,7 @@ const defaultSeriesParams = [ mode: 'stacked', show: true, showCircles: true, + circlesRadius: 3, type: 'area', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx b/src/plugins/vis_type_xy/public/utils/render_all_series.tsx index 3bce5ddc2e85e6..e915e6d4966c50 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_type_xy/public/utils/render_all_series.tsx @@ -51,7 +51,15 @@ const getCurveType = (type?: 'linear' | 'cardinal' | 'step-after'): CurveType => * @param getSeriesColor */ export const renderAllSeries = ( - { aspects, yAxes, xAxis, showValueLabel, enableHistogramMode, fittingFunction }: VisConfig, + { + aspects, + yAxes, + xAxis, + showValueLabel, + enableHistogramMode, + fittingFunction, + fillOpacity, + }: VisConfig, seriesParams: SeriesParam[], data: DatatableRow[], getSeriesName: (series: XYChartSeriesIdentifier) => SeriesName, @@ -67,6 +75,7 @@ export const renderAllSeries = ( data: { id: paramId }, lineWidth: strokeWidth, showCircles, + circlesRadius, drawLinesBetweenPoints, mode, interpolate, @@ -158,7 +167,7 @@ export const renderAllSeries = ( stackMode={stackMode} areaSeriesStyle={{ area: { - ...(type === ChartType.Line && { opacity: 0 }), + ...(type === ChartType.Line ? { opacity: 0 } : { opacity: fillOpacity }), }, line: { strokeWidth, @@ -167,6 +176,7 @@ export const renderAllSeries = ( point: { visible: showCircles, fill: markSizeAccessor ? ColorVariant.Series : undefined, + radius: circlesRadius, }, }} /> diff --git a/src/plugins/vis_type_xy/public/vis_types/area.ts b/src/plugins/vis_type_xy/public/vis_types/area.ts index f22f8df1752d66..912b3d8d48e952 100644 --- a/src/plugins/vis_type_xy/public/vis_types/area.ts +++ b/src/plugins/vis_type_xy/public/vis_types/area.ts @@ -98,6 +98,7 @@ export const getAreaVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/vis_types/histogram.ts b/src/plugins/vis_type_xy/public/vis_types/histogram.ts index 732833ffecc802..9af4cfd7b43a3e 100644 --- a/src/plugins/vis_type_xy/public/vis_types/histogram.ts +++ b/src/plugins/vis_type_xy/public/vis_types/histogram.ts @@ -102,6 +102,7 @@ export const getHistogramVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, }, ], radiusRatio: 0, diff --git a/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts b/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts index 791d93bb646b23..874e69b246a4d9 100644 --- a/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts +++ b/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts @@ -103,6 +103,7 @@ export const getHorizontalBarVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, }, ], addTooltip: true, diff --git a/src/plugins/vis_type_xy/public/vis_types/line.ts b/src/plugins/vis_type_xy/public/vis_types/line.ts index 6316fe44582290..2e8944f44daab8 100644 --- a/src/plugins/vis_type_xy/public/vis_types/line.ts +++ b/src/plugins/vis_type_xy/public/vis_types/line.ts @@ -100,6 +100,7 @@ export const getLineVisTypeDefinition = ( lineWidth: 2, interpolate: InterpolationMode.Linear, showCircles: true, + circlesRadius: 3, }, ], addTooltip: true, diff --git a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap index 339fb5a7ab68f3..08b3393fafe482 100644 --- a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap +++ b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap @@ -33,6 +33,9 @@ Object { "description": Array [ "", ], + "fillOpacity": Array [ + 0.3, + ], "fittingFunction": Array [ "Carry", ], diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 006727b05b9056..e3b4565913ad87 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -196,6 +196,12 @@ export const xyChart: ExpressionFunctionDefinition< defaultMessage: 'Define how curve type is rendered for a line chart', }), }, + fillOpacity: { + types: ['number'], + help: i18n.translate('xpack.lens.xyChart.fillOpacity.help', { + defaultMessage: 'Define the area chart fill opacity', + }), + }, hideEndzones: { types: ['boolean'], default: false, @@ -812,6 +818,7 @@ export function XYChart({ visible: !xAccessor, radius: 5, }, + ...(args.fillOpacity && { area: { opacity: args.fillOpacity } }), }, lineSeriesStyle: { point: { diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts index dea6b1a7be0c57..269f10159892f4 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts @@ -149,6 +149,7 @@ export const buildExpression = ( ], fittingFunction: [state.fittingFunction || 'None'], curveType: [state.curveType || 'LINEAR'], + fillOpacity: [state.fillOpacity || 0.3], yLeftExtent: [ { type: 'expression', diff --git a/x-pack/plugins/lens/public/xy_visualization/types.ts b/x-pack/plugins/lens/public/xy_visualization/types.ts index ea28b492477c18..531b034b532425 100644 --- a/x-pack/plugins/lens/public/xy_visualization/types.ts +++ b/x-pack/plugins/lens/public/xy_visualization/types.ts @@ -464,6 +464,7 @@ export interface XYArgs { tickLabelsVisibilitySettings?: AxesSettingsConfig & { type: 'lens_xy_tickLabelsConfig' }; gridlinesVisibilitySettings?: AxesSettingsConfig & { type: 'lens_xy_gridlinesConfig' }; curveType?: XYCurveType; + fillOpacity?: number; hideEndzones?: boolean; } @@ -485,6 +486,7 @@ export interface XYState { tickLabelsVisibilitySettings?: AxesSettingsConfig; gridlinesVisibilitySettings?: AxesSettingsConfig; curveType?: XYCurveType; + fillOpacity?: number; hideEndzones?: boolean; } diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx new file mode 100644 index 00000000000000..3ba29e4f72c837 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { mountWithIntl as mount, shallowWithIntl as shallow } from '@kbn/test/jest'; +import { EuiRange } from '@elastic/eui'; +import { FillOpacityOption } from './fill_opacity_option'; + +describe('Line curve option', () => { + it('should show currently selected opacity value', () => { + const component = shallow(); + + expect(component.find(EuiRange).prop('value')).toEqual(0.3); + }); + + it('should show fill opacity option when enabled', () => { + const component = mount( + + ); + + expect(component.exists('[data-test-subj="lnsFillOpacity"]')).toEqual(true); + }); + + it('should hide curve option when disabled', () => { + const component = mount( + + ); + + expect(component.exists('[data-test-subj="lnsFillOpacity"]')).toEqual(false); + }); +}); diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx new file mode 100644 index 00000000000000..eb8d35c54a99b9 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiFormRow, EuiRange } from '@elastic/eui'; +import { useDebouncedValue } from '../../shared_components'; + +export interface FillOpacityOptionProps { + /** + * Currently selected value + */ + value: number; + /** + * Callback on display option change + */ + onChange: (value: number) => void; + /** + * Flag for rendering or not the component + */ + isFillOpacityEnabled?: boolean; +} + +export const FillOpacityOption: React.FC = ({ + onChange, + value, + isFillOpacityEnabled = true, +}) => { + const { inputValue, handleInputChange } = useDebouncedValue({ value, onChange }); + return isFillOpacityEnabled ? ( + <> + + { + handleInputChange(Number(e.currentTarget.value)); + }} + /> + + + ) : null; +}; diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx index fb6ecec4d28013..a683d4fbf514c3 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx @@ -7,7 +7,14 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonGroup, EuiFormRow, EuiIconTip, EuiSuperSelect, EuiText } from '@elastic/eui'; +import { + EuiButtonGroup, + EuiFormRow, + EuiIconTip, + EuiSuperSelect, + EuiText, + EuiSpacer, +} from '@elastic/eui'; import { FittingFunction, fittingFunctionDefinitions } from '../fitting_functions'; import { ValueLabelConfig } from '../types'; @@ -133,6 +140,7 @@ export const MissingValuesOptions: React.FC = ({ /> )} + ); }; diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx index e7ec395312bff4..b46ad1940491e6 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx @@ -14,6 +14,7 @@ import { State } from '../types'; import { VisualOptionsPopover } from './visual_options_popover'; import { ToolbarPopover } from '../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; +import { FillOpacityOption } from './fill_opacity_option'; describe('Visual options popover', () => { let frame: FramePublicAPI; @@ -74,6 +75,22 @@ describe('Visual options popover', () => { expect(component.find(MissingValuesOptions).prop('isFittingEnabled')).toEqual(false); }); + it('should not disable the fill opacity for percentage area charts', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(true); + }); + it('should not disable the visual options for percentage area charts', () => { const state = testState(); const component = shallow( @@ -128,6 +145,40 @@ describe('Visual options popover', () => { expect(component.find(MissingValuesOptions).prop('isFittingEnabled')).toEqual(false); }); + it('should hide the fill opacity option for bar series', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(false); + }); + + it('should hide the fill opacity option for line series', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(false); + }); + it('should show the popover and display field enabled for bar and horizontal_bar series', () => { const state = testState(); diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx index b8b89f146bdc07..b07feb85892e53 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { ToolbarPopover } from '../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; import { LineCurveOption } from './line_curve_option'; +import { FillOpacityOption } from './fill_opacity_option'; import { XYState } from '../types'; import { hasHistogramSeries } from '../state_helpers'; import { ValidLayer } from '../types'; @@ -61,6 +62,10 @@ export const VisualOptionsPopover: React.FC = ({ ['bar', 'bar_horizontal'].includes(seriesType) ); + const hasAreaSeries = state?.layers.some(({ seriesType }) => + ['area_stacked', 'area', 'area_percentage_stacked'].includes(seriesType) + ); + const isHistogramSeries = Boolean( hasHistogramSeries(state?.layers as ValidLayer[], datasourceLayers) ); @@ -110,6 +115,17 @@ export const VisualOptionsPopover: React.FC = ({ setState({ ...state, fittingFunction: newVal }); }} /> + + { + setState({ + ...state, + fillOpacity: newValue, + }); + }} + /> ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts index 4554c34b97c555..aff33778258fed 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts +++ b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts @@ -524,6 +524,7 @@ function buildSuggestion({ valueLabels: currentState?.valueLabels || 'hide', fittingFunction: currentState?.fittingFunction || 'None', curveType: currentState?.curveType, + fillOpacity: currentState?.fillOpacity, xTitle: currentState?.xTitle, yTitle: currentState?.yTitle, yRightTitle: currentState?.yRightTitle, From 111e15a0549df284fa3254057797a7359ffca9a8 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 25 May 2021 10:25:09 -0600 Subject: [PATCH 09/61] [ftr] implement FtrService classes and migrate common services (#99546) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../development-functional-tests.asciidoc | 9 +- .../lib/providers/provider_collection.ts | 12 +- .../functional_test_runner/public_types.ts | 12 +- ...r_context.d.ts => ftr_provider_context.ts} | 3 +- test/common/services/deployment.ts | 60 +++++----- test/common/services/index.ts | 16 +-- .../services/kibana_server/kibana_server.ts | 2 +- test/common/services/randomness.ts | 93 ++++++++------- test/common/services/retry/index.ts | 2 +- test/common/services/retry/retry.ts | 104 ++++++++--------- test/common/services/saved_object_info.ts | 74 ++++++------ test/common/services/security/security.ts | 32 ++--- test/common/services/security/test_user.ts | 110 ++++++++++-------- test/functional/apps/visualize/index.ts | 2 +- .../functional/apps/visualize/legacy/index.ts | 2 +- ...r_context.d.ts => ftr_provider_context.ts} | 3 +- test/functional/page_objects/time_picker.ts | 2 +- .../page_objects/visual_builder_page.ts | 2 +- x-pack/test/functional/apps/lens/index.ts | 2 +- ...r_context.d.ts => ftr_provider_context.ts} | 3 +- 20 files changed, 292 insertions(+), 253 deletions(-) rename test/common/{ftr_provider_context.d.ts => ftr_provider_context.ts} (76%) rename test/functional/{ftr_provider_context.d.ts => ftr_provider_context.ts} (78%) rename x-pack/test/functional/{ftr_provider_context.d.ts => ftr_provider_context.ts} (74%) diff --git a/docs/developer/contributing/development-functional-tests.asciidoc b/docs/developer/contributing/development-functional-tests.asciidoc index 110704a8e569a9..f0041b85c14ebf 100644 --- a/docs/developer/contributing/development-functional-tests.asciidoc +++ b/docs/developer/contributing/development-functional-tests.asciidoc @@ -139,11 +139,14 @@ export default function (/* { providerAPI } */) { } ----------- -**Services**::: -Services are named singleton values produced by a Service Provider. Tests and other services can retrieve service instances by asking for them by name. All functionality except the mocha API is exposed via services. +**Service**::: +A Service is a named singleton created using a subclass of `FtrService`. Tests and other services can retrieve service instances by asking for them by name. All functionality except the mocha API is exposed via services. When you write your own functional tests check for existing services that help with the interactions you're looking to execute, and add new services for interactions which aren't already encoded in a service. + +**Service Providers**::: +For legacy purposes, and for when creating a subclass of `FtrService` is inconvenient, you can also create services using a "Service Provider". These are functions which which create service instances and return them. These instances are cached and provided to tests. Currently these providers may also return a Promise for the service instance, allowing the service to do some setup work before tests run. We expect to fully deprecate and remove support for async service providers in the near future and instead require that services use the `lifecycle` service to run setup before tests. Providers which return instances of classes other than `FtrService` will likely remain supported for as long as possible. **Page objects**::: -Page objects are a special type of service that encapsulate behaviors common to a particular page or plugin. When you write your own plugin, you’ll likely want to add a page object (or several) that describes the common interactions your tests need to execute. +Page objects are functionally equivalent to services, except they are loaded with a slightly different mechanism and generally defined separate from services. When you write your own functional tests you might want to write some of your services as Page objects, but it is not required. **Test Files**::: The `FunctionalTestRunner`'s primary purpose is to execute test files. These files export a Test Provider that is called with a Provider API but is not expected to return a value. Instead Test Providers define a suite using https://mochajs.org/#bdd[mocha's BDD interface]. diff --git a/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts b/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts index 1aa5df1105f460..2d05d5bba5ff6f 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts @@ -12,6 +12,7 @@ import { loadTracer } from '../load_tracer'; import { createAsyncInstance, isAsyncInstance } from './async_instance'; import { Providers } from './read_provider_spec'; import { createVerboseInstance } from './verbose_instance'; +import { GenericFtrService } from '../../public_types'; export class ProviderCollection { private readonly instances = new Map(); @@ -58,12 +59,19 @@ export class ProviderCollection { } public invokeProviderFn(provider: (args: any) => any) { - return provider({ + const ctx = { getService: this.getService, hasService: this.hasService, getPageObject: this.getPageObject, getPageObjects: this.getPageObjects, - }); + }; + + if (provider.prototype instanceof GenericFtrService) { + const Constructor = (provider as any) as new (ctx: any) => any; + return new Constructor(ctx); + } + + return provider(ctx); } private findProvider(type: string, name: string) { diff --git a/packages/kbn-test/src/functional_test_runner/public_types.ts b/packages/kbn-test/src/functional_test_runner/public_types.ts index 915cb34f6ffe50..4a30744c09b516 100644 --- a/packages/kbn-test/src/functional_test_runner/public_types.ts +++ b/packages/kbn-test/src/functional_test_runner/public_types.ts @@ -13,7 +13,7 @@ import { Test, Suite } from './fake_mocha_types'; export { Lifecycle, Config, FailureMetadata }; -interface AsyncInstance { +export interface AsyncInstance { /** * Services that are initialized async are not ready before the tests execute, so you might need * to call `init()` and await the promise it returns before interacting with the service @@ -39,7 +39,11 @@ export type ProvidedType any> = MaybeAsyncInstance * promise types into the async instances that other providers will receive. */ type ProvidedTypeMap = { - [K in keyof T]: T[K] extends (...args: any[]) => any ? ProvidedType : unknown; + [K in keyof T]: T[K] extends new (...args: any[]) => infer X + ? X + : T[K] extends (...args: any[]) => any + ? ProvidedType + : unknown; }; export interface GenericFtrProviderContext< @@ -84,6 +88,10 @@ export interface GenericFtrProviderContext< loadTestFile(path: string): void; } +export class GenericFtrService> { + constructor(protected readonly ctx: ProviderContext) {} +} + export interface FtrConfigProviderContext { log: ToolingLog; readConfigFile(path: string): Promise; diff --git a/test/common/ftr_provider_context.d.ts b/test/common/ftr_provider_context.ts similarity index 76% rename from test/common/ftr_provider_context.d.ts rename to test/common/ftr_provider_context.ts index 91d35a2dbc32a6..6d21aedfe1d5ec 100644 --- a/test/common/ftr_provider_context.d.ts +++ b/test/common/ftr_provider_context.ts @@ -6,8 +6,9 @@ * Side Public License, v 1. */ -import { GenericFtrProviderContext } from '@kbn/test'; +import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; import { services } from './services'; export type FtrProviderContext = GenericFtrProviderContext; +export class FtrService extends GenericFtrService {} diff --git a/test/common/services/deployment.ts b/test/common/services/deployment.ts index 65466ca966ad25..b250d39ce65d65 100644 --- a/test/common/services/deployment.ts +++ b/test/common/services/deployment.ts @@ -10,39 +10,37 @@ import { get } from 'lodash'; import fetch from 'node-fetch'; import { getUrl } from '@kbn/test'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; -export function DeploymentProvider({ getService }: FtrProviderContext) { - const config = getService('config'); +export class DeploymentService extends FtrService { + private readonly config = this.ctx.getService('config'); - return { - /** - * Returns Kibana host URL - */ - getHostPort() { - return getUrl.baseUrl(config.get('servers.kibana')); - }, + /** + * Returns Kibana host URL + */ + getHostPort() { + return getUrl.baseUrl(this.config.get('servers.kibana')); + } - /** - * Returns ES host URL - */ - getEsHostPort() { - return getUrl.baseUrl(config.get('servers.elasticsearch')); - }, + /** + * Returns ES host URL + */ + getEsHostPort() { + return getUrl.baseUrl(this.config.get('servers.elasticsearch')); + } - async isCloud(): Promise { - const baseUrl = this.getHostPort(); - const username = config.get('servers.kibana.username'); - const password = config.get('servers.kibana.password'); - const response = await fetch(baseUrl + '/api/stats?extended', { - method: 'get', - headers: { - 'Content-Type': 'application/json', - Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'), - }, - }); - const data = await response.json(); - return get(data, 'usage.cloud.is_cloud_enabled', false); - }, - }; + async isCloud(): Promise { + const baseUrl = this.getHostPort(); + const username = this.config.get('servers.kibana.username'); + const password = this.config.get('servers.kibana.password'); + const response = await fetch(baseUrl + '/api/stats?extended', { + method: 'get', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'), + }, + }); + const data = await response.json(); + return get(data, 'usage.cloud.is_cloud_enabled', false); + } } diff --git a/test/common/services/index.ts b/test/common/services/index.ts index cc4859b7016bf3..02aafc59fa80f4 100644 --- a/test/common/services/index.ts +++ b/test/common/services/index.ts @@ -6,26 +6,26 @@ * Side Public License, v 1. */ -import { DeploymentProvider } from './deployment'; +import { DeploymentService } from './deployment'; import { LegacyEsProvider } from './legacy_es'; import { ElasticsearchProvider } from './elasticsearch'; import { EsArchiverProvider } from './es_archiver'; import { KibanaServerProvider } from './kibana_server'; -import { RetryProvider } from './retry'; -import { RandomnessProvider } from './randomness'; +import { RetryService } from './retry'; +import { RandomnessService } from './randomness'; import { SecurityServiceProvider } from './security'; import { EsDeleteAllIndicesProvider } from './es_delete_all_indices'; -import { SavedObjectInfoProvider } from './saved_object_info'; +import { SavedObjectInfoService } from './saved_object_info'; export const services = { - deployment: DeploymentProvider, + deployment: DeploymentService, legacyEs: LegacyEsProvider, es: ElasticsearchProvider, esArchiver: EsArchiverProvider, kibanaServer: KibanaServerProvider, - retry: RetryProvider, - randomness: RandomnessProvider, + retry: RetryService, + randomness: RandomnessService, security: SecurityServiceProvider, esDeleteAllIndices: EsDeleteAllIndicesProvider, - savedObjectInfo: SavedObjectInfoProvider, + savedObjectInfo: SavedObjectInfoService, }; diff --git a/test/common/services/kibana_server/kibana_server.ts b/test/common/services/kibana_server/kibana_server.ts index f366a864db980d..63803bd511bd14 100644 --- a/test/common/services/kibana_server/kibana_server.ts +++ b/test/common/services/kibana_server/kibana_server.ts @@ -11,7 +11,7 @@ import { KbnClient } from '@kbn/test'; import { FtrProviderContext } from '../../ftr_provider_context'; -export function KibanaServerProvider({ getService }: FtrProviderContext) { +export function KibanaServerProvider({ getService }: FtrProviderContext): KbnClient { const log = getService('log'); const config = getService('config'); const lifecycle = getService('lifecycle'); diff --git a/test/common/services/randomness.ts b/test/common/services/randomness.ts index 88b0411f98033e..82f06fb681066a 100644 --- a/test/common/services/randomness.ts +++ b/test/common/services/randomness.ts @@ -7,8 +7,20 @@ */ import Chance from 'chance'; +import { ToolingLog } from '@kbn/dev-utils'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; + +let __CACHED_SEED__: number | undefined; +function getSeed(log: ToolingLog) { + if (__CACHED_SEED__ !== undefined) { + return __CACHED_SEED__; + } + + __CACHED_SEED__ = Date.now(); + log.debug('randomness seed: %j', __CACHED_SEED__); + return __CACHED_SEED__; +} interface CharOptions { pool?: string; @@ -27,52 +39,45 @@ interface NumberOptions { max?: number; } -export function RandomnessProvider({ getService }: FtrProviderContext) { - const log = getService('log'); - - const seed = Date.now(); - log.debug('randomness seed: %j', seed); - - const chance = new Chance(seed); +export class RandomnessService extends FtrService { + private readonly chance = new Chance(getSeed(this.ctx.getService('log'))); - return new (class RandomnessService { - /** - * Generate a random natural number - * - * range: 0 to 9007199254740991 - * - */ - naturalNumber(options?: NumberOptions) { - return chance.natural(options); - } + /** + * Generate a random natural number + * + * range: 0 to 9007199254740991 + * + */ + naturalNumber(options?: NumberOptions) { + return this.chance.natural(options); + } - /** - * Generate a random integer - */ - integer(options?: NumberOptions) { - return chance.integer(options); - } + /** + * Generate a random integer + */ + integer(options?: NumberOptions) { + return this.chance.integer(options); + } - /** - * Generate a random number, defaults to at least 4 and no more than 8 syllables - */ - word(options: { syllables?: number } = {}) { - const { syllables = this.naturalNumber({ min: 4, max: 8 }) } = options; + /** + * Generate a random number, defaults to at least 4 and no more than 8 syllables + */ + word(options: { syllables?: number } = {}) { + const { syllables = this.naturalNumber({ min: 4, max: 8 }) } = options; - return chance.word({ - syllables, - }); - } + return this.chance.word({ + syllables, + }); + } - /** - * Generate a random string, defaults to at least 8 and no more than 15 alpha-numeric characters - */ - string(options: StringOptions = {}) { - return chance.string({ - length: this.naturalNumber({ min: 8, max: 15 }), - ...(options.pool === 'undefined' ? { alpha: true, numeric: true, symbols: false } : {}), - ...options, - }); - } - })(); + /** + * Generate a random string, defaults to at least 8 and no more than 15 alpha-numeric characters + */ + string(options: StringOptions = {}) { + return this.chance.string({ + length: this.naturalNumber({ min: 8, max: 15 }), + ...(options.pool === 'undefined' ? { alpha: true, numeric: true, symbols: false } : {}), + ...options, + }); + } } diff --git a/test/common/services/retry/index.ts b/test/common/services/retry/index.ts index 4914b3cff2261e..08ce3f9bd46611 100644 --- a/test/common/services/retry/index.ts +++ b/test/common/services/retry/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { RetryProvider } from './retry'; +export { RetryService } from './retry'; diff --git a/test/common/services/retry/retry.ts b/test/common/services/retry/retry.ts index 8ea2a52b6adf69..5c823e256ddc8d 100644 --- a/test/common/services/retry/retry.ts +++ b/test/common/services/retry/retry.ts @@ -6,64 +6,62 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; import { retryForSuccess } from './retry_for_success'; import { retryForTruthy } from './retry_for_truthy'; -export function RetryProvider({ getService }: FtrProviderContext) { - const config = getService('config'); - const log = getService('log'); +export class RetryService extends FtrService { + private readonly config = this.ctx.getService('config'); + private readonly log = this.ctx.getService('log'); - return new (class Retry { - public async tryForTime( - timeout: number, - block: () => Promise, - onFailureBlock?: () => Promise - ) { - return await retryForSuccess(log, { - timeout, - methodName: 'retry.tryForTime', - block, - onFailureBlock, - }); - } + public async tryForTime( + timeout: number, + block: () => Promise, + onFailureBlock?: () => Promise + ) { + return await retryForSuccess(this.log, { + timeout, + methodName: 'retry.tryForTime', + block, + onFailureBlock, + }); + } - public async try(block: () => Promise, onFailureBlock?: () => Promise) { - return await retryForSuccess(log, { - timeout: config.get('timeouts.try'), - methodName: 'retry.try', - block, - onFailureBlock, - }); - } + public async try(block: () => Promise, onFailureBlock?: () => Promise) { + return await retryForSuccess(this.log, { + timeout: this.config.get('timeouts.try'), + methodName: 'retry.try', + block, + onFailureBlock, + }); + } - public async waitForWithTimeout( - description: string, - timeout: number, - block: () => Promise, - onFailureBlock?: () => Promise - ) { - await retryForTruthy(log, { - timeout, - methodName: 'retry.waitForWithTimeout', - description, - block, - onFailureBlock, - }); - } + public async waitForWithTimeout( + description: string, + timeout: number, + block: () => Promise, + onFailureBlock?: () => Promise + ) { + await retryForTruthy(this.log, { + timeout, + methodName: 'retry.waitForWithTimeout', + description, + block, + onFailureBlock, + }); + } - public async waitFor( - description: string, - block: () => Promise, - onFailureBlock?: () => Promise - ) { - await retryForTruthy(log, { - timeout: config.get('timeouts.waitFor'), - methodName: 'retry.waitFor', - description, - block, - onFailureBlock, - }); - } - })(); + public async waitFor( + description: string, + block: () => Promise, + onFailureBlock?: () => Promise + ) { + await retryForTruthy(this.log, { + timeout: this.config.get('timeouts.waitFor'), + methodName: 'retry.waitFor', + description, + block, + onFailureBlock, + }); + } } diff --git a/test/common/services/saved_object_info.ts b/test/common/services/saved_object_info.ts index 02ab38d4ecb1db..1558b364f53916 100644 --- a/test/common/services/saved_object_info.ts +++ b/test/common/services/saved_object_info.ts @@ -6,48 +6,44 @@ * Side Public License, v 1. */ -import { Client } from '@elastic/elasticsearch'; -import url from 'url'; -import { Either, fromNullable, chain, getOrElse } from 'fp-ts/Either'; -import { flow } from 'fp-ts/function'; -import { FtrProviderContext } from '../ftr_provider_context'; - -const pluck = (key: string) => (obj: any): Either => - fromNullable(new Error(`Missing ${key}`))(obj[key]); - -const types = (node: string) => async (index: string = '.kibana') => { - let res: unknown; - try { - const { body } = await new Client({ node }).search({ - index, - body: { - aggs: { - savedobjs: { - terms: { - field: 'type', +import { inspect } from 'util'; + +import { TermsAggregate } from '@elastic/elasticsearch/api/types'; + +import { FtrService } from '../ftr_provider_context'; + +export class SavedObjectInfoService extends FtrService { + private readonly es = this.ctx.getService('es'); + + public async getTypes(index = '.kibana') { + try { + const { body } = await this.es.search({ + index, + size: 0, + body: { + aggs: { + savedobjs: { + terms: { + field: 'type', + }, }, }, }, - }, - }); - - res = flow( - pluck('aggregations'), - chain(pluck('savedobjs')), - chain(pluck('buckets')), - getOrElse((err) => `${err.message}`) - )(body); - } catch (err) { - throw new Error(`Error while searching for saved object types: ${err}`); - } + }); - return res; -}; + const agg = body.aggregations?.savedobjs as + | TermsAggregate<{ key: string; doc_count: number }> + | undefined; -export const SavedObjectInfoProvider: any = ({ getService }: FtrProviderContext) => { - const config = getService('config'); + if (!agg?.buckets) { + throw new Error( + `expected es to return buckets of saved object types: ${inspect(body, { depth: 100 })}` + ); + } - return { - types: types(url.format(config.get('servers.elasticsearch'))), - }; -}; + return agg.buckets; + } catch (error) { + throw new Error(`Error while searching for saved object types: ${error}`); + } + } +} diff --git a/test/common/services/security/security.ts b/test/common/services/security/security.ts index 52fb6bdd70330e..b8fea0a0c59b26 100644 --- a/test/common/services/security/security.ts +++ b/test/common/services/security/security.ts @@ -10,23 +10,27 @@ import { Role } from './role'; import { User } from './user'; import { RoleMappings } from './role_mappings'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { createTestUserService, TestUserSupertestProvider } from './test_user'; +import { createTestUserService, TestUserSupertestProvider, TestUser } from './test_user'; -export async function SecurityServiceProvider(context: FtrProviderContext) { - const { getService } = context; - const log = getService('log'); - const kibanaServer = getService('kibanaServer'); +export class SecurityService { + constructor( + public readonly roleMappings: RoleMappings, + public readonly testUser: TestUser, + public readonly role: Role, + public readonly user: User, + public readonly testUserSupertest: ReturnType + ) {} +} + +export async function SecurityServiceProvider(ctx: FtrProviderContext) { + const log = ctx.getService('log'); + const kibanaServer = ctx.getService('kibanaServer'); const role = new Role(log, kibanaServer); const user = new User(log, kibanaServer); - const testUser = await createTestUserService(role, user, context); - const testUserSupertest = TestUserSupertestProvider(context); + const testUser = await createTestUserService(ctx, role, user); + const testUserSupertest = TestUserSupertestProvider(ctx); + const roleMappings = new RoleMappings(log, kibanaServer); - return new (class SecurityService { - roleMappings = new RoleMappings(log, kibanaServer); - testUser = testUser; - role = role; - user = user; - testUserSupertest = testUserSupertest; - })(); + return new SecurityService(roleMappings, testUser, role, user, testUserSupertest); } diff --git a/test/common/services/security/test_user.ts b/test/common/services/security/test_user.ts index d5e1f02e1bc8ca..8b0a1c34e790cb 100644 --- a/test/common/services/security/test_user.ts +++ b/test/common/services/security/test_user.ts @@ -11,41 +11,84 @@ import supertestAsPromised from 'supertest-as-promised'; import { Role } from './role'; import { User } from './user'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService, FtrProviderContext } from '../../ftr_provider_context'; import { Browser } from '../../../functional/services/common'; import { TestSubjects } from '../../../functional/services/common'; const TEST_USER_NAME = 'test_user'; const TEST_USER_PASSWORD = 'changeme'; -export async function createTestUserService( - role: Role, - user: User, - { getService, hasService }: FtrProviderContext -) { - const log = getService('log'); - const config = getService('config'); - // @ts-ignore browser service is not normally available in common. - const browser: Browser | void = hasService('browser') && getService('browser'); - const testSubjects: TestSubjects | undefined = +export class TestUser extends FtrService { + private readonly config = this.ctx.getService('config'); + private readonly log = this.ctx.getService('log'); + + private readonly browser: Browser | void = + // browser service is not normally available in common. + this.ctx.hasService('browser') ? (this.ctx.getService('browser' as any) as Browser) : undefined; + + private readonly testSubjects: TestSubjects | undefined = // testSubject service is not normally available in common. - hasService('testSubjects') ? (getService('testSubjects' as any) as TestSubjects) : undefined; - const kibanaServer = getService('kibanaServer'); + this.ctx.hasService('testSubjects') + ? (this.ctx.getService('testSubjects' as any) as TestSubjects) + : undefined; + + constructor( + ctx: FtrProviderContext, + private readonly enabled: boolean, + private readonly user: User + ) { + super(ctx); + } + + async restoreDefaults(shouldRefreshBrowser: boolean = true) { + if (this.enabled) { + await this.setRoles(this.config.get('security.defaultRoles'), shouldRefreshBrowser); + } + } + + async setRoles(roles: string[], shouldRefreshBrowser: boolean = true) { + if (this.enabled) { + this.log.debug(`set roles = ${roles}`); + await this.user.create(TEST_USER_NAME, { + password: TEST_USER_PASSWORD, + roles, + full_name: 'test user', + }); + + if (this.browser && this.testSubjects && shouldRefreshBrowser) { + if (await this.testSubjects.exists('kibanaChrome', { allowHidden: true })) { + await this.browser.refresh(); + // accept alert if it pops up + const alert = await this.browser.getAlert(); + await alert?.accept(); + await this.testSubjects.find('kibanaChrome', this.config.get('timeouts.find') * 10); + } + } + } + } +} + +export async function createTestUserService(ctx: FtrProviderContext, role: Role, user: User) { + const log = ctx.getService('log'); + const config = ctx.getService('config'); + const kibanaServer = ctx.getService('kibanaServer'); const enabledPlugins = config.get('security.disableTestUser') ? [] : await kibanaServer.plugins.getEnabledIds(); - const isEnabled = () => { - return enabledPlugins.includes('security') && !config.get('security.disableTestUser'); - }; - if (isEnabled()) { + + const enabled = enabledPlugins.includes('security') && !config.get('security.disableTestUser'); + + if (enabled) { log.debug('===============creating roles and users==============='); + + // create the defined roles (need to map array to create roles) for (const [name, definition] of Object.entries(config.get('security.roles'))) { - // create the defined roles (need to map array to create roles) await role.create(name, definition); } + + // delete the test_user if present (will it error if the user doesn't exist?) try { - // delete the test_user if present (will it error if the user doesn't exist?) await user.delete(TEST_USER_NAME); } catch (exception) { log.debug('no test user to delete'); @@ -60,34 +103,7 @@ export async function createTestUserService( }); } - return new (class TestUser { - async restoreDefaults(shouldRefreshBrowser: boolean = true) { - if (isEnabled()) { - await this.setRoles(config.get('security.defaultRoles'), shouldRefreshBrowser); - } - } - - async setRoles(roles: string[], shouldRefreshBrowser: boolean = true) { - if (isEnabled()) { - log.debug(`set roles = ${roles}`); - await user.create(TEST_USER_NAME, { - password: TEST_USER_PASSWORD, - roles, - full_name: 'test user', - }); - - if (browser && testSubjects && shouldRefreshBrowser) { - if (await testSubjects.exists('kibanaChrome', { allowHidden: true })) { - await browser.refresh(); - // accept alert if it pops up - const alert = await browser.getAlert(); - await alert?.accept(); - await testSubjects.find('kibanaChrome', config.get('timeouts.find') * 10); - } - } - } - } - })(); + return new TestUser(ctx, enabled, user); } export function TestUserSupertestProvider({ getService }: FtrProviderContext) { diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index eb224b3c9b8798..b87184bab3c0d7 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context.d'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const browser = getService('browser'); diff --git a/test/functional/apps/visualize/legacy/index.ts b/test/functional/apps/visualize/legacy/index.ts index 187e8f3f3a663c..914559e5cea925 100644 --- a/test/functional/apps/visualize/legacy/index.ts +++ b/test/functional/apps/visualize/legacy/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../../ftr_provider_context.d'; +import { FtrProviderContext } from '../../../ftr_provider_context'; import { UI_SETTINGS } from '../../../../../src/plugins/data/common'; export default function ({ getPageObjects, getService, loadTestFile }: FtrProviderContext) { diff --git a/test/functional/ftr_provider_context.d.ts b/test/functional/ftr_provider_context.ts similarity index 78% rename from test/functional/ftr_provider_context.d.ts rename to test/functional/ftr_provider_context.ts index 4c827393e1ef3b..a1a29f50b77611 100644 --- a/test/functional/ftr_provider_context.d.ts +++ b/test/functional/ftr_provider_context.ts @@ -6,9 +6,10 @@ * Side Public License, v 1. */ -import { GenericFtrProviderContext } from '@kbn/test'; +import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; import { pageObjects } from './page_objects'; import { services } from './services'; export type FtrProviderContext = GenericFtrProviderContext; +export class FtrService extends GenericFtrService {} diff --git a/test/functional/page_objects/time_picker.ts b/test/functional/page_objects/time_picker.ts index cfe250831e06cc..d3b6edaffdbd32 100644 --- a/test/functional/page_objects/time_picker.ts +++ b/test/functional/page_objects/time_picker.ts @@ -7,7 +7,7 @@ */ import moment from 'moment'; -import { FtrProviderContext } from '../ftr_provider_context.d'; +import { FtrProviderContext } from '../ftr_provider_context'; import { WebElementWrapper } from '../services/lib/web_element_wrapper'; export type CommonlyUsed = diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index 3ed5d74808fce5..997a1127005ee5 100644 --- a/test/functional/page_objects/visual_builder_page.ts +++ b/test/functional/page_objects/visual_builder_page.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context.d'; +import { FtrProviderContext } from '../ftr_provider_context'; import { WebElementWrapper } from '../services/lib/web_element_wrapper'; export function VisualBuilderPageProvider({ getService, getPageObjects }: FtrProviderContext) { diff --git a/x-pack/test/functional/apps/lens/index.ts b/x-pack/test/functional/apps/lens/index.ts index ab7cee13ffebda..d0466b8814fec1 100644 --- a/x-pack/test/functional/apps/lens/index.ts +++ b/x-pack/test/functional/apps/lens/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../../ftr_provider_context.d'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const browser = getService('browser'); diff --git a/x-pack/test/functional/ftr_provider_context.d.ts b/x-pack/test/functional/ftr_provider_context.ts similarity index 74% rename from x-pack/test/functional/ftr_provider_context.d.ts rename to x-pack/test/functional/ftr_provider_context.ts index 24f5087ef7fe2f..e757164fa1de92 100644 --- a/x-pack/test/functional/ftr_provider_context.d.ts +++ b/x-pack/test/functional/ftr_provider_context.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { GenericFtrProviderContext } from '@kbn/test'; +import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; import { pageObjects } from './page_objects'; import { services } from './services'; export type FtrProviderContext = GenericFtrProviderContext; +export class FtrService extends GenericFtrService {} From bca1c14f9c6531da416f28890c6121fae4cee96b Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Tue, 25 May 2021 13:28:05 -0400 Subject: [PATCH 10/61] [KibanaPageLayout] Solution Nav specific styles & props (#100089) * Fixing sticky nav * Adding some side bar styles * Added a built-in solution nav title with avatar icon * Adding tutorial docs * Added KibanaPageTemplateSolutionNavAvatar * Added KibanaPageTemplateSolutionNav * Increased limit to `core` / `kibanaReact` plugin because of additional CSS --- .../assets/kibana_template_solution_nav.png | Bin 0 -> 142856 bytes .../kibana_template_solution_nav_mobile.png | Bin 0 -> 163747 bytes dev_docs/tutorials/kibana_page_template.mdx | 37 ++- packages/kbn-optimizer/limits.yml | 2 +- src/core/public/rendering/_base.scss | 7 + .../__snapshots__/page_template.test.tsx.snap | 93 +++++++ .../public/page_template/page_template.scss | 15 ++ .../page_template/page_template.test.tsx | 59 +++++ .../public/page_template/page_template.tsx | 35 ++- .../__snapshots__/solution_nav.test.tsx.snap | 238 ++++++++++++++++++ .../solution_nav_avatar.test.tsx.snap | 10 + .../page_template/solution_nav/index.ts | 13 + .../solution_nav/solution_nav.scss | 22 ++ .../solution_nav/solution_nav.test.tsx | 71 ++++++ .../solution_nav/solution_nav.tsx | 103 ++++++++ .../solution_nav/solution_nav_avatar.scss | 4 + .../solution_nav/solution_nav_avatar.test.tsx | 20 ++ .../solution_nav/solution_nav_avatar.tsx | 31 +++ 18 files changed, 755 insertions(+), 5 deletions(-) create mode 100644 dev_docs/assets/kibana_template_solution_nav.png create mode 100644 dev_docs/assets/kibana_template_solution_nav_mobile.png create mode 100644 src/plugins/kibana_react/public/page_template/page_template.scss create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/__snapshots__/solution_nav.test.tsx.snap create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/__snapshots__/solution_nav_avatar.test.tsx.snap create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/index.ts create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.scss create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.test.tsx create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.tsx create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/solution_nav_avatar.scss create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/solution_nav_avatar.test.tsx create mode 100644 src/plugins/kibana_react/public/page_template/solution_nav/solution_nav_avatar.tsx diff --git a/dev_docs/assets/kibana_template_solution_nav.png b/dev_docs/assets/kibana_template_solution_nav.png new file mode 100644 index 0000000000000000000000000000000000000000..4ffec1990ed0a4e30cda9daa917d33fd982e599c GIT binary patch literal 142856 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ʋ z0@&KYOut4akg{q}WQ z2oQ@(7Lyg_kBPazN7|1hN(m00XiNHmV9$f5r=*{JM>9VdV`cdZQ~9UI=8_Xo0KsQA289CB(4cxPr zEu{WTH3)NB-HV^WpS8&&a@$@|?T+M8FHpGF*!l#aT-doWq*(EJ`uKRQ=vdxyXzqMX zo>?V325Sx$C}5`wcpgxOIK8C4IQ>c`e8t6q6OT!*B7;pwg~nAi#jhfwtnTv%v@oYd z=aa2GLWViLuQyt!mt}t&6d2u8Z`V_f%&&jbN0SFG(6n7N->DQ76rl}E-WS&m5-gN> zytWv*+l$V~U8l|yb*LyVzn;CVk+&%55=p@#96j%KDkbAo&2B$3mv>#a734F_y_xrP zu;EP+^)PwsQPXO?Ntfy*#ePEN_EoJ+H1lCf0XHazOspaB>D+fKbiW-N$R5 z$KcYXRW9&RVbG7qeWZ2X^)8E0=gj(PLCSGImeY@i>(J8yvP`^49P@!>Y6i8$bjh{} zPxvokr;FaD!&P;*fmYaQSqz}OSGwy9lR4i;!DlK7RMAJ=ShO&xNJT)+4V_+`U!-y_ z`D)dl27n;P(Q|6(D-cbdYQuKlEN5L#^X(_j%EXVGJPfKI_gfg=CkbvTlzsiPpH)(UMOK45!iL-oy8g=5GsP6OUv~l|-VIkx$x^43wli)*POOO2K zf=dtRAXhTi76#X%)+Wif5Uxz0tv;s*OavpBQ&8E>kK#Wf`bCHm=6jxqjg^)37?)Hu z+FwAU?u?i^(b2;`Y3ak2m2lxup*PJpd42ZDC7@i%tW|Pf-7PJ^w^c`9S_kU-mslbq{H&5xLqi66~F!dmFv%ej-pTe zrt!RBd+@B)1B;K*Am09k*lqo3Z|?2>Y)F0JNSe>cl^N1i0$W(43@^-1y>i@AO04tc zMY8+CHDS2KX(IDP-9`%nqIjp!X;5oyFWq1s^@-a}L~mPHe187?xwaRmHYUmt_@;M; zp0I&WVaNuqo7(dTf@r;SQ|ACTb^2Vkts$_g)*=SP&jzQ0A6v!I430iEQCEWmJtz$F z=iNKYB@(y*+kMBA0uev|th+nhY<{JR>z%OKbBXFo91B(-&)opS6f`$z* zby*yXf3^v4igR%hy!9M13kt%^#?jXWBY4K@`kD53c(5En-3xI9NyKK9qy4+jA-=} zGCkg-)8ZD6Rt*FtRu;fme-P^4><1z*!T0oT$#W-P*MXzzCoFf#1$S%X1}{8$f78cu zu@d$+=2t@Z)O-xIx?59u7Ux{9kPL;rst8m29SuBAN<3Ga%aUu`HyV$ek4(?k+Nyne zgo_Cff)Qks*>0z8@3z`rh9#Dc5N-@$Kdc@oB$G2`XU}0Y@#MmlSH+W*`$To@EtgK$ z)4R3XbXeF|YI1oK+cktW+R%%GJOj6HnRI}bd-O>T`$5F9!$P5VMshDhoc>X1b@uvB zVw!z?6@rT|VnH3*XO*TzrYP?{F&AK{N>$YmJHkbpp|0nOzZeq{qNSH|oLU_9#G?J= zEvpSBR>p!AFQI3aWBn6AOH^fvSiWXaO$WS^Y5y7Hd-l!ywo|d%eNV4gYJDhU;E2E)i+ST3 zwLM^iRZLsH2vt&S zy-fp!DRSMz?%G(4I&S4V$@1-2Ro7i_lHe~mPPM4NOkIx0T{wKkcDB@$wKCFkLuow` z4{ow?U0`yKK;@r7y;&UcFh;Dw^f7!Q@Jnp{h~ zn?5!K1$yEFe(U>K9Z#=K!{R9SIpj7!pDKXY#OHu(eyYYZj4zSgZ(2HEEqEC=--G2Q zEn^gUwbY7JAoitR7$cu|?0(c5nRxWx z&3zQVVW@-ti^Udu{RHifGx+7U8*n82&b*M@f+v>G=GiYUnCU!t@tK4x5sU!SDSico zh%*SMJ6@oNM@M5d>XZsRCUZ*lK0QwY5YXj1IR@W!_A@cM%3e_$o5)^1`Byx?*AH7R=_#qekWUM8u{X_iqC=N7vsY9BIQEkt|z~4JR{9BJwoIz zkB?*mIb1EribnGddBz2gbu1j#=SIx?*7fC(p8VDcQ8hz+ZF9~gKVk&hyriMe8RbmV zN)A2A@AJ`Re}w$eG(sludKSRBW?P2ncfq&KJQ?2yVkW5G$5`1c%wn7UcArA6SL^}) z1vP~&Zmxg01y;b+YzJzy-9_)KTNcA7*gma?{YOq0o4M4p*Y11_F1hQipTmkDvvz{* z1d=blsH0QGZY(CgW0y^QKiwp#$mIR&)ieZlxtHlxjnhY>Ul||0UJ+MG-mLMi-UgIC zob9o3+E%dDrce!GsT+hM=C%^jEK`-7(BE!?sSnQ7<+KSUMULogJ5#(Pn<_(u1Tx!s z4bZy|CvZ~=WWsI?f~(2G)E-ndq~8H71ZbFVX4Ihz^kz2v@nUdrZ@n)2#zLF*_mkSZ zFUV`Xh>emL#2>3hw-|r$nWLb5b+gn?1`c}J*E{nq`mC&5kca7Lte-x~-hj&pXHOPC z^icSg>7NAmZ#1y%P{wrRyi}eS6BMh|Z~uUai8^tCmNJ`68 z&Hl@n&SMd8 zEiGv}aqL9z(@nz6)7K<($m{c@-~x`Y5N!6>Z@=DR&U%`kHg#Kk2~l$p z+ceH{>_)d7`$pxLeT(*{GB~Q9{`?}%{y}{f(YqaX#W1mk+a<|SK1y`(W7mbIbtxq! zX>ZJqfGw?f(F6;$n)-Utcf(0kPR+rQ-{E?EmRPAl_hVzC zoQkhpIDr7F-XEI}<%6=$!^+V(6(}_E^Cq4%xsmbKBO_rW4w9BEew6 z4<07lV5d89KGW{o-efsds5|?(#z#*t6T?wO{B;)dpA!ZzMXSNiGz2nv!JhurKcwlX zghDKt%h#XiLeG8-FX*}|S6m#}GcM<62b0Z}lIXN z9bB>v{T;5e1v&_ zP=CLsDOl^D6>KW|1iBD+X^XS{+=(THjt2j;FzR7q;!o-ns3j^rV8qDq4Em>|O_e!VgXs zVt(c>1cDgU6IEl;Ck6v!O+WU0ti%h0Zz3luIU6X;XZpo^T)voXA_Ol^cK{4Gg9cBj z(W_aLi)on^xr;e^f2}W?>mk|w4{Ec?cB{2Q#W^aPFF!oW9N#S;g>?&ymx6MRQu4Nl>Z^VWBp;^zkalB}KAXetTx zuTK~m=P#QU>uuBS!j|7$x79|6sOjjWamK%@UTL4IE>5GWsla7*|h72^@GH30~5;WoC z2W)z2+5qT-X~rI$k0@xGnS;(qv|T z1}Xh3MYXKuKGOMK(RO-E0f%eq;z&5N@ugZjqrDGRDIiBTyHdQue~j$2MVsUkJbiP;*}K+RhBn~v)gFPzEVEt zm5jka$M(?>#$$Xt-J)1&6-rD0)E=vPWkuzBan+3pLzg4Ui5!$iAjoc!NAW!_F0RCT z@xddUe)UoF{$EcYNjEcoB_$y-rtf06WPOj;c>B4Wz^K2pTZt^&`)@0F1#ay@e70{p znls6LA}jac(Q&04o{7+H>~gV zAcgi0dAWm?Q%$Eerwa~4n~y3k2a;wubaH0N1QAY6M^S?PWWG0nJiZg2OIE&!FEOaX z&8F%AbAV?i6$mU21gb7=}x3a z&1dRYOAeA`wZfoG^XyBvE8~64DfBNP$4NgQ8p9YentxoW`x?r*w@b^XTzt@IuR8iH z1&~BSL#UoJ>e1)I1eBjMYW>ELR}r7A(3MLTYp8Kw6u?k#aobH~ZcnE)&*Ja*{yHKg zB_a~Avc4{xsmKveEt{ColA(dT#>A2>Ioh4qc4{T2-yAJWGS9fWx_`$nSut7fUApRY zI&*-qTh3{`bF*O{H?<#$%_P5G71$l(HV&d{&SJM>M@YA>=WvH02@lJy6G!k-t7bZi4nN`A%r}>J zaI$DU6w3-sqt#)?<#%c4;aZz1Q5^0pxetKejKg>c;h2F3=kVqaIb&g$idM8Pc9eo| z7VWyVxug>W$Wmo&XO|X`4omSY`}?naxvuklxn66c)gK@RN3#th`5etsG5ozVn#6CO zn^4CbS}>$2a@n&G@cV#e7>aSWeVo^V3!>rQS*);g34{t1Jhbha&O-pW|Dqs|YxkDS zhKL5-Dd@XXDTgo5;G@zkINy>2PT{#$R_=bSbLn4RCP4tGjQ3s(9_!$zL5)inrShx6 zCBr8@(JcdW`VGnyciu|6=T=|AOsK12J0A}M*H03&{{}qwRX7lSZc0E>8xx!u`DU-6 zT%znCARyMjtp~^SUbJotvUdzuFwq`zuJHWoD&mcHy~sqlHgi)GM=54@HomM@@(ph# zr^QEriBP0i2xijv;SlvnWrGDJsg-Nlc90PNE{Y8CdCsh7g}6m{Da#SW1iUh>e6&5w zn(a_4@b|Jss+nfIt)Y_o>W|w}oIm-vu74*8V^S8-C&v-X&DdV0PqF1KPV`4bOxGsy zv3G0@=`qbTYz^Y;{fV~EmB8VJSw2JQ?${%DKB|wZ)|=)ic+X?=i{RqVEk}6;$EB*^ zXiK$fd89y}0bC26{TWF?D(@k;ZO0%yo9n8D>y@=s*Me3ecQII&ESe*27x4v-) zsNu0pqW*~jyQ&a7YEFVsY9Y5g`pWcb1l2Qv#p)kH((J<{B_Bi*5MClZE}N5d^LyAu zG-^T8VM2=zwZ!4q*dlSJakTA*nG|iApo+Ikzkid6lL^F292j?07k| zX%5hG)`LxR`J%iWp>Q><6uxtD49TTuYXFpJRPxaRuFIe{2ZRjZ^|lhj$laN`nx@6A zaqI1J;;?#e%kotY?S|M){ucE{J8$pSOSR_(0w4Fk5?PU?1i<~mo+k|NCeY4b3s*_U z(ZGv7yn^vvHilr`?*rlk995>t$1QfY=t5I+FaQD@N`SzER+keAPt%DibN%y2m@EPj-Hd=fb-iNl8c0QmtpFW|D+9-KkKlkGIXTU;#}PtY^3oB0m7!n5C} zIzhw(Bc`4is+}OMlUI19?_|H}BPtac>Q|*+Ki-^IYc`9&`s_T@itV)9-X5`hxNi$A(yRV}z_R1>(c%wV@qe!~HXpLP{L`z1N%$pUdVzzoUEJj>IWX-Rmz_kx+u z5l1@Qy*FCbPLZt#Muc|PUKtbu8o86=H(Uo5TFLbpFdIh_aTKg;r;@SgyqDP=a&(@w^S60mvUx9R}whqwQ?9P?bCvT2|s9Y*ss~j;o+{* zf+$wnxa0HJds+Nmr~Of6yw?*E5fO2Qo&6Ax4;mUK^kTrg&(id`>=*!+<2lv&Z|G*h zHJ~DR6a+TK*eVEK*OmmqIYEw&)RX}dpNTK#E43Rc;NJ`%6oc-~zy zmVHFicGc}2E>*Lz|FM7}_9T<^b%o`j|q3lxyIFOWO!b>>F%8C>{l zGQIHfX?r9*z+8&~pe`MAfFQ5@2qjN)mdv7F&s26ArKixYw~1raZs@PI%zD(CMQ}6B z5(aLru$gO=zBu94GfG!*CUKgftG2(rH{Isduru4RsAFP3Q&x;IFjFdVR$rPXcx!Hn z&{HfG;m*Jza_yEvUL&Q=)^LuNs#Qx9;d#==unQ7So5M(R#1y5aWyavySN{hq$;R*c zCm6Nmsl(J5wPgT4C)G1E@O62lz`9)c=g%BHcN7IvWF|k&8GN8^&od&Lq4;A?u_yM{ zSZHLuZ2+diz`13GC4AC6d^xxZF8?F_ZO zRmw8NyMBMVN;oPXE>&7BvMhl;$oT65F$<@L%E8_*?s^}rJ|^P7cvC}$O>V&(EyT!w zx-(CEM0mB6qE}^<;9{{jq*6Ex6DEE=k~Uv4?{&4NnxMvVzEzsSYBjcLc57sm4zCt> zc0Lk#{>9^n@S|#Nk*rqJt18V^TWVz`WqRy@qJ&bl6rU!u+3@f?*2l|?{zO8H1Z<@6 zBdbML-yh6QTXeK(NBM@4QDn1eY0TwRHFoo!l^(<|`=HRcl@$}1vHRB8$dwN2Q`GSI z^*g4(7uH4OefD1@+# zB}k26`Z>*{iZ%Uv?H8pbJ$cg1$?Zg%!nj^9x~v|=CFm>4rxKSsD$yx^Ib(#jzig~FW>u{AO;hRkWF^u+~UM}DmM)fgA}k{y?TeV z2AXiZ-i|(`{Zv7%ri)5C{Bs^sX zAf}aS3kKc|n)=xR?6V{;jVGb-Ly2(=KZ}5GoSAHGEJl;f@(h4ouw)AaNY~T|PKeM( za6M++mTQ$26U_$G64GQQv3BpUV_tUzW@GEOZ|@;zM$PFi@bH3*&^@&%0M9dps`r+t zmbR@~TPH^gp38;clDq_1BF`>62?+?GfSbFzpDmgR3iHvZJIbio(J&vn=thkL-&%Z4 z>*I~5UG%-p)yH~fYr3pi*?84cvnT6Fa9T>=^S)lup91QxEt~izEIh~ zJc`2iN?IaQfbW;F#mVPrflM>{pX?S>-}mZ1EI3=Gygee>bnkG4SDVT{T`SsnaX%w) z>uoInjkDYpsHMz%9NGgM$%Y6eyGMH@}h z%-H@LbvDcCZ{@=J-tI39>5nq z3e?WxuQ-#U!V}9P!G>zAOD}%3W^e&?!B!IgVg^+e6>QlAh>xsj(w{PFVzY0H)mY3!vpk;S(5Mxk`7Zs%fZ12uUF1xv@ zHrzg^VX))k&EDAHYLGR%m=b{(5|IECxK#T6`}bVW)Ue7g?q5e5kYnwq3{VW-DKHSU zQX&()Z5^H~ku5cEy&k$;Wm^1ZnA>DIj%!;C0NW-dA2&SIiBU@|W+$BE(&MQkgL-CG1uD^y0 zUvd=I#Jf`#DK)ivkI16)w7}fFmtpqWFCsEW!=Gj)ge&qJc7UAMy|){p2=Yb{IL_;X zm9_nnR1byTJUYZ&4fIHHTKeAGXvS~4fYbL*<@FL3KvN}#SWL7sCwEGdk|-e~?&U~+c#bLc&TnSu|8^8^v-lzeAbZLP`yB%Oj1jqtWcI8+Dmp4AbYS z3R{VOsFGc{dVBThAvd+$Caz0ptxGXu8*#$1_+nB6XVJ-n>*3&7d;IM+46bAYVckPp z_Z-7`gAEcDE6aY^A;8VRn!+l3#||>K*JcBIo)>d0cFlgh_aLucF6A(L(gpk{Qiia2 zv4Zfrq5tDuqoDM^(XUdH$n=RSo|^%9sN}BtwCTr(SgOsCl5GW_)rZddrDTzIY%?Ob z#3(>u&bdHoI}(74KT#+udMkBDx6C<1j`>q%*DqgRM4oo|-Ab!oKcquKfj?UP-H)`qk}@9mc&+_+`x>l~ZWcqd0d4u*`NDj7g zzb^oRq#|^yQ9KYoZhrDKr|#h{pyW7u$|s-Iefp$l|G0h-I%0O%pl#}qBmrm0J#7{m z>w=e0v)-|FqeyjID73F<`0AuOAI@BEj53m#9B!H7%k)(_9=22F%FQOh)aTR?p2Zl9 zD>=&x?920B;_dMM18u z+KzpP>U@@P>Pp&i&R9^0DWdUc0dvyB?00+Xea0UI@?qN_JXVCMt64=5Ryq68kanevgoL&FRDH;Z8r{sEg;eR|r*r7}IK|YA z=JeKBqcy9+W<~bzT!ocw)uUQwf^fH>WbX3}(>y#rN97O||BVac;oe7s`QYn)cxQvvQ=^?7i9La%ed325Y%Stjj&GM}7F^dt5V_ zMqL5E87?K>nN~{5D_nWqS4(0Hwm{~Btp*U{54N>_ksn?uNq$ipxjmztsSA-3$(PKf zF>7RY*KOKPcN*A*H%+I+W@H$j=2lp|5My|6AsY|)kdJhyJ20cq>LoC06~wnUua-Jt zu`P(^`BM4M%wXqC0dV3#3K#4#<10xV20@nCgx%>!*ao$B^D^|t{6hfw2J7Op{^Y1b z_q_W8V!WOjkFiB%CcFC;kgid<{g}j2&5}3$hyg5zU0mj}7^-jb&p5->Jm;0$uPV8| z(m*s?wTTP5`UcHiVlE0OV+z}+Uh6j_>C*281s&MTO8x$w4NBPGkixN7IV!-Ri`eGU zP%>K1`}$h)xm^ZT8q${;kX32{8gZ=x3fhdc&#`Ww6@cKZ<8tNO>yoXwdKCbM7;D%t>wIyTB1Nw9T;(+ERI~3Y=4F zcO1y3qoKbtR9k!0}#zg~_OK?YY4Z*{wtV&18)z};A^JDTys_|fr4 z^DLp4)RER<@)>(5Ou6_Wx2?rXMw443m><7v9R2{nObwgJuiHID-lTLEtRea%U`Ne)0tM1Mx!dP=8_z;wtX3?fe8PZ{pq} zLzdmNL5N4NWb4G<^tbS1`vs+t+J2UDgL->dd?>|v3vlWJ^w)oi&iPU}ybPMkE7C z>|qObcK`c4xe0#nJgL)l@-F~HTXVsmTFxU=r4pgD19?*MU|or_XaxNEwjcS$sKfQ5rY_3lN`SQ(7?Pr@Mz zXy#Aqr;x@SvQESaBv$@!U-;5A`gpd^n!(c264+`eDA_q#Z;xw2s{bSeqKt(6m3i6! zqwLKzkk(1GH(&b5@K4q$Wp)-LkR%C*kzP#S(TT$(s_s4zl%iTXA!THg!)`aHae)*R z23mi47aB-UCw2Tg;v9O_3ih2 zN7DgrEWkZ(;=gBPRB-IDN9*pjyArVc?5{um`d92>0O-Hh|FCv_Ov(SG(^9!p3n8yInyPLxSuvz{o|HpLY|BpNSf0-=(|LfMnHH61z zGLsmb-Awzduf0rU73xjM=wghLWUb;xmtu|^KU$`x(zFqCBnS^`OK-0{3m1F%@FAf6 zUjdBf*erceaB%Q_(7T`A-7+E~tyHwMvRYatT|GU2VI6l%h!;-Eq|QkD;Qcx~%Hd7O z_~CVwEk2Hd<+KFT&J>5yeM(}K=^FD&6H`+xzg%Tc&s28XnING%;rgq*?Ed{zmikq0 zT?9xfKBdaGrnS*Zx?KIHh`#)plYD~!YmPiGhWR5L(s(jnH%yeGL`H3?&JgUsvO(@X zf$pw`7c{~0!KA;t?r@?x0Y8d8`S7a$X954<6ix;;=`O%Pa@$*Yg<>#bpz-0u7j{dy z#@}rN3Qy|SGqH!|sQ48?F2ua#{G>x}f)Kht3cA=L$ua-GyEhCKRXFGSX{*jC4vo?V zWJ@440??o{KTwKdAd(wie=%L}zKVxH4-oT5a+PtGtG^6Jlp>rPr-0$32$_DY{HIkR zDiAvUQf+lNlDA$uZv>1JS^~PjzAY=Wx#!mpd`(sOpI85UuaT#Pm0Bsd6Jl<@j*fyF zf&5o|f_MW!Pwb{|`0S|M4^dG9etO;6BY%|+GT|8X25MTT+0>v;$ol%|+C8ED zkFfvo7;pey0bQw%5<`ghIZPotIz;aI860H(qi*~h2pJ6RhJP(70U2|dbW3GZtFcl9 zeV6|lq9{V#IWPZRPrz!3N5A|8Dgt}7xXBtWP~JXN2&H0|N;*4s0a6hIQW=<-67Rxz ziG$jvM~USC83MFBTbEF8%a-SVsUsO+JIl5@)PmqzE{rCnQP*=U9vgE*a_Z(27!h;X zy^)p!z)B@3Z-G!*jmNpe61)^<+9oYLi=VOGP%~ZRlJtHKL1xT^AmZMr*aixuA`HH|s8B_Uk z*@$?Jome!o9vQ2z>n)s*)P{KH^W8-IdKK)Q9hJjtB;9|Eyh``^H=Eec;mN6R3{Q_j^H#+yJ*R`;Y z9~>M2skJoM3fu}ePJ3jTCjg!&@hKu=uo1e-%GDxt?Fw zxXkz`Y46#)*RM4lo9m>NK$4?P!zaXVPo5ac-`8p%>q=Yj-6cB zp#-$3i_=}k^(X;ZC1vH-3Ex{Fx3M!?fMXfC;N0>?t5yu)|0S+-j5a#HYPy+OlmeiS zf%A{1@a<}ABsuKb%Vm#-YyRVBc8eHkf#-&bvQLJWJ?EI8SyzuxABJRT_Rhy8mn1D+MVKtPVL-%Z2( zPRfv=!>|gP@ajyhy+YrAQMR?J?k4_CF&`QWYG=+DFbIzk0LoVpU?T z$dqbs1fTbi-zMpcKf+GuJ2`fydGU)xZLiMmd`<| zzD?=tJD*`XDeKw? zMkiZ!hf|BUs|5EyG{dsMHwk>_dxh7TyqDW+qcBKpw7|{4w#Mf~`*>Mmv;v zbw;c79%F4fqND&@dpYG6vOx$RvE6pOy(~62{Q<-JsXYzZnQc+LLHO`_p?A$t%ts5Y zbKqSb{G%LDBwx`7fGpk~9KdVcai?osf>VYTs#Q}@wKR@3=M?{=SU#zKFt4B=%5b2S!OdIKLLujR(oHVTYcs}tx zRXmc*4?eW`D)!*jgt)h^dZ{L=wsaS~QTi2;_y5D*TSryZb#KE*L?uK@K#-P@22r{d z>F!pL2I-dWP(nJT8>A(V(jncQhwkq4E}rLB?%(&0@r`ec@6Y$$|L9=sv-etSuQk`4 zb6wXp7X(fgyQ9`v8=_HLlQ&daK8%dc#-%EA;ji-ft4lSFhCdToN;=7M%(CMKhuzGD zTIG#?$xNAdp3KtX;7%9uwVtgc>E+4)POAO688fhA1^8gF&9a`H{>82F+EE`VdaWAU z2nA_k`ZeR+QrmHqoAZP-{rLrti)>GFv@q4yFPtjQweEaCbfvp`aK)}W-fn+(<(e7_ zh530*_N^TM(7R{{2jQaE^Pg-UDz`6>ufPrc@N_ud-r$rH*eqD0L?Z7?0nCd9t*ffG z%c6O21My&qccR_$+CYJm0=BZ#Vz)#0r8|5DY7KXF=w#U*t!JXMWL>`O-@d4d!Py?o z;~P~Lg?ZDEBvgvij-}kXa&tzH!QLh4?JwaP&+3x(O>*(07O!AflgkMzEgtq_B>(li z!~Wds&;;Z9?}bX(1)azf>w3F$o&!+$-i;zn@rC``REMehUCQZNha;DVhLRzPoF*9o zua^?b-hxA+)q7`v_;xniRUB_zX#M`4U^&`n95Y#W%boP$?KdRpGAYT{a2*nsL9i2P ze8hM|C&+Vh*_ABNnwy+|ro5PmAN*~g14A#bstDxB!QGTA9;t>-Qd-Q_{4X^y8mVAHaEOJ}i zTvITU)QiCcHuK!QMF!0u&DgemE9<@PHA)MMi{iw^vwO>Dj$5A{5VjNes7GAew9ZUH zE+@xOtvGoa26%JEc}7NKuTxBCN23SW*rD+0&)cI$A#oo8nR&{tSBJODqHdl5Ogso{ zQK4E;P|#BS3IEH%r)(eh5d{y&41S+ZgqVI4)!9*&AmA;c`usGZlXbn8#Nfe0ubihv z@WK@yVh2qfe6B;qvjd`&IAgR(Rj;e+zgrUI%UeZ6!KjRKqiuYC>(ww)4y{_-hzq!N z_NT+W?EQn@;JRpIRE+xi^9hZtq|PXn%LyNmJl)s}FDIw-<24xmY(;)Sw?A*Y<+YQc zix4R;w&ag1<&N%doNU(JYoq)K6{>nFo8=z%!R*8rszujZQLrMChxOlz-y@id-R#HO zf?*_vy?Y@WdWBkLjB{-9Y{ujq=Y&hB)Gx}1w4m@izH*^^C}>`h0DPC`PT@HLypDaYY+TF3Ih8@mkDQ#J$y zF$yL1d<7KWzEwLS7~b*Gs~_2!I(yQ4`pa7_d9OR6OIyM)k#7ncq2%EcORwCbG|zCm z%By3$g>QGX2hZcp)*9CKHu#KDGkkphrFA9C=S7+mQNWav4)XR-N3Q@Bfy6KJd=TQ;h z(l82K#0E%2h1N-ba}y^gwzeqMQlok;4x zn(`J(>^AJ3+&e|GeEkP1pT}rBzyFEy2-d&;u=nyrSgpibsqbXG+NR2|PATV zXMdY+S&no;+MYPhdT&0JluqM#l5v-9eL_vvX5x!psPq*go2$A9iX|odzD+vO3O!lrQnAOBs-sTLN7r6dVsaT5a3Xq(zptuN!DR1+Ft<} zK*IlcD}%~5!CQvVNQgy8Duq(7EhM^FB0qGsRA8846W|NiaXS0hm|V{fBLE;jHVCg6 zx>saYqEwZeyUwQ#fZ)7$NYNC)3r8%H&^Fl5yG4Fn&j&nSsKJ25S@VpNN2rA^i9rl<2E-7N>bAE8LzjLS8w&p^}-MO~XtF!+2 ze6qCRQ1=>b6s`DroVm z_YKf$d$h&7n80ok4lrQ58X`LhF$vTqRwW?XnPX$Yh996i0dFm<@bmd7G$q`h_=k+V zJVF&F@<<<9b}VT?B~3r>%NvVv;E(=vfv+K`w>Patf_HIL>*6UVYzezQ+Voze?0rFC z0Fu6}%^`bzI&M+1uD@tFMtK521W04bRE&&0KIY}!LF>c$BK68Wt45~j>BYZh>RoPB z*8Y2WoXgN-yws3rFBfNH6J(Xa;fh%_tJD^2$A;icwQt$Tu!cJmg@qYFzg;b z)1jop#z>2)6UZ0hn>^Q@ZMf3zI^LdEIaZZQ0Nh7S#+Xkh)1g?R+!|qq6WKba_i$c% z>;m`ft2@tLWZluo#hoe^;L{m6p6NsP74P(4xm^3kbnA`2IoZ~dvco=FH??qDPI2y> z6W^(|QBj*rpyC^5wcno7r*-s^wQu)$xO~6NO%Jry5(D{JH&> z7}m>ZChbzmWVhveHmFB?=cUl-8=OS8P>3+ySD=#PHy(qhok)=?-~T^c+M5ut!0~`r zOjL$-(Fp*ZmZ#1l+~>ZHauM}BA;Zs3qDSia=6MA>VxM7IoOOk#gLp~n?H58S2KAR; z(;CUg%bkMj;J-wcbt?xtp8{n8?a4moK%61RYhRV6A%zDLZxh(Eq5|rZ+Vh4@KXeX- z!hm}s4v1EtPMXZHnUUUT6g;%z51svV;T?Cq@)a8vGU%TmP6jr&2qq}4X_u|v1!r-9 za?X#l*N>{X@?5jGFSsmUhghrO#C}N53~FtExEhqSnUK6R0nD zmlJk6t5=dK88lwT05C|0X=bnRbET8LmpnGz7Hu8D@C3803bZdXn-i7YNUBnA=(1Ed z8s^=87ZlL14d-W5P*Jp(!su@H+QR~uy%xPpHe=L81!;WxS$BR7`|4SC;)@IDhscXp zgAH05z zY-d?7yjRjR6Rj{7GvNN+qI!e6*-Ov6(z}|w+Q8aZCpmYD8EBc)+4PL3ODdti(qE@u zHsH+C^Y_>i9#UE?W*&a}@<%ET&W!UUbiWOmnsCGI(oG(}aK>s7O{EJP7$-^S!S;iJ zY6TI6@${PeDKGozkY0RRH5QyMc86nsSoa^4d@ekh>xHvls^RrOV5w3U!z;rj`JK z;S1MudhE3CMis%c*UKp5HFg?5FV@*^5*PccdNT2AGFh(gKQ_EH8sG`om6X!DN}%gD z6}!t)17&J>Ni)Z%q`i&`OXDjygScgu)08`_5PmK5ZeR0vurPzJ!~dXGUgb zXLgF~+Hmw@0jo^Rjdl+S+_oxig!ZZZ#9M<#snJgE9qGM1NZLyt=B09l4~MI)_1i0! z6K(ai5=6i+;&eDv+ux&3iCYWo=rY+jjy++PKH-5(KG_uPR<6`S==w1cEJ3~iiZSgRTXJ1HKO($pe~H*u=6Dx zV3Cllu=ieHo(V0D0C$wv|6qA-do=7wNjeq)S@?>=FAU5iM zjPf)8E~&<`Z@-!{`MTqH6&lAWS^2_6kBGzk@C)&zKW#1s7A_+SFFB`5lw=XcN}zVY~?T! zbMy#$`cSVM@UFaZa&!Z<(*1tUo-@@uHk_95n3t1N4MM6~ z2Z-hWT%=Q&h=G>g@l_yk`{*J$I+_-OK|cc+i2q#wO)-yj&{&Iiv0)k8rr6DHXaMMb zMz+XD7b1wA$SmC<@6EZ}e=j7%n^d?jQEd=7KoCv6$h#n9jAt_^hsfg3(EYgyf`JV3 z;CBiOtUwAMi^f)`DU~2V7&<>&s*ifdV}I2JaaiDg-W!N%KGBhxR3q_Y&~?ZajU5>M zFoW)R6v*ko$$i(*zc)k31q(<`Lbm$U1{N1!ElLs@AR}#=w)L(YOO(S;fc}Oy85{d# zyhJY>;xQmj>hrJnh=DfYqp2Sn4ZWF}{jT0HTO!r?i-uvc9rVUei92?G_1-M-o&Wdq zivJw!{kI7L9FJn?ev6BceyCi5btY=Xm72kc$0NQnsEMGM)XN7bU-#uvm@5ossHA7T z$Z^UKK=MG8mz5>GQ51}cp*}miC$Fmd9FnGBW>!E!(JWzYT?(uq7Ub`O5oiVn^SK{B zl-pzeD^3BYo|eiO&HwMh!HEC=RC@o9`gsYIewy@lR)O)=WXXI@>-FzHy$KxiaSR83 z5)C~quK#0+l6=)>%I(yE!TAXClYpix{*w%jslg&$R)eghM_Rq=+r%~5T1BNtuk_^$ z4zxzDT%%p4Q(*MP^{~CY61T2611_wruV1n5VfI|{th z?j-469->hVFhk5HqfM9FS~;fi+7}72uooL-l{C!^YJ!4!@$z&tDIUvLip3btm3HsV z+_RuJbaJJak+d9Hy$1g^XONK;#UNxjbja^g@axjQCp5LN@Gl+cZy^?^&-y+QRb>?l z1mGZ+G`BXl29%A_6g^QfhGZ;}E2+WIW2ytxtoQP4C+hnnEQ%!7tVKAxi1fR*UPqVJ zMMqOpaB%X|7azdH0{0LQymS=1)rOv1RnlHfPqPEr#tTPD$q?$tX}WsT ztU*LY5!OfB_ZU^yT4=S}lp7m-Bs3Xw-(=E3$f7WMTNHh?t+D1G4TW?mZC+=ZrZApe z8PWRu!28d^`hP!=0I8=C`SG0pPB|}Pn(nm36kZ0Qd927P!n%-y!WgB^<70z@pS=qlq(x^&9M+Fvt^ zyPvp--<~guWOmYeBj%y#l2oZ6?fsrDx2uw15*?Qq*{F)Gr*l`u`<_8qgkmW73^6q# z_9y$Q92F&}poit+1@~}#c90Y*8*9_mxzz39KWW&0p4Zqoo#*OlXH@>p$tRsMG}BC( zk>Mbf48y;vzBD~!UqtNQ{p>Tgvcc5Z0w%WE?@al>Wh?8Ap zOA7l(#5`|$PLf4|xh=3nn|nI{+(E5lM^2?F;Fb;8Luh4RB4i=z4P=-CLol?!8NPNkc+0DJLm3CCS2o$ z9jx9RZ8T*rLLru0@o`nJTqG>X=gn9e_Hr{YCFEw~`<1~z4NA=xDd82JQ?;WGfumPP zP(~Ngj1P9vWm6VTLPCkNz6uxTFt8L;HIl`LAANgUKuemn;NQ!nsbc&pY(X~$**CJ` zt~}=LN5`RMTE)zv4bUpk4yDbXn`ee?v>bQ4TdCsk1xZXcL~3o)RtIQu*^XtoMssg% zlqABoVfs=0;_;8H+=QS!lr(aXp*t~j?RK3rJAXd{q_#893sF70PMoYHE6u+iE8xtp z)Xr%}TaYxXJj6p(jK*^yo|JL+h)|n*jy(k?vbEpr!?6c@Zn65#>D!s&Hl$HTj5*(| zuFfv8rG?V`{Y#6rYjhmJzb}xD3ql}=Rr*;)G189&D{k8b@kZTz*gQmX?XJSLQgKAj z7}joEd7;F}x}Ij`4lm;*X=#eFJ8vq3@?BPYKYgm-=S)+Oks%jDesALM130*pU|r3iqcr(ObG)`(o%xqP!&2+_Me4?cJKeCi zA+maRXgwU6DwXciXjT09(ayGYJA=N_dR4bR)^OIEvI*~m<=#k07Ct1;#1Yu+l4$7K zw4Dty+j!8x-<59lpQ&?x#3{v%3$ZI4hzDq?-VY@^w~4ZE@=8};Rs~mS&}`liM->FC zDCuB{x)=#D7zW*A-Pt>)?5f1PUD(*VEivg47o#7XZmb$)zDw@cL$v(muf$&(p}Eub7@k-HYx_Zy4Ys^ZYbjZUkDz4)mxxYRYQQJ&WnnL#XkB>Y5(p);L|bf#O}ciDoxLc#<4ut zSjz3$?D!n|V`u6^GY{rl*EFv%%~YyHABWHEb&Rr+rDzA-+`&GI0o{=wxlZ#niNE$~ z5264DK2{Qo_TU$5KN=+@dx(Im6>M2zzEskN`*PnbkYq#&%gs*c^Ib9+k9vo@x$C=6 zZEF~ReMgTxl;hym${3FxQ0oM0CN3E|JO+S_J-12-)O#<>)FUM4DHswP6D6%|+MuCa5r_v;%H3PbSeNA*GumP+ zF7E~T*7k5J(tT!8K>C^3jvfdEHdZX-+e@$b%ET_#G0>ZU23uc_F%iM?Uv$ z#hXaB;ZX&erCx*Y862X_o0Uo%^2@yfuC9xwtF4zVD(=K^CuE54YZ(TX8Rv~Ff4hiL z`i|5K6GPr}qwX)``RNr@siV=Q5P|Ft@z9cNql);{B}>zgk+L*%QIe|(%ePd^LiXX1 zU&yaHv({+*VFsr}`s)>W#3MaEM`~8aY-StU_3v_M06SoP47d3P&UI<-()9wA2ew_- z(*Lr>;-W{K7|IqyP0@Tx;*R6r!>lTOdKW^AH%KlePr{>O{n157)9IdD7itzmc(cU0 zm{M%tJ7c2({*8Iw*Q2Z(xOlfmVc)#a91-a%3mSdQSNG$J8u!!gX(053@>c|BV~I*t zlKkFpKIO>GLm^=b@z3oDM1UYAmpRomr%bBs&uY(A6&S5O3YW;+53ZzNo!`A|>v@0C zVs0W8N2)7!QIyAX3!cG9RCQ@V&%TIPEXg+*^i4R4M@uk1Dg0r3VU_M2XU{r3-cYGW zQ*A_5DNX{D(Fi5kJP&7+0=+V!s#KxtKxc+JI#eq9<_Aq{YYMqM`8#KZ7{S~f*gt-i z7+v>Fe^9=Xr&3F=_~Mo=)o-SaW_*kj)DZtqOa|tn27RdVtG|5?8b;aYR7>h6u z>L%c(tgV~vJddNgyaU1fMnLu@q7P{e{m)MzL!VV$j9!a$(ketsskl@R?Ow|@@K6Ts zK7hQz!d}Ud7YmKB%SE`IJT(jSxnpwj)vpUun_Ox-yE6SwLKk4_XH7MCAmlPpx}=B# zf1fSerrSlUIOfNgvX;jfLomaS5|d3ujRGMZxRRQkukS$meJ^i)p~j>_@_73=lW(pPV2>7upTz|075A2RkS20_v-e|5R)kI+}LX>vZR|AKm5;&MY6x?kru^& z{M$ZA4xa+%8z!kZE<8q;mf+Gg6Q-LkNk(7z@oB;|VKy9u2oM2M#k+rhA)pm79E3;t z9%-^~p85R)=-DsEVl&mjtK!r;SEfzJ09r}<9~gWvawQ>CzYvP zhBbLNBMf4Kq5*g<1tq7PiMNHQ&pRZ@n+Vdop0I9e(%VnNwO|{iUHJlT7wJPL#Ku52 zqb-^(ajmjR8@-f)IC$Msbx+cKAlPdJ4T3S_nE!WJ1v0)XA!4S86{%TgjjzTi?w{251xEVph2t)Cxdn!74JjhK?fh5TR;krJ{42GSi5QRSYUU$^4y$%mu9(5RDtZ?eL~7m%?Oy~sX0?@*aI-x19)Ip&ZGx_ z$IheXLq3u`mUbV8(C4hJN$iw0Su_52WAiI4vsdUlN1DmOP6iqTo0b;rt!o(BgKKfe zXvV8GRP+niGFDb4j}wez44*EHLrX6daSur`{x%47B#(TAc%l!}g%ZuQX5v4CyRaXb zfmrq%<(*=d84-LJz`F*g5(WL33p@h017~{EJb}u)t_>ZdeP9Kr%kvwoC86*t>g^`1 z4w|a_l#8%Z{OPc&_W1X#$ts4?P7-@S>x?Y_M01lp3H%%g&VOw^QPCne^zx@2ZNdMJHqKNRY;LQ_0SjutU#witGjNVAj{q#XG zd0{@Ad@A`sm7kL4bk{$VmJCBn#bOT(&(l_L>V9A8unq@|_xzU#WtN(Z*njzbprVp& z0dINgGkqMc&aC`;O$4T5aTvNzl&`>M;X85$MBS2OAb`<{;;lGB>-Rr?D8deG{bU~^ zI>K*sdnb?gQjH|h>plVt3%caAp!A6Ah>gRNXn0&D0i`v$CzrMV$DvGZp>rcC`8Qyj|cD3ApwYtw^MCBeo)CdwexcH z1CI$`5+U|RwXeAFut33_zw5->Ow8$N4RY!b74LoCXaT{PeMM!?TO1gu9YAfUb`O0o z_fW24ZDrhL+ysn&Uhm0CMS+?*p5g9Rt~rk*$ENkf+gM>sonL04B|6*lDWoL&y+`HR<2J z=b+#C*j^xH_kUf1hUPhzCFvWY3p5SF$H2m4bCz^A6BbtAYhFWkT;;UnIDCU~`uDdG zfN(X;MYA2S^~9SP zDOY}y!Emm>(cU`y5Qs>qs?6%^Y|Z0N5^@@`dD*k36bpej-k7wEY*cx#(VfklLwto> zmSdBovkmb*Z;d@@1AQ)%E?TzoV}m#`J*n{lsh(}l9^FVG$2M+t=_pXq%%v6?qe3i<8SR&S=8I|+lo4Sl;&)d<@BRut1pr-GIZdA1F3q3tmPkrW9V}S>_65Y zp(kIgS2`c@jf50y)!xRUAWPq(TZlpmoGmQmPa2J?gC$^<&=O4jSX-W?;O1_7m=bsD zW4kp`-BTq;%sbKu#L%o_DtvMageA?nzq><$5anoy#_OZ&3lh;;K3A`a*6rz9{mvou z`ehhU($fHkBar!3pm`Xz(*XZvI)gTnL9SW|edZX$v3z+7V zk2mjp0Rk0{UWBM_+D0G6S1wAI)i&-;yv?EYUM*2?Gp}eVL3G((?{wL5B?Y+JM<&yu z{MT-6jFo<@WmuxLS()40?DEu7y1@>_%@PM&Jan&KGu_2?j=9gxDWh z+3k8b(=WG8yURvUe|*O96+Bcuirt`_lEYE&)@%K(CRli}tYLBM$b!Y)&==W{l-fzF zuG*wKX{(7e(Rk`7uw8r7YtZmWqr!x25F7($6;~V7-Dqn-FLYeGl>lXi)&hFf5I6EJ zpr@=dHOuu}xP79zxs@YxPBa{U)Mnl`67e-*Woq&M@@S>QtZT2UbZ?$z5)j|&jDMAy z8;by$r@3r$`P;F8Pw(*%k-tbNpaB8Wk`gOjOoTFHp}MozQ(QD#)zmLRH>lU& z3>eePz5Gm(zlpfJ^^7ya;`{V^n4Z%kJFJG3!hMp8q1SI;u(D3CR4P?(eA@l>IJZbR z7`NjRXvqRu)DN(rs8aiBuC=M$uZP=%8Z~xXv~5K01&3RM)N`)<7n?RGS9mVnwF^OA zpl%e~3%yoJr;S2~sYxvcKuG_p&FdmwwLQJ0f~P~_IyG4oP`L?Eg`=gqXX0vQ_Ju$J zTl0oW22{N105~vgd%C70kor+XNXWz7-(L6lyF^Ib={H8r!-%*Y+F9BN^(w8_C}Tu} zal7@0^ORobclv9eZ~_53aI!9g{G7-l=1a`m&f&${!%+8fZIRE$?dpi(x{v&zSnP@on%6+ z6C)LWnRmJ0#k5?#4hVm?J2P5-=pqQ?8 zN^0s+#mgTj$&-|k*T+BgvdBSEzM#vKHEL5$%s2Y_D?x+hfmZS2BqLIsv`BtKZol4vxYE6=wh#X#M6&I_~uG4FF$dn&I$~^&Egs4J8P$t{Pr?(cWeH&OmmBqf5A%#%ZF9VVyC+g9)@M7T!$t)jTnvBI#~SNy4or}>H1-%(hd}p zZFeTSBdYa8ejb6sSY+_4oj1@nwBc(g{MX|Xn-l6{r>dEA7i`4p(*=pH>15?{r^`JN zO3KWo`sE7}w=lY*CrrPLhD$SlCtuZ*ULsyxbY9oy*3BxY$92H2T|cNODymm>@Isdy zl*7-olvP!+7EH&};{L8jNa{@$h#M}JwKyWk+JEwA>FFc%y3Yy(mIOZoV8F+ZscDla zc1Um5N*-`gQ@%!~v#2{$uEvu!>`7Ew^L5n$jGVCdO)}`Th-uenz0|O14L1wMpUTT+ zz5K<@h`Q!G2^I}U3B^i`evh8wD{5;C{OMzWQ)9M&${D9Dzyf)gU2q z>rzK?$E#6olA-F6PU09HK50;4M1HM?V5xd9E1?S<^=qS68w6H zEw}4x_Q(5lP*`dhrzo8)J3Hm9__l`vKY~3-0~{QGVpCa0-51mqazG;JbG$5h@cUH5 z0?L%CYc5emln0R1dh9Dr)Xx>Nt_Mgb;?wooz9g@K$~*17{BSJGX$MzY>qr%{rtKt$ z*?eY4jCSflz9^=K%e;Z3mv1ma9*{VX?IiMF*$y`$xL-|ryUhozB)bbnGiu=uU3nun ztyaDak;5S{IO}z%Qm&avYYEoBzPuMzl#Rpg<<#@icHV{0#0H)%dBvP#*}>Y&qwzlA zU#?1{;25G{XFjf+wtld#N_chXApXQ_Q3=7bgv+NJZF=kH*x~d3B#|iw zaMG?AhH$asOBv^rZCF)LHt69yz><1%eb~m|p8r)RT!h4RO!7j#%%Bi3Cnj0zKTdN& zQHUqR-&BT6+H5z%&mY|ej2fh5g<=#$9;r>g9gCgSJ zx9fM9+zt*eKXDwns#V!XjaSv~)C^iAWmEAH*`Cf|`SZzeDTR!5gECv`pwd6Ij*V3$>;j`MV zg`>^@%^lsjx(MBC%^xTFQppf+ zVQ&Ja`ctoRBe~KYulrOa-AsakexH&J{i<#=%%@nGL#2eZ^COzE=A~_l* ze#g-%I<+PGg|M3_jK)8vt;pKDLI0>fuW;(>Q zi7E@~XCfiH8tklPn`heqD>myk4iu~BpZT42ca>C7#c^9S%;vN7sG?*1D}FvKK$J9`s%ga!2{xPrjUgS|&Xkoqo0Lvh_+OE+Ml{oI)wJZQG7f z+`zdoJ$R!`;D&?0I(!ZT)+&lcuZMLp7?W}erTW2yJh7B&XB5nw@txy5Sg@1_D@F5}?f-r_nTK4ssLynbl@QY^H*SEH9y zDX0duCQl&WI9i=`&W=xyyIG2^O(UD%SF)h;(dhtrp4Y5y#RM^>85Yg~GwlNqM?> zo2UW2zvaUBou|u0FWY4a6+JS(4DT`GOwwjJ+LMJyO8|k|%k_oex@D=W-PfG9t6_B~ zGY_C(hzZg%wiQfDjIiA3Nu5|Crs_ShpmtAH<&ugX6 z_3uLJE;}iD51$r8X^1AOP85;lvXkud%1wr8bG8aWu(f^Bb#*6(2>6}@nG$#a(WOO@ z!5-#*d4QZtr@((HIs=B#qs#9R5xMz9c{l)lfwC}8zIURRyAv+DH30m(dV@(r*=jXI zt<1pf;Kr??PUd(%cdk+SF}xDroOcjV|KwB1UE#NZ{5M8lD~x8Gp-b6&r1#N?Kl&A_ zS47(M5L1q7v(8u~b%kzGJA66|UQ>Z7%)D80pO!vCH?B z0zMEPNz`R+4GYN2%YSGNn8zvrm~wP4O_%OrU|wEbWOK@^piK3`fqQhhtYbIK0cc|9 z*Zw55QzN_cudkK?5n6>x@-%645<1Ju#LB8rRDbMTY=a-53`D$bS_>e8X;}Hng%QHR zcrG7roZ|DxffrEcqkkO-c${N|7rqY}2>$8oD~$D2C zW69w`dKY4|xP`DIVbl*-4fO`epn8}%z-*ANPg+PYUP8InoYsJHtWOYeE#@P!Q1K9A z*Dse_p8g1owR2u2ZtnwwC@3gSyDzRUb}~WvqU5!sjnS_9lPPLDN-C;WMDMG zcQQ%4ymqK^EWDU;+36yI9~u@r87A3fU7o}R%Ih?`!td4-XS4c`_m`04=U>YN!(<6@Ljck>H`(|gZM{}1xju-SdrPMpNGP)NVE@9KJCx$ zj~nW==Vm94WJ7!!Nn=OfvKgY4GUa<5)s1*lwhis6%wvG`sp2-V9w9F7Z|2=FL!n9 zD3O!4!*jLTfn%MK-g-|M@BAJIm;L7RHX;YmUl1IlaOlt(tQIza8dmW-7;jvU$5-T) zKwc#hFWFtWsD9fIWpra8vrN-{y24F~`IDCWRmJ}B;TniVQR|mMY2<;aPMa2-n1mq0 zBZkBi_}JokbS=G&h|#3rtq}qEO)Srsb?>IX_&i5SBMVFT*dSF}W&>DfBKOQt6|`y? zrn5e3kh~_Ldwe*ywL(6HM#R;uSp2N*GEg(QAH=K>F5$#H6Z-&I^9zN z?z#^A91qz~S@vw?Fqr&Vx z@oSR&ti#x&u_j8y1zVk*s^GvqCN^vm5+*>k2^_6E=;0oU$izmLKWLWIAyex zF2#SYlLETyi!R3cC6zmsi}hPS1VVA1KJ(nZjrORe1o6(Ft3sMVWPf4Vw)c;iX~30wZo0ZLTZ3A8qIs*-unYR~O} z;H42Ma3kw37k5JAc7>b(-21!a*&J_~c1W*V%Y6>^5-U$s)D}dJEP>+Su~>m#Pk5c| zrh5o0RZd%Rr&})YP!*`^_xbTT(=v!cw7zCZ-6paj>p|&rqH?f$wY<5xd%X`5XXm^( z5PF!3Uxm0fe9;&L7Bo3^=BDnXSRnE?>OzM+wtD7bD{_^%v~*GKoYf9*l}mK}?gAYk z7eqvpOe|;CRkDBxG#O|IJ^(CX4`3!8drP6byRj}$b^hiXriiK7*<~IP^~3;Xq7_%t za#lgAg+NB#cToyOtlSVk-I3ziciO0+`hw&;QbHpEJwPR=dfs1Tt^si7DC=(ikBB0w zZR$0qR#~D(g;us*w!ebxLzC&uVkj>;^nAEQJ{%C>#SILy2zea)5UD0AP3iE>ClDVl z_@rCTxVu7WpFd~5z*3NIe{jS!HmlMA4Mm_CnN`SyrqBxu3sZJY9UOtWiNaatF%5=m zwxHzT?T{fwwFJl16vtKB3%BCvJVj$1V`^TrZMg6*X(zxzD=`~>;pj;rIc-(%4I zeDAccBO_sNUkL_6N&95#9!o+`2PkY(CmKG>0x1Bz5ft+9xxD<= zgdp;p`@%q-*>+%=A2TBkK;8MB4#WNb6}?;9=ADp=T3+5o?HRBQ7)0?Rok?mj%^YCz)r!*WRRhoKx+uZCV9WcJQUi+ardt$#^e zKwe>U7QQztkMIrrWVGAFt1XX1@z&bfnv#J*Nl4K9sX}(0+V=hpiC3yhjtGeV6=cQx z<3MP59|SN0)=$hzvg=!eo|Msg%9O<`33E$9e+wxOC@{^M+Ln%C8E^?*WswPclLtt1M-%XqQBlxFu~ zzANDQcUg1@>A8=caM*q+%A@Q-(`uYAmNhGY%P=;kIw(#_$1OshMC?r*O#C$$X2 zPOYFT+9rbJV?;`WnKP2Q82sg#_Xy$DpP(1XG4KwTp6Zo_mBq6&o_`v|TyKQmEs7$b zsH`mgBu3>k9W8ZaU5>hPJ+0_vgH&)Hzk)_od7V^3TpB0-D-%WgZQ#TQ?c*|}2@l&z zsiRS-Y(JY0CS>?;aRmtE-TA9-M8Q0N9uvmi6)qFT;&UB+N!4&#J;h7n`yI;~3HaPZ!F6H;N??8l~s&*=Zm3(8!4MMSYw z-$1c20wqD~#m8YeiQkR&aghRz`gMgy6QT>%4P3I{wfxvy)Qyfa{9-&V!w)Cqhx5EZ z^~kW1Aq%r*zz+6^ltOYFG6__8K1a6uXZ{aQZBT_vl-{;6HUg>mp=fINz?_(K{@L>XU^jt085y>_qWXNdi7#j`mu5fsq}$ z@SouA-8rk&J;9&~|6DDc54y}0{EP{G02!B35hO;ZAQAN#<&5`X#25I6h2BDbv48Vs zSuZYYH;0}i>f6xkS0MG@w#lWglw<^s4fe^xO856S>$>t)ARVF9#Oe0C>8b*6g#Juu zaiy{xB>BnaccP4A%&C;WcNTMSy>oEy8;|QYrtK}ZwXx5B!rPjt3>-H|c%@^kXCe_L z;dW`|7;>pU2n!MA@%ZhMvnaNa@xsC3s26vMp+JiZ|RMw86=wwzZh_O1YcV@JzK%-Pg~~!HQJJr zWC&ua+I_ZO7!icv(#pf|--P*#(B zrNTyL8E&q^mx?749Q1_!qh<)fD_T_F3=|^s$=^>{yN9wmQo|l!KjC#&ynL}fnzt8A zf7nm1L}fhw;$jn7L5=TJE?J*9&tIT3UrVR^U3)W3&eqMk>z^s+G0?wB>m`Zg^f;M` z;C^mFJ6l1BqEq?{+R|}FSG~qB)dFvYTTb)%=}P(i;V;SE2(N8$r(#p>@{NY`?1m$+ z&Ekp|`#r{@hD5<2Gnu(Hc&&C6x{o`)LdoD(jPPQf$NGI} zppqb!wn{37=$6Z$T~ZR7HBKs8l1GZIp00?S)ay%T;v?AUj_xfPpz_Aa3B`K}fq-FO zECSgxEGTb0s6bp)SXjRjZlTxOvZ~Xz)SJEQG;B5>@g>TO5LkeA1mfzmPY{Z$Gnf4M zDMOhls47xMUww{g!?M$#m6cgIu7oJIZi2~5_L9XaaS324g@qLrr5~CoO4CzfF}U%! z`lyPT%wnmjQuw~1rKKyg6rHF$Ul}ozVBOQS7W}e5JNUGEx6P-Bsk)L$f4H(37wN42 zmE@5fG(}et-Fc{r@{d#&^Hpq?H)%`0*JBe*1=fcV`B?Jxt`Z;SL)umD#(kF&?jCue z791O7#&?fX9x3DUBwhKM7^wq?G#8&8)R#k`9u~rf4U0Q1A&^z~=4qd$@1C#Ef2k27 zm5cQFv$aX`$LkA+AyX+{KgYcvhv5eUmMXHfV_nh#V4;D#9C0#!5`SX;F9f|EkD&mjUWEcSa@ZakjKBC}y z9*R5wI?r!W`w3eQvs(}Il}0l_EfOkx#27S6aiYQ}DYkU9`PK|ouCLvrLgU8&5+y#qOU62^gEO z6~2$hy`RgQ;)NH569rW{&cR0#qjhI`Ca?WWHa!2n{1Tz*HB@~?;i@GBV@(Yb?e0CTf7kvY-*f1Z^&80=l@f8X zuiVNd`v1He(oKsbuc8#DyFu+kMQiHAWnvzae<{bA$|w49IKwFzStR~9C+@`F$t!*R zmeEma9(ki$zoI{gL~)fe0OCqvZqN7?s)>|dv`z|T`kjUcB_Ss{kNqyD@8-(e`!eO^ zIq@T7QJk>L@F4fJzpa)Wjn_Ag?eG<(@?oYmt+1zgd>#8FIrhVaNowdPq{WjUGP~r- zW}+aA!Jj51LVpHb!1ZMpsi-`ZS@iK#R#6_ASpOnh4!P*#vnenC&$@!4=ZHK$0{`^Q zBV+u&U_^(%V303g=__Gxk_vAe-{X|2YN^wZjuef>lawizKew()ls)pII70RwQX-;o z2+26L>eLlqX6WoBAi*&HZU4`0KMzyKAAmV7BOl<)BvKD7xS)#JYN2j}!{ zPn;YnLIJu?I_&+}&X+ex=?+bUjO$$zsc{jcKl{t`tPC$wG1n$isKu2FMmpIrf0krI zY^(3v+r}@5Ga^L{RVhhU@aFk)XK6~rs;3MDfR%fN__u={bRDFk(oJ{C#DEK?_@}*)Bb5Qcu*BATLMDV{Sq4@jy>>;g5oywj=H8Zs z1$_VeM?)+`W5mCBn0M-mf3`zNi0f?1XvQShH9Ld1PY|IBlNz*{=gb4)MN zKetc{{pC-6dviTd%%4hjwy*0LWAsoI~ue;`t<{a4WOowMu< z!LStfbIuz#=d*sg2%O-h6cnyaIO`5~b!(_A;CaM<85V2RivP#GjIE56#PH#7gCac!CH?pN0bSXv?GiYki@zR_1bTYU1cCe> zR|61uUS%Fl?5{qUDp?SxYo0JI#N3*!3hlsuxw_?8wI0uZxw?2dclB%UC@i(aX!wY} zeAlZ)pz2I-T)$Q%Tbjsp^Pn@oxQ(v3F8(vMIqFwU`!l6}P%6``?sUQZ^RV(3{y)R; zGsU6?#S6$b1*`o?tBF!kXG#9FzxHEwq05Axgk!hRtmdG{MYn3&{!5bmRM8v@|JCLJ z$6?>I#f@VBA=T^a2i}YGBE-P}JHP-=bz>dZU@D76wcCXy-5?{cK!+qRCx@@1X4F=wP^bk>nI!TJmD za)7GCbcOCh1$q!bkWdCyUu<9OFS=jq-Tk|?V&6)h6uy^_3KM%x`nBeAKYyVmMmx9S zvaFXcblQG0TNw$6R&4h*eF-6HfRj;C`wCniq+p}^37~Ku4V5hnbQKj;Twd%zLx~(F z>fa${gkekbygEOseg4n*cr2UOpnFZZwM`#QY#TJ?J${;^nA~OWYhPvmR$w)a zuN>dlAlfMmP9?@Sme2|bm3L&UiW_*Jf!iYci?d_pa>Ocgi1FhQy+oo}Qi+EBvG3?+z>Pq$N8=-OI#kh^K0iV!*x9IS6qOgcf3lsIl9RESg zCe7Wh^?b|O0j~&I>mM)8oxyV>+b(NA$RM+9u9rJ5QsYFc?N|COTISFW>&tyt7cWQJ zr1`)4GT$z{{?^c?sbO*PwtcbDY$@aYe7pSSe)ogtzOam2^i7X_irjasInoCJa%`+JIPR6LP@GnE!275AZzB!@y?X_7$h8S6YN1%OaTkQO-t9ZBFAJLgsS_;eR zQYT$WBSKRBcWV3XS`;NHVHbXM?9YB0@S^c$To3(F?lAtzJcNG1W&G1?wO4mku7>eT zi=k3&QVX3sf~Zz{%BQGM9qPe5#IsG%W%VBE$7C2^rm@0vnJ)v@exi%d+ct#5=|LB( zxbF)^*DMAwZkTFYMLC_y-CjaXt-g^LTd>^`b?;N;RClfprcN!c5}mJgH)t-G&D1lPyM;E|{=@{1y_%;1eXt0nLE`@BA?NN6q89x@aksWw zw=r`pw1|7ygS|RG4^_S|z79M*_9LKY@`Ao?8ZP9i2{Gd(pQGz{lz(&MN09s9+1nT3?3*Cd0slIfqH#Oz7b%NF8_b2Lz^u5}CM)FVI^FYTK4+x|>6mT80Vb|EH8g`XF#26c-Ip(`ohfB@! zUuc!F9EOYS?&vxGM{r}=&~gFK0q>1)>C)VI3RYeY3?^yeI$N=#YxcYb=C1zX4lbhi zW=hr_<@=1w#`lI2b+i<89;|ckVKJ-!E#2`_FSdp2>+AFS&K9dBdp9-}cSphPMy(8| zjP+YaJpH&^zQT-{1jT~VskUad-qUw9cvcWyfcFWvl4sQT&vtqe*94BO*KiEX4hL+| zEbzS!b*xiH=pT*w&Y;10p3BX*yW8Ksz2A}E=m)gX>1qv(w|A(IQ+2bjh?Nd*T*AIz zTEb(t0^X6Ub*f6*uSL~cV)59%f+4oi8Ke(~R@3XG(G+cE-1*LOMud@9Ce!)0^_($M zb}N=jL`qeU1Stk^Sd-yA25Yxxt6Cx?y3{Z5u#@5N)yAOx$%n8C%zKxH6l#Q+sa)S6^7tFI z#C5A?RV6vr$W12XpgTyfU%!4@L=f0Z_FwVm9lsB>p8!-x?!&pE2pY>DtbUvrpWsZS}&U=hpWN z@eqYQqI_JGFnrz!4O@0M&Jxb*&Gq{vrIbu8>T66`Sl{eph0-8A5xGgngfug<8W z>izkQm6cU-iU?{`}b6^7j~3x zKeFsT_Kev0YE$kUaB}=VZi!CR=n0Lbz6Rd#yuzxp0^Z}rUMsaLu=Nu=mg30~Ct%73 zti!>ChSk$I6WS5sHg)dbzzzG4UoU4rMDF~PL(KN<%=Gm0jaWfJSQPxp_|uP{uf8kr zNWjB|g%Vs-!4K^uyKv#h|9*Mm{{ZU$&v^CYx%vNd>b%3p?9xItJpJQ%dZle4_4{-6 zc{oOW&p2qH;kPnw*aV!nLSRaDxveT?jZeYngCf{#!%;0AMD}Sg3^&;0^7F%TPnx=J zzXI!!%UQk#{y36<4Wn+|a+==K5Tz!%4~v?=r>@rNnN(c_ZlxRH?p+Js-#h1vs@Pk{ z;0Z1`aNg~{+f2U%m_P>ZG*_0-G;l6&v!TChB8%+7)8M{22u3gf@2Q-#H zU*!Tj#Awe;f8lJ4lM$0+0Oy|(1$-}QUYZ{7zweE=sp8*L9RY9M zec!%*q&(*OO$oNxTfX1A|Eb5^V9(&G6eYQ|=f`hM#)Wg--SoqcA^5xX+{c|AhOpvZ z)x_Cqv)^)MBt5s&^Y7;K`RLV*l9KasZt)_M2{x&->p1KTxyhV!Ua1w-5Edh|E^#g8 zVq@zC(&3yGAD5c>#zRIuvF{(F!XWM<%?rbay?>Q>h7z{D(E*p5v#{_iC3(97x^jKh zs;9foe?5PD)7jEi?IKr|l?{M%5kzku&ZZCp=q_0@RUxUw^kF`LWd-qLfQ6s z8*vKfYJBIBqXaeC^|$Z$##P$%*US2=L#jp%L4Xf=_M5JfW!T@2k3HHZh%45}iQuQS zmTF>C6@0ia-2l6QiO=+e^ZTIvRz#d*k;2MT|CJGWdHM#|rFhZx)eJ7Xnx9Dg83CJl zlrc52a0X$suCXdB&RCeU!T4w~5n~Wy;aKst5&C$`Vu6_p(pHlnu$|{u2t~2x9%~0} z8hH$sii$@7)h27G3^Hf(3d5cZqKgzLFgr9g=A`=g#)J0lYS*%+Z zc=`*MoXjC}&$*tCycsiU=FHKaH2gMPBZPS@3ef#7Euv%OU_su}HYs$6tJgx)X2U_7 zRDMS7idp!?wDj{-nnU@>DZcc=#nioohV0Zuk)k?2qQOXBIT@4FxKQRW)QDN1+gCkT z6{`B9YGdUKaIP;0k=4?C6P2jAdFE%FVi7#l$PP`3VIW8&>K_$vx`?Q3s0=7TO zTsNAPAFzrWp_EHlri+DdXl7?>x@zTLI?v8YTc9+@ub#|)r|KTlQ}+d3RILaHO1ul~ zdjO+cqvAR}PH*JQy>}07G8kgjJ==9pAlIf6T~w=xT$^^=W~X8ys^5sa^tCj_+dbPK zotT!Dn|ph~Vx8Zk8T0o^N$@1Lb-?bv6Q}VPRC*09myvPa^6Pcp_QB`Lo*04`1%R(R z+?Ff)1uuPW!;x@xr-x42KrwF-zMI*5PP}ea8|aRdd7xvuSp%NK-UdtSjI9GQde!~T z#5v2X82zxXsNGn2dgL5yrYG%3q=x8wu!;+J+~~uy1V*TMEw|^WyQh>U50|FG^7z!K z|1>hrQ(zp7$iT9+%IIv&W_UsQs4&oKk$RH-@QEzGBt3@Gbvj?G=V;l82hBctFzRA& zyFB9nbdzfybGa!^MmA|W#}8`@0z!A-?N!!3`Gg-wx5cLBUGp~b2L5W%88|-c_fOD; zm11(OJ+JiLvE08YZ;42Da|keZ=*h2DD%;d3A15#@5*Jd`RghT%!;Zr(-hWMrkUzTa zT0K|RCS3bAuPP0gK0go6v_Q7a;tL%utYt(Yi@z2u`$khobDYR288%owkZ{BaY*iCX zLyVEkSpVkX{jf#89V4xyY8eo!AxrJ{Ikj?ISyOf*6K+6H=@;PQYWS$hz8JrSrqcr( zK1;jl%Tm!lvkAtF|}`oWJDe4W=!#z(hS+03#HU)s!PyS7TvviKUb zzquF7FE6!QZYq+^u}SgvVK1g7QK@ma9S5emY!=~4ww2iZ8sxV&U}GeLO+HjeIK^w~ z*1=}W(enBERcQJNZ`ExE&HYKO{{2{lmTQ_P^53RedEjK;d}Iz$ zsf1M*i}e_|Wam($z$e?)c(o_M!!{PB78?Ak0A}hdTc)Kmfsi@p3S*o&}9n z&@(591;*t#Ji|K4aWA7r;hf^e_{X!qo|kM@SQ&Pn5!yFYmKjG!>7miuabQh4fzph* z2C}mYuQ|KOxw+}|BvsJo!I*+N&qbFlSlunq5@ z%F_5KzO~!-GqM2)oO908#|J10Jy;mb6SpE{ERy6;|I^uiO3XmCnZba}pROKVZ0(Xn zaX8hCMGBPX(33u6bhG0r}Yq*ZdmQBCpAWEdx@y6QoLNGJkk6T@Jn9 zw0vzQfP^Lc(B{}O_*+dz-dQ}MbaREwMY=D8_@Xl&c`hn_SDv-#$Y<>kt2k2!nab~9 z_{_;JJ#_qaUZaYsD%gilCC0?;i{rvE7itPObnf2?;)z8{U{!CGIAKi~c_KtZ1dbaV zJm$SJ;+b(ZxU$3!P1jY(CmXGfBI0q(GcTP4_)a;4y`R_bIJdFtcit1R(QAdF}?URU}!M&om&p1X-6K{ zTU1^%_x9#}aOR$0!|Iv5HFIOsG&R!_OyMfdOC3rL54Zd>2D|6OPp7fXITh0ge@ckRnoZ2<-SSIhXAHqL)G@7EP{{Ca_5rk_n-8kN>O(CO z54zzp$&d=buzL*5dyG^lFvS%t9*%0noL*iYF4a;3^iRP?;gVXVoxU~;3njnEd#b&` zwn=jDWv@nF-Hn@1*0O7jm*}W+r@`@{SJ?^K^|Cp3g4<>Z=CjqL(fOIYq6TQ&FYx?6 zfV4}Ng_K?Tzbe&NI8!W=9Ll~kst+e`?74S7*3e=e$Q+^oRzrHA;)_R7&6*u=;F(OF zoCwzE_doAAy9YeaS{L<`q%Jg6(F&tAh=={}F)M+{bmUxTntF~Z^gKS&MA$7WlZshO zI2(EX%YY39aH&w0LtJ~x;>z)@lDtOuo(B&3&rig$oQazI9v=x6Ei=R?!4I9n00 zJwdl9@Ycu+wkF43P~X(D_{gV7J06KxGoM_xSGz2=6|1u&m9XiLkMGrJa@Fj)tZy>! zH1HzuXc~rTWa0sMo1!6YLlY;Y6MiVWpU-L-0JV*bCaqXOuWzp^W^j3Ehea^=Hv$GR zUOJGMU*m#d4=GsaKQH}A|qC^^O`M-1*3Gv)ck3O z0*RAtGL$e$<9Y-?T`xEFo`_kX1Pgk!}uMR+F$Y1)NZw1%L!72ze zTwInu9!-oZeh! zKn*rZu#Av}()d?rk@?)`CdjFB1MT}~H}xvJXkXaWZ=g+N_AU!qSt(gB$A#(vMTN_R3*PN&MR99wlNvceuc6WH{mG^t zq5NfJvDgA1q12kSLA0|4K5l~s=M7Lw;h57X!5k?eWENSX*P6AW$bQAG=SM76hq4&$ z^W)K*E#)|&dv!RHA~m^m?91cLm^MZ+adaLVE)^!Ap#Kc~f?gcf{xPU`O-{fYoUTs~ z6-!JL7ZC}CAc2h3CY5)9&D!7`V(5*0l8S+fy6Md|We!d%@l97;@#G zec4HlKk}q)&yOf8%vBQU9d)MF6<-2FEk1pI#hS>qdxu%4^UKpKt{!&pmbkvc=%S{9 zw0+cQYuHi=3knG-Tcx0+x!IZROzbr*bLyGb`9gtc)o%iWO_0 zs9Ti{6KHnt0+32lny9&M88&$z{kq+wg-<6Otb0v8Q_hHsV}k{JD!#~GoPZZJ^JVKT zCBY!0!`3n^N_VH!w(e$tP;qMQmo6(Hlp7Fb_edH^Px~*PB zoUn&$IKZjq+lSKm-j~uAFsD3Cuuc@h9F!EEDcQuVHwv9ji^r$L>*CBFG*0I%%ylPWWc3G(MS(_W#xq4gK1ArrICAB)kUU!Lh?+X z$!PlZi#J;A)_ay`9ZTDKJ2v5`nSCs*W`?_x6!N~fK8HiqjyqOx2J`neXKH_%ez>s` zN)+@xF`48!%13K%K4nJE-12-a*;5A-8m>TH;y3Hr3`r+@;^bV1or#SwAVh6_{Vx># z-$e)4ix~E5{=~KOS3x1j)yWAQ($m*(6wX^}#s!_N?bdcCDR}ZKSPx3!53}G6Dv>%Z zB+~)3&g-H-j^C&UsIIqcQLWLtmQ_=O@lIW;L~XKNnF-TD-k~>s-K+Zy(BU^J?p*#a0OrfB5_yG+^K_gWQxjIdv);yN$}|;R5c` z+>hhkt9`~4RJGQd49jer;|hcry_F08+iVkiB`1;*{GH#dS>-9TbfNO|o~)d@%^KAJ z6gQuN!7cnHh2Wm70L(oaE;eUFSh!JX&>xQc9`GaX{y{yd3qAg=mfy6h)if9CoPBLi z8O!5bpQ*3=(o9cjuT-3gixDPCve%@xoszYmq~YC>YPOIwvvpUDqNj1bTV%V)R#a#A z0ioZcae>^pot=@c_r<;jSG6h**$=>fz80N5nJGj~zH)wt=-WHr@576|mm`~$V@@&$ z(IgorifFYs#CW4)4^9ST=AVLa?#@F}XOYr~6t0E!eEekM44DmeXje(!FV0WdJQF`Y z|DUj6`^P{3k8$h=>iX%=XZI1Y^SZA74PD(0LbE**Dt|bA#mFeJIlabC)$-xwHDn|| zbKmc}m9DOG0CH)&(v}44GdIs=9}@-}!CB)MYL9 zVXvczDe~co4f&`ghU!m=p;7+{WUtYRB<#AUX0@_+#hLgRoh@gF3_wCjS|TePsFfXm z%NhfosA;62Gzn1Z*6G-+YVrMQVtDmSocd@9(Sr&;ZX8aE$KXN9UX2!zQ7#7L?p4lG zJcoQd?`d*O*ot7=Pi@zl-aaw%U&bRH4n`NE*ViDM$0#x~`~EFs2*`V=tJ^9GE~ZsL z%Ly%X0s%B1T3m5wh)821_`Md}6NP0pGy#2nJRXf)Jf;19?>yrVa28 z7Ct@YjCM(3OxR)B^NNL4;#>+#4|so9>59GWun*Sl_@Bj(N3rIZBQ^{}+bo_8@aBO~ zGw@v}=~5KEi~Q)2q;Cw(7r$=Fb_hK3;xE%RI(Le^XCa;q;(3T=gn}3X1<&qu`E)e6 z(GsheY;F!(`+w;e4{g&9|NW(%IV1o1eE9c3^<#Kr)>wP1ZWKbTze{8w*x}*5r z&m$HvO`P>gwXI&VX@_t^iRu9r5Z~{2S!V|lwW!~KPHOo4>S`&PHi%d2VJ_45zEEU< zZ72NIM;vobPRnh&vvPEOawi;!3pSyThA(fIBWeiyxix$+nYr$0K)9n%5t-;WF3!18 zp#BZ*iyKOoE7#-S=B{bt%++2oL{|L#j3n_+WW~HIFe;aJ(@Z)SmzMj?i3SiGD5hA@ zE9Lb@)(a6=%l+3??Y_D_t~$3Q6n(92lARmbOyJiskhM5Anc_4$1!foCQ@L0{%<54v zR)r#g4v9V!I2=Wto{*ZncIgN6p)MPEgpdclO{8#E5Q41Uew!OBlD%!PAgj1bQ@(!G zcg|=j%YP6x=Zi=eF{g1uXp({j==c#IxlqUG0dV5X08!BYrpTZ3KzueLBn=o|G{YxA zsSDp=4xRQGa*tzEHyHt14TaTnw=Aon0gJ{OmiS^gU0RCy#fm{kB4nAUd5|d@G7%12 zX8A>Q=@+%5SD)+-&xnva1s=r!eD4OZpEfbl+EeLbeWspQfsN%cI&%E<$WTGq;4zN- zr}xXdPhHgAF1lpqREvltr7Z5irmdHu|38xX_VV%RWHR0WF_|u|XMtQnC_>~4J%3cR zqTp@E%Ioa)ZyymLE9$d*x-P|ea$p|9=RJm_@Gj2|^m`0Bq#vD;WAJdww3#~#tL%zk zam=PQY2+6!MO~UJ=@M;eY9K?YgS7hP@q4|YWPaqeD{!x-4@&QrU402VKcD;Vl{9sH4z;GWU5P_;_FusL~S6=iO@+TdTcQgS$NI6|A zt-!8UMypdoOMWh_9}}EnG0Y&|zs~@xN}Y7CnN4lr(Z~~9dB99ix;mACwJT8D5{>UQ zF2D2piAuo!79;L`B;i-wuEZ2itD`Sw;5Uy90rMuKiP~sgJ?@_9YccWsD{A9~ph08( zdi;k=J$eLUpP8rsZ29J+t!Y@eP?F36PXb?$5$@2rF9TE6EsltQ!uv*ct-pdfNXtMj zQu4nl%^qdCYx$5PF`YaedGx9U&7n->z|Sg$73l$Nnt3n}d-jRqe?5l6fx4AziRjWd zH==}jXWwjiz(gv1%S>N@q_F8X?6+88^wXC_bYbXjSNEs2E2E{29M2JdEkxvCvzdD9 zMWAi<@}1f$?nt1tBM>A6gR$#-er2z0PO^)3e(~DOKnn*PfRf;jWUr1#Yn51DGG4a8 z05RXtEKS)|L8O_Xd)R9W|i3V zTeNmC79)%`d(GtLls@sTx-?P81s{MQR9C#=F;ovCBi}FEc87t+C?OCq z_ROBlF)-yJ3a+FD_IWw>NM_CmuIr9eBXbBXjrl19+Wlq>qF_wWwOBK|TzkxHf3frD%faL2 zC|YY*slJe`(9-7|(qu6(hgNr=T|o#W_9}`fz&~VPtB1j4z@Q9t?TNhhNSLk{K4lEF zEP~M70E)U%#&$%wjulPP-R?aec-WU-?8{y!2T$~gzIpd^ai^+CV`Gwitlk4JumhD? zP7Zoxx@z+Lt;pov_Ci9Rc7?1n0?vUqc`8s8rTuOaTJzH&UgL9w zd|xniIwVOs_YP3+Ek6FOZaMhZ%Lpi`Sf~41j7fTiHp;9FmzMr{U9-yRko{-*URv#4 zsep-?4a<+adPykMv|_gEIoW8%L(>Dsn4pQ0=EEvDne+F*&~)Bfsjjsn(hyr>zmeD1 zsSe8+Lqr*xIs0GA5W{s$C1*S@E^|>~F|2FB!M77%07B&eg0spJbe8VPRPO_f`hVyEhAnZmCz^1AYHL=<= zAuQ&Q(;@|2LOsT5W}O7)jN1J4X+h+e<$b$)s%NZx2c|iB)Qu<9e3Yq96RG=)e9%qydYYcRt^CYIqTAoUH3KT>?}* z_=q<{I6zH zoeB({B-%Z?^@3KP41Q+Nnq@dP}zVk#c9lQLmM?%+=1z7{H z7wQ-{XfqBYcPPslm;Rhg7?g@ujgiyV3p25bn5ptiJD@1L7Qb1K1OiS$QlQFhdausa zW!$l*DRU(%G4yQ715C2$zLqyQo%tVgdjH9cGn?CTiON(BdKAm>MGR0?R zT4IyENTurdM#ItHGO6Cye`1Ufzre6-dqkt5X9_;F@V5UlflBPT`bX}vT6?odfuY;x z%-0N0vM=G*<(MnlBB>x)SAVJEUig$Nzy#0cW(!saA9v+$#J$|CQ~Igic{9>)8hHIn z=F>LLes|=kGqU0M)ySj!hVbB`sJULA$GNi6QdHNB-KOU|Z?14rB9}W6p>#^6M59&3 zdvtmtf&~(9+Md9xs_6I_k@F0S41EhEGi*o#Mkj-_4_sRP=tXByOOLb|==DYZ{1Xa$ z;MTe1sOZ3-hyt#<(9fC%*kC7lt|8Q2vPL#&8T^=EO_%Ec`-L3JchozSJjDI^Os`Z< z9fBg{`f^ABj+4^SeT`f9@|rw&pH7qWn2O|L?K~`Vj^GDyjx|r%t#C}*sgFi%1LO73bOZ+8-hrcXzS5XKX?V*o%%N@xZi;Nx&8Gi6F zycn?wgorFZz3o&h%6HtK4n_e!MBX^;IsBh_pi`}5)U{XB3->5%lI!G^2#cgP+{5wA z4eixqTMx&Y*d?4jbKchK`3#PnlY4TcrF;7%SeV1t>DARYc*33}`qDM8_hm(D^%d@m zNckWoi`p${W?8*7%$)yvztFGqP#Ja>t@uy><+{5%xaY8Fr-XrnAueoL? zDgR0u97NKn#W`h$Y!@k9Ew@({?}E%rX~k@33#Bp1vAx$EbA9tS!leLM8@NCLiCxNP z$uO(kVJ3>MmFO|*owEvq!5D-*!uDw;ewI3=_q!~;!jd8$z*2jW$h9rN@Z#_1GmUw$ zS#f5*+ojX@fmzaLhpuE`!ljB3|NV7?E&>a`sSY_+3UUMAjqSQVL!lc-yiKW z+d*8UfQ4urRKbcn81}ozTn%~#rlx2z+@16A5&F(pgGeFaxB4yc@^fxQnfZFkqMow$ z{Vcx7dY16I`h56U2au+3kj zuhRowPF2ms+~VD&nJ-cR^!j1guoQRy2uiPa74)ML+wRvL^ESp7^UvOA!^R4+bxtS? zM(t8p&OGs%=!5L;f4>h!edTf_j4Y1^ z)s?iBL;>x!&ER@M_x1gzQ7J>6BXOadW)JSZcRc7-82d6Eu}_izAbuX-1tR$N$* zaIF$Ab;HykG6Z7-#xy|#lMX^J=N}7{d^=wIwoF9waoiqb7+yZOuR z=D}kcGi5`LSUsQo#FRx?aF}L3`r_Z0Gh3vx_uTZvvNv@(Y1RW8ktVNkJnSzUOLlGl z+m2M`2U9~tfc@LM`m%`64taGDG_kOr;@9~f{DArwY?f`3y`N$WDti-+o*oUlRyJ&x)bCfSkpWwm=Yi)UQn090yqnM| ze>1V4TwqXcn7WmbXT~YoJAyMC3t;saIDQ=w>cxIGTZ1biAz~P={q9D^WFpOuzxsB$qw|+7>r}>c zL!3z>q8#uec;<|r&`)lVDX|7&{BG*f$UjPhcv-)N^Tu*ty~og8d|S?EjaOeZ)^`7` zG<;}Ha{!BEd%G2Uvi1*GbB}2zZm(QuZYi-jk(2vh7vjQ5*^}H+?UMsw2^?GM(ro*A z7l0c+%}ZZbWmdoZLX*44yVsk;+A`nVB3}Q?3i%LhD7CMVoC*ifrce@lh!Do7_ki%0 zj^h~AgY;ndZBggWLzy(mC*UwVKsw;XE13 zV-fO>1@q?#*S$mehB6<1EGQr5ZaLdk+sm0AoqY?J7kGzyaOh}Tnzr!nySgh^?uGLs$M!k1tKR09nTN(UVE=AJn8p$8O~TkA!Sx;rN$hMbzNXa{9ZXkFqc z*UhMF>ipYD60`p|9=YQ%Y*}eUf_f0>agf@KBd|~A^+p=M;XaQ@5)Dc}B#CsQsa1@b zkzNGi;M`%&y@-SisA&Pu{jIkfXG)z|j=`M^gRp{i{M{$<(86}4GJpf%wahD*8l&`YJDeqY}NAOCp_l#7kj{+vGo$l_x0VQwX z!cC)F&lPTi$gqJ>pKkqcR;|XxC20Aj*I;2CZ6{N=4=NJp{_+M@Z*9H$b467MZerTg z)O2nA{A~mLr8xuOlRD|sjH!#{;*ZH&&WZBL7al{9)0slOmT4vdzb)GtvM$Q?&%=+?U>Bmy0THbAwT(eT4Ajm*h!4gNor!1X9;b5=t48ieg) z%)tv08zkoeHdB6<`?h_@=_*fih(1p5{rF^8s63-e9;ugX#USIi$j3!~U5q*Mi5nRr z=Lcy;MDSlFwShUvVc=q}ZUJQwT^Q1^e-r)BZ~f^fb=$xrI`95p$PV`ftWzAye#8F= zl0QTx!C&{5UPZg7vjEf>Y&RiXqqe)+%vs*YXev(sW&hn*^KkOYo^dYNJ5p-1@B82W zu3P(mV(Q41|Ve#7DZyM=|nsYYVgk za`yM(C6hw@ zkLc~#R;}+h?BUOG6n= zZ32F0Ze!j(+D6<#;(7|X1KCx}5wJ%W6Y13&9@X44mC(C?yvEaND*C?)S;rb#KZ6*# zSf0i6onFk!e#dHuP)Bnkqk}+1xclizh98m_n@p`n9D9;ThGQ8beEq9nr7uzCTLhM( zr_MCJrl#hL2LOlLVTUEo6YQ6YGD_oEDzNR<;>khlGph%|dW7XtJa8D9gOHT#Ahd(< zzmZvt0h2@`dr{nhGwI2CM-12m+ws!;X`}V$x_2jl{0`^$=r8=j+*OOUT{pR%2*FPY z(~^*eSrbw$TpI~Hgc9Sd^$~i#HG4MB+v)npP+ z+t%~6vmJP~KES_5w3^dFh4P*lQ#ntuwL|J;^cn_I@X_Y67*wT$jbIBjZ*C&9=)d&YqpRX^N96VbuBVFOZAcDZsva*mX8w3}{*$-Z5NKAFHD! zD~r?-!tBz8_ArscDRawegj7$8LKs@OMk45Z0vJIkoh@QTJyl2b=48IEQcC>!#y~6i zgatQeXyBHoGo7J~tGgA?A$-3*CpRZe?7*+Kt^Vvg-@d?FgyqtC0vGC{eo>W;62H4T zQU)Z;ZiC)NdE2F#d#fkw=!#1x$;hJVU9rXN3M^$+LGU%0GW6gg9mjo-(*g>g2DB0#Qq+v~5I22zh8FEYaxkign{ zd+c=vwyhD~I2aTI&svk(SWDTD7z*E`)!#n{ z(1|Lnn;bNzNf{D6dzSfQHzrTJgFx6@L3ax~zH-bv-%=6k(v8zr?-9sFTVK$ zvhG34Irmg5XgB*K*SbN$a(ErK$MMsCa}3XreW`!J!^=_hdGcnR_0B^~jaR0p ziv}BWam@n0vngDU)P+qyf&_f~+?&WukE=@6%uxhRSx2%*f7u99hk@UB1XX8SGqJKc1gnEFZP5 zJ|OepP66ak3OAcJH^g^uuKWR|qH?3W-z8~w6kd=tb3)3Lw}c*c5XV+%$ITd z+^_20_^ZoII*?A#H7y;id z^QJ3n2L)+JjZ`qD7z9DYB!a2?5u{-5{}H4Z2&FFljEB|xMh$-@cMBuWNE3-sL1A_P z$%yPpu$=mQcc2csh#T{Rj9yd4QdDTk93mzDNRX5??^MAxKj)}zoWNT&c>`lL)?Q6- zhwIu1#>wQ3J{C}c4n3^e!%Bh|?rtuwZ%CJo`s5*=*lwlexYZqEZ|>AGReE?r^mf}e z`{#@4DXMr3ItS-(zX2;%D4V1H;;=z?tYy8FBrDx6v(aro9O-LhN>9xu8G;4A18Ol} z&+&FS+Ay06`_wR{8q(nnoT~e5j$ zHxJfcB*nMGF-aITj(BL&U%hNpEQ+?9@_fa4AkbH1wIy zqLh+QSa1>_-(i(SQ@a~?f?pmwZA6qXZk(=FMJOM^C>?&YiD6l0zq!6$b)xX@vy;3K zkzaxgi1B$vkOqLnU$=NyO0rHXhHPX5FgnrrVBr(~o4HkOh1Ihr%bwR)W_=0EWkVEb z$OAoFo-gN6rDOU=O-ACWNvZI&5_`c8L3khlA zOWMnThgwKjsO(_ISU+I0JhlwVd24Leo= zOK0fU8SQf!LWw?tr`@}sE7dzz&qbw~-+O-DB7v?(BpamNtQ>!|O`tV+C!dS>Y4@8w zq3juPimSF{D6GVnIF!TqR-z`}{uXpcRz028+Rg zYs^`{)62*>!S6Yo5UxXuR7snk;ajia?TlocLHcaW`M(oFWzmY}xiRX9$*S>?lYXA6 zQhQFCe=J_B3E7En0n29ENJYSwbiA68RXrNA#6p5W9Y@sH*2iO$oWc-Pk)%av0=-d; zQ#K~da^RGG*zT;iDPobGVBI{q9~@f6->&Rv`0WtqcoJ!2_%Be zSbf;eM*!`a((g?*Ej{&1neaS+ zyQziR;MRDqm~->@6VspX7P1v;S=oo|e&vN_925p?{*cq|Fw~Xp2gZfpAaT~Sdn9sU z_k%ntb$A7pmD<LkhlXJzL zElEzjJEL@0imvW1{Nv}Qv=!#iBoPP$@9#}8>(z7cSr!UHxpeNBh6c#1;9ICq zo3ODniYi@D72#FjoNsZ10F6Im<8_hltyfhYgoubIsy(~^iSpDoAa*7VfMC2joiA#z zE#l>fE1^0x*(CINqcKF^GK#e)LSjWv@%9~5zB>dDGfgTEejzF`qPR_F9weHdIaorlixoJONxtrADz~EB zkQr$eXPW(G0c@P(L^a-A<%Q4o=PQy@9EI@LBaM6u&_d_un&dQYpe*QdHziO05v(T_MV35@iOvVV#Ru)yam|i zNoBca4ixiX0fC%Uj~nkvuQ^u$6_2(XKhTx-`W6g1S&~5tF%&7~4J%}SLD0UQJALfn z&K)C)mJjnH{wWWEN+xfv%X?ukbT9iB87y~tKYMccJlM=Fc07fNt7qWnOvUVOe|7E9 zC=2Vv8|OT_~=W`GGL z=|*;p=Xv!di<6VR%7AlgaK}N&WdQ9C_th;4mq= z_k=B^*)hq1Khn5x8ILGSl(x&ErA+;MVw~%rD)knl z@B3g>BZ8OB8Eg?m+nlt60WZ48zCzh~y4X(JFFoq!it*n5AafcCD&u}df)$d&j@>8m z6Us6BT*S$Q)rFRHz29dta#xD078YzX?rUt{2dkwxI+9Dbl-CM9`tPpK`eKkY%O0gd z;reCi;drtm7_Jg$i?h2I2m2YXi&x&(_*uNOa@q34Ej$PUef2W}%LTeoA1rk~X7XTW zd@%@Ecz@*6+l52l>rZyX^r_#YqRm1yU*nw7Qs8ke8h?DGv`r3;slK{f_Drlvx|dbB zgk|G32)e_$WY1zwtgR5L8r7EnmBqe>Lzc`&+}5dLJ{$4grwet?BQa4K0G1Z-9&VXm z5GiUz=8U|(QJD|k{TmumxZ$5Ed`!qN($5edpc8mRqZZqh_~@5yjhga|sI<*>vOy@~ z3xNY7lJ#no$uy{HhlBYs*VK0*jKhw=6Ve6>L?nx|^WgatuoR@jegIlyG=5h?a_%y8 zju*bh8{Vp-K}cK_y!2O&6~R#>@7<^QTnTZop~mduS&2FezZZHN;sxSNS)IYmyAj-G zBBxf?RpdNV<-Zq{?CK-RonXFZSNNO^kp(c10{B~58rQXJ9;`SG)~+m@Fw7IPP{DPZOBJKp&++T1q~ia$2wN5%=nkbW4%L;q#`oJ z&}Q6|b2n=A`(F4~)$a|Z60s8#bLWQAnZT1uv!L^uv(-WR_ra{dSzX<7534^S5=ph;wZk%IZ`kWSa`A*Z;FguvaNBkl$! zFb@p)*=>6Z3;t4OIXY|J4zII^yP%7oLt(zW4<5ti6&B*#_M7`1gdT+EE^TfW(Yh2z zO%tygft4T&q$yx>EbU;`&~>n({p1-_3SVlA;cSynU-zw`TOB2_Y@!#n!!Ra(V`1Knaxfj@vk3|$2qBErIBpE4qz2`Ct}Wap%&?r}qS?Zx$M z)!%}I|1fcB%3=xs8uT_HR|CU_wGG|iCsF+;X_U6nCQXLrQ}7sn!d8R))@@+dR1A@X zNvh|dZ5)ze2c-P-;oJq~LLL>IF%oB7q$Rls=DcVcX?YUw#9=K^W_a$or25k<5wp03 z9jwmMTU=RvjibtL{Vj^$v;URZy4EwOkBKf?x1nXmnfTqsa8~zeh9K5`baZs!Q3Ma! zmrPGy&wF$NZj>3uZybtRUQwMsI%&yw2qID}n!owOY!Ol%taXp4ojb1UFAuDFPfqh85n0Tp zWS{YcLIUT>Y!(}_;wCwj*}}=73X1Eqi(c$`B89U}Ab)ZApCpp-Pe>A}x5SFWnrsnP zcncO&-^+efQ%{?;4$ruelIA@vV%7F#q`ab9-qWdGE}R39W8&Xc3^9{>z@AaHY%TE) zX~Y>vb*T9I8xnmOtHzPoUpBbLfQ|dVXnV`BD8sI8loAX;M34>z6eOiPMCnjc8l}6t zK?ITR1|^i1&S605hM`-Dp^+S5i0>NX+0Xla``G{X{9%AQuUL7ma}~VITZ|669S(^4 zl*^I)3<^8?ylsW*a32)Ne@V^c4HA^wV?0BtNC+(yU^4-QIl{d&!!;BjOzEI3kU9f9 zh|7jgc)na}^jj7VYp<^cR^4U` z?5s6hE|^QI-t_Tq7K2`jyPekn{l)Fc-*pMVMoZS_UGT0%!5Nl7lKwaT_ExTS)$lu1 zimK~zT+{xBl><;5%e4z-8?{1tc?*_GH*GE!t{@aBnyx8C{0{RUdB9=w7^pmzixu}L z1%W6!3u@r>6_$GgbG^t@!1qrPkhdq9{#vkmVW7iywWitF4ac*cCL`g!le=1^D^+l{;PT8nfLN~KN|@Zu)5 z71Rgu9#u6@jSRlRDjNK&u?+;tB1Ecrg5;j3w5?&F}XAhLKw+K1=J!zPT$K^ZY?gfL$y z)dSF*=Tkh(xo}5l;X-$$&<+7A<}`ePJUlhih*+L=8XOE%1{ho)Ud6}PXi!PZ_pftvR3*ig+3p#@x97=2euyT-`_*s5D=$Xb((a>B6b@Nj{^lgbAP65NK3lKJ=299M$ zZAXKe$s$lX;Q%aOIqq9P-VS`ERGT>1r>5s6+o+Ta|3(*G#bdJI+zT4twbn@h$~+yX z9?J_uXYzOGx{qU`PDgGDY`rK7yE?YWBF{a&wG-I}oON<=bO367*v#bEd`TgM$}?M z?f^|Heb4&LWc16I-b>^*1q!GK+NzyBSMsz)#UkofH!i2j3yXYNS5|_{piRY1)4V32 z2H#ar_GW>e^AEpDXk}roMR)hb_-&y>gKDux>OrlWX$rzo(}S94)WEOIXL<2YO3|1Y zbwrkhGp&8@XJfAOP84#BT3rM2{DDF|H4Qam_Ia2ZO@Yt%-}%YTh!1Rf4McbuM52lPTus!_=x z6l0?)G{a)OnOhx{{Ul^YJzd&(49csZ3x)CvIyI%19@Ax?-gxKEb*f(sjQp;&YN;~c zs{7r1E4xmE^>f^k8KL;drIZIiWl4;K^&Ngx-mI(@&x^*W)NSx5s20=ck}sH^+cw_mS1G= zYVE@7&y#OHhz>)LBOvOXM9ORZYSv?74#nxRj9?nQ{0DXMkj$q+(ZI0O&Q|=*)N(*x+`%%hK~+y$ z|6k=+zxR2|p$q{Q;|)|sfcNi73WHVe{(eRK|G8R<^>^mV@G*+iOuwjvVkVQ}47 z%fYjWKmW(5?jQUAO$|O|3>t$2iY|c+pcup@tA7VT{T~A0|81iy%q!xehIONZ8bqM2%@1UM7|lXIsgQ+2+hTS5c554^8j#XMxMukzXvBG@m2sT{X^}&7Qt3gqCPmdussH^?5b;g$AFJ0W zeq@1f;An9s!av1m^7ULFq-%NW*=ENbX-e&1q)f>%-^hb8$SoE`eR!kJ&H&XS z^Q$pBDr5v7_Ba`a78KD?{_EQuNM^Bc<_$v9lm@@J-b#Q9 zH5K|lkb%*WNq`gu6)C8QY3TfBiK>;}P5s;zO#>H;95DJ83q^&IF_G$weKCm(8ZP({ z&m%@p+}B{CW{<{4kO?(&=4WT|HWn}LYwgU6pc!hvT=3Heg|PQ1QAMOp6`wwJQ~*i| zM%^gn+Iawcx)9ay{@s$`&d`$sTS93^-EEUJA$*9{_wXR(U?T=d89 zr~vcx0`l`8($|;+=|wcP1ORCiDY!07@DBwzZCSCU;Qp8IpAep#M7p4S#;hagwg_R~ zDqviD4~SbU7aN?}BMTc)!m>Z$@4S3JyoY@U1GVDc|NTqv@;BPgnU1Eoq(kR3ZNOlu zd`b)UitOK&ezOovxE4=_VF?I`}df*gm1JU zx}*tuA92*1{KR2plfC^ejUUI9jjH%^9=lk7K2IYnWg|=Dn<|?* zL2|kbCqV?*x83YWATNQuurdOmw)c@#SCbob;2wTNf95$^Deoo?N@S*f0{mN_%0(~t zko+z!clY|c?hL`@aXR4jumPZJhhQP*q913ELZdoKXC~Q|Qj2wGmqOQ8oJY%K~w&;IW$`B)J zR&unzgi~@oEW(P_h7eVr=w`ghc}_Bz&&_5!y4!h{7imNc196Z-t4UO7MDG3g@7hrD zpxnpgfNI_iR4~t(hcg@a6__(bmn7;wtkHLz3f#2y+&ro~E#b3drO|LHW-g5MXpw__ z`pEmrZ*G*~A&Qe;D)O8GTrgGW&zKlisGR)fQ#47^5!0?*G&edp^+l9sJiVMp`T!rccAE} zh=7dd)(NBq_dyfa|EsZ1a%QhCXQ~qu)D`1y1uW;<9G6WWXNT;RR_`^9i|qr9$BZDV<#tDqK2MhI>M z`}anL?pBjSq&%()5hexXGM1+!FLa0};YpzSau6JrocVWmsJ7SUNC9%~iF(23My&dV zAjau?3oPyRlt25KL*1LJ!j&L*1{8Z5#S>2g@@?`4z8VKyMfnE?MLM7NiK6eik;KtE3M`6-5G#chbrH?*+XcJeHp(bc*H1jRjN_HZ? zR1wug#(YQZuMuIq3~mFYuIUnpXH(!+_f{}>=zMREwDTj=0?NxPm#Nw##jj?n(j@Er zM6yZ5T4s2uf2>AtOWUQd!+o(;8mRq2U@`fte0+c^=tUc1yn-yok^+Ikt=2eRveczM z5yo4hO)~fJni!zM%CH8uL@ZE(V>K>&M#Nk|yA)d0@q-ip$?_paI$!ELn))6#+)}ku ztD$id+G4BLGi>C{+g@^GPgctWH6+zF6fcklN$Pw+k}@)Ae@ET8#Tl4^ESXfl+#xlJ z31XmE!vJbySh4sWpOSnkS0PNCRtH8hIRX`wO_{dCETtxdEtBx1bC9fR)q^wa?NGG9Oz4=*UZ!sv(SFQl>5k zu-V^4fFecYyr0lKIWN6b1eL1&%qX^LH$F* z_E?S-0X>fv*^`R(ZFQBebR;`}w$p0uiTep+%DYwz9?Dx{X6|^B)9@7Dw1^RLs}ek= zg8bj7^eg~|Fb<6;_oaD#OJ|rKJfeW9x}NOGo7@^8!Ne;y{vh0r>^BO`K<)GQhg#bA zZm~|DKeiwegx?X13dO`f*Sv=f2GzXu--`>b#B(jRhENw&H{4CHbd6=5gfe7cdvc3w~wh6QwpKF5hUu?VTR})3YpCDjGag z9&I0oK~o6xQV_R|2g>-*LI0Go8Vgn|rNi<^fF6i4-_g*kHlw`%+x{f@vu(2zK`$_r zS&ov%jKmbh&{7VRoyYn2!O8PK6UapV{?p^Xe`*2%vo?^1VXZ5@0PXQUULy%tsU8Zv z^{nxD`(|lTaWQHguZsT>F25GE&9{qZC$@9Dd@vYdRqLJvV9NJn2K-3mGs+AU_G zeF-SlSD;srI*qgxH5a3?Op#A^3)>*`5IIbQ@<{*$=Yv_MPpL*IUG>)~J1FEK#o}-4 zLGJxuLBLwiA!EcGgiHF%`f$pz5dc5vud$8nXPoV5+57mYi%ESXkk-x|c-`U;52Kbu zZGA?b-?PQKMU zGIMcMJNy%W0sRqH05}Nkddc-a!U_#-F}|pkb|6r^iSS{x^;8Av)r?N3fnWb!&HfCb z1zR-fRPKU2i@0|ku3P2UK?J`$n9_3JVnxbc(K8&`Rt0%t~lP zRhY=h0s{7kb(}wZp~zC}>w|MT^=`y4+I%?Y z&Yx?KKA`(8^uWcF_WTK8{ zFR#nY@xMo-`=`$Qd(*E4ovaF7Zv(t}y@N)P7_z!6UKysXwDW&&#eM%j$Li?bz;+Y3WP#m0!_SW>r-=Gp2hIo*~!wUfo0Bvl8qDJQ0&BW-I+*VrhFZ;iK z&;^Qv!_nSq8~>Xu0z>p07&k2c-lhLPlZZMD?K;E%{{5Rg;}iF;>r-D}$5}LD?Ja#s z(tNrnx6E+u)@od_R)q|x76i-pKc7V(5=#sT>RCTpx7~Rzo6k0pS^O3XgP9_lg!G~8 z{i!^OH&=S)Uc9PsuHTxj?(8%=+8m3ivVi@auV44CgITejuaf$G#Z1)2&Nn+E(ng?H z1XH!U{>~?tI`4_r>24^5+@?w3vAW#bd-eY3^Be!(?)Pcv_cRP&HG3x0}}{)alIz2E*4ueR(gy^e-=Wt5&#oJ2q}lTvSTzm+7*a$R+*uvi_dyk5K%A zkJX*Lr^@t-1De$dC`DN38W6F1jmIY`e9mj^DowBMyeGIHnB`$N-;`i8QnO_Ug@&wx|9!QWA_mOJ?%dt zx8L`oiTt`B0Cv*r@7OY+O#Hl0r_mJ>g~Y+9j1_btpTcYV3PQj?vCVL zJku!EU0N#tK*BziKbQrjovGbDd?F@C#L9Y*0}K%*{bp~5tII}ZYO$`oFKmxHO9 z%+C_>VxyBffBYedB`Nz}`u~{x-K^V!1k0xf@Cq*k)R+2-#fx|5uu$EK68p_^f0|BH z6QNwymzOKc1+WUEPPV<=|Le7e0%+qND#uaq*`9ec$;1TKtb-O8rzs1iHp~UO^`D-F z9U7b_ZwtA42$RzNucaXNdIj_F?8u5t$Td(Qh4cGh6XVNIGRIeDSRSYQdDb;|!vQa& zI!yqnC8AX1r-9jECgR}L3!DEjIMiToccpNdt+WJ4c2r^e%{Kc;4`hlw0(&f`(QS81 zFaJAYLFVoCT~~P^vm#oeA1P;^m^&?ZJ?Tyt$l1PJ?bk6`Erzxc1M0HFgXBbiCXM2+ z^opr%$FB^n|HqwdKME2UZ&^s5KoB8~=SM3Xxqw@8#6SI!l9t!KA#<}^#DWn&%$ z(|c6pIv!3sOsz;sMJ{*8oqB9-)gP!dD$&VC(>8;}r7ML?L&W%>X%GiJ?4c8?*}f;5r81K#X@rly;AI}L{`1~pOv!qo)~bw=SJ?|@;F;A$TF#J z`XFL6aQqz2gZ7Fc%tw-&F5+hDeY^o$)O_)5*B9q&Y}?A6-M zpSW)wZBFd2YEe(D%r|+kHk<%BYdBK>#?mdcx6jxOAb&eN@!z|Dj$`1AE`Hr*vE{yO zD)-*Zi?}=VU(8RFfz}Cq6nx{Z)B~w-^JzAYn*WwgPj7!4Lyhde&(j+i692xVem=b+ z_xl{hkm$@0wVvVxrCjI^W0huu%kV5Dzl~~3 zMYCh#5q46R7lKE>maf`z40jxkvzP(0GTjX>S6vk=%*Kcvk^JosL`*CUVI*-+gKx_2 zFLz@}n6-x`a9SNxh8*-JGSO9AO~fzqT8^66d!JUocwc{emr$xFC_DP)WxFbB)YHB6 zp`I&MdLYvTGCq;Ol|Z9)C-`HkTz3R&J%)_SOu#1YvHIg$42jEAvmls@sQa&$67guz z1|mhYbH;54%PPB_y4QdI5)+4VU@(h43+=in`Qh*kr}@s7kLBRm5k+`fPtvZ_X}Osj z5WX3-zw{cM+iP~WhZWdbsjlxIZ|i7PTUN_oJoc(7R>_fa*&~|cQ~j*OWkUjbPXC?? zf5T^)vVTSrd4AB8Z*w`HcYa8UWM}CAT zspOd2)CP%r&osEC#j~mE`<@llf@P?N=BAJ#s3&Z(T0HgpotNqUSdp|{d5US{GU`_+ zdqyEPytcFSr6X!b+ODl+bK~#tKBAX=hx;>3#OspBCXTPnL;TjS`x^^>*;}U*dtP5$ zipp|dm46~6*Ms`%S&kRdk+A6!DW5rw7z;S;=K>lW4WNsxr+xQ+GH`nIsD&KdB4MKk zn~C-M95=x_aBgEoeLQb`Vb&~7&a^^rxyv7djz(aQ6^MFov_M@T$nu`O|5;)G<3WfG zxBb%3cKKKqEtMxui!Blk?E`v^diYpVH9jG*)70b3B|zbemQ`ilJ}K5AkWTYZffVf6 z$hT73ytxwJJE(7CluuWf6jfa|l!Q|qG(HO_9eyn&f-RrO#w7>ikL5JE*&6brto|TR z8c|C4;$ZcP6^&pL^*oDY@$Y^wZLC|GJ%yC~Yj6BJ2lUvgXPP`d$ZsDOno$k8^ z>G0=8W2CCHywbxF@Ys*X%J;j}V!wNpPVZl2+Mmj*oP}Ln9G$3<#%=LC8R#zdZ_VBF z*k68PQ|Y#=@6ev#pQdM7>v=?O#L*khOeS@6dGHaMVctsaER#iE)iVvS-rMv*fls5b z`!8`cP4joGB3IYmVymQHlR-`Db%DS3E!Hj8)7Y-wUW+t6A-4}?kRFfCahsooz`aYU znX0veT2N?WXrXzNa#M7%LoZiVW@hUhyTjL2O*)TD9M={_r|N#t2)OJg7wa_20T_>U zdbETyIh=R4br={SEjpa+OYXv3ScN_zS&#DKL72=D~1FV zGn4|3YL3e%eLv2rgj_>~YOJRov+8iW@n50zzT2*-SyA-Q_77n~+{r5qCbXcRjFscj zG>^y0;>WfK5>4RW5wVxOjir^qK$*L5iL^!G<0UhRaBn?ZUFd6EjCXh>O5prQAR7_~ zd%tHMPN;i4!nr94@vqUScCo0MS#UPT&H+rY2Q#rG%z7oC+PD=E#hw*Dz z!15B7yJKZ1zn1Fhir`h3T#->wi(F2pp7UlC3>c^=8x&No>!+4}VJu_E~$mt{IO6{9%<=&KHsvfbxM z*!4MWR6lwP073^6WA?7K@_qj#{%WnT>&C=D+_FHs0VYaFZR^71=6YLWQ*_sX} zW=}^7jBp$#0)s!$f59^I+XvRUnd9ZTNB!BAliMW6YlfrFf@M(r&zl+b=vpUOiuw>w zbvC_b7ELyT7(TlNZG9cfQ(%nHiWt1jJs^SmT!|$CQPGvatQmpmQSJ3rc)eaWopp%R zvCsO9hIaDeuWNao7wmCP8>bddf(;e|W0)zTG;E^i*yR^sClaj?x&oX>`I}vcQ+U3O zGp*tGcM+U6XSiCmJ2WuByf+c2%~K>lUaZAXmoDg{z1p9~u9~kD*BM14WK*Q|(sKL@ z+e%Lo-mk@YY(Eyjk;V&x>~2FaDDt13M7!u1YgN0cpiPQhsR1 z3Io7`IQ1e8FE1sM3^pOR9q*}nr=+OPLmv^3k!MeGT5aSLS%B|3LAJ}vC3szXd_R*( zH9!6(`6Jq@EOy;GnS7rw z>ClHvEngw!@j~@gM~R^z)nW!Ot9>uQwda21{N|x6!j+>xyf4Dd=bKWVlweMAnf1lq zxO?U7&NkYt{^^;+`gnEao$NK5)+5o879NpK#pJ~kNGZIAz1iFtYXJ1F9d_RWHSHs3 zo34qwd}Ui~ar_Q%Qg~oT&4iP1_5tMOj2*K^alG#Z4uAU9`sb{k9s12%Z0?g48BG~^Je@fLDTphe#+!4kY(Us?oJ()aa-&M&v`^q zi^PJ>5ZZ`ODa=^!xLPGNI7NJ-QSZ3oEaEOZC{;bHq+=lMA=it zG6Nc>XffzICww5wP4J5$)#NaGIyN3f8uqufC*z!w&Nst+KI=ThOIfSJIi9Cw$d^2$&usbVX!9Au9&(nIfGlCRI`EhPCtiE4_~}aSr2*yJO`HN1Rj|?WWUe zkcB26XfM(=8^p#-^&Xk@#JhTsQJK5c8q~`n&kEeK5s&cR*dGg4HN^qvw36HU zFgSVGrvP2nYP>i>A_$vQ0;BY1&%|~H_Lt*Lu^|hz&;-#kP`^wep%{dX&w){ZPszVL zZdOJo;d1%2X?NkmwRPPWwq?K3ls8ABm|8#jh&xDqrDrVnqINsiWmCg9XgF|<5*w{0 zJgV-frA8qicG(R<|4HWlI6ZR;KXVjNF-d)(;=R8~TiAb%U!^hZzL}KHS z_m)8;IFEhAErwo>S@J001Qj2WPLxcDyS~DH7mu%&#B4CUT?9w!V6UFtCS7wxE_Fu9 z=k=)1k>l;2>11!c|7@3X)3TUtV~to~5YP$vl~AYCp18BJWe} z<_uj^A_%nu73~R6gFlc<7zaETizD|N9<9>LlOxW{5tFNO|Hi_HcrAWh&vlkka#3K@ zXooqQby(K`%c9h3a(^!`K|8;G`gHIVP#n4z_}D{i``?ZaR48hKpeqcKnMqP>GsBii zFfw3}j<{GVSvgJT(64QTFa4nNjhS}Y@K_cC9xR9SpJ*iQtCe1OQ(xHSTB*g??Wv8y zfcJ_Nd_w89Q@NuGt%29JL`#Em`*pk-fH{9hd8kzb&;GiCQOD(LVKYq}@$_Nlgv~KK z5JF3TVpD`JY|^W4Uw|9Vd|0>wdfwrf8~#}7O+wk(KWQ3#Kn2isKLY_V+gYq6x$EoM z2J4(FB96hAz>LfDK9%bzztw$M=R0%hwLVjphcVx0 z+b1W>ZsC<^95-g*BXdKA@9zvqgT9)gY!?Rkggu#u7;`(fse~vrkG)b&g_*4dJE(3iXe&<1wghyeDb#%*_{yC}Ar6(y&Q#Y**Jz`e z#nu`namc+V#1KSOSTr1l(eAPMH%H4By4J_?5xWaXz_fCwKWS?Onx<#6e5nn}&Dajb z?4Qo^z48e^7qF=Bap=uk z`0(O~;RRE7(`7RRs{zj092IY(=Xf4LKDK`Dad34{lSQj(bluy^0?+N5l%EQ#c8%k7 zR{CC>S>GT8DVRZ{Tjn*jPuwBENqg8hj7CzKIeC|G5Vby`3%X1>Yh60MipW@B8ek&_ zeE4S}hY>PVSZEM<1<-0U&uK}$&lG9+z~zNFV?}rR)gtjEjz|8USk(H#SAD7t3s2%^ zeTyAgDUOZ_8wQRwwC`UQsLY%LPEv#9T4x=fGuMAbCz#nOSS}dhM)@%1}4U1ho5b+e0J1H(;H~o$m0e10bP%X zSgh1j=}K-8#*}>eNji#JcA@zK+;VY$!Ea`e|6@?RUW4oH7pJ(=hsm2}F^?i4r8#a{ z%^gpiAL=)`bGr0o5ptO-+^}|7>WJxxpb$(KGwI=m;mVyg`7dYPY8NsjB^@Z1iANo{XwTot~*u) z0jPeq?l=an9?~_Z6pq)QEIb`;4qP_N=#|p>MX3!cT{Bqpo1W)El?XWlGlBmXhVW!J6<`J)XbZ=tHBk z!RB6#>C|xf(Z}!a1oWhEVtjDaO$O4tJAHiYKuct4hu~&tDz630%be$NT`>>3kGF+Z zq8wI(6g(4}^jT5n=#A@hIC$ivwbpJSI=$;=k%&PmpTU*>xS8vby>XACyw4phlg=t? zfXP=C)`v*xg2p_GD+hxIa`9a+!v{aKe@G(7%otchdIFRb>z|#LmFW#yM4G?IsB}`j@N|g?zrM5Y z<~LohdUix(-cW36{&ga2Hcw0aCQ+B&x@yeITKN)N7S5qi2tt;@| zZSPlhAYK)w{n}Aj_py#oK};>{!sl{-M^b3l%M!{YV#c7DI?4#C@j_51B~Gnwd-)k= zf;iYo^gn;YRnQ+Ee)*-?Vi1D!+IpsD?zI_Uj|z6lb<^UMsEONpZk^o9P-SZ4D_{x7*sUjJF`Vim?HFru?A9 z$jr(@y`ua>8jc}nD!=}WN5Fwa>?PyNqzn^MaOErWU=tPZzryYS&;Ic4BPGt#CO0V@ zJZCg6uVd?VGXP*CEz^j4H$pIyo-r*jCh&(17yrpdMofNC8~jY zHRcnfJeUDd5Z>*q@owVo{(wWF7pZ6bc~;bDI|%f&b+X>|{&!hRGG^yjq?dl#E4 z#R;f>G3gcNf^eE%`moPxkD>18NHJ1$dGcc8Jj_|eRPIF2BMLz(nGv|4*?<8$KGsVU z)}U8sQ%jb=0!0K3i}L7-SLnDoa^(_wM!rgj%+O}h<*^{u?Bon4S|tI?@UcRQXacWI zdJ^SOcIL&yl-QfZER05-mpe<9PlH;VUsP9_WPz~O{JMA*wNby)kBbAvtSjAKv(OYG zrdWzBl6g#)LvNKzQ#>Pra>?8h>j zZzp2mE!?}CL*i2XLng;$zF>_tM&V3s>X*MssQaWpC%Aus*!GD>dYl~=tTb^-o*mzM zC6(PG<|pevU_i6uA!dkF6r1rS6VR25XWYqI$mDkzVN5V_y%cphtBOJfIN)QVElNsT zkfP+D_}AWerno4Y!EJ$!O`Meo3O+$=os%ncic@cs^IuB6T<+}kp8_75YChRWIBRCr zX_#H-eBab$Jo)v$FUI3yZd&6ylV(IK$%6AQGx&hs&l}`uMp8kHz85BM=irn~D)c#9 zky-*-n9bObssYFpTK#bVSc_-Z0mm_V2#8(DG}hR(^#ulBGUH`SFnW%GYte2lahWOd zZRg1092~kMZHs~`;vOn;=v{7%75P#(Iw4A7;`hfsBb0rygPLHiI|CURcwsunIvj~= zU(JRe9Be)DJn}BmVD-TYc*OwHt(B%qTq3q0w-UQKfvKPP9LF#Om)cx+Y?tY5exj)1 z0}<|k7mURUHwqgcJ17_(`AI@?r*$?i@JT< zRCeCDP%J@9%&hSXW(Ui^cxKx8b(dTGA%~nFI-390zu2Iw;NmBy$&4xJF0>^O3=e<* zx7Tot9qmtu7YU2p%IW#je@H3JcT`CYZGJXbpv@ z3b{4knOrKRo@*4)b?YHw%9Z)?)U=2LTaR+PQCGl;T$5VJ37NPcaYym?Zn!8M^oawF zg%s2HeZ9a2zN;ql z0~co5bpCP}Z;4K|^EBLrc7OV4^Cuggn#KNeE|}|rwkV8SNYL%v+?v%m!p+?Du{?haoiL*vTncX-zHb zIS8(Hp}!jnF_`@* z!FILd;w#K8p66(Ez?|c@J_)XS16%D^f-f|A$UnuX9KoNy z+K2Pe7^{#A=N2F{Ag))&!S+&F26KYdd8QE?QoQN1ai8mma90YS7+pmxi}f!ahHYhM zx9WdZ&U!L$huE2q!?{gEZt{G7j=D#(_kvD3GPJQYjq)~xT-0^z)f=fONzi0HypJ*x zBpRh>9gerO056@)beWx<5wf+!bvu>Q=M1;;fIHb_re<4oULGJ!Vn9MbNY?=3xr**} zN&M=fo0xod?F;t@H`%y{Pi&TKJ2G25=W2In!S@XTVAaR}q`7~3-tKWlb(M}dIydTI zF^aqSX;}lr&A$GPo4viB+AfKMpfo`rLN5ZYDXG}B-Q?HSAD-T3_qyTBHx~fTtedJ= z{5?Kas-8~@pR%o3)LfIv4;Y`>$U&4iie%GkQ4#9P&quv}TXQb#kiqY(!9I@IYE zwyLg4qN!fJ(AOUcUBXU5`dXU`#mTFfu$TwW3ElMS9owrSro^L|oqz2&gkU~6-+Z?M zvF%9k&35Lv1hqm=4N<~(%uS;32{y(iJz)}adW~+qzzH=0jFw6`GyQAj8za??@sHJ2 z0AUl|jmHghz`p7l$Y?Y{9&bx=WN6u^_$42mDsv^@eyVMug=Lm^M_3V=mPqQr(EId7 zSFAwgp1#BAf@y!|5*-0Rk@yMdCS~U6bz?0SW^X8$+B4iul#8Yfz*2hw+0kM1mL4AA zC>`3mOMbYx#(J(2veotiE0^1n{dlu+rlL#!rj>1=8%xv#q89>vkip6g%prVGXC-<@lO zACGO$&vAEGWcQW&95h z_j)kY6OJE7%&yT_$JC$iG|Nd^Oh(F0U^BMCV~dAvH3PhN*;7Xo21fJK^m(7No_Pq8 zo@1T1UMoxa;Qc1LmBhgQISH#a3vfA-qM!DD2Muoecbb6x-=z%kB!?#gm_pBN{Q*^} zbgyH*O5``<=_ucwxkp3DxS}`D+-!yfv$gaC_g&I54yuWC0YP=UIvJPmhAVAXi2LRK z+vui+H|=3e0Hb$7;O;jEgfaMt5DbhE_dOMir(A@|!`URtUch9tNc%E8+xSMTRCclJf>x9_pgq9{ zE;}H1ft80uWFXYtxPS-7NjR|Dfv1Zjcjy?Xo z8w5<2_m9HKxHJkiitfA#6c3bp0o?%!9sZ2nm4p|wF&qJ2+hU^!n&RaPV1a!8XDmE% zgb!>xUzTPxMzr8bhY>MZBla+^?F;Fee(z9}@_)~DN`>{ME-r?a-kw1b0rqAaOt*V+ z@38x>L&%h&gSo8iPFDQ>$ABrX-nnc%%`?q-#+UT`7QBRzr%=tZ%nF-L)6=%#ViFLL zPHF)ec2Y8a^RHOMm7-+<_sR^QvC#@a&Y>&C5d?Tqp;!I9(d{(t#BF z@l~<>>*34#$aIXjBY3W>BeEFj4DXgHfkz=8f(-!@L6$wz{!PNfEzmL`V>Ia=)1e zLh|5q|DAruMsavANck@RilM_#Vvk<%ZIK4JB1*QLnN*P(2LW=Bh*4^c0@)jbzGS`k z+jA?-nk>i``EOH9$}!v)D!s=)WyRZ~%$m<3NJJZqJHhus@1~=MFMLODqP8fg$TR>A zeNOX!Ff&rA9yZAB-ttl^cw?+kP9~b;Bd}n~Qo+qC>V8JbUX9>#Wj^-!aRb1jx|e0| zG8kMwRhr2V@lwKo<;f=*|BAkE%bGK#{pMK|o5NB&Pfvuf*ID1mmTSVXN58^yF?XO) z7D=ng!sP|$24Z+$5ok<8fL&2F?MpXt%gn^#x!$HV6$Pko<-~y|(Za^VpS~m_#G2St z0>T4!dPWU%6o2`t?pVO{u*{i2N~DUjQdmD zca{XZUV;$yRGmZI+-a@d!o85qzSwr#da@O{udQ7%-zEFdDzyZNT~2=82|?#+hIlLq zd&#`ALuc)dWpEPw@-ZmC6ckX^S){$aF(?0;CYC`qwQaq56U6cX!1USEyPAQ;V00b} zIC`5-D{)a#f(l%Vv|RKq=j@=S-b4YmVL}lp=K|Hn#5(4epPng+)v6gLR+ew^_L}Ww zK4t<2a>%a-a2&4+QHC$1ct;YN{nFr9zU#q<0p6Nouz|K(~qO*&8*iD|MvFo z$>8j_;F|(eFI?JQf>G-+JOX(~R6;W`n)XdwXoq^o0Cp6g-Sh+CtdnTQGaGdO$o?eg zxtwjo!Td4lpaoZiS9_;DA$|>D|2S;!vS*&6O(MVb(tlZLX$>NrZsY3K&%s1$KkP{W z{&kBk#4`fMtN$JVUP}$2_kEB@Zu|yiJ8asyp&+m%K1)28`z%tQhuVF<=M0Y`qedp} z`0lCKrS6hb`<;I0<jHeL#-+`y4OBueV$gH@k0c$=v54@Z1DsXy!?JPQmu2_LGwHIQAVbLp2>Jt73D}E z6zGBC4KEYcLnxWfF_X-m00tuIOW^k} zb~7op4?D#dtRj1yneaZX%@*XWJ7`1aPp!Vz>i4%9n*#7kz74<(G5B3UhAb#p8&~js zd_e`|le0B;x{$P*iNPLpOdMI67xNJ+g!AfU`idAm#bO0)8AA0#S-f3HdVYi2%3XF1 zIzVur*Y|WMv8McH1iUP}#h1&>75MpRfAKC)lR+cG6K2vjmKG2ms$xr!+G7Q}3mW z?cG`Ot#>qO>sxG*q+s?uQif;S4jD;fY4? z)0+;ODHVAc0~4a$hKq(Chifq~SFlL70d_$yvrjmCP>AYlZQ?DMiYc%g`1GWZ>mUTh zP}d$#rfS)!l`m8IhCzN+|7*BN=9)6O+K*yfRT-l6GM&nplxxKs$fd?zzi5=cw9aXL z0Mb%-udWv!B+Uo@JSSG0v|H^P09wWWZ%qEW8o;5|PFs1rjb}=~9r_NBLL=-R>w_Ie zwJ+Hg1+ihoJwh2}K`aqa^9^SX8F_i{ndTta5g2e;ki}6;)~a_*INX5^+H!=70<2jU zr`^2w=gqD}o}wrui1o$*T#bNUM?=}+hPoGk8Zd(pJrP#|vzMtsFp*$1oP}0)U3_k9 z%1^+C3wTLd6{8NWxKxV+AfW9Ys5LYOnw5Y-S_}^(W)4k3rLy~Q_fGcip6>VFb395t zXnoKx8pCNKcOw)4Nm6Ro0Wd56vEF!9RZODnWBpH6d!o)#h+%jZ+=U=>J%iT zk|$@8Hg1$XMcIcvvyc$F4)E{TR|yE0SzN3F&Du!tuzo57XK~oidF=KQpl7P~H+Lp% z?!Cx9tOT{a9a1TzyC6zVPvyHt|2-s%=*p93(BM8gl64V|DiQi?;9@!Q)>$YQj4YM3D15DZM_y>{Y^z_RO!1U85;?oi@s}{ufq%JOEp` zz+CS>x?}?Rx_AcpL~;hJ!~6hJ00xW$R%t4mogD>_RjQpP&ZjUCOY*xE=w>W(x;(!& zRb$f#kdjKx*7GCIr$fA?#_F(OqwxYKlGBxmg=LV=sOhY74$Jqon=Y<*-rdWAt?)EP zARI-}W7zbxLDCnb=|BkEK6USbW@&o*0q?=o(kShE~ihJ|@BdjVh^|F^U3l~iM*ASbfs|4s}p?N`W^rlzo3&dcfR1 zc-|RJ6Xy$$PZP8AP#$oB0i-6jr8wRnUw^%yd}}z*Nt!0;%9HZQ-O})F%2?3^DW983 zPkQ&Z3fXb4a@M^2PAPt>CCx&WN2SBTZ4rHgT3d!6--4YcADTQqsCZJuf>f|07bm9k zbnb1jlOQub6|U^bcvQ=xTi3NNShW=~@B9_n-kZdBt-S7&+=^VsCHJk>;cW}?h{i*w zI)H2hp;+BLK;_4T5BGqKJ5ZYs5&Ht^`6 zGIn+8W0G8qDJCx+H4U?%@sGepY7c2%5dIr7mihy~4Mnk^)w>W^Fq@F6ouBMQpzCO^ zMfH$z){WOZ+k0c1HwgTq;$8__&#@~2sU}n&x!`bY&fIw5Jmd*-79Gua zxSqIj3688neaMdMVWgsME60MNYXgQaK&pU2Z@LP+LT+?VgbMSS?omFOp*QoZui3yV zRKo}oRraA-BSvPvngD$66y`oNe0Y{cmaz<(QvvOW^bwb*g#mbigpr%9acBT4N|b5SYoH`hI$yUGYpgC(>YOJdf8_%MUbV_CM~{`lHe~XaTe+!^EGU(EkHS z(}Qf>lQ(SynhDN(H-CM4ep3iCJrCqxLtVPq4<PaOrK0jV`yJ!H;XET9A@W)YQdrJM2R3cg7kPsF546YBEZ9`SjR zaJEbcB-1#}j*HQJq=yfl0azF)n)-|yg!{XE%IT5GXwj)^{IFN_wjz-ANCx_TCV3=$jsdLbzj$c z{_0FKr5wf0XEq(*+_{z}W*}sZ|6Jw-*!K(s;rKYdt8;@@-4IR7KJ%p-E5eHcGMFve zN~O2tinO0Qo#w{6s_iDfW;nD?U8$lbKL%g%X3+2&ihzzZPDi-?OvMk>$yR~0HO;g<~x$DSK_<1v};)ssqu^Q&231IKq$q_9OJ zar~3>Q-wu_6)`L0HL9}p{PRUIb63V)G7z!v&*y)c<7m!9FZU^jxqiI2b zyep3x*&pMD+^X=y!naUwE1e06j^ibLvvJ}?eQ$3EASJlU%q;t!ZjC$V$lJhz6K$E3 zvsP}iU7Xx#e!)UX>TsF*AR)40_sJlRBd2&+pg|Qa6vFartf4G+b#|63&Bi+Xr=wCu z9lUvlY+w|Bh&2cGKP~pnkH+xN< zsV9oLIbmIFsxuN**Krj=xPfI%WizVl6H#FX|8&!%W%q`_30uxne!!IAa$8MEY=3!z zhPwLB-aX?Qe*-2Ne-5zt#f39pP5AsuOLcvQ6HodS#3!Q*H9$!%`=8N4#F?vAjg#qz zPS=!9BAQfi4Y*673XkScpB8guIe7FWMeijFSU9@Lbo^$GC#h@9mZ<^SNuQJli94sU zwAn)R-L2euKMNmxLDB9fz@7rdd)BM?uyfrGea!%8Ta95=>CFzXu=(zAZU6W}@_Yo) zp_!6dPr|52wRJUTeTf)=*=VC9DrhO6@D5wo{k?!oLEr9;RRvxtG_Ah?!Wp5AN^7!k z7Y3e<^>rb#&n65y9<6ZiXS-5_-KJYKI=2cLLUnHJqu$QI0jqAy;NMFWA8g5gxB&E! zT!?&Q5pChQyzAk!wUlzdl42YFGiU$s@eGjEIL$+^LOVfyHUpf38-Dw+&(E(R3em^L zzdPJGuN13aY_1BeLSz@+O7D>0LO*+T;Pk^;f=BmyJ+45?7vHuXfay1*y&!P!kjP>P zS@1#e^C=L4;`Iusu-JUiH+9I6Dm2s@T?#&Gjt_L znyO~G4NZiSCX>8Vu)6vg9gui2+D9xKd}M_Edf$)VwTpOy_P>911q?AXUtwTlzGrr6 zq;z$+F0jIMe|1AXx}GdGM>F$Nf2H|h`HGm{%zIa^*C7Zc{XB`%=0@w64S7&Zrju>j zwIAyi`&NkkhCfLg5RU8Co)>theg6LZ-NUkN?*BNJj+4JIbKi_6yuJNVBBF-Maoi7Y zYrLG}xjMSCh8mRCXq2e;-|0w>qB&QGiQSWo+1XqO3R3nbFHa`A&jj6baKN7y`uUZV zl9LfUl2Q20f$09K8&?E{p)Otcc?CHC(Q+qNM4bV;&3n-Lol6v@Vf*Z_dXm>rUZy*F zWE)jAR_iyUJdh`@6#C%YBeKHpG6P1_{Hc#?MF_7weCq8s1(D(bUM$S z5S*ztxmi2_zk2YfMyRX~n6(gB#5pBzq8XFxVY%nQbW`5h*_AA)ePF-W5M9vdY@uH1 z*k}A>sOaMFUw7buR2~!!C1Co+gu7A$b_hIjA*7(81!MIM|K2?Do2 zBo{6MnFdCHgVlkAnx-dodRn>aobYg+@~Q(5T%mFG`6S*-J$^G4u;sA6F)F)1S>b#TUtg3Yd#fAZM2A z2NL~-V&o6^(}T|vIM74K#g=N5bKp^Ei_KDEHyx{rJAd^^639m{YR+sf46JYWS*XO% zSv+D!HB|io$CevBY16}bs)<@)HIHa`fiuFU^ath;I*$cRz{*ZIM9rjnk93V4+&b4X zYwKm+;HCjtX>r?S^ye?asaLu#tXqKr?^X6&$B&6J%h!U+Dk`xxzjn?_`s;rPJLIrEnTKgme1qhSA*Fy}b0{!A6eVz+B5}X~t(T z-R-=#Itu@{Y}Ajhbr$h8re1K5kWq#-_e17#Lv*f}fo={w97)1i{&cp9v7gL3NUfZ#RH;^qdQx49a>HB&gq<$buCamO{fD9~q zCrKm6w7w<~ot9%|UxO9No$r3iI#g(u1ko4mASDSXa~OUb;{Ib;4&WkdFPy_*VLZhA z;|%z~>#0>N@3Syi@Z^~Pt)8{x7bC31oyTUT*ED5REPU!Jn;tW$sV4F{NDaQ4rtW{O ztA<(xU4C|s8D+WAlMSF*z&X9;Ng`i|9f2ab9VWKK{8|*>wgo8u;!cTyHmkDr`wv(9 z^E6S+L0t>Qb|WR#Weym{Gp>~=#-fE8708ZA7aXr1pw=qWztI`EbPo2wwLU(V2`Qml zvM805^ADDbA!7aXD(k9ZB%{-q4)|WJ`ZJFs4>`PoZ7jRvu7Yutr#^7k0L>4eMoy#L z{^vJ&;DO98puI8ORv7t3t>c{^R; zo2K35o*(KMp{56hIGsZ<(3Kj(05j!;>0+~5QY2yKGP#1&WWyCWYMd=~ic2|uU)KY{ zEO7$2i5UnumlC&TEyNAB9cEf4=KlSbL5<}(ITrY-b7O~Mk2TqYsiI{c(S5##a&Oe# zZWdf!Lgq94h~LX1L-Fb&o#CpLjQcy|P}zL@p+fenN9cq)o;Z%w=z@&L$*7VQD5FZN zr1sEMrm~NqDx9*~+8oK1Sb%yn= z0=s60x?zPaUy6`TT=aRx1Tc+vARz5fJ`vw+XJUK=1FF21DZrGGVgS0|IN-Ii+}l8W z9&zA!4o1Jqwm2Gf3s`(mTvy;~TuQ7uFF=(jEEJ$$`owXx&S0*4--uD%-qztw&nuO9 zey5O=pb7+Fl`Bqo-o_1zZ-d6$SzT%3lS-LCHA2-=z11qgi_OVtlp6t_?Xmu$t&Y!j z!V$|3*R|G9a7N@`*wV-8f-D-WNUF38S;{5mv#LfnDJfqR_d5z^24(1FNc&k^lJ^mc zAbypTH#KO1bt60om*p~$*CVjE|H74(HBIS-f~nigcR}V6m4{TP`9jII#Bab9?D*T~8Ajal5-?VHxHLheg3>#&4#8I;_QV36)Or5wxW zWZ3S)Z~%c01>1@$;YKl*A5XM)*na(GsA9JKOcXNDzg5t~XJJx;MyuPgbInxx0BoOw&cLLLJ8j^r*5zH$=Re((kK>J0m^yAI@D z6TByvFB0&Kthx;Uy4*FWCnM-AL{ESqLm4O=CoFtswzcDIF(7JsU)AWmEXf?g!btvH zBp5QaZfk*W3R5RyCxh-Ov5D{5I4QE?GG5cI#1d{TRczhfD~x@KXGLcs_r+Om9ie;doAftd>rdRK(F`T~m7}?u z>4^QMuSCxLzD>bG)b)b|^Ls`^^ekA7O5A3-ruQHvg3YKRzr|e^7QlFoXYppebp>v> z)e?RuAg{N_%xc_IcxjqCxu3fZ+&cNjQYBs$-IelJ+KX&&@8s^L_@%%k5~%c_%Dn6s zP<5c&W$GPVVvc0oqa%NIthZv}Ns=QGQ|j8Y2TyN3$wr4PnFTWNMJ-_}C&>kFe0ig{ zA^6={7X+<#zjW0s3@g3BhseC)w?EcN{_;8syTU!svjJ6sbsEaDjU|laSK+$poYl7v z&4F_c45^&jlZi+AZjn;X-LY<7XLnm!;v6aU3yX&6n(jLDatEw)*dl^=!@qdLmB>Ak ztBJ&vm;x3S>BKBkHmO7t4&Jp#5kt?!TqdS0GDI&&Fk)NjjcCHX%mTj1tDeBtn&!w+ z4LY9Lt-)azEslc5@>ckBw1xF-{+S-?vke;?`YA#=jsuMOQy(b2KcFUoZw`8CUX3~ z2MTdvK&3X=ia*J%H*(Ls?1Zwc&t#Hjrj*CeUj8t zwyMqthp6D*Py{<;@2zMVEGRUFpLzkgi~*panqB@rxhKY|ech~#0E*w`ioPKmeqqSn zIgfGAklMoOJWkmE^(cwoY&ciCkGa5YuI<~M9faV@EwD2G``f~wA&a40l%Rbx4BG(D zf^*sy)Bc^!{aI<9)cr$ehqFQnspqDXE4OYA6`56Pcx^wA2T66?iew!%npx6Yxg&{t z(IODsK-pj^76N-bvwY)A{ z5BpQcx~qxWqV0vtkEEDw(A3Y-;0j9H9ofod%-54E#oquOQ+BuZ{L&-=r0eJs)6+ zUAuF8*(Q8VCrAhSjbaH}Rz>%}wnpSykQPvL(KPkFs}i2?A?VSv##ZuBY_UOm;>^-E z?uYds^I|8T>iF`;li6kbb>cB{bKS~oPGJVB_$>Q!E=88`RIz}Eyfg}>#`*v3DUk68I~8C??n`$pcPRucL7K4ZApd?dGVzoFjp zQ$l+m*9;)viZKr$eW`XMjFS1=Gz?%Q~Hk*bS$$9aDr97Z`Xw;9^lcI>nosqrrZdV!6SNe{qmt zq3%EiCTsi7RSB8Py=|X+in2vP?kT* z1qI={Zs#egq1)0EAUBJ9Hr2lOcL*1JRdNGzQo-1BSI97%z{o^|1o(;kl$*yK2iytc z4$V!Z8{b~B=eT5wv|p6qQvjy2{5u~UrL$`5{igWtVV=lKvmSEN8yj;3Uf?_9?FMpB zW5I;`+bv?!+PJ?`elTR_Q=%GhxGNX^ng}>7y8vW5d_G0`qQY^4rMT`OO20XhZb*|Q zyyNNRB(TVTNcO^SyCT^WnPRDwmQV|tYu0VAIS#-<@(a60#gp+P`rlg=91~VUb)i2` z%^}US#xdoi8w)(mu2oUS)ptj8hl(b@zI|$K)|=1jJ8+9^b!Duc8|?LhxyOBc5ICFN z0nO7wfVi;^&|o%cLp{O;1&2s(9$0@j_Dyf44ZXZgk~CNhgd%2>PJ8tI1euS zlSnUsnz*Uy2-nJxEaq!_{(&{`)@rl3*70}OdH74R7X8w?Cl25b11j)ECT!Dnv4!Kl%6r5QA~Cy^GKaqVxv$zKaNmH7oCq4G&UYaM#|=#7 zzA5q$WUODER&3c%Jvj|SMuc+9^VRn7JI01G(7RSFywNM%O$mZF5_D1Fq-3iMYJ6rj zQ#K7`)(COOP8Z1eG%M=Z*)X67CRE(Sgt3$TE7}^Ed&ifSf@iu2FT|b25R=p z)FbN;ynu;v+&k-ZLQ&Z8SXTCz-Y-yOI$)o18~`EsiT~U@o9m1%3dsVuXQGRx@8ExGTsbM?uo&VH-T$OX`-ji~wnD`sjK@TH$zwKq5v zBqsXK0Zqp{pjbd{?T*}>xN3JNyuOQRYX*nEi*a9-37GxRd{nFI`Z-o*d0|hOv)XrR zc*?G3e=}F^40M5_CB6yVdN;K|5C>{hG<;zj%+S{NyJt{=`8uz4z6=-DWI$}*w%rh@ zSXuQyWH9@ACXt|>Y^zziPifa)ljhWYoo(5kKGL@GBF9FA{NroatcSEZ#G}m8=L|}+ zE9}OVd?Py0ysWRZayMgR|IUm<}b8LE6WJbZG z+Cr|-7yJP7V;J6(4a&v_hlAe_KxT|mMY#Q!*EMx@u)o=T`N3^;pc%5WBGbIU6s!t; zC2z=cC9JdJosfQ6ipd;5P&Bh1`=E43e}X*_zb$lk(49fXKO12cdrF|DiiKtQh!wai zfhdayM-n50lfZUBFYb3iefx@5-Zfsi_C`XVwn+GE^X4NJx9ArI`x`C;ne|&7`DfYu z%)GA0ctO62oNE5TQRYuMKHom*C+F2&Ro=vPjAfbF{;q5SjVaMh6!^o`@o=fWo1*4GQLO zCc*O1kN8WOBK|?(R*W9et%^M9s6w?UC%nAT#2`(@szec=r9{;MjyucQ$2o2@Kjl(H z@77p?AC5!N!f)^PhiwB>Tt{7XX^!C+F3+K&=pvI+t;clS7osG7luqDmx9@C)iqx%& zui^$eP=vK{-}q@d}=7bgjAiX7GY+E;;HCL^e;Hsda52+BbHaN>8e5UToa@%&e95J z{9GClMqp=vuT10E)h--6uW)D7RIT#++Kt0g7X|J)Ev4*ZiFa0Nsandci|?QxUCsPh zzBn|ymemTDJ9P`@?Yv1+^w*_m0QE&Hir$Mb2GhoE9hDc?>(LukTGsHxwyak*1l5(2 z%`W&{N%Gs6EB`)KWLht@;>RAre}IOz-v5^(65+Cpz;vq<0o8uksI^Ax-OrPj=B=>A zcpGi%se}9$Cw0V~ClWf*lkuD8>GvTH(q;Dl~2|AJa@{D`rzk zAKvr=MefhQa2lD;}^P8c3haCt9R z`XE~^ZE$vL5s)D&l)F%_s8P#j&UidNHV}x81x#h*av;=>%}bZIKjj~bgN%{S2V%bd z0NEqF?vtfzcw)BBuJ@o8tso0ZF~!hE$g0CO0eFR~7|V`i!6wp&OJn6~x#}5QVbNz2 zA#`fgDT^)^()T9X$li=N0v6AAE`*H0Z&YDC_bHA4qGq}XUsbVEkT#xe`Jz^-q6ep5 zArD;>@^0iOAZyaU?~V2PEWahLPocBZwt|`vt57tB^4|`R$Q0jN??a$5&}2{&e`aL4NfRuK^~jH9EJ^q>4-L(;1;Vw}KE4 zG-)D$y2^`17{(A5qUS_B+86dY0rQP{21UEiE2GK=3=vC14urbpYNna*6pOtA^b1Q8 z!g4^K%YlVFQ!DuF?#K7J8jCq{p}TR&W4$re63GoLYMdOJS?M7KlQI%jk6b`4xZH`W z4U1okS!kf8VtS=hoeBvR>i6zh3-3%lu_mG-zQO1?`O@_`qOKxMgvc=EUyS9%XGmXs zg8W3?*Ml+81^@nK-o$Wa>FWG1IKqtv%ibw<3mb8)dJF75QnRd`%+3VhG)4??u**w z!YYBgC)=h7(u#8@;TMZ5gwwo#iBbLg`|ue)W)ldN{S03#8yuzVZ*6b+gU?QyiPYSr z(pvR!SN?@)CKMWURh!;4;l<9K4K4`S2T6^{(s1YI!V- z=f%dpTW=j+bHi;pC1Gs38sKf2Y&Ri*%nVhJ397Pl$3sqb^1z zfsGR9Ed^y#_KhquEyuk{uri_~Ov1>tyPjUw1elH|BRj{-Zwud^Q-NS+tD`{{32Mco zppkLMKQA?|_v~IMVQecgZ&pP-#NPco8+0>CW!Ok8AdM zP|-`Yl|7Z2r(E2R1*!GuJ=uh7P>EiLxVK0<&*S5R5XbVnTEPG1-G}>hA5epIyEG_v zR3R`!9dnXLUzXO#2f}WMPN%;As4Y@;yMKl=cX_m8#}EkExjTVS8q8FhDW#HW+YZL? z8dW~d8>{ot29)?)StMC;#2!IhB||FZqZm{tBC1=-eM|fhKX)AY`ah}v5+j3J(>09k*LLVIo3+JU z1gW`RnbyBPW@(WNA#D)%ad5!XsM6_wyaAu?Yn@!D3{((bp^(EHhARMI@MM(ubeo zG6on?*TaB0n*vJZ06#Mw4`tfaYeeBlhRxS6R)xNk_xD@z{d)}?)7psuQ|l6&POg=XpLS#eVsw0_F~LGd3;QhMFU9*Y=(wi<+$-wj zwGiiXiyC>G?Ng@6AMm>Gjo7&%)~_Ax5}w0zeOXFc)v6vqStJ}Yex4%6gz|yiizyC1 zLpvl9raNCDIkAgfaZNbNGbAQ+_f`AYG|}n^F(zWv3Ka_5vz272pu}^bKGz?+ z%!RPH%&t5QMg<}7#|$+w@+Y#fHvtwE4|?RbU?P&I6-KZRyWUkQv+c7)tk1#6HEaA< z3ss&7#7X%Gx#~ed$FBQ2!42ZE!knDP8+eIkRRvV~vsIc*RN^Ge=9Z0OF@ILY&qM#@ zO0FL69$wS!oD*{TVX2bHmFTTnYOP@fpc^OxoY%@~y}F3yfY5uywf9_3@RM<4;1y!| z&V{jR2d0Q)fC;!JSqlqJKZ>}3d|nx;e|C!r;e$tJk~|#rkkyj|ePmN3!VK1B#c!1J+Aq|79hIu@HBb|n$)g=u_^wteOxg?@zae^TclMkCj$i}?H*A6r`TsYH%jAuP8)+>fnt z?Ftoycur2JfoZ(pZ0su2_!ESAU>hkie!pbNb5mF$;)o3jI}szh^OkC>V;SdzCS^@{#hcwGxXuB-W!KTC|5J{_UH;^U08M{-w1?AqE5glcuY4d zEjtqW7HUMcEnzK89kvcRQBwd6#p7DY(z8iD$6k1JM7gWU;~f3;aIwWyA*3>alzc?l zyp?Ku;}CqIpWpsTS0{gu<}t7y&DD7o*AMS_7}|6@4EQ)Z@2>?V|9<=$g+09IRRvl? zNDeibC`G3pie^)ektOcnc@uuD&22lpsx#4QsyXk^C&&I1y?*~XqvcoCx$u@qMu zMfQQ*)c~ZH)nPPBy=meMky9NL57(t7NKDWXUsr>AR2T!hH5_k;c&tHAa zMwAo6)BKq3?xq8M5z;Reh^#LZWK` z;4zsprsup__VQ!(e2-ZS=;2Re7D4y|*%zMmT zG6#$DY2hLgA($#M*ZSMIv-F=;*`I@J`uC6n`Xg^yCR~v zUR18HO+B%CkmZ*@G0Rn^gdA)=Z42E2@<*l(zEIJySoSrts-n5LA(h+XRY2HkV|)*) zhZ{kMIBuLj9c_2(1B5$6wDw4eZ@Ga=vR4CO+Q+Vc8wa2|TWi*ys`Qa9&BxuKLDk16 z+Lu2u3wx$h&iiS~$SJ9zQ2F zG)h9A0_k>^JD1tkFh7a6$eO7HcdgAA|1-GAzpfhes6ovAFPV-3q zuiu9gO~NKN;nUN=7_?c6&FAZ>Pd|1rQry1zxTz9mJ*y1lYT%^;A%!=O-AY8?e4*c} zzvh>o=X_9K)pNibKjs8eb&ow4_xir7IbP#Ye46wHIyGO@3x|koCTHZ@3$p7X8!>OlK5Q!!-wb|H6JL!I4-%(2|7m=GE%FENL<0DOpJN# zg05`O0AiZNGbzqWjyWTzm}+!JeYX0@k#&_(inzJ>O*AUlq;~zB2&3>8wbB0DBqou! zwm0v!LLe(Z&5;)7(sP4prn)DFMLgd8DyOCwXls?yc%Le2MAe?oUYl=FdrgY{?cnc# zS=l=rz#t>qczOvuHX3KLpf%3<#F+O*Dj@}UC>|zfcPh|Xdu2g3@J#EwaUUGui;BpAmhG(sQ*;6b=lQ-^(sg73ex3txP zf0j|y`8*uF8^!6?$9AsU9np5!_udiuzV-1%vl>t9ykDLZY`*L}8$o;rkDQ1(b4lj7 z=0HFF;7}lTLYjG_?$Dv`)JsN)dNhMZfAMz%#3J#1m5)`4DhXn>Iwp^vQoYqTSsGaE zm*`6pGW^mZWZNst+<0Th$C)``#-E*5QAWsa zprkp8_ME@>PPG^F+6ltRVz1TAY=8^?-1@6T-1KAJx8lS#nJ{Ihu~RteB}o4mxhE?k zkq6m}mU9tyTF>QuMz^L?>)=WbIvy{mq!$AJL@}VEm7{< zZ=GtuB&}$8jkFQ8OW@}bc{@Ht!Ar+)k^o<$6Co2@1HTU&KuO4rAg#}O5pf4Zu^m2r zAz!I9mUPhf_d!8^4eIy!LX*n?%7|M1jJaI`cDc3ts|~oDsbV`H$jMwUfH+GFwhvaL zd}%mnLRd%1E4eM{%NQc5cp@H-oa zbl#313Os_x!qwDDB zZla?TIJFr&ZAZSjPG4x-To5)kycQI1KU5J3+`%Aulxrecjd}(?uMC%4j|82zN>LI6 zVpv(l8We(WacYfviWsdG(Z+fwxNqthR_=EE1-NM9Scv5y%^t|TIx(#)im*XLZd^n3 z*~@&?%raoC&<@x8aG%da^e2Aj?xi3QI77-gBrrJOi(%@ArE3`acAq-q|5w52xo-=1 z=hd2VqH}8>b44^WN^J1-1xNiyU>zWR0NHvV^N=ae9WRr~?ZKEDDHVNNi@)f$_TgZ) z4@5vmoYanE*SG-XDy`l)q_@K805&9)87!~*TQ*v?t=iF(AVQ8@;6M{*@~!h_@?cf~ zea}#zV1w_k*R%SjqCyVYYDt5$%o^#gc|qQf3vr$NX&pebJL-K!T4%_Rxm8)uGZ&hI@ZU`EZlq8?qwVZQt#a}Qb+yOu7+smYru3?V0mQ?1c|o-EQt zq+N9e5k5B<$ou?1VvT2VqIIo{eV9lAurZ)rxqOYC3+y>0(?2B2iuqWtA zUw26)+4`-^Zm;>%J(VYVu)pbLf7^_G>oV5>Ucs@k*Nw}=j7%>e@fDQ zR|R3;@5?o_m9&J&A5&L5?>2hBmjIZ)p%@=U-?Lq>mRSjA(5c_(F>@jHc^Wpol{&>| z3J@GKi@njPns?2_64duHqqdCg@2`-lhTwP37TVyq9|`$4DO;FKl<&UIDFgRMl{t9r zEPKB`4=j}EU9Pkn7=3B;w@84yVP)T17**h4_1~IG!-2bn`V9)i7+}HKgF-&E zYz~=K3Tf%v2djTO-;6KoPPmlj1d3Nww!+%}C=x4<=&2xBaIG}m^Z`t-RYK4ri5Dm_ zq&@=m?Ci8_{knqM;O1^|SoDDhU=M9WSfzzW$6FZm%!cnmv;kN;j8`*)awE{phfeJ# z7qz;=5LSY*T~_Oj&adu2HbXH)@`Jx>22fH3S~*85WD#I>JEf@AVfg2}2&t?ZHQkM!dH zgYL$>{|F}SOnSj$ahl}gmMu*>jP@k1r-VScnVg|@EnK=isd(a`b0U==I~VC>D15if ze!Rt*CcJ<8^RwHmte7xq#t4{VB8`$`QH_o#>jg{gHP8fF`PCVZ?B6?qzVzyOEeNkL z?q9fc{kx2y8go6foMZH5`ejj`b%CVf))B95c=%HFhSH)fGeo=Gpueg-{BC`zAgy{_SgZa~-5w)8<4RNW*(tkmK*6%X`*^dtd zKiibEBrP7TUNn&nHf6X`u4<){##dlm>#Ly{fxo)7GH%ng_-mj?agN5})$tsX7DiHY z-C9pxPOYk#8^q>dNfB~@k%l#AA&;_(*CEV)wCoXBlzKScya+k+Tkjb2x8AYV_lodw zitm$pqZPQps{JdipGxk$_czK7F$+9vMPc{`3PS<=VzQ)cmAJMSSA$Lup!Uapl~%ST7Riqnj0&>38U@c#5ErQq&Rl3)T;BQkkhCo^MYzQ zsd^}c-g0W{!r7Ru)qF&e>vI5(n*RN{8t3u6a{Hk~2oz!vy>)lC!){4?+y?MZ0j;P& z2sQ{beS&4IJjs<%slhDaeZ9f9zss``s6MSa1y_}1mJpcMcJ-8g1{OJd4}@$@dc56? zT$nntzeTM%@RgBU!@xer>Sn|K-XSB@&=T{PH@bBo%x3#;;`=-s%^GF2@@;Rh{w{)MCEu7WF`o*n1cGSc0@jb z>V>$=n%P3~xzIzZAb)Yfmfu%_PB9{aO*K@8YH5FH>kMR^-=g5)H?3=;{|RT=W5GKG zBXWw-Ocs7j-DyFb?^Qx=AZXrE-GNIB6i*Yp`c=wvT|1r0gU{}z2Xht|PYMi>sItX2nT%L4CliI6<9et!Mx;}c^2K3vjKyXpB53u9ylC-!m!Qz(d7 z40rVzSbHsj$AIYvhX+o)B3fq7c=7&{u=S^saZT(#HaHc8GQ0y}Wc^U{4!q=aga87& z_H8?|h0%gA*T#_~-kC}1%gbaVRb1ICs{kF3j_wVY)_#6t)aq$A`NmMQ3be_JF>z#U z{~#f7V^}y4G4^K&9@=G)9Xjw(k@EEDidmieTH_y0A>)bO57*va1>kZv$?V}1R>*x4 zCsx;i$Izcb(&%JcrWqoANFH2%iVB)&#ZREHB?tBJW3@%;rCqCI)oD(9paPa+qNhpT z+w%)?@*S%xt^nnr^o2%(Sifh`WJ3Tb5>Sl8&&wP?DR(whVn;nP?P9{Mb9<+4b*r_m zV#?~*1%NCs*Kml5{sMvQP7KQK^-c}W%Qgnxl7QV^w@CB79Jo}Kyr!^E{u1~)##!}z zA_3LV%lW5x^exkvgtxqyVF(|5;zUHRkm)8I?8_q3Ph^~J|nvUTbX+#T#$**4-iB& zCg#NJkp=P$J4?D^B@$ZeS&ssRN9zjvcXTUPq!C9)1rDA9fqRcP%MC*LK4+sYDg#Xu zVJB@m7$?B!jbtl_Ee@6N4ifTOd05yT<$vsbLN7PA)?&ABfP#S^NDv|75C6FyRfueD zq5l#e!#8QxW>5f02W}1vV%$?T`z4G`g-H-8Oq7p;H<)$u6wyKd~ALJkoIPFVXq71#f|g8cmVVkBEZ#>wQqr zkIaFRTn>MwRMz%c$m+TPc7>pKD%bhxC?bQy2#LE8k`AADswtb|%=p1v*gJ$u6r)ZtWKXJFi1Beo4%4t5sgE5@;xCh!`y-1M|<>%HBg5!w#UQx0~u6G@N^ zb=tt`Ki~Hy@^E~3;L+&bv2%An@xJm*Vw)YtvVF;hw90QaBN`|9&T(~aJn@a*a^V|~ zH#cQg9Nyl`;$c6RNapT6ZyU5dadGh7Jtb=95hgVd0&FW8xL9e{C50K(t}w${`C8YX zCo6?HzmC@TQJ!~6&~}*hPA^OD1v3$JB6rdbIq?lBy2~^!s-e3UKq*5zn!7sL$WL@k z3tNdkxBDyUSbqaSyuwXGH8c?b*>h$hb{Bls=aMen-J|{YOOV?empGr-{h?E_0Cnk_ib7JN>91p*q0o_8!7dM(9XZMMo%QZjWgFg0 z<~a-;XNp&-6KD42m_fKw){SL)IZefTSsOSs1euRs7f{Qpvw1gDe7I!3<8O(Z$r|zA*5~c>qws>>$RD#>HNha6E39R`DL(ej?x8JK}`?%?`7o#s!SeR3Y?M=CU!rMzJ|#9zEN zntR;a&tz{+X33?S3L$Hzb3@J{nP8}vsCY#Cw9y)wsr)C?*Dn!}$7hBL-7?$et7)qEy zcWXYD331%K$KT^*5A`4#|K!20!%@Vxps%WoAh-hNim`xbIQsAkQ&xC>;H`qFCmX1y$61IB3eakwf zL^6jFWRCgYuaF0_G{=GeC{BFYOEmv~P$QO7QaF%31`u`EZUeAqQInWqnT3kTllu^j6qCtluX%c3wlPuwyp1`Zu zS2daEf`U0#nI|~(WwngR9`l>luxVd_aO_%L7?G8&(@tA4D|-6Fzrsa>zl4igNbjIm zWD@_Eb`gc7L4js_xh&Fpieq8f=b!>SeU>-?4Zu2@Ri{z@Lo|}-O!eJap_0O-(RwAM zv~rlNSRRr=ua4%#L)MuxQhD#}ztt(!GU2+(!EaD%6>FgseVXX-VAn}W8W;YLVXt98 zWCQ~)ELxoowK!qmkPN{%(& zX9QLb+pnJ>g)*XFVRsiEZtH4YGyr$;z~?chh~@|A5O(Ihk$F|W5Bgs}1_gJY?w0td z+3hcjgLjDP(b>yU=~5nAWEAw4oy1ySj1Ex#y)>cSItVhzXQAUTcqQrD)5%0@L~-M~ zaqSSq%Tqd7qTgPG@oz|(ZrA&)*fprV->RisygOUKs)LQy=s|xR2TTSK&lP?4{J#oF z*%;UbR9O}76#o+FT^L^gQAcja#tT)Vtu~5_60MpcA|N;4bP~6NdiDU0|-dG zJvMZJ+;8?OlIKw$w8CDv?y^tLAu2`g9;poa3Ftv@{830oMlcqV(+$>tEJ``C zq!C6vFV1n!U!oN^sw%9AxH?&TKbr1PbW^oh*I!u+PkCp+!@OeX89?=F#z*>ci!_X|O^1gfwY zijprt9!TUndWQwZRgt$K&d3mQ9;0V<_#HO$=dzLJ{QpZM*hKp_fgs2#pZncIM@bZ_|j`IsVKq&qdt0J{oBvbq7IiQdNrk?}4FC1}^$8jg zmh2L;d-v(Sl4OOJ0xlc}5xyNwkAg;-hP3_~i~Z+k4@}sQ-uoJgj5&N|Snx2q6#?x} za-;u@!}#+v6E-uv9}e*X`Q8tyh$&)DLL;(&{cYrrRcRsk4e^)mUKjzsK;iKT#A5wh zp!3%c-9LrA#c>E>LUOeK^EYWmuQQVU=bu>;{$Wag|J(of&;Pey4|4wJNKpjHmj#k8 z@#wgClz-~E`fQbW#SdZB<@_U)NJhoMBc}v&9bm{EJa#8YGvabOkOweFHUtuGngo)P z{0O_{QbBtkzTwG_eK2x9_Lt)sSpz@69r3tv3}I*YNXXjZ8Cw2SbiE;ca~Wd<-bPMu zn5!mULGS=hN$zV6Je^XYgn?{|=|MLb10K7z+~_rWK|41hj@#y1dkS|R0-OK@_@C7o zOs({ilM(`DxOW!vCXi`MRG_bn%jwKE&*5@g8Wxm;5R9-Wt(SLhOy`d9e{BGvNoQvK zg-$?J6F-^MJa|cX+0*Uo4=nS!|19O6qoNFQyPFFa0aPs>2NC8g&=AOifPvj>bvzNy z>`v$kW`C4BATC*8mn!hJHhD;Z=DnD2K(e$Hhg5_5PX!z#rQ<;kJ6_QEUGn}K1E$*% zZ$~J;*S~+e!XWxX@9^OasQ~lK4PL8pKL2@?h_AdPC+(B7T9sqDYu%FoMdZi|^ziBk zbz{|uMxWv}LguwZ^q)aSIza_+_-6wrgnokgt$n4g+o(br@ggkbbfP<{=Rc`{5AZib zck5bbo@s5MHmwhP0ybxK4lsE($KkiMFn&Aa?&|c~!QkHS8M9+2WsD`j4E37D(r*v{ z0Op5Y2T-3I6disgPHEV)ZagbgGz3^VybZsh$^{JCc!Yq8&PZ6TQ1jE(Hq1OzZ~K@1kH48FGV zAyfR7FlwVcj>9e^VVvwRI&Nx8?2;h%sA>vl_(*s7-M6WY=0sh4sx?|>Z=Pne!+Eo2^E7<8m(L*2|K>}yXA)2qSh=?*?nqycK3hNRiIb%hggU=P~f;J;Ss_;FJG*4>*1pU*V zIC6^P)=|WWL6T!g5(e-8fh49#bM6%bZ*%)pk3R^L6Bm^Am)ExJwxhCPX%g+Ez%#iEUwjH zY=GMEXKqzb5pLH+{X)lIoILo%PWCfu@g{Eg6FhJMmM2R3e|i1*+~=(U>+bo;RL+}7 z<}Fq{D!igOiIT0m^;HwhWW2TOyf(dRpF=c#*>lf< zA)Slk{qp;dN-dMFs-epTn@3C>Xu=K4twR&IZVa2zY5SAA_X=j8orK62`pgv7q6)GD zlNtJfxQc*lQWOn6k6NQMM>ASMN8j8CJE;9p;v3w0gexrJhZekW8flfM2QJ;UjyL?m zE$I}5od{r9TaMnVboEt1O zx@ZkvrLHPrl1Td9S>rFUZdJ1VWu+Df<}5o-O=3OzgT8aJk_p zs$24M(0jLOuRH;C(3jT<9?6_TPb&@(udsIF)JPr{OiGKM)>7VT2vGd)<+s=nu)gnT z9)Zhj+CS1JnRSRflJ1`>HYTVH9PmZOL0Y7t_Q|HaZ-xHb9y zZ{I=?6_gNZKC~bpA}KIYq$Q+VMWnl9LqMfLX{iy?G3jO?3L@RYfDzI$as$S;=i>W& z{(&9Gj{Cl^>mBF$IuFI`Z1<7?Ic!u}HHJ~_-Sj1?M_h_vUc>!7@?RJ1JPQ6xhr-d$ zs20#ryuo$nEcY7TB>`Qe>K~K3OkgWNr>h-;@KWEMrfskm=#5^N4;6akp<4ZpL>3I- z@#6Mr6QadvY39}t{&!5mOn<`b(e+dN0*GGGE7&PB#p1CINf8l9j)I8ccr zuUCQ4WhS?eg;?afW^Kzy&TrqAswDnak7beLh2F>aGqC{Qj4R`#@5s1i7{M!1h(Zys z38Ip|fg(|WeqfMq!ld2xIP`m%_?QVs)AxaHP1pt-l%jP7)Gez` zq{>?Gype)j0ufBqUBgy<%L|>#=XF$lvMJIn{Q{<0wy}!Yu!&9D|7q3RKO7)8IPtRv zsmo3e`RTq{%Z~<*Z1-Oym%8Wbm#&jQ?p)*6-y_5}40P$NM01R$>4l4h3-i6|0B_eDJY0peCQesXGlhu1reaRaU7qS^n2B@WnTkpMlp9pEL#)7YCwIM z^W+>O1BPdF)H$5D6l3nnYuJxhIG7O-p+`=r*3#mV4muMW9)Jkz>d&nC2?Du3n@N)d zP2)iq7y;)97S%4FC^ugP;UoZw)J0;ta!!1`2eJg5EYcpa_u3?H2W4T*|LCy3_ofTa z_RJ2Pe-Ep}%lx$fli^~c;*#5a*%#@VjCS>VNg*P@UC~}gh@kDBs(NaBm9AB;YKxgw zadH_bUUt5>L?^d_+ln0wfJ`WPeRj;^MS{RRw&5{(5qz&>>mup(HA3iCQ$xTTDgY20 z^rn%8*2l=CnBXI?O=9I1>YfraVOT(YrBA6Dq&lOLhcEj1=&A&`lYBO(pQlN>ylaL7 z0%(u3^wsB)$q#l!Ks+~qoLo(dzIzh2O-$?wI{hu1*Fgck1fMj~U%Kah5FpR5ot=Eo zQVOKBs8d9myi-*iOuIx+Rdp?Ch(9H_`_!h_zbp1+RwC$Eq<-Bx5bHBtq!R!YW4y#R zAI&fR;DfwMKy+|8$7U%#2%jr6EGh>0lIhrHA5gf6K6K;1`3U&?3w}lrERjR)MbYqg zpMkUdE-u{|yNV3(KBWlX*Q}1W^`=4BAo{)@q==Sx@QT@JRNwGyX+8x2da!{4Cb70h zAqtQ9ttZN)M~ZYVgZ2Nhwr$f+Ren_Cj0O2HaW>$|dt4^f)>ygz^Ep1ok)Ss-uXdoa zZ5M7aS^r6$YxvLCwiry}wGtdAUH-C-Vu&XP%h*u~u<{=%d2R)M4g>#AqjsKs*H?Li z33%{)(sFWKki?gH@0@xv`QSHLr2g_VzAgY6cECebR-#w&HXVf0MaTKcHTfiY*l6`E zJi|k;{AXm>m*1r&T#SvX1O{IMxIE96tEjUHZFVz9csTQ*zde( zmor(%9|u`sG6#>-t=q$+!LoP+)Ej7T-2DtiU1*H1fYKb4D&c=>TwJD(P$X< z=!}dK^(SX-lW=y>Qnzey23d+?dgz-y3mXFCuAVfWDADq-wk@M&EC#nZm3FJkt}3k) zCzrAnICf0Fzxv|j-}e`N9!&>^K!yT|A~qVEn=@6`rL$h^ZZ!;7a*0@jX(fC#GN;u6ek7!86t&)8P&5QsgO8O1{s07agE0Q zVF>@tt6=Y*2i_F z<%PeBHG1c-K$zdx2FYq)p*I|h~0%wMnb!z>BebHy8GfkMv$&hxqR|VQZ0IeR51ec*#lb<^edkj z`4p+jlyBb;GsA_?W48dg68n$)Xw@MRLOnpHgRd{0 zAvjKqkj33cjS&9LHXfun5=KwIE@_$uoZ+RncWew^9jZfjOnBE@mTTqxPRD#PJgSS< zCmP{P2-rIN>D&$6gM=1fe~lt0HD~ zvszzdBW4GCm?d3|Pf7Gk;{4mI_u_fH{4EafGZuHdUrrwN?aR^{V-?(cWeyKGAFSbS z6YjS_SF_w=$E!B4Ep{ix3Bi|MpABE!K?l9sDlMI?P&ew`-@Cs#;t^7P@FnZ=PNVP6 z{+JKv_9l=^CV+vB7LsgFr{n*O{+;_- zs`3EhK9aAs>T2QX0-@PR;VVtACteR94)y?c|ADtxLih=ndq#sfvi_3JSxKFKu`qr) z-+83SAV?_jtZDdm^7n+eM|ab+#Bm+fMtaifd4hzz0NiY1@N@Wb&x6q%2lps@f!Bkl<)+A~d=TuTS2uAd?$wDXF@L$+Uo1r^REw6k z{}GI%o)1_FMq2EkRva_+askx8&&V(#ArL@DYjb?51!I3abzC_mNsu>dR^sW&6l}iI z)pB7} zXc!MbLVX!`kUX_bkTs@BxukGzXySt5MSO#f=iwR7>f~>1`i*UU*w;1@mi0~6yR&ZX zF;t)XGOF9}em;7Ej?))NN@{6@(Ap&5x8w>SLJiYY@g~3-N~o#CmIg^UR3HS~M5+Xq8@*0q|1QBce$SoDr5db-`x4V_;xo>(rrkuE;VtjBci6U@*+*bt*l3(;PzHV@)>?gwr8aN5W0-|*(2sOIx)!NGwsjtdC)F^ z&^Kk1T!_zSi(9W=0ovp4t%1qwqiGTqR%Lt-%Img})`FAL8J78P81I>_d4wGhMj?kD z*!tn1=^fk_Hgj2WE|sc2Cz#QyTdQ`K)VNA5A42~qbr0bewLEhY<(&dft>Qga?k@?j z3aDM9HKdGSQyqskDL?dRRI1%yyw^m%GGO@z_c&o>$+F5#j$qT=kKid z>Lw1cq2G(TX>Zo@HffKsSnZAo_wt|P{++F2jN<7DV3|BbHIB^rN74=0oKzUhbo-y- z8E&lGlIvNJ+7japN&N(+zL42Ttof5wDi%QNaGF}~F#6I)z!NZYFY zWSQes#S$8Qlu^v64iciQecE71gh6B3>_Z9cfU-Z^T#a?utQWoTaibo;;g8o(be?1Z zug-r8U~6C%rxXW7R2}?0q5yhR1tXZ4+T9Yj-gp$&`|0Kqv0|7#db*CFbly2JhO^&G z2j29mYYns?vg1>)H~>n?Pl;{lD@*mM`(_UY`3Dy>uZA6NO13}Lw){;&)#$aE-06kq z+rVelLz-G>WRN9XcJZXFX5xh=W-*PeUemt?r3McT9nKTX^BP_11WQw~g^8hdByTLT)L`~2lgn`UJB>{sHP9F87 zJ)OGW`g8baRe*9-ceHa6KxvZxddDxjKRlL-XcszU)>VZ(vSu-XZesR3reQ}KOtBh4vCo~&@BxPH&P+hSz z2+QH>p1yfWrzwN#n=R=Yg?Stm%pU1>XqJdwxELBFUO`uHv%GPnv>OZhh5S(e%VE*` zdyj*CWadx0KiFx)!>GoNb|6oI$Cj_-UUs)3gjt-T(*mfs1^bVno?RUrRX+aX#P*y# zmaD=1a>D+BEjZHmWVmk{OlQ*D(z18PPkl=mvP}vNR3qQ;eANf3DN3bk=uaiocS7@^ zu%hK^T;J4n@6~{P*#)~SVum+POpt@{5}(o5%}N%`-@3Mqt4xSqWxspq7sDtyZU+XO z-+e!xo#GXnJ8l!V*@67|@JsNNj`sWU3OT&fDAU-29EBozQ!O>zW1l$gQ6#UWy!r&{ zw8X0^8H;S4EI#z``@Jiwq?Gv{*tov$Ww1hRUizPb{jgJ@X8MsifeMRCg|GtYcxE&9 z&+eC?zg1rvJ9RPQ+c<&{VQy+~;%Lon=t$}@q>+;wzIw>g`f51Hx>HOu zYU*mOxS(3UiI;T;+QZ5E#U%mFEz-;E^F-H&;h1B!#sdZ-o(rvus^1?Y;;8#SDc z%OR060*EDN?MSYkcwRBJZQnv`lXJa#>JAEl1m@G9T5lV#y4y-npJPhH6hsi{mSiwb zlz{+)4s2o=VadKe*P31)w+^eXFbs78Qj-6o?hu5|H6n(780ytQxX(0pKS{98&OwRA z@MK^kN8wGZt-r>myhi*_zxQ`QBWIg!S0R2q-0QO~q032A_ct=)@#(Ab? z_H_X3E%OH7{OvZ2;1jz~HGqrb9^uHCG3-chDs-80;^OVrX`fff9jaa{TgE&2Xw#!V zKRn@q_ZNPICFmvxKWP0iZ9f%R8_#Fx&2B9ydt~-#=qElq@|~^HuGxx^I z#By?hi!bmk^{zA0y8So);F$XbQ1BWD3GMHtd7<-bx9~M~y1nI~6$+NzypZXvOnwCh zE*QIeOj<_uMDthi*lVl}qa(5=FFP{n2o)wZ;66Ym8xFVS8B^8h{aF!u9HXF;e_26> zUoZb9BYUs?ov)S2!M8A>LH=X`1<~s~Zi^q>7k@Hx87Z%ld%7+lPNJMJ^wv=1+ZtIL zp)c;cLpr7fOsoxHbyapqC{Bn>>OHwya(mt=hp=T#Vz|-fgE(l+jM3y9v_IWCBrt zx|7Dkgq#llI1Bc_(rMDWt$GX6X4dR&9&3DBb5yO2h6@_He3q#dP>?QxeKHG5L+a9lCs=4PgddsdJ0- zX4|NDkVdKi+u(Qq&&JG?(7+m5pFXdL+!z4Q(GJ0M6tMNmeQ$6(zjyNZuHHDT zh#;zTxR#9T_mg(rEh-n;SWV9A6(9Yq|72kH)bE=@%*2I>*#N9+#2d10c`b8dc0K0y z31rYZec~Yfs;e*QY~tckG`v8JZSJ7;>~VUuf2!=9PXHC^;mby?T+*dis93 z+IXj8<_B8C>+3*eeIXm7cjpWs`ZXr$<-Q8xrTV+?EidFLS6OcgqkQg| z500&SI5CdS5TYr1R;7g==XXRH_@5z(B@sx-ChPE)kAaE33O;qml2EZA=c^t{2Euh$ zxEwOBI`^IS+SG9oqKDicnuP3ty?Pg#cVej`xJm}C<9*u!E0d2Y2Z~gcG9%F#%&I9+ z;U4J_sJ=nvpPg!5+HM5W>qzE5D2dX5W;D)@JH^cD%4N(ncIGag5mA>Ln6L&n>%S94xek^s{D2#GGaA zI+q{@^D_LT&+dnDKx^Xpo+x6e*+mr91o(Bw#D`x+J(AC}hvOtnL?)QN=kU0KWuY)J z|ELdWVXbHUJuw33R;`?8VJK`T`hcN$v=H`h0EX<_ zy=)HFD_87B0x-)E45DvlYi?(5XLio53{e;dZP@m8cgtPg;Vk)|K_(u)F=`N1sC2~e zx;?{(y?YJ$?MEIWXLN@{4#oM=e;|b(#-0*O^*LgnjzU2$rrFn}J~gto9~g!xfaR2X z?e1zC9Bb;_BEWeUQEi23Ch1_%l@NVDy$d=W#c%Nmf~q_jYkA9YDHIR?^DKB5x04zA zz72MtnmowfZ*$AA-jZEZDN*)tyy2Q~IG0Hf!Y}w@(z?iv7fg~h4v0o>=Sw;=c2Emg z&&lm;)YD-*LA!ge9>*MD6V~3Bbty_UWZTOK&|*ga>RwRS=kS#9uqfV8IlgbJ?|;0F zaEUaMwAcC8zRpaZ@PTfOg4`0IHZ2cb8|)p9D|71Y$W91kaj7{R_E@16_j4~<$J-cs;I%3 zzms%<2DjERIC;8yn)fb=3>PdIN(LUy|CRUN=()_5Y}221gdGfm&_owASinY!XgG}Z zKF*C0=Qe)fY(tFlDiNLO({P0RbzP~Apy~baPef>}S3c=Ly+h7v={F{BbXJPl$2Eih z^+KLjTeynU4MW#RNlAx3d-PD#=qc4;KV?@G4bzW{#!!(Df->Ju&5ZY#MlO9V)Xl8k ze<&;-_hB_&y(K$Ps^jU!m$jEqP!J-m-ov4<`^DVMyjDNzbwf7gn!F+?LIi`|+bg>p z45Usq>7YKJQpAwxSvBXq1c90gz1AZ4XzYX2iUS;9t5$dHc1X8{|MGS?0XtnP5+Nla zwf%Q5I-Q320efw=Q zRR!-Qb)qU{EGz@5x*56BZIcx=&La?B^4*q|zwsBGtEM&nE7waxR=SZ2+T&Ccb{Mf5 ziZY2afk&8hEQiHA5qDAPT=DQky>EY57XB&on9O(*=sUK7aG~)ZAKYYuKSFv-3iEh( zCx9(lWv)l)MPa4uW;7d^U9~bn5eOvf)LI9*MEs7+yX_~QpjQB$=Si{iZ`nFM{W8jXc%R@ z28asJ$&mm)>zT6l($`+!{Z9{Hqc`Wmq-x5}Y<2Y_g!pf?A^*50_AK&lW~;R!r-E#{ zM7M}IGo}`LVovfKu5-dt%fO*nznN9&?t-#`w&yJp3Qd%0APfc(1(i{WbFIJ^!uHtN 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 XPWs>T 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%0DMjXK`kW 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 + {...} + +``` + + +![Screenshot of Stack Management empty state with a provided solution navigation shown on the left, outlined in pink.](../assets/kibana_template_solution_nav.png) + +![Screenshots of Stack Management page in mobile view. Menu closed on the left, menu open on the right.](../assets/kibana_template_solution_nav_mobile.png) diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 7f2d0768a1fb9d..a585a0fc7542f5 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -9,7 +9,7 @@ pageLoadAssetSize: charts: 195358 cloud: 21076 console: 46091 - core: 414000 + core: 432925 crossClusterReplication: 65408 dashboard: 374194 dashboardEnhanced: 65646 diff --git a/src/core/public/rendering/_base.scss b/src/core/public/rendering/_base.scss index 936b41e7682bb7..3a748f3ceb6fd3 100644 --- a/src/core/public/rendering/_base.scss +++ b/src/core/public/rendering/_base.scss @@ -49,6 +49,13 @@ top: $headerHeight; height: calc(100% - #{$headerHeight}); } + + @include euiBreakpoint('m', 'l', 'xl') { + .euiPageSideBar--sticky { + max-height: calc(100vh - #{$headerHeight}); + top: #{$headerHeight}; + } + } } .kbnBody { diff --git a/src/plugins/kibana_react/public/page_template/__snapshots__/page_template.test.tsx.snap b/src/plugins/kibana_react/public/page_template/__snapshots__/page_template.test.tsx.snap index 89fa05615a0391..a80e3a67fb2db0 100644 --- a/src/plugins/kibana_react/public/page_template/__snapshots__/page_template.test.tsx.snap +++ b/src/plugins/kibana_react/public/page_template/__snapshots__/page_template.test.tsx.snap @@ -2,6 +2,7 @@ exports[`KibanaPageTemplate render basic template 1`] = ` `; exports[`KibanaPageTemplate render custom empty prompt only 1`] = ` @@ -33,6 +45,7 @@ exports[`KibanaPageTemplate render custom empty prompt only 1`] = ` exports[`KibanaPageTemplate render custom empty prompt with page header 1`] = ` @@ -58,6 +76,12 @@ exports[`KibanaPageTemplate render custom empty prompt with page header 1`] = ` exports[`KibanaPageTemplate render default empty prompt 1`] = ` @@ -72,7 +96,76 @@ exports[`KibanaPageTemplate render default empty prompt 1`] = ` test

} + iconColor="" iconType="test" />
`; + +exports[`KibanaPageTemplate render solutionNav 1`] = ` + + } + pageSideBarProps={ + Object { + "className": "kbnPageTemplate__pageSideBar", + } + } + restrictWidth={true} +/> +`; diff --git a/src/plugins/kibana_react/public/page_template/page_template.scss b/src/plugins/kibana_react/public/page_template/page_template.scss new file mode 100644 index 00000000000000..4b8513311114d8 --- /dev/null +++ b/src/plugins/kibana_react/public/page_template/page_template.scss @@ -0,0 +1,15 @@ +$euiSideNavEmphasizedBackgroundColor: transparentize($euiColorLightShade, .7); + +.kbnPageTemplate__pageSideBar { + padding: $euiSizeL; + background: + linear-gradient(160deg, $euiSideNavEmphasizedBackgroundColor 0, $euiSideNavEmphasizedBackgroundColor $euiSizeXL, rgba(#FFF, 0) 0), + linear-gradient(175deg, $euiSideNavEmphasizedBackgroundColor 0, $euiSideNavEmphasizedBackgroundColor $euiSize, rgba(#FFF, 0) 0); +} + +@include euiBreakpoint('xs','s') { + .kbnPageTemplate__pageSideBar { + width: auto; + padding: 0; + } +} diff --git a/src/plugins/kibana_react/public/page_template/page_template.test.tsx b/src/plugins/kibana_react/public/page_template/page_template.test.tsx index 2ad9a81e7916c9..43f96a6c2b98cf 100644 --- a/src/plugins/kibana_react/public/page_template/page_template.test.tsx +++ b/src/plugins/kibana_react/public/page_template/page_template.test.tsx @@ -10,6 +10,46 @@ import React from 'react'; import { shallow } from 'enzyme'; import { KibanaPageTemplate } from './page_template'; import { EuiEmptyPrompt } from '@elastic/eui'; +import { KibanaPageTemplateSolutionNavProps } from './solution_nav'; + +const navItems: KibanaPageTemplateSolutionNavProps['items'] = [ + { + name: 'Ingest', + id: '1', + items: [ + { + name: 'Ingest Node Pipelines', + id: '1.1', + }, + { + name: 'Logstash Pipelines', + id: '1.2', + }, + { + name: 'Beats Central Management', + id: '1.3', + }, + ], + }, + { + name: 'Data', + id: '2', + items: [ + { + name: 'Index Management', + id: '2.1', + }, + { + name: 'Index Lifecycle Policies', + id: '2.2', + }, + { + name: 'Snapshot and Restore', + id: '2.3', + }, + ], + }, +]; describe('KibanaPageTemplate', () => { test('render default empty prompt', () => { @@ -66,4 +106,23 @@ describe('KibanaPageTemplate', () => { ); expect(component).toMatchSnapshot(); }); + + test('render solutionNav', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); }); diff --git a/src/plugins/kibana_react/public/page_template/page_template.tsx b/src/plugins/kibana_react/public/page_template/page_template.tsx index eb834d00402ef0..0bbf97ca6ddb57 100644 --- a/src/plugins/kibana_react/public/page_template/page_template.tsx +++ b/src/plugins/kibana_react/public/page_template/page_template.tsx @@ -5,10 +5,21 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +import './page_template.scss'; -import { EuiEmptyPrompt, EuiPageTemplate, EuiPageTemplateProps } from '@elastic/eui'; import React, { FunctionComponent } from 'react'; +import classNames from 'classnames'; + +import { EuiEmptyPrompt, EuiPageTemplate, EuiPageTemplateProps } from '@elastic/eui'; + +import { + KibanaPageTemplateSolutionNav, + KibanaPageTemplateSolutionNavProps, +} from './solution_nav/solution_nav'; +/** + * A thin wrapper around EuiPageTemplate with a few Kibana specific additions + */ export type KibanaPageTemplateProps = EuiPageTemplateProps & { /** * Changes the template type depending on other props provided. @@ -17,6 +28,10 @@ export type KibanaPageTemplateProps = EuiPageTemplateProps & { * With `pageHeader` and `children`: Uses `centeredContent` */ isEmptyState?: boolean; + /** + * Quick creation of EuiSideNav. Hooks up mobile instance too + */ + solutionNav?: KibanaPageTemplateSolutionNavProps; }; export const KibanaPageTemplate: FunctionComponent = ({ @@ -27,6 +42,8 @@ export const KibanaPageTemplate: FunctionComponent = ({ restrictWidth = true, bottomBar, bottomBarProps, + pageSideBar, + solutionNav, ...rest }) => { // Needed for differentiating between union types @@ -38,6 +55,13 @@ export const KibanaPageTemplate: FunctionComponent = ({ }; } + /** + * Create the solution nav component + */ + if (solutionNav) { + pageSideBar = ; + } + /** * An easy way to create the right content for empty pages */ @@ -48,6 +72,7 @@ export const KibanaPageTemplate: FunctionComponent = ({ children = ( {pageTitle} : undefined} body={description ?

{description}

: undefined} actions={rightSideItems} @@ -62,8 +87,14 @@ export const KibanaPageTemplate: FunctionComponent = ({ return ( diff --git a/src/plugins/kibana_react/public/page_template/solution_nav/__snapshots__/solution_nav.test.tsx.snap b/src/plugins/kibana_react/public/page_template/solution_nav/__snapshots__/solution_nav.test.tsx.snap new file mode 100644 index 00000000000000..02673577095348 --- /dev/null +++ b/src/plugins/kibana_react/public/page_template/solution_nav/__snapshots__/solution_nav.test.tsx.snap @@ -0,0 +1,238 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`KibanaPageTemplateSolutionNav accepts EuiSideNavProps 1`] = ` +
+ +

+ + Solution + +

+
+ + + + } + toggleOpenOnMobile={[Function]} + /> +
+`; + +exports[`KibanaPageTemplateSolutionNav renders 1`] = ` +
+ +

+ + Solution + +

+
+ + + + } + toggleOpenOnMobile={[Function]} + /> +
+`; + +exports[`KibanaPageTemplateSolutionNav renders with icon 1`] = ` +
+ +

+ + + Solution + +

+
+ + + + + } + toggleOpenOnMobile={[Function]} + /> +
+`; diff --git a/src/plugins/kibana_react/public/page_template/solution_nav/__snapshots__/solution_nav_avatar.test.tsx.snap b/src/plugins/kibana_react/public/page_template/solution_nav/__snapshots__/solution_nav_avatar.test.tsx.snap new file mode 100644 index 00000000000000..ede09c5652c310 --- /dev/null +++ b/src/plugins/kibana_react/public/page_template/solution_nav/__snapshots__/solution_nav_avatar.test.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`KibanaPageTemplateSolutionNavAvatar renders 1`] = ` + +`; diff --git a/src/plugins/kibana_react/public/page_template/solution_nav/index.ts b/src/plugins/kibana_react/public/page_template/solution_nav/index.ts new file mode 100644 index 00000000000000..abbcde9a084869 --- /dev/null +++ b/src/plugins/kibana_react/public/page_template/solution_nav/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav'; +export { + KibanaPageTemplateSolutionNavAvatar, + KibanaPageTemplateSolutionNavAvatarProps, +} from './solution_nav_avatar'; diff --git a/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.scss b/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.scss new file mode 100644 index 00000000000000..bdb88b2ab7baae --- /dev/null +++ b/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.scss @@ -0,0 +1,22 @@ +.kbnPageTemplateSolutionNav__title { + margin-bottom: $euiSizeL; +} + +@include euiBreakpoint('xs','s') { + .kbnPageTemplateSolutionNav { + // TODO: Fix in EUI + .euiSideNav__mobileToggle { + height: auto; + font-size: $euiFontSizeM; + + .euiButtonEmpty__text { + overflow: visible; + } + } + } + + // Rely on the `mobileToggle` of the EuiSideNav component to title the navigation list + .kbnPageTemplateSolutionNav__title { + display: none; + } +} diff --git a/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.test.tsx b/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.test.tsx new file mode 100644 index 00000000000000..1ba6cc924cda1f --- /dev/null +++ b/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.test.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav'; + +const items: KibanaPageTemplateSolutionNavProps['items'] = [ + { + name: 'Ingest', + id: '1', + items: [ + { + name: 'Ingest Node Pipelines', + id: '1.1', + }, + { + name: 'Logstash Pipelines', + id: '1.2', + }, + { + name: 'Beats Central Management', + id: '1.3', + }, + ], + }, + { + name: 'Data', + id: '2', + items: [ + { + name: 'Index Management', + id: '2.1', + }, + { + name: 'Index Lifecycle Policies', + id: '2.2', + }, + { + name: 'Snapshot and Restore', + id: '2.3', + }, + ], + }, +]; + +describe('KibanaPageTemplateSolutionNav', () => { + test('renders', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + + test('renders with icon', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + test('accepts EuiSideNavProps', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.tsx b/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.tsx new file mode 100644 index 00000000000000..4aa456f716dbda --- /dev/null +++ b/src/plugins/kibana_react/public/page_template/solution_nav/solution_nav.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import './solution_nav.scss'; + +import React, { FunctionComponent, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiTitle, EuiSideNav, EuiSideNavProps, htmlIdGenerator } from '@elastic/eui'; + +import { + KibanaPageTemplateSolutionNavAvatar, + KibanaPageTemplateSolutionNavAvatarProps, +} from './solution_nav_avatar'; + +export type KibanaPageTemplateSolutionNavProps = EuiSideNavProps<{}> & { + /** + * Name of the solution, i.e. "Observability" + */ + name: KibanaPageTemplateSolutionNavAvatarProps['name']; + /** + * Solution logo, i.e. "logoObservability" + */ + icon?: KibanaPageTemplateSolutionNavAvatarProps['iconType']; +}; + +/** + * A wrapper around EuiSideNav but also creates the appropriate title with optional solution logo + */ +export const KibanaPageTemplateSolutionNav: FunctionComponent = ({ + name, + icon, + items, + ...rest +}) => { + const [isSideNavOpenOnMobile, setisSideNavOpenOnMobile] = useState(false); + const toggleOpenOnMobile = () => { + setisSideNavOpenOnMobile(!isSideNavOpenOnMobile); + }; + + /** + * Create the avatar. + */ + let solutionAvatar; + if (icon) { + solutionAvatar = ; + } + + /** + * Create the required title. + * a11y: Since the heading can't be nested inside `